From dd48e899fac12bdea706bb2b8b044808abaaa503 Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 17 Jun 2026 18:09:49 -0700 Subject: [PATCH] web UI: on 401, reload to the login page instead of a cryptic error toast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sessions are in-memory, so a server restart (or a session TTL expiry) leaves a still-open SPA tab holding a stale cookie: cached views keep rendering, but every mutating call 401s and surfaced only as an "authentication required" toast (e.g. saving Settings) — a confusing dead end. Make api() treat 401 as "session gone": flash a notice and location.reload(), which the server answers with the login page. No reload loop (the login page isn't the SPA), and authed sessions are unaffected. Co-Authored-By: Claude Opus 4.8 --- src/web_ui/index.html | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/web_ui/index.html b/src/web_ui/index.html index 2cfd72b..398f7c5 100644 --- a/src/web_ui/index.html +++ b/src/web_ui/index.html @@ -549,7 +549,19 @@ function toggleSidebar(){document.getElementById('sidebar').classList.toggle('op function closeSidebar(){document.getElementById('sidebar').classList.remove('open');document.getElementById('sidebar-overlay').classList.remove('open')} /* ── API ────────────────────────────────────────────────────────── */ -async function api(path,opts){const r=await fetch(path,opts);if(!r.ok)throw new Error(await r.text());return r} +async function api(path,opts){ + const r=await fetch(path,opts); + // Session gone (expired, or the server restarted — sessions are in-memory): + // the cached SPA would otherwise just throw cryptic "authentication required" + // toasts on every action. Reload instead so the server serves the login page. + if(r.status===401){ + try{setStatus('Session expired — reloading to sign in…')}catch{} + location.reload(); + throw new Error('session expired'); + } + if(!r.ok)throw new Error(await r.text()); + return r; +} /* ── Library ────────────────────────────────────────────────────── */ // Cache the ETag of the most-recent library response so subsequent polls