@cats-inc/cats-platform 0.1.1 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +2 -2
- package/README.md +6 -0
- package/build/desktop/bootstrapPage.d.ts.map +1 -1
- package/build/desktop/bootstrapPage.js +81 -4
- package/build/desktop/bootstrapPage.js.map +1 -1
- package/build/desktop/config.d.ts +11 -1
- package/build/desktop/config.d.ts.map +1 -1
- package/build/desktop/config.js +5 -2
- package/build/desktop/config.js.map +1 -1
- package/build/desktop/contracts.d.ts +66 -11
- package/build/desktop/contracts.d.ts.map +1 -1
- package/build/desktop/contracts.js +50 -1
- package/build/desktop/contracts.js.map +1 -1
- package/build/desktop/hostState.d.ts +4 -3
- package/build/desktop/hostState.d.ts.map +1 -1
- package/build/desktop/hostState.js +22 -30
- package/build/desktop/hostState.js.map +1 -1
- package/build/desktop/hostVersion.d.ts +1 -0
- package/build/desktop/hostVersion.d.ts.map +1 -1
- package/build/desktop/hostVersion.js +29 -5
- package/build/desktop/hostVersion.js.map +1 -1
- package/build/desktop/main.js +234 -37
- package/build/desktop/main.js.map +1 -1
- package/build/desktop/packaging.d.ts.map +1 -1
- package/build/desktop/packaging.js +10 -4
- package/build/desktop/packaging.js.map +1 -1
- package/build/desktop/preload.cjs +29 -0
- package/build/desktop/preload.cjs.map +1 -1
- package/build/desktop/processSupervisor.d.ts +2 -0
- package/build/desktop/processSupervisor.d.ts.map +1 -1
- package/build/desktop/processSupervisor.js +28 -13
- package/build/desktop/processSupervisor.js.map +1 -1
- package/build/desktop/readiness.d.ts +2 -2
- package/build/desktop/readiness.d.ts.map +1 -1
- package/build/desktop/readiness.js +2 -2
- package/build/desktop/readiness.js.map +1 -1
- package/build/desktop/releaseDescriptor.d.ts +85 -0
- package/build/desktop/releaseDescriptor.d.ts.map +1 -0
- package/build/desktop/releaseDescriptor.js +246 -0
- package/build/desktop/releaseDescriptor.js.map +1 -0
- package/build/desktop/tray.d.ts +1 -0
- package/build/desktop/tray.d.ts.map +1 -1
- package/build/desktop/tray.js +26 -0
- package/build/desktop/tray.js.map +1 -1
- package/build/desktop/trayMenu.d.ts +22 -1
- package/build/desktop/trayMenu.d.ts.map +1 -1
- package/build/desktop/trayMenu.js +61 -0
- package/build/desktop/trayMenu.js.map +1 -1
- package/build/desktop/updateInstallHandoff.d.ts +30 -0
- package/build/desktop/updateInstallHandoff.d.ts.map +1 -0
- package/build/desktop/updateInstallHandoff.js +39 -0
- package/build/desktop/updateInstallHandoff.js.map +1 -0
- package/build/desktop/updateIpc.d.ts +42 -0
- package/build/desktop/updateIpc.d.ts.map +1 -0
- package/build/desktop/updateIpc.js +71 -0
- package/build/desktop/updateIpc.js.map +1 -0
- package/build/desktop/updateManager.d.ts +76 -0
- package/build/desktop/updateManager.d.ts.map +1 -0
- package/build/desktop/updateManager.js +342 -0
- package/build/desktop/updateManager.js.map +1 -0
- package/build/desktop/updateNotifications.d.ts +64 -0
- package/build/desktop/updateNotifications.d.ts.map +1 -0
- package/build/desktop/updateNotifications.js +143 -0
- package/build/desktop/updateNotifications.js.map +1 -0
- package/build/desktop/updaterAdapter.d.ts +72 -0
- package/build/desktop/updaterAdapter.d.ts.map +1 -0
- package/build/desktop/updaterAdapter.js +198 -0
- package/build/desktop/updaterAdapter.js.map +1 -0
- package/build/renderer/assets/{ActiveSessionPermissionChip-BYr8cDpb.js → ActiveSessionPermissionChip-BoDkKkmi.js} +1 -1
- package/build/renderer/assets/{App-BbuTWT6Y.js → App-Bs1eRarv.js} +1 -1
- package/build/renderer/assets/{App-B13AzNko.js → App-C4S1Wa9f.js} +1 -1
- package/build/renderer/assets/{App-n-RtGh42.js → App-CNJj5gi9.js} +1 -1
- package/build/renderer/assets/{WorkspaceAppRoutes-BktWrQK-.js → WorkspaceAppRoutes-CFAuhWGF.js} +1 -1
- package/build/renderer/assets/app-uJJx-k1S.js +43 -0
- package/build/renderer/assets/{conversationSidebarRecentEntries-BNPz3X1V.js → conversationSidebarRecentEntries-CPGopayy.js} +1 -1
- package/build/renderer/assets/{useDraftSessionChips-3z_Je4ju.js → useDraftSessionChips-BsOdYfWw.js} +1 -1
- package/build/renderer/index.html +1 -1
- package/build/server/app/renderer/settings/settingsDesktopErrorLabels.d.ts +5 -0
- package/build/server/app/renderer/settings/settingsDesktopErrorLabels.d.ts.map +1 -0
- package/build/server/app/renderer/settings/settingsDesktopErrorLabels.js +16 -0
- package/build/server/app/renderer/settings/settingsDesktopErrorLabels.js.map +1 -0
- package/build/server/app/renderer/settings/settingsDesktopPreferences.d.ts +11 -0
- package/build/server/app/renderer/settings/settingsDesktopPreferences.d.ts.map +1 -0
- package/build/server/app/renderer/settings/settingsDesktopPreferences.js +30 -0
- package/build/server/app/renderer/settings/settingsDesktopPreferences.js.map +1 -0
- package/build/server/app/renderer/settings/settingsDesktopUpdateLabels.d.ts +31 -0
- package/build/server/app/renderer/settings/settingsDesktopUpdateLabels.d.ts.map +1 -0
- package/build/server/app/renderer/settings/settingsDesktopUpdateLabels.js +101 -0
- package/build/server/app/renderer/settings/settingsDesktopUpdateLabels.js.map +1 -0
- package/build/server/app/server/index.js +1 -1
- package/build/server/app/server/index.js.map +1 -1
- package/build/server/app/server/platformSetupRoutes.d.ts.map +1 -1
- package/build/server/app/server/platformSetupRoutes.js +42 -5
- package/build/server/app/server/platformSetupRoutes.js.map +1 -1
- package/build/server/app/server/requestRouter.d.ts.map +1 -1
- package/build/server/app/server/requestRouter.js +2 -0
- package/build/server/app/server/requestRouter.js.map +1 -1
- package/build/server/design/components/runtimeChips.d.ts +1 -1
- package/build/server/design/components/runtimeChips.d.ts.map +1 -1
- package/build/server/design/components/runtimeChips.js +4 -1
- package/build/server/design/components/runtimeChips.js.map +1 -1
- package/build/server/index.js +12 -1
- package/build/server/index.js.map +1 -1
- package/build/server/platform/auth/sessionSecretProvisioning.d.ts +23 -0
- package/build/server/platform/auth/sessionSecretProvisioning.d.ts.map +1 -0
- package/build/server/platform/auth/sessionSecretProvisioning.js +291 -0
- package/build/server/platform/auth/sessionSecretProvisioning.js.map +1 -0
- package/build/server/products/code/livePreview/realProcessAdapter.d.ts.map +1 -1
- package/build/server/products/code/livePreview/realProcessAdapter.js +7 -1
- package/build/server/products/code/livePreview/realProcessAdapter.js.map +1 -1
- package/build/server/products/code/state/appExport.d.ts.map +1 -1
- package/build/server/products/code/state/appExport.js +2 -0
- package/build/server/products/code/state/appExport.js.map +1 -1
- package/build/server/shared/desktopRecoveryBridge.d.ts +46 -0
- package/build/server/shared/desktopRecoveryBridge.d.ts.map +1 -1
- package/build/server/shared/desktopRecoveryBridge.js +20 -0
- package/build/server/shared/desktopRecoveryBridge.js.map +1 -1
- package/build/server/shared/i18n/catalogs/en.d.ts.map +1 -1
- package/build/server/shared/i18n/catalogs/en.js +37 -0
- package/build/server/shared/i18n/catalogs/en.js.map +1 -1
- package/build/server/shared/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/build/server/shared/i18n/catalogs/zh-TW.js +35 -0
- package/build/server/shared/i18n/catalogs/zh-TW.js.map +1 -1
- package/build/server/shared/i18n/index.d.ts +35 -0
- package/build/server/shared/i18n/index.d.ts.map +1 -1
- package/build/server/shared/i18n/messageKeys.d.ts +35 -0
- package/build/server/shared/i18n/messageKeys.d.ts.map +1 -1
- package/build/server/shared/i18n/messageKeys.js +35 -0
- package/build/server/shared/i18n/messageKeys.js.map +1 -1
- package/build/server/shared/loadProjectEnvFile.d.ts.map +1 -1
- package/build/server/shared/loadProjectEnvFile.js +18 -19
- package/build/server/shared/loadProjectEnvFile.js.map +1 -1
- package/build/server/shared/platformChildProcessEnv.d.ts +2 -0
- package/build/server/shared/platformChildProcessEnv.d.ts.map +1 -0
- package/build/server/shared/platformChildProcessEnv.js +22 -0
- package/build/server/shared/platformChildProcessEnv.js.map +1 -0
- package/package.json +19 -27
- package/scripts/build-desktop-installer.mjs +438 -37
- package/scripts/build-test-ui.mjs +13 -2
- package/scripts/generate-desktop-release-descriptor.mjs +258 -0
- package/scripts/validate-release-assets.mjs +422 -0
- package/scripts/validate-release-version.mjs +217 -0
- package/scripts/windows/Test-WindowsInstallerSmoke.ps1 +55 -1
- package/build/desktop/update.d.ts +0 -24
- package/build/desktop/update.d.ts.map +0 -1
- package/build/desktop/update.js +0 -173
- package/build/desktop/update.js.map +0 -1
- package/build/renderer/assets/app-DnVQMpW_.js +0 -43
- package/build/server/app/renderer/settings/settingsDesktopStartupErrorLabels.d.ts +0 -5
- package/build/server/app/renderer/settings/settingsDesktopStartupErrorLabels.d.ts.map +0 -1
- package/build/server/app/renderer/settings/settingsDesktopStartupErrorLabels.js +0 -11
- package/build/server/app/renderer/settings/settingsDesktopStartupErrorLabels.js.map +0 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { DESKTOP_UPDATE_CHECK_CHANNEL, DESKTOP_UPDATE_DOWNLOAD_CHANNEL, DESKTOP_UPDATE_EVENT_CHANNEL, DESKTOP_UPDATE_INSTALL_CHANNEL, DESKTOP_UPDATE_SNAPSHOT_CHANNEL, } from './contracts.js';
|
|
2
|
+
/**
|
|
3
|
+
* Bounded IPC surface for the host-owned update manager.
|
|
4
|
+
*
|
|
5
|
+
* SPEC-111 section 3: every command takes no arguments, so a renderer cannot
|
|
6
|
+
* supply a feed URL, filesystem destination, shell command, executable path, or
|
|
7
|
+
* installer flag. Every handler also verifies the sender is the current Cats
|
|
8
|
+
* main window before touching the manager.
|
|
9
|
+
*/
|
|
10
|
+
export const DESKTOP_UPDATE_IPC_CHANNELS = {
|
|
11
|
+
snapshot: DESKTOP_UPDATE_SNAPSHOT_CHANNEL,
|
|
12
|
+
check: DESKTOP_UPDATE_CHECK_CHANNEL,
|
|
13
|
+
download: DESKTOP_UPDATE_DOWNLOAD_CHANNEL,
|
|
14
|
+
install: DESKTOP_UPDATE_INSTALL_CHANNEL,
|
|
15
|
+
event: DESKTOP_UPDATE_EVENT_CHANNEL,
|
|
16
|
+
};
|
|
17
|
+
export function isDesktopUpdateIpcSenderTrusted(event, mainWindowWebContents) {
|
|
18
|
+
if (mainWindowWebContents === null || mainWindowWebContents === undefined) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return event.sender === mainWindowWebContents;
|
|
22
|
+
}
|
|
23
|
+
export function createDesktopUpdateIpcHandlers(input) {
|
|
24
|
+
const { manager, resolveMainWindowWebContents } = input;
|
|
25
|
+
const logger = input.logger ?? (() => { });
|
|
26
|
+
function assertTrusted(event, channel) {
|
|
27
|
+
if (isDesktopUpdateIpcSenderTrusted(event, resolveMainWindowWebContents())) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
logger(`[desktop-update] rejected ${channel} from an untrusted sender.`);
|
|
31
|
+
// Deliberately generic: the renderer learns the command was refused and
|
|
32
|
+
// nothing about the host window topology.
|
|
33
|
+
throw new Error('Update command rejected.');
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
[DESKTOP_UPDATE_IPC_CHANNELS.snapshot]: async (event) => {
|
|
37
|
+
assertTrusted(event, DESKTOP_UPDATE_IPC_CHANNELS.snapshot);
|
|
38
|
+
return manager.getSnapshot();
|
|
39
|
+
},
|
|
40
|
+
[DESKTOP_UPDATE_IPC_CHANNELS.check]: async (event) => {
|
|
41
|
+
assertTrusted(event, DESKTOP_UPDATE_IPC_CHANNELS.check);
|
|
42
|
+
return manager.checkForUpdates();
|
|
43
|
+
},
|
|
44
|
+
[DESKTOP_UPDATE_IPC_CHANNELS.download]: async (event) => {
|
|
45
|
+
assertTrusted(event, DESKTOP_UPDATE_IPC_CHANNELS.download);
|
|
46
|
+
return manager.downloadUpdate();
|
|
47
|
+
},
|
|
48
|
+
[DESKTOP_UPDATE_IPC_CHANNELS.install]: async (event) => {
|
|
49
|
+
assertTrusted(event, DESKTOP_UPDATE_IPC_CHANNELS.install);
|
|
50
|
+
await manager.restartAndInstall();
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Streams manager snapshots to the main window. Returns the unsubscribe
|
|
56
|
+
* function so the caller can detach deterministically during shutdown.
|
|
57
|
+
*/
|
|
58
|
+
export function createDesktopUpdateSnapshotBroadcast(input) {
|
|
59
|
+
const { manager, resolveMainWindowWebContents } = input;
|
|
60
|
+
return manager.subscribe((snapshot) => {
|
|
61
|
+
const webContents = resolveMainWindowWebContents();
|
|
62
|
+
if (webContents === null || webContents === undefined) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (webContents.isDestroyed?.() === true) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
webContents.send(DESKTOP_UPDATE_IPC_CHANNELS.event, snapshot);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=updateIpc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateIpc.js","sourceRoot":"","sources":["../../desktop/host/updateIpc.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,+BAA+B,EAC/B,4BAA4B,EAC5B,8BAA8B,EAC9B,+BAA+B,GAChC,MAAM,gBAAgB,CAAC;AAIxB;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,QAAQ,EAAE,+BAA+B;IACzC,KAAK,EAAE,4BAA4B;IACnC,QAAQ,EAAE,+BAA+B;IACzC,OAAO,EAAE,8BAA8B;IACvC,KAAK,EAAE,4BAA4B;CAC3B,CAAC;AAWX,MAAM,UAAU,+BAA+B,CAC7C,KAA4B,EAC5B,qBAA8B;IAE9B,IAAI,qBAAqB,KAAK,IAAI,IAAI,qBAAqB,KAAK,SAAS,EAAE,CAAC;QAC1E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,KAAK,qBAAqB,CAAC;AAChD,CAAC;AAaD,MAAM,UAAU,8BAA8B,CAC5C,KAA0C;IAE1C,MAAM,EAAE,OAAO,EAAE,4BAA4B,EAAE,GAAG,KAAK,CAAC;IACxD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAE1C,SAAS,aAAa,CAAC,KAA4B,EAAE,OAAe;QAClE,IAAI,+BAA+B,CAAC,KAAK,EAAE,4BAA4B,EAAE,CAAC,EAAE,CAAC;YAC3E,OAAO;QACT,CAAC;QACD,MAAM,CAAC,6BAA6B,OAAO,4BAA4B,CAAC,CAAC;QACzE,wEAAwE;QACxE,0CAA0C;QAC1C,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO;QACL,CAAC,2BAA2B,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACtD,aAAa,CAAC,KAAK,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC;YAC3D,OAAO,OAAO,CAAC,WAAW,EAAE,CAAC;QAC/B,CAAC;QACD,CAAC,2BAA2B,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACnD,aAAa,CAAC,KAAK,EAAE,2BAA2B,CAAC,KAAK,CAAC,CAAC;YACxD,OAAO,OAAO,CAAC,eAAe,EAAE,CAAC;QACnC,CAAC;QACD,CAAC,2BAA2B,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACtD,aAAa,CAAC,KAAK,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC;YAC3D,OAAO,OAAO,CAAC,cAAc,EAAE,CAAC;QAClC,CAAC;QACD,CAAC,2BAA2B,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACrD,aAAa,CAAC,KAAK,EAAE,2BAA2B,CAAC,OAAO,CAAC,CAAC;YAC1D,MAAM,OAAO,CAAC,iBAAiB,EAAE,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC;AAOD;;;GAGG;AACH,MAAM,UAAU,oCAAoC,CAClD,KAAgD;IAEhD,MAAM,EAAE,OAAO,EAAE,4BAA4B,EAAE,GAAG,KAAK,CAAC;IAExD,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,EAAE;QACpC,MAAM,WAAW,GAAG,4BAA4B,EAAE,CAAC;QACnD,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YACtD,OAAO;QACT,CAAC;QACD,IAAI,WAAW,CAAC,WAAW,EAAE,EAAE,KAAK,IAAI,EAAE,CAAC;YACzC,OAAO;QACT,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,2BAA2B,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { DesktopUpdateCapability, DesktopUpdateError, DesktopUpdateNextAction, DesktopUpdateProgress, DesktopUpdateSnapshot, DesktopUpdateStatus } from './contracts.js';
|
|
2
|
+
import type { DesktopDistributionIdentity, DesktopReleasePlatform } from './releaseDescriptor.js';
|
|
3
|
+
/**
|
|
4
|
+
* Host-owned update state machine.
|
|
5
|
+
*
|
|
6
|
+
* The renderer and tray are presentation surfaces over this one manager. They
|
|
7
|
+
* request bounded actions and observe snapshots; they never choose a feed, a
|
|
8
|
+
* URL, a file, or installer arguments.
|
|
9
|
+
*
|
|
10
|
+
* The provider is reached through an injected adapter so tests exercise the
|
|
11
|
+
* lifecycle without live GitHub requests.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Platforms whose signed old-version-to-new-version upgrade path has passed.
|
|
15
|
+
*
|
|
16
|
+
* PLAN-101 gate G3 admits one platform at a time, and SPEC-111 section 9 keeps
|
|
17
|
+
* Windows and macOS self-update disabled until signing is validated. The list
|
|
18
|
+
* is empty on purpose: no platform has passed yet, so no build advertises
|
|
19
|
+
* self-update even when it carries a valid release descriptor.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DESKTOP_RELEASE_READY_PLATFORMS: readonly DesktopReleasePlatform[];
|
|
22
|
+
export interface DesktopUpdaterCheckResult {
|
|
23
|
+
updateAvailable: boolean;
|
|
24
|
+
version: string | null;
|
|
25
|
+
releaseSummary: string | null;
|
|
26
|
+
}
|
|
27
|
+
export interface DesktopUpdaterAdapter {
|
|
28
|
+
checkForUpdates(): Promise<DesktopUpdaterCheckResult>;
|
|
29
|
+
downloadUpdate(onProgress: (progress: DesktopUpdateProgress) => void): Promise<void>;
|
|
30
|
+
quitAndInstall(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export interface CreateDesktopUpdateCapabilityInput {
|
|
33
|
+
identity: DesktopDistributionIdentity;
|
|
34
|
+
nodePlatform: NodeJS.Platform | string;
|
|
35
|
+
releaseReadyPlatforms?: readonly DesktopReleasePlatform[];
|
|
36
|
+
}
|
|
37
|
+
export declare function createDesktopUpdateCapability(input: CreateDesktopUpdateCapabilityInput): DesktopUpdateCapability;
|
|
38
|
+
/**
|
|
39
|
+
* The snapshot a build without update capability publishes.
|
|
40
|
+
*
|
|
41
|
+
* Used as the fallback wherever a snapshot is required before the manager
|
|
42
|
+
* exists, so those code paths cannot accidentally imply an update is possible.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createUnavailableDesktopUpdateSnapshot(currentVersion: string): DesktopUpdateSnapshot;
|
|
45
|
+
export declare function resolveDesktopUpdateNextAction(status: DesktopUpdateStatus, capability: DesktopUpdateCapability): DesktopUpdateNextAction;
|
|
46
|
+
/**
|
|
47
|
+
* Maps a provider error to a stable code plus copy that is safe to render.
|
|
48
|
+
*
|
|
49
|
+
* The returned summary is an English fallback only. Renderer surfaces localize
|
|
50
|
+
* from the code through the shared i18n catalogs, so the raw provider message
|
|
51
|
+
* never reaches the UI.
|
|
52
|
+
*/
|
|
53
|
+
export declare function mapDesktopUpdateError(error: unknown): DesktopUpdateError;
|
|
54
|
+
export declare function redactDesktopUpdateDiagnostic(message: string): string;
|
|
55
|
+
export interface CreateDesktopUpdateManagerInput {
|
|
56
|
+
capability: DesktopUpdateCapability;
|
|
57
|
+
adapter: DesktopUpdaterAdapter | null;
|
|
58
|
+
now?: () => Date;
|
|
59
|
+
logger?: (message: string) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Restored from the host state file. It is the only update fact worth
|
|
62
|
+
* carrying across a restart: a provider-dependent status such as
|
|
63
|
+
* update_available cannot be acted on in a new process without checking
|
|
64
|
+
* again, so restoring it would offer a download the manager cannot perform.
|
|
65
|
+
*/
|
|
66
|
+
initialLastCheckedAt?: string | null;
|
|
67
|
+
}
|
|
68
|
+
export interface DesktopUpdateManager {
|
|
69
|
+
getSnapshot(): DesktopUpdateSnapshot;
|
|
70
|
+
subscribe(listener: (snapshot: DesktopUpdateSnapshot) => void): () => void;
|
|
71
|
+
checkForUpdates(): Promise<DesktopUpdateSnapshot>;
|
|
72
|
+
downloadUpdate(): Promise<DesktopUpdateSnapshot>;
|
|
73
|
+
restartAndInstall(): Promise<DesktopUpdateSnapshot>;
|
|
74
|
+
}
|
|
75
|
+
export declare function createDesktopUpdateManager(input: CreateDesktopUpdateManagerInput): DesktopUpdateManager;
|
|
76
|
+
//# sourceMappingURL=updateManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateManager.d.ts","sourceRoot":"","sources":["../../desktop/host/updateManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,kBAAkB,EAElB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EACV,2BAA2B,EAC3B,sBAAsB,EACvB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;;;GASG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,EAAE,SAAS,sBAAsB,EAAO,CAAC;AAErF,MAAM,WAAW,yBAAyB;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,eAAe,IAAI,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACtD,cAAc,CACZ,UAAU,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,GACpD,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,kCAAkC;IACjD,QAAQ,EAAE,2BAA2B,CAAC;IACtC,YAAY,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC;IACvC,qBAAqB,CAAC,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAC3D;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,kCAAkC,GACxC,uBAAuB,CA0DzB;AAED;;;;;GAKG;AACH,wBAAgB,sCAAsC,CACpD,cAAc,EAAE,MAAM,GACrB,qBAAqB,CAqBvB;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,mBAAmB,EAC3B,UAAU,EAAE,uBAAuB,GAClC,uBAAuB,CAiBzB;AA0BD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAcxE;AAQD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKrE;AAMD,MAAM,WAAW,+BAA+B;IAC9C,UAAU,EAAE,uBAAuB,CAAC;IACpC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,IAAI,qBAAqB,CAAC;IACrC,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC3E,eAAe,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAClD,cAAc,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACjD,iBAAiB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACrD;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,+BAA+B,GACrC,oBAAoB,CAkMtB"}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { resolveDesktopReleasePlatform } from './releaseDescriptor.js';
|
|
2
|
+
/**
|
|
3
|
+
* Host-owned update state machine.
|
|
4
|
+
*
|
|
5
|
+
* The renderer and tray are presentation surfaces over this one manager. They
|
|
6
|
+
* request bounded actions and observe snapshots; they never choose a feed, a
|
|
7
|
+
* URL, a file, or installer arguments.
|
|
8
|
+
*
|
|
9
|
+
* The provider is reached through an injected adapter so tests exercise the
|
|
10
|
+
* lifecycle without live GitHub requests.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Platforms whose signed old-version-to-new-version upgrade path has passed.
|
|
14
|
+
*
|
|
15
|
+
* PLAN-101 gate G3 admits one platform at a time, and SPEC-111 section 9 keeps
|
|
16
|
+
* Windows and macOS self-update disabled until signing is validated. The list
|
|
17
|
+
* is empty on purpose: no platform has passed yet, so no build advertises
|
|
18
|
+
* self-update even when it carries a valid release descriptor.
|
|
19
|
+
*/
|
|
20
|
+
export const DESKTOP_RELEASE_READY_PLATFORMS = [];
|
|
21
|
+
export function createDesktopUpdateCapability(input) {
|
|
22
|
+
const { identity, nodePlatform } = input;
|
|
23
|
+
const releaseReadyPlatforms = input.releaseReadyPlatforms ?? DESKTOP_RELEASE_READY_PLATFORMS;
|
|
24
|
+
const base = {
|
|
25
|
+
distribution: identity.distribution,
|
|
26
|
+
channel: identity.channel,
|
|
27
|
+
currentVersion: identity.currentVersion,
|
|
28
|
+
};
|
|
29
|
+
const packagedFromWorkflow = identity.distribution === 'official_packaged'
|
|
30
|
+
|| identity.distribution === 'preview_packaged';
|
|
31
|
+
if (!packagedFromWorkflow || identity.provider !== 'github_release') {
|
|
32
|
+
return {
|
|
33
|
+
...base,
|
|
34
|
+
provider: 'none',
|
|
35
|
+
canCheck: false,
|
|
36
|
+
canDownload: false,
|
|
37
|
+
canInstall: false,
|
|
38
|
+
unavailableReason: identity.unavailableReason,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const platform = resolveDesktopReleasePlatform(nodePlatform);
|
|
42
|
+
if (platform === null) {
|
|
43
|
+
return {
|
|
44
|
+
...base,
|
|
45
|
+
provider: 'github_release',
|
|
46
|
+
canCheck: false,
|
|
47
|
+
canDownload: false,
|
|
48
|
+
canInstall: false,
|
|
49
|
+
unavailableReason: 'platform_not_release_ready',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// The release-ready gate exists so a stable build cannot advertise
|
|
53
|
+
// self-update before its signed upgrade test passes. A preview build is how
|
|
54
|
+
// that test is run, so the gate does not apply to it.
|
|
55
|
+
if (identity.distribution === 'official_packaged' && !releaseReadyPlatforms.includes(platform)) {
|
|
56
|
+
return {
|
|
57
|
+
...base,
|
|
58
|
+
provider: 'github_release',
|
|
59
|
+
canCheck: false,
|
|
60
|
+
canDownload: false,
|
|
61
|
+
canInstall: false,
|
|
62
|
+
unavailableReason: 'platform_not_release_ready',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
...base,
|
|
67
|
+
provider: 'github_release',
|
|
68
|
+
canCheck: true,
|
|
69
|
+
canDownload: true,
|
|
70
|
+
canInstall: true,
|
|
71
|
+
unavailableReason: null,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The snapshot a build without update capability publishes.
|
|
76
|
+
*
|
|
77
|
+
* Used as the fallback wherever a snapshot is required before the manager
|
|
78
|
+
* exists, so those code paths cannot accidentally imply an update is possible.
|
|
79
|
+
*/
|
|
80
|
+
export function createUnavailableDesktopUpdateSnapshot(currentVersion) {
|
|
81
|
+
return {
|
|
82
|
+
capability: {
|
|
83
|
+
distribution: 'unofficial_packaged',
|
|
84
|
+
provider: 'none',
|
|
85
|
+
channel: 'stable',
|
|
86
|
+
currentVersion,
|
|
87
|
+
canCheck: false,
|
|
88
|
+
canDownload: false,
|
|
89
|
+
canInstall: false,
|
|
90
|
+
unavailableReason: 'descriptor_missing',
|
|
91
|
+
},
|
|
92
|
+
status: 'unavailable',
|
|
93
|
+
currentVersion,
|
|
94
|
+
availableVersion: null,
|
|
95
|
+
releaseSummary: null,
|
|
96
|
+
lastCheckedAt: null,
|
|
97
|
+
progress: null,
|
|
98
|
+
error: null,
|
|
99
|
+
nextAction: 'none',
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function resolveDesktopUpdateNextAction(status, capability) {
|
|
103
|
+
if (!capability.canCheck) {
|
|
104
|
+
return 'none';
|
|
105
|
+
}
|
|
106
|
+
switch (status) {
|
|
107
|
+
case 'idle':
|
|
108
|
+
case 'up_to_date':
|
|
109
|
+
case 'failed':
|
|
110
|
+
return 'check';
|
|
111
|
+
case 'update_available':
|
|
112
|
+
return capability.canDownload ? 'download' : 'none';
|
|
113
|
+
case 'downloaded':
|
|
114
|
+
return capability.canInstall ? 'restart_install' : 'none';
|
|
115
|
+
default:
|
|
116
|
+
return 'none';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const ERROR_SUMMARIES = {
|
|
120
|
+
offline: 'Cats could not reach the update service.',
|
|
121
|
+
timeout: 'The update service did not respond in time.',
|
|
122
|
+
provider_rejected: 'The update service rejected the request.',
|
|
123
|
+
metadata_invalid: 'The update information could not be read.',
|
|
124
|
+
checksum_mismatch: 'The downloaded update failed its integrity check.',
|
|
125
|
+
signature_rejected: 'The downloaded update failed its signature check.',
|
|
126
|
+
unsupported_package: 'This installation cannot update itself.',
|
|
127
|
+
download_cancelled: 'The update download was cancelled.',
|
|
128
|
+
install_handoff_failed: 'Cats could not hand off to the installer.',
|
|
129
|
+
unknown: 'The update could not be completed.',
|
|
130
|
+
};
|
|
131
|
+
const ERROR_CODE_PATTERNS = [
|
|
132
|
+
['offline', /enotfound|eai_again|econnrefused|econnreset|enetunreach|offline|dns/iu],
|
|
133
|
+
['timeout', /etimedout|timed? ?out|esockettimedout/iu],
|
|
134
|
+
['checksum_mismatch', /sha512|sha256|checksum|integrity/iu],
|
|
135
|
+
['signature_rejected', /signature|publishername|not signed|authenticode/iu],
|
|
136
|
+
['download_cancelled', /cancel/iu],
|
|
137
|
+
['unsupported_package', /unsupported|not supported|no published versions|dev-app-update/iu],
|
|
138
|
+
['metadata_invalid', /latest\.yml|latest-mac\.yml|metadata|unable to parse|invalid yml/iu],
|
|
139
|
+
['provider_rejected', /http (4|5)\d\d|status code (4|5)\d\d|forbidden|not found|rate limit/iu],
|
|
140
|
+
];
|
|
141
|
+
/**
|
|
142
|
+
* Maps a provider error to a stable code plus copy that is safe to render.
|
|
143
|
+
*
|
|
144
|
+
* The returned summary is an English fallback only. Renderer surfaces localize
|
|
145
|
+
* from the code through the shared i18n catalogs, so the raw provider message
|
|
146
|
+
* never reaches the UI.
|
|
147
|
+
*/
|
|
148
|
+
export function mapDesktopUpdateError(error) {
|
|
149
|
+
const haystack = [
|
|
150
|
+
typeof error === 'string' ? error : '',
|
|
151
|
+
error instanceof Error ? error.message : '',
|
|
152
|
+
isRecord(error) && typeof error.code === 'string' ? error.code : '',
|
|
153
|
+
].join(' ');
|
|
154
|
+
for (const [code, pattern] of ERROR_CODE_PATTERNS) {
|
|
155
|
+
if (pattern.test(haystack)) {
|
|
156
|
+
return { code, summary: ERROR_SUMMARIES[code] };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return { code: 'unknown', summary: ERROR_SUMMARIES.unknown };
|
|
160
|
+
}
|
|
161
|
+
const SECRET_PATTERNS = [
|
|
162
|
+
/gh[pousr]_[A-Za-z0-9_]{16,}/gu,
|
|
163
|
+
/github_pat_[A-Za-z0-9_]{20,}/gu,
|
|
164
|
+
/(authorization|token|password|secret)"?\s*[:=]\s*"?[^\s",}]+/giu,
|
|
165
|
+
];
|
|
166
|
+
export function redactDesktopUpdateDiagnostic(message) {
|
|
167
|
+
return SECRET_PATTERNS.reduce((redacted, pattern) => redacted.replace(pattern, '[redacted]'), message);
|
|
168
|
+
}
|
|
169
|
+
function isRecord(value) {
|
|
170
|
+
return typeof value === 'object' && value !== null;
|
|
171
|
+
}
|
|
172
|
+
export function createDesktopUpdateManager(input) {
|
|
173
|
+
const { capability, adapter } = input;
|
|
174
|
+
const now = input.now ?? (() => new Date());
|
|
175
|
+
const logger = input.logger ?? (() => { });
|
|
176
|
+
const usable = capability.canCheck && adapter !== null;
|
|
177
|
+
let status = usable ? 'idle' : 'unavailable';
|
|
178
|
+
let availableVersion = null;
|
|
179
|
+
let releaseSummary = null;
|
|
180
|
+
let lastCheckedAt = input.initialLastCheckedAt ?? null;
|
|
181
|
+
let progress = null;
|
|
182
|
+
let error = null;
|
|
183
|
+
// SPEC-111 section 2 allows one check or download at a time. Repeated
|
|
184
|
+
// requests join the in-flight operation instead of starting a second
|
|
185
|
+
// provider request.
|
|
186
|
+
let pendingCheck = null;
|
|
187
|
+
let pendingDownload = null;
|
|
188
|
+
const listeners = new Set();
|
|
189
|
+
function snapshot() {
|
|
190
|
+
return {
|
|
191
|
+
capability,
|
|
192
|
+
status,
|
|
193
|
+
currentVersion: capability.currentVersion,
|
|
194
|
+
availableVersion,
|
|
195
|
+
releaseSummary,
|
|
196
|
+
lastCheckedAt,
|
|
197
|
+
progress,
|
|
198
|
+
error,
|
|
199
|
+
nextAction: resolveDesktopUpdateNextAction(status, capability),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function publish() {
|
|
203
|
+
const current = snapshot();
|
|
204
|
+
for (const listener of listeners) {
|
|
205
|
+
listener(current);
|
|
206
|
+
}
|
|
207
|
+
return current;
|
|
208
|
+
}
|
|
209
|
+
function log(message) {
|
|
210
|
+
logger(redactDesktopUpdateDiagnostic(message));
|
|
211
|
+
}
|
|
212
|
+
function fail(cause, stage) {
|
|
213
|
+
error = mapDesktopUpdateError(cause);
|
|
214
|
+
status = 'failed';
|
|
215
|
+
progress = null;
|
|
216
|
+
log(`[desktop-update] ${stage} failed (${error.code}): `
|
|
217
|
+
+ `${cause instanceof Error ? cause.message : String(cause)}`);
|
|
218
|
+
return publish();
|
|
219
|
+
}
|
|
220
|
+
async function runCheck(activeAdapter) {
|
|
221
|
+
status = 'checking';
|
|
222
|
+
error = null;
|
|
223
|
+
publish();
|
|
224
|
+
try {
|
|
225
|
+
const result = await activeAdapter.checkForUpdates();
|
|
226
|
+
lastCheckedAt = now().toISOString();
|
|
227
|
+
if (!result.updateAvailable) {
|
|
228
|
+
status = 'up_to_date';
|
|
229
|
+
availableVersion = null;
|
|
230
|
+
releaseSummary = null;
|
|
231
|
+
return publish();
|
|
232
|
+
}
|
|
233
|
+
if (result.version === null || result.version.trim() === '') {
|
|
234
|
+
throw new Error('Provider reported an available update without a version.');
|
|
235
|
+
}
|
|
236
|
+
status = 'update_available';
|
|
237
|
+
availableVersion = result.version;
|
|
238
|
+
releaseSummary = result.releaseSummary;
|
|
239
|
+
return publish();
|
|
240
|
+
}
|
|
241
|
+
catch (cause) {
|
|
242
|
+
lastCheckedAt = now().toISOString();
|
|
243
|
+
return fail(cause, 'check');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async function runDownload(activeAdapter) {
|
|
247
|
+
status = 'downloading';
|
|
248
|
+
error = null;
|
|
249
|
+
progress = { percent: 0, transferredBytes: 0, totalBytes: 0, bytesPerSecond: 0 };
|
|
250
|
+
publish();
|
|
251
|
+
try {
|
|
252
|
+
await activeAdapter.downloadUpdate((next) => {
|
|
253
|
+
// A late progress event after a failure must not resurrect the
|
|
254
|
+
// downloading state.
|
|
255
|
+
if (status !== 'downloading') {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
progress = next;
|
|
259
|
+
publish();
|
|
260
|
+
});
|
|
261
|
+
status = 'downloaded';
|
|
262
|
+
progress = null;
|
|
263
|
+
return publish();
|
|
264
|
+
}
|
|
265
|
+
catch (cause) {
|
|
266
|
+
return fail(cause, 'download');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
getSnapshot: snapshot,
|
|
271
|
+
subscribe(listener) {
|
|
272
|
+
listeners.add(listener);
|
|
273
|
+
return () => {
|
|
274
|
+
listeners.delete(listener);
|
|
275
|
+
};
|
|
276
|
+
},
|
|
277
|
+
async checkForUpdates() {
|
|
278
|
+
if (!usable || adapter === null) {
|
|
279
|
+
return snapshot();
|
|
280
|
+
}
|
|
281
|
+
if (pendingDownload !== null) {
|
|
282
|
+
return pendingDownload;
|
|
283
|
+
}
|
|
284
|
+
if (pendingCheck !== null) {
|
|
285
|
+
return pendingCheck;
|
|
286
|
+
}
|
|
287
|
+
pendingCheck = runCheck(adapter).finally(() => {
|
|
288
|
+
pendingCheck = null;
|
|
289
|
+
});
|
|
290
|
+
return pendingCheck;
|
|
291
|
+
},
|
|
292
|
+
async downloadUpdate() {
|
|
293
|
+
if (!usable || adapter === null || !capability.canDownload) {
|
|
294
|
+
return snapshot();
|
|
295
|
+
}
|
|
296
|
+
if (pendingDownload !== null) {
|
|
297
|
+
return pendingDownload;
|
|
298
|
+
}
|
|
299
|
+
if (pendingCheck !== null) {
|
|
300
|
+
return pendingCheck;
|
|
301
|
+
}
|
|
302
|
+
// Automatic download stays disabled: only an explicit request from a
|
|
303
|
+
// surface reaches here, and only from update_available.
|
|
304
|
+
if (status !== 'update_available') {
|
|
305
|
+
return snapshot();
|
|
306
|
+
}
|
|
307
|
+
pendingDownload = runDownload(adapter).finally(() => {
|
|
308
|
+
pendingDownload = null;
|
|
309
|
+
});
|
|
310
|
+
return pendingDownload;
|
|
311
|
+
},
|
|
312
|
+
async restartAndInstall() {
|
|
313
|
+
if (!usable || adapter === null || !capability.canInstall) {
|
|
314
|
+
return snapshot();
|
|
315
|
+
}
|
|
316
|
+
if (status !== 'downloaded') {
|
|
317
|
+
return snapshot();
|
|
318
|
+
}
|
|
319
|
+
status = 'installing';
|
|
320
|
+
error = null;
|
|
321
|
+
publish();
|
|
322
|
+
try {
|
|
323
|
+
await adapter.quitAndInstall();
|
|
324
|
+
return snapshot();
|
|
325
|
+
}
|
|
326
|
+
catch (cause) {
|
|
327
|
+
log('[desktop-update] install handoff failed: '
|
|
328
|
+
+ `${cause instanceof Error ? cause.message : String(cause)}`);
|
|
329
|
+
// The handoff failed before the process exited, so the downloaded
|
|
330
|
+
// update is still installable and the user can retry it.
|
|
331
|
+
status = 'downloaded';
|
|
332
|
+
progress = null;
|
|
333
|
+
error = {
|
|
334
|
+
code: 'install_handoff_failed',
|
|
335
|
+
summary: ERROR_SUMMARIES.install_handoff_failed,
|
|
336
|
+
};
|
|
337
|
+
return publish();
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
//# sourceMappingURL=updateManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateManager.js","sourceRoot":"","sources":["../../desktop/host/updateManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { DesktopUpdateErrorCode, DesktopUpdateSnapshot } from './contracts.js';
|
|
2
|
+
import { type DesktopTrayLocale } from './trayMenu.js';
|
|
3
|
+
/**
|
|
4
|
+
* Native update notifications.
|
|
5
|
+
*
|
|
6
|
+
* SPEC-111 section 5 requires a check started outside Settings to report its
|
|
7
|
+
* result somewhere the user is actually looking. This module owns that policy;
|
|
8
|
+
* `main.ts` only constructs the native notification the policy asks for, so the
|
|
9
|
+
* rules stay testable without Electron.
|
|
10
|
+
*/
|
|
11
|
+
/** Where the check that produced the result came from. */
|
|
12
|
+
export declare const DESKTOP_UPDATE_NOTIFICATION_ORIGINS: readonly ["tray", "settings", "startup"];
|
|
13
|
+
export type DesktopUpdateNotificationOrigin = typeof DESKTOP_UPDATE_NOTIFICATION_ORIGINS[number];
|
|
14
|
+
export declare const DESKTOP_UPDATE_SETTINGS_PATH = "/settings/desktop";
|
|
15
|
+
export interface DesktopUpdateNotification {
|
|
16
|
+
title: string;
|
|
17
|
+
body: string;
|
|
18
|
+
/** Where activating the notification shall land the user. */
|
|
19
|
+
navigatePath: typeof DESKTOP_UPDATE_SETTINGS_PATH;
|
|
20
|
+
}
|
|
21
|
+
export interface DesktopUpdateAnnouncement {
|
|
22
|
+
notification: DesktopUpdateNotification | null;
|
|
23
|
+
/**
|
|
24
|
+
* Where to open the main window when no notification reaches the user —
|
|
25
|
+
* either because the platform has none or because showing it failed.
|
|
26
|
+
*
|
|
27
|
+
* Null when the result does not justify pulling a window forward. Set
|
|
28
|
+
* independently of `notification` so the caller never has to re-derive the
|
|
29
|
+
* policy after a failed `show()`.
|
|
30
|
+
*/
|
|
31
|
+
fallbackNavigatePath: typeof DESKTOP_UPDATE_SETTINGS_PATH | null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Error copy for notifications, in the same two locales the tray uses.
|
|
35
|
+
*
|
|
36
|
+
* These strings are duplicated from the renderer i18n catalogs because the
|
|
37
|
+
* main process has no translator. `settings-desktop-update-labels.test.tsx`
|
|
38
|
+
* asserts they stay identical to the catalog entries, so the duplication cannot
|
|
39
|
+
* drift silently.
|
|
40
|
+
*/
|
|
41
|
+
export declare const DESKTOP_UPDATE_NOTIFICATION_ERROR_COPY: Record<DesktopTrayLocale, Record<DesktopUpdateErrorCode, string>>;
|
|
42
|
+
export interface ResolveDesktopUpdateAnnouncementInput {
|
|
43
|
+
origin: DesktopUpdateNotificationOrigin;
|
|
44
|
+
snapshot: DesktopUpdateSnapshot;
|
|
45
|
+
locale?: string | null;
|
|
46
|
+
/** `Notification.isSupported()`, resolved by the caller. */
|
|
47
|
+
notificationsSupported: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Decides what a finished check should tell the user, and how.
|
|
51
|
+
*
|
|
52
|
+
* A result is announced only when the user cannot already see it:
|
|
53
|
+
*
|
|
54
|
+
* - `settings` never announces. The section shows the state directly and
|
|
55
|
+
* routes manual results through the shared toast system, so a native
|
|
56
|
+
* notification would report the same check twice.
|
|
57
|
+
* - `tray` announces up-to-date, available, and failed. The menu closes on
|
|
58
|
+
* click, so without this the command looks like it did nothing.
|
|
59
|
+
* - `startup` announces only an available update. The user did not ask for
|
|
60
|
+
* that check, so an up-to-date or offline result has nothing to say and
|
|
61
|
+
* would nag on every launch.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveDesktopUpdateAnnouncement(input: ResolveDesktopUpdateAnnouncementInput): DesktopUpdateAnnouncement;
|
|
64
|
+
//# sourceMappingURL=updateNotifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateNotifications.d.ts","sourceRoot":"","sources":["../../desktop/host/updateNotifications.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,eAAe,CAAC;AAEvB;;;;;;;GAOG;AAEH,0DAA0D;AAC1D,eAAO,MAAM,mCAAmC,0CAA2C,CAAC;AAC5F,MAAM,MAAM,+BAA+B,GACzC,OAAO,mCAAmC,CAAC,MAAM,CAAC,CAAC;AAErD,eAAO,MAAM,4BAA4B,sBAAsB,CAAC;AAEhE,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,YAAY,EAAE,OAAO,4BAA4B,CAAC;CACnD;AAED,MAAM,WAAW,yBAAyB;IACxC,YAAY,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC/C;;;;;;;OAOG;IACH,oBAAoB,EAAE,OAAO,4BAA4B,GAAG,IAAI,CAAC;CAClE;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sCAAsC,EAAE,MAAM,CACzD,iBAAiB,EACjB,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CA0BvC,CAAC;AAmCF,MAAM,WAAW,qCAAqC;IACpD,MAAM,EAAE,+BAA+B,CAAC;IACxC,QAAQ,EAAE,qBAAqB,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,4DAA4D;IAC5D,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,qCAAqC,GAC3C,yBAAyB,CA2B3B"}
|