From a02deffe61119da607aecd7b750a313192ec6212 Mon Sep 17 00:00:00 2001 From: Silent Mode Date: Fri, 2 Oct 2026 22:45:36 +0200 Subject: [PATCH] =?UTF-8?q?Theseus=200.3.65:=20Updates=20panel=20can't=20s?= =?UTF-8?q?ilently=20fatal=20into=20"Loading=E2=80=A6"=20any=20more?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settings › General › Updates used to stay on "Loading…" forever if anything earlier in the shared C.get().then((s)=>…) init threw, or if the version IPC rejected — the .catch(()=>{}) on the version fetch swallowed it. Users then had no in-app way to run "Check for updates", because the button sits in the same panel. Panel init now wraps in its own try, surfaces the actual error on the status line (missing IPC / fetch rejection / init failure), and keeps the Check for Updates button functional even when the earlier version read fails. Toolbar chip is unaffected either way — the auto-updater runs independently. --- package.json | 2 +- settings.html | 59 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 440db0d9..0d02744a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "theseus-navigator", - "version": "0.3.64", + "version": "0.3.65", "license": "MPL-2.0", "description": "Theseus Navigator — a browser that follows the thread. By Silent Mode, a Deviant project.", "author": "Silent Mode", diff --git a/settings.html b/settings.html index 921a7591..ce7870dd 100644 --- a/settings.html +++ b/settings.html @@ -1786,27 +1786,44 @@ // Fires an IPC that un-dismisses any lingering session chip and hits the // release manifest. Renders either "you're on the latest (vN.M.O)" or // "vX.Y.Z is available — the update chip in the toolbar will offer it". - const updStatus = document.getElementById("updStatus"); - // Show the current version by default so the user doesn't have to - // click "Check for updates" just to find out which Theseus they're on. - if (C && C.appVersion) C.appVersion().then((v) => { - if (v) updStatus.textContent = `You're on v${v}.`; - }).catch(() => {}); - const updCheck = document.getElementById("updCheck"); - updCheck.onclick = async () => { - const orig = updCheck.textContent; - updCheck.disabled = true; updCheck.textContent = "Checking…"; - updStatus.textContent = "Checking…"; - try { - const r = await C.recheckUpdate(); - if (r && r.updateAvailable && r.updateAvailable.version) { - updStatus.innerHTML = `v${r.updateAvailable.version} is available — the update chip in the toolbar will offer it.`; - } else { - updStatus.textContent = `You're on the latest (v${(r && r.currentVersion) || "?"}).`; - } - } catch (e) { updStatus.textContent = "Check failed: " + (e?.message || e); } - finally { updCheck.disabled = false; updCheck.textContent = orig; } - }; + // Wrap the Updates panel init in its own try — any earlier failure in + // this big C.get().then((s)=>…) block would otherwise leave the panel + // stuck on "Loading…" forever (silent `.catch(()=>{})` on the version + // fetch). We also always react to the fetch's reject, instead of + // swallowing it, so the user has a status line they can act on. + try { + const updStatus = document.getElementById("updStatus"); + // Show the current version by default so the user doesn't have to + // click "Check for updates" just to find out which Theseus they're on. + if (C && C.appVersion) { + C.appVersion().then((v) => { + updStatus.textContent = v ? `You're on v${v}.` : "Version unavailable — try Check for updates."; + }).catch((e) => { + updStatus.textContent = "Could not read version: " + (e?.message || e) + " — try Check for updates."; + }); + } else { + updStatus.textContent = "This build is missing the version IPC — restart Theseus to refresh the panel."; + } + const updCheck = document.getElementById("updCheck"); + if (updCheck) updCheck.onclick = async () => { + const orig = updCheck.textContent; + updCheck.disabled = true; updCheck.textContent = "Checking…"; + updStatus.textContent = "Checking…"; + try { + if (!C.recheckUpdate) throw new Error("recheck-update IPC not exposed"); + const r = await C.recheckUpdate(); + if (r && r.updateAvailable && r.updateAvailable.version) { + updStatus.innerHTML = `v${r.updateAvailable.version} is available — the update chip in the toolbar will offer it.`; + } else { + updStatus.textContent = `You're on the latest (v${(r && r.currentVersion) || "?"}).`; + } + } catch (e) { updStatus.textContent = "Check failed: " + (e?.message || e); } + finally { updCheck.disabled = false; updCheck.textContent = orig; } + }; + } catch (e) { + try { document.getElementById("updStatus").textContent = "Updates panel init failed: " + (e?.message || e); } catch {} + console.error("Updates panel init failed:", e); + } // ---- Passwords section: three states (setup / locked / unlocked) --------- // The vault lives in main.js — this UI just calls IPC. No plaintext ever