Add built-in auto-updater with tab-bar update pill
Wires electrobun's Updater to the /dl download host. The packaged app checks https://miniscp.com/dl on launch + every 6h; when a newer build exists, an accent-colored "update tool" appears next to Connections in the tab bar. It announces the update, becomes its own inline progress bar while downloading, then flips to "Restart to apply" (two-step: download, then user-triggered relaunch). - electrobun.config.ts: release.baseUrl = https://miniscp.com/dl (baked into version.json at build; miniscp.com fronted by an external proxy for TLS). - rpc.ts: checkForUpdate/downloadUpdate/applyUpdate requests + updateStatus push. - rpc-handlers.ts + index.ts: call Updater; poll on launch+6h; stream onStatusChange progress. checkForUpdate self-guards the dev channel. - rpc.service.ts + new updater.service.ts: signal-based state (available -> downloading -> ready, ready derived from downloadUpdate ok). - tab-bar.ts: single bg-primary pill; progress fills the pill itself. - icons.ts: register mynaDownload. i18n: tabBar + menu keys across all locales. - menu.ts + app.ts: "Check for Updates…" app-menu item -> UpdaterService.check(). - docs: build-and-release + architecture updated. Unsigned builds still update (applyUpdate strips the macOS quarantine xattr). Verified: tsc --noEmit (exit 0) + build:ui AOT (exit 0). Live pill + full download/apply flow require a two-build test on the host. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,10 @@ export const de = {
|
||||
newTab: "Neuer Tab ({mod}T)",
|
||||
closeTab: "Tab schließen ({mod}W)",
|
||||
options: "Optionen",
|
||||
update: "Update verfügbar",
|
||||
updating: "Aktualisiere",
|
||||
restartToUpdate: "Zum Anwenden neu starten",
|
||||
updateTooltip: "Update verfügbar: miniSCP {version}",
|
||||
},
|
||||
options: {
|
||||
title: "Optionen",
|
||||
@@ -245,6 +249,7 @@ export const de = {
|
||||
},
|
||||
menu: {
|
||||
about: "Über {app}",
|
||||
checkForUpdates: "Nach Updates suchen…",
|
||||
quit: "Beenden",
|
||||
file: "Datei",
|
||||
newTab: "Neuer Tab",
|
||||
|
||||
@@ -28,6 +28,10 @@ export const en = {
|
||||
newTab: "New tab ({mod}T)",
|
||||
closeTab: "Close tab ({mod}W)",
|
||||
options: "Options",
|
||||
update: "Update available",
|
||||
updating: "Updating",
|
||||
restartToUpdate: "Restart to apply",
|
||||
updateTooltip: "Update available: miniSCP {version}",
|
||||
},
|
||||
options: {
|
||||
title: "Options",
|
||||
@@ -249,6 +253,7 @@ export const en = {
|
||||
},
|
||||
menu: {
|
||||
about: "About {app}",
|
||||
checkForUpdates: "Check for Updates…",
|
||||
quit: "Quit",
|
||||
file: "File",
|
||||
newTab: "New Tab",
|
||||
|
||||
@@ -24,6 +24,10 @@ export const es = {
|
||||
newTab: "Nueva pestaña ({mod}T)",
|
||||
closeTab: "Cerrar pestaña ({mod}W)",
|
||||
options: "Opciones",
|
||||
update: "Actualización disponible",
|
||||
updating: "Actualizando",
|
||||
restartToUpdate: "Reiniciar para aplicar",
|
||||
updateTooltip: "Actualización disponible: miniSCP {version}",
|
||||
},
|
||||
options: {
|
||||
title: "Opciones",
|
||||
@@ -245,6 +249,7 @@ export const es = {
|
||||
},
|
||||
menu: {
|
||||
about: "Acerca de {app}",
|
||||
checkForUpdates: "Buscar actualizaciones…",
|
||||
quit: "Salir",
|
||||
file: "Archivo",
|
||||
newTab: "Nueva pestaña",
|
||||
|
||||
@@ -26,6 +26,10 @@ export const eu = {
|
||||
newTab: "Fitxa berria ({mod}T)",
|
||||
closeTab: "Itxi fitxa ({mod}W)",
|
||||
options: "Aukerak",
|
||||
update: "Eguneratzea eskuragarri",
|
||||
updating: "Eguneratzen",
|
||||
restartToUpdate: "Berrabiarazi aplikatzeko",
|
||||
updateTooltip: "Eguneratzea eskuragarri: miniSCP {version}",
|
||||
},
|
||||
options: {
|
||||
title: "Aukerak",
|
||||
@@ -247,6 +251,7 @@ export const eu = {
|
||||
},
|
||||
menu: {
|
||||
about: "{app} (r)i buruz",
|
||||
checkForUpdates: "Bilatu eguneratzeak…",
|
||||
quit: "Irten",
|
||||
file: "Fitxategia",
|
||||
newTab: "Fitxa berria",
|
||||
|
||||
@@ -24,6 +24,10 @@ export const fr = {
|
||||
newTab: "Nouvel onglet ({mod}T)",
|
||||
closeTab: "Fermer l'onglet ({mod}W)",
|
||||
options: "Options",
|
||||
update: "Mise à jour disponible",
|
||||
updating: "Mise à jour",
|
||||
restartToUpdate: "Redémarrer pour appliquer",
|
||||
updateTooltip: "Mise à jour disponible : miniSCP {version}",
|
||||
},
|
||||
options: {
|
||||
title: "Options",
|
||||
@@ -245,6 +249,7 @@ export const fr = {
|
||||
},
|
||||
menu: {
|
||||
about: "À propos de {app}",
|
||||
checkForUpdates: "Rechercher des mises à jour…",
|
||||
quit: "Quitter",
|
||||
file: "Fichier",
|
||||
newTab: "Nouvel onglet",
|
||||
|
||||
@@ -25,6 +25,10 @@ export const ja = {
|
||||
newTab: "新しいタブ ({mod}T)",
|
||||
closeTab: "タブを閉じる ({mod}W)",
|
||||
options: "オプション",
|
||||
update: "アップデートあり",
|
||||
updating: "更新中",
|
||||
restartToUpdate: "再起動して適用",
|
||||
updateTooltip: "アップデートがあります: miniSCP {version}",
|
||||
},
|
||||
options: {
|
||||
title: "オプション",
|
||||
@@ -245,6 +249,7 @@ export const ja = {
|
||||
},
|
||||
menu: {
|
||||
about: "{app} について",
|
||||
checkForUpdates: "アップデートを確認…",
|
||||
quit: "終了",
|
||||
file: "ファイル",
|
||||
newTab: "新しいタブ",
|
||||
|
||||
@@ -25,6 +25,10 @@ export const zh = {
|
||||
newTab: "新建标签页 ({mod}T)",
|
||||
closeTab: "关闭标签页 ({mod}W)",
|
||||
options: "选项",
|
||||
update: "有可用更新",
|
||||
updating: "正在更新",
|
||||
restartToUpdate: "重启以应用",
|
||||
updateTooltip: "有可用更新:miniSCP {version}",
|
||||
},
|
||||
options: {
|
||||
title: "选项",
|
||||
@@ -245,6 +249,7 @@ export const zh = {
|
||||
},
|
||||
menu: {
|
||||
about: "关于 {app}",
|
||||
checkForUpdates: "检查更新…",
|
||||
quit: "退出",
|
||||
file: "文件",
|
||||
newTab: "新建标签页",
|
||||
|
||||
@@ -157,6 +157,16 @@ export type AppRPC = {
|
||||
managerConnect: { params: { id: string }; response: Result };
|
||||
managerOpenStack: { params: { id: string }; response: Result };
|
||||
managerClose: { params: Record<string, never>; response: Result };
|
||||
// auto-updater (electrobun Updater)
|
||||
/** Main window: re-run the update check on demand (menu item). */
|
||||
checkForUpdate: {
|
||||
params: Record<string, never>;
|
||||
response: Result<{ updateAvailable: boolean; version: string }>;
|
||||
};
|
||||
/** Download the pending update (patch-chain, else full). Progress arrives via updateStatus. */
|
||||
downloadUpdate: { params: Record<string, never>; response: Result };
|
||||
/** Swap in the downloaded update and relaunch — quits the app, so may not resolve. */
|
||||
applyUpdate: { params: Record<string, never>; response: Result };
|
||||
};
|
||||
messages: {
|
||||
/** Editor → bun draft mirror; safety net for the non-cancellable native close. */
|
||||
@@ -179,6 +189,16 @@ export type AppRPC = {
|
||||
managerState: { open: boolean };
|
||||
/** bun → main: the manager window changed the connection store. */
|
||||
connectionsChanged: Record<string, never>;
|
||||
/**
|
||||
* bun → main: auto-updater lifecycle, drives the tab-bar update pill.
|
||||
* "ready" is not a phase — the UI derives it from downloadUpdate resolving ok.
|
||||
*/
|
||||
updateStatus: {
|
||||
phase: "available" | "downloading" | "error";
|
||||
version?: string;
|
||||
progress?: number;
|
||||
error?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user