feat(electron): auto-update via electron-updater + GitHub Releases
Phase 1 step 7 of VNCprodbuild. electron/main.ts calls autoUpdater.checkForUpdatesAndNotify() once the app is ready, only for packaged builds (app.isPackaged) - dev/test runs have no latest.yml and would just log a noisy 404 on every launch. electron-builder.config.js gets a matching `publish` block pointing at this repo's own GitHub Releases (brvncde-dotcom/vncmail-plus) - the skill's recommendation over standing up a new distribution channel, since the repo is already private. Flagged as the "light decision" the skill calls it, not blocking. Deliberately defensive: no code signing yet (step 9), so update verification can fail on macOS in particular. Wrapped in try/catch + autoUpdater's "error" event so a failed check is logged and swallowed, never fatal - this is background maintenance, not something the user should be blocked on. Verified with a --dir packaged build: checkForUpdatesAndNotify() throws ENOENT for app-update.yml (expected - that file is only emitted by a full `electron-builder build`, not --dir) and the error handling swallows it cleanly; the standalone server still boots and serves the app normally. npm run test:electron still green (4/4) - autoUpdater is a no-op in the unpacked dev/test path this suite exercises.
This commit is contained in:
@@ -3,8 +3,8 @@
|
|||||||
// Phase 1 of the VNCprodbuild rollout (~/.claude/skills/VNCprodbuild/SKILL.md):
|
// Phase 1 of the VNCprodbuild rollout (~/.claude/skills/VNCprodbuild/SKILL.md):
|
||||||
// step 1 - base config, no targets (superseded by this file)
|
// step 1 - base config, no targets (superseded by this file)
|
||||||
// step 6 - this file: real packaging targets + branding icon (below)
|
// step 6 - this file: real packaging targets + branding icon (below)
|
||||||
// step 7 - electron-updater wiring (GitHub Releases feed) - adds a
|
// step 7 - this file's `publish` block + electron/main.ts's
|
||||||
// `publish` block on top of this file in a later commit.
|
// setupAutoUpdater() - electron-updater against GitHub Releases.
|
||||||
// step 9 - still open: code signing / notarization (Apple Developer ID,
|
// step 9 - still open: code signing / notarization (Apple Developer ID,
|
||||||
// optional Windows cert) - both are human-owned purchases, not
|
// optional Windows cert) - both are human-owned purchases, not
|
||||||
// configured here. Builds below ship UNSIGNED.
|
// configured here. Builds below ship UNSIGNED.
|
||||||
@@ -79,4 +79,16 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
category: "Network;Email;",
|
category: "Network;Email;",
|
||||||
},
|
},
|
||||||
|
// electron-updater feed (see electron/main.ts's setupAutoUpdater()).
|
||||||
|
// GitHub Releases, not a new distribution channel - the skill's
|
||||||
|
// recommendation since this repo is already private and this needs no
|
||||||
|
// extra infrastructure. "Light decision" per VNCprodbuild step 7, not
|
||||||
|
// blocking, but flagged: switching later (e.g. to a self-hosted update
|
||||||
|
// server) would mean revisiting this block and the `provider` electron-
|
||||||
|
// updater talks to.
|
||||||
|
publish: {
|
||||||
|
provider: "github",
|
||||||
|
owner: "brvncde-dotcom",
|
||||||
|
repo: "vncmail-plus",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
// deliberately the same server, not a reimplementation - lib/jmap/client.ts
|
// deliberately the same server, not a reimplementation - lib/jmap/client.ts
|
||||||
// and every app/api/** route behave identically to the web deployment.
|
// and every app/api/** route behave identically to the web deployment.
|
||||||
import { app, BrowserWindow, ipcMain, Notification } from "electron";
|
import { app, BrowserWindow, ipcMain, Notification } from "electron";
|
||||||
|
import { autoUpdater } from "electron-updater";
|
||||||
import { spawn, type ChildProcess } from "node:child_process";
|
import { spawn, type ChildProcess } from "node:child_process";
|
||||||
import { createServer } from "node:net";
|
import { createServer } from "node:net";
|
||||||
import { get as httpGet } from "node:http";
|
import { get as httpGet } from "node:http";
|
||||||
@@ -156,8 +157,36 @@ ipcMain.handle(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// --- Auto-update -------------------------------------------------------
|
||||||
|
// GitHub Releases as the update feed (electron-builder.config.js's
|
||||||
|
// `publish` block) - the skill's recommendation over standing up a new
|
||||||
|
// distribution channel, since the repo is already private. "Light
|
||||||
|
// decision" per VNCprodbuild step 7, not re-litigated here.
|
||||||
|
//
|
||||||
|
// Deliberately best-effort: there's no code signing yet (step 9), so on
|
||||||
|
// macOS in particular an update download/install can fail signature
|
||||||
|
// verification. A failed check must never take the app down - it's
|
||||||
|
// background maintenance, not something the user is blocked on.
|
||||||
|
function setupAutoUpdater(): void {
|
||||||
|
if (!app.isPackaged) {
|
||||||
|
// Unpacked dev/test runs (npm run electron:dev, the Playwright smoke
|
||||||
|
// test) have no latest.yml alongside them - checking would just log a
|
||||||
|
// noisy 404 against GitHub Releases for every dev run.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
autoUpdater.autoDownload = true;
|
||||||
|
autoUpdater.autoInstallOnAppQuit = true;
|
||||||
|
autoUpdater.on("error", (error) => {
|
||||||
|
console.error("[electron] auto-update error:", error);
|
||||||
|
});
|
||||||
|
autoUpdater.checkForUpdatesAndNotify().catch((error) => {
|
||||||
|
console.error("[electron] checkForUpdatesAndNotify failed:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
void createMainWindow();
|
void createMainWindow();
|
||||||
|
setupAutoUpdater();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on("window-all-closed", () => {
|
app.on("window-all-closed", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user