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