diff --git a/apps/stage-tamagotchi/package.json b/apps/stage-tamagotchi/package.json index 2789b25b5..0cd389680 100644 --- a/apps/stage-tamagotchi/package.json +++ b/apps/stage-tamagotchi/package.json @@ -112,6 +112,7 @@ "reka-ui": "^2.9.2", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", + "semver": "^7.7.4", "shiki": "^4.0.2", "splitpanes": "catalog:", "three": "^0.183.2", @@ -161,6 +162,7 @@ "@types/audioworklet": "catalog:", "@types/culori": "^4.0.1", "@types/nprogress": "^0.2.3", + "@types/semver": "^7.7.1", "@types/splitpanes": "catalog:", "@types/three": "^0.183.1", "@types/yauzl": "^2.10.3", diff --git a/apps/stage-tamagotchi/src/main/services/electron/auto-updater.test.ts b/apps/stage-tamagotchi/src/main/services/electron/auto-updater.test.ts index 6bf6f0f54..ae3365ddd 100644 --- a/apps/stage-tamagotchi/src/main/services/electron/auto-updater.test.ts +++ b/apps/stage-tamagotchi/src/main/services/electron/auto-updater.test.ts @@ -139,6 +139,15 @@ describe('setupAutoUpdater', () => { expect(service.state.diagnostics).not.toHaveProperty('uninstallExists') }) + it('does not treat build metadata as prerelease', async () => { + appMock.getVersion.mockReturnValue('1.2.3+build-1') + + const { setupAutoUpdater } = await import('./auto-updater') + setupAutoUpdater() + + expect(updaterState.instance.allowPrerelease).toBe(false) + }) + it('uses silent relaunch install on Windows only', async () => { const originalPlatform = process.platform vi.stubEnv('TEST_PLATFORM', '') diff --git a/apps/stage-tamagotchi/src/main/services/electron/auto-updater.ts b/apps/stage-tamagotchi/src/main/services/electron/auto-updater.ts index 5d983e4c5..7cd3e6495 100644 --- a/apps/stage-tamagotchi/src/main/services/electron/auto-updater.ts +++ b/apps/stage-tamagotchi/src/main/services/electron/auto-updater.ts @@ -6,6 +6,7 @@ import type { UpdateInfo } from 'electron-updater' import process from 'node:process' import electronUpdater from 'electron-updater' +import semver from 'semver' import { is } from '@electron-toolkit/utils' import { useLogg } from '@guiiai/logg' @@ -14,6 +15,7 @@ import { errorMessageFrom, tryCatch } from '@moeru/std' import { committerDate } from '~build/git' import { app } from 'electron' import { Semaphore } from 'es-toolkit' +import { isWindows } from 'std-env' import { autoUpdater as autoUpdaterEventa, @@ -63,9 +65,13 @@ export interface AutoUpdater { subscribe: (callback: (state: AutoUpdaterState) => void) => () => void } +function isPrereleaseVersion(version: string) { + return (semver.prerelease(version)?.length ?? 0) > 0 +} + export function setupAutoUpdater(): AutoUpdater { const semaphore = new Semaphore(1) - const isPrereleaseBuild = app.getVersion().includes('-') + const isPrereleaseBuild = isPrereleaseVersion(app.getVersion()) const log = useLogg('auto-updater').useGlobalConfig() const autoUpdater = fromImported() const feedUrlOverride = getUpdateServerOverride() @@ -173,7 +179,7 @@ export function setupAutoUpdater(): AutoUpdater { await semaphore.acquire() try { - if (process.platform === 'win32') + if (isWindows) autoUpdater.quitAndInstall(true, true) else autoUpdater.quitAndInstall() @@ -209,31 +215,21 @@ export function createAutoUpdaterService(params: { context: MainContext, window: tryCatch(() => context.emit(electronAutoUpdaterStateChanged, state)) }) - const cleanups: Array<() => void> = [unsubscribe] - - cleanups.push( + const cleanups: Array<() => void> = [ + unsubscribe, defineInvokeHandler(context, autoUpdaterEventa.getState, () => service.state), - ) - - cleanups.push( defineInvokeHandler(context, autoUpdaterEventa.checkForUpdates, async () => { await service.checkForUpdates().catch(error => log.withError(error).error('checkForUpdates() failed')) return service.state }), - ) - - cleanups.push( defineInvokeHandler(context, autoUpdaterEventa.downloadUpdate, async () => { await service.downloadUpdate() return service.state }), - ) - - cleanups.push( defineInvokeHandler(context, autoUpdaterEventa.quitAndInstall, async () => { await service.quitAndInstall() }), - ) + ] const cleanup = () => { for (const fn of cleanups) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 59f9f161b..7bd541f4d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1297,6 +1297,9 @@ importers: remark-rehype: specifier: ^11.1.2 version: 11.1.2 + semver: + specifier: ^7.7.4 + version: 7.7.4 shiki: specifier: ^4.0.2 version: 4.0.2 @@ -1439,6 +1442,9 @@ importers: '@types/nprogress': specifier: ^0.2.3 version: 0.2.3 + '@types/semver': + specifier: ^7.7.1 + version: 7.7.1 '@types/splitpanes': specifier: 'catalog:' version: 2.2.6 @@ -9491,6 +9497,9 @@ packages: '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + '@types/semver@7.7.1': + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + '@types/slice-ansi@4.0.0': resolution: {integrity: sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==} @@ -23397,6 +23406,8 @@ snapshots: dependencies: '@types/node': 24.12.0 + '@types/semver@7.7.1': {} + '@types/slice-ansi@4.0.0': {} '@types/splitpanes@2.2.6':