diff --git a/src/main/index.ts b/src/main/index.ts index 8d432d5f281..bca05a3b85c 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -14,7 +14,13 @@ import { registerShellHandlers } from './ipc/shell' import { registerSessionHandlers } from './ipc/session' import { registerUIHandlers } from './ipc/ui' import { warmSystemFontFamilies } from './system-fonts' -import { setupAutoUpdater, checkForUpdates, getUpdateStatus, quitAndInstall } from './updater' +import { + setupAutoUpdater, + checkForUpdates, + checkForUpdatesFromMenu, + getUpdateStatus, + quitAndInstall +} from './updater' let mainWindow: BrowserWindow | null = null let store: Store | null = null @@ -113,7 +119,7 @@ app.whenReady().then(() => { { role: 'about' }, { label: 'Check for Updates...', - click: () => checkForUpdates() + click: () => checkForUpdatesFromMenu() }, { label: 'Settings', diff --git a/src/main/updater.ts b/src/main/updater.ts index 8cf25c7c614..5b6674ad9f1 100644 --- a/src/main/updater.ts +++ b/src/main/updater.ts @@ -26,6 +26,54 @@ export function checkForUpdates(): void { }) } +/** Menu-triggered check that shows native dialogs for feedback */ +export function checkForUpdatesFromMenu(): void { + if (!app.isPackaged || is.dev) { + dialog.showMessageBox({ type: 'info', message: 'You\u2019re on the latest version.' }) + return + } + + sendStatus({ state: 'checking' }) + + const onAvailable = (): void => { + cleanup() + } + const onNotAvailable = (): void => { + cleanup() + dialog.showMessageBox({ type: 'info', message: 'You\u2019re on the latest version.' }) + } + const onError = (err: Error): void => { + cleanup() + dialog.showMessageBox({ + type: 'error', + title: 'Update Error', + message: 'Could not check for updates.', + detail: err?.message + }) + } + + function cleanup(): void { + autoUpdater.off('update-available', onAvailable) + autoUpdater.off('update-not-available', onNotAvailable) + autoUpdater.off('error', onError) + } + + autoUpdater.once('update-available', onAvailable) + autoUpdater.once('update-not-available', onNotAvailable) + autoUpdater.once('error', onError) + + autoUpdater.checkForUpdates().catch((err) => { + sendStatus({ state: 'error', message: String(err?.message ?? err) }) + cleanup() + dialog.showMessageBox({ + type: 'error', + title: 'Update Error', + message: 'Could not check for updates.', + detail: String(err?.message ?? err) + }) + }) +} + export function quitAndInstall(): void { autoUpdater.quitAndInstall() } @@ -38,6 +86,10 @@ export function setupAutoUpdater(mainWindow: BrowserWindow): void { autoUpdater.autoDownload = true autoUpdater.autoInstallOnAppQuit = true + // Use allowPrerelease to bypass broken /releases/latest endpoint (returns 406) + // and instead parse the version directly from the atom feed which works reliably. + // This is safe since we don't publish prerelease versions. + autoUpdater.allowPrerelease = true autoUpdater.on('checking-for-update', () => { sendStatus({ state: 'checking' })