feat(updater): add performAutoUpdate and eligibility to store/service

Additive changes only: adds isAutoUpdateEligible() getter and
eligibility fetch in initUpdatesStore (keeps existing skipIfRemote
guards); adds performAutoUpdate() in updatesService for the
download/install/relaunch flow with cancellation support.

cc
This commit is contained in:
vicrodh committed 2026-04-13 14:57:57 -06:00
1 parent 46f8693f16
commit 10b5d95852
2 files changed
+93

No files matched your search

+76
View File
@@ -1,5 +1,7 @@
import { invoke } from '@tauri-apps/api/core';
import { openUrl } from '@tauri-apps/plugin-opener';
import { check } from '@tauri-apps/plugin-updater';
import { relaunch } from '@tauri-apps/plugin-process';
import {
acknowledgeRelease,
checkForUpdates,
@@ -316,3 +318,77 @@ export async function disableUpdateChecks(): Promise<void> {
console.debug('[Updates] Failed to disable update checks:', error);
}
}
// ==================== Auto-update ====================
export type AutoUpdateProgress =
| { state: 'checking' }
| { state: 'downloading'; downloadedBytes: number; totalBytes?: number }
| { state: 'installing' }
| { state: 'restarting' }
| { state: 'error'; error: string };
let autoUpdateInProgress = false;
export function isAutoUpdateInProgress(): boolean {
return autoUpdateInProgress;
}
/**
* Download, install and relaunch the pending update.
*
* `isCancelled` is polled before kicking off the download and again before the
* final relaunch so the caller can abort mid-flight.
* Returns true when the relaunch was triggered, false otherwise.
*/
export async function performAutoUpdate(
onProgress: (progress: AutoUpdateProgress) => void,
isCancelled?: () => boolean,
): Promise<boolean> {
if (autoUpdateInProgress) {
console.debug('[Updates] Auto-update already in progress');
return false;
}
autoUpdateInProgress = true;
try {
onProgress({ state: 'checking' });
const update = await check();
if (!update) return false;
if (isCancelled?.()) return false;
let totalBytes: number | undefined;
let downloadedBytes = 0;
onProgress({ state: 'downloading', downloadedBytes: 0 });
await update.downloadAndInstall((event) => {
switch (event.event) {
case 'Started':
totalBytes = event.data.contentLength ?? undefined;
onProgress({ state: 'downloading', downloadedBytes: 0, totalBytes });
break;
case 'Progress':
downloadedBytes += event.data.chunkLength;
onProgress({ state: 'downloading', downloadedBytes, totalBytes });
break;
case 'Finished':
onProgress({ state: 'installing' });
break;
}
});
if (isCancelled?.()) return false;
onProgress({ state: 'restarting' });
await relaunch();
return true;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
console.error('[Updates] Auto-update failed:', message);
onProgress({ state: 'error', error: message });
return false;
} finally {
autoUpdateInProgress = false;
}
}