diff --git a/apps/desktop/src/updater.ts b/apps/desktop/src/updater.ts index 5cf69469f1..f49f4ca450 100644 --- a/apps/desktop/src/updater.ts +++ b/apps/desktop/src/updater.ts @@ -14,11 +14,29 @@ const { autoUpdater } = electronUpdater; const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000; const INITIAL_UPDATE_DELAY_MS = 30 * 1000; -// Blap update feed (same Codeberg release the electron-builder `publish` config points at). +// Blap update source (Codeberg). NOTE: Codeberg does NOT support the +// `/releases/latest/download/` alias (it 404s) — only tag-specific +// `/releases/download//` URLs work. So we resolve "latest" via the API +// and build tag-specific URLs from that, instead of relying on the broken alias. const CODEBERG_BASE = "https://codeberg.org/Enkisu/Blap"; -const LINUX_FEED_URL = `${CODEBERG_BASE}/releases/latest/download/latest-linux.yml`; +const CODEBERG_API = "https://codeberg.org/api/v1/repos/Enkisu/Blap"; const HOWTO_UPDATE_URL = `${CODEBERG_BASE}/src/branch/main/HOW-TO-UPDATE.md`; +/** Resolve the newest published release via the API. Returns its tag and numeric version. */ +async function getLatestRelease(): Promise<{ tag: string; version: string } | null> { + try { + const res = await fetch(`${CODEBERG_API}/releases/latest?t=${Date.now()}`); + if (!res.ok) return null; + const rel = (await res.json()) as { tag_name?: string }; + const tag = rel.tag_name; + if (!tag) return null; + return { tag, version: tag.replace(/^v/, "") }; + } catch (e) { + console.log("Couldn't resolve latest release", e); + return null; + } +} + function ipcChannelSendUpdateStatus(status: boolean | string): void { global.mainWindow?.webContents.send("check_updates", status); } @@ -32,6 +50,16 @@ function installUpdate(): void { async function pollForUpdates(): Promise { try { + // Point electron-updater at the latest release's tag-specific download folder + // (the baked app-update.yml uses the broken /latest/download/ alias, so we + // override it here each poll). electron-updater then fetches /latest.yml. + const latest = await getLatestRelease(); + if (latest) { + autoUpdater.setFeedURL({ + provider: "generic", + url: `${CODEBERG_BASE}/releases/download/${latest.tag}`, + }); + } await autoUpdater.checkForUpdates(); } catch (e) { console.log("Couldn't check for update", e); @@ -63,16 +91,13 @@ let lastLinuxNotifiedVersion: string | undefined; */ async function checkLinuxUpdate(): Promise { try { - const res = await fetch(`${LINUX_FEED_URL}?t=${Date.now()}`); - if (!res.ok) return; - const text = await res.text(); - const latest = /^version:\s*(.+)$/m.exec(text)?.[1]?.trim(); - if (!latest || !isNewer(latest, app.getVersion())) return; - if (latest === lastLinuxNotifiedVersion) return; // don't nag every poll - lastLinuxNotifiedVersion = latest; + const latest = await getLatestRelease(); + if (!latest || !isNewer(latest.version, app.getVersion())) return; + if (latest.version === lastLinuxNotifiedVersion) return; // don't nag every poll + lastLinuxNotifiedVersion = latest.version; if (!Notification.isSupported()) return; const notification = new Notification({ - title: `Blap ${latest} is available`, + title: `Blap ${latest.version} is available`, body: "Click to see how to update.", }); notification.on("click", () => void shell.openExternal(HOWTO_UPDATE_URL));