diff --git a/package.json b/package.json index 0d02744a..9ce02f52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "theseus-navigator", - "version": "0.3.65", + "version": "0.3.66", "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 ce7870dd..892d41fe 100644 --- a/settings.html +++ b/settings.html @@ -821,6 +821,47 @@ { tag: "he-IL", label: "עברית" }, { tag: "zh-TW", label: "中文(繁體)" }, ]; + // Updates panel — intentionally runs STANDALONE, before anything else. + // Previously this lived inside the big C.get().then((s)=>…) settings init, + // and any throw earlier in that block (an unrelated feature failing on a + // specific profile) left this panel stuck on "Loading…" forever because + // the version read never ran. It only needs the appVersion/recheckUpdate + // IPCs and the two DOM elements — all available at script time — so run it + // immediately and in its own try, isolated from everything else. + (function initUpdatesPanel() { + const updStatus = document.getElementById("updStatus"); + const updCheck = document.getElementById("updCheck"); + if (!updStatus) return; + try { + if (C && typeof C.appVersion === "function") { + 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."; + } + if (updCheck) updCheck.onclick = async () => { + const orig = updCheck.textContent; + updCheck.disabled = true; updCheck.textContent = "Checking…"; + updStatus.textContent = "Checking…"; + try { + if (!C || typeof C.recheckUpdate !== "function") 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) { + updStatus.textContent = "Updates panel init failed: " + (e?.message || e); + console.error("Updates panel init failed:", e); + } + })(); // sidebar navigation // "naming" is intentionally absent: the Registries section was folded // into General in 0.3.21. Leaving the id in this list threw a @@ -1782,48 +1823,9 @@ refreshAegis(); })(); - // ---- Manual "Check for updates" ----------------------------------------- - // 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". - // 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); - } + // Updates panel moved OUT of this block — it runs standalone right after + // the shared WEB_LANG_LIST so a thrown exception anywhere in this big + // C.get().then((s)=>…) init can never block it again. // ---- Passwords section: three states (setup / locked / unlocked) --------- // The vault lives in main.js — this UI just calls IPC. No plaintext ever