fix(idaa): increase spinner timeout to 35s, guard sessionStorage with try-catch

VERIFY_TIMEOUT_MS 8s → 35s: worst-case auto-retry cycle is 27s (12s abort +
3s wait + 12s abort). At 8s the "Reset & Retry" banner fired while the second
retry was still in flight; members who clicked it cleared their stores and
reloaded mid-attempt, landing on Access Denied. At 35s the escape hatch only
appears if verification is genuinely stuck (slow Novi server or missing api_key).

sessionStorage try-catch: iOS Safari Private Browsing and certain iframe sandbox
configs throw on sessionStorage access. Wrap setItem (onMount) and getItem
(reload_with_uuid) in try-catch so the component degrades gracefully to
location.reload() rather than crashing silently.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-05-19 16:04:28 -04:00
parent 14e84884cd
commit 53fd5e7de4

View File

@@ -83,18 +83,29 @@ const IDAA_IFRAME_RELOAD_URL_KEY = 'idaa_iframe_reload_url';
onMount(() => {
const uuid_in_url = new URLSearchParams(window.location.search).get('uuid');
if (uuid_in_url && !sessionStorage.getItem(IDAA_IFRAME_RELOAD_URL_KEY)) {
sessionStorage.setItem(IDAA_IFRAME_RELOAD_URL_KEY, window.location.href);
if (uuid_in_url) {
// Guard: iOS Safari Private Browsing and some iframe sandbox configs throw on
// sessionStorage access. Graceful fallback: skip the save; reload_with_uuid()
// will fall back to location.reload() (loses UUID-preservation but doesn't crash).
try {
if (!sessionStorage.getItem(IDAA_IFRAME_RELOAD_URL_KEY)) {
sessionStorage.setItem(IDAA_IFRAME_RELOAD_URL_KEY, window.location.href);
}
} catch {
console.warn('IDAA Layout: sessionStorage unavailable — reload buttons will use location.reload() fallback.');
}
}
});
function reload_with_uuid() {
const initial_url = sessionStorage.getItem(IDAA_IFRAME_RELOAD_URL_KEY);
if (initial_url && initial_url !== location.href) {
location.href = initial_url;
} else {
location.reload();
}
try {
const initial_url = sessionStorage.getItem(IDAA_IFRAME_RELOAD_URL_KEY);
if (initial_url && initial_url !== location.href) {
location.href = initial_url;
return;
}
} catch { /* sessionStorage unavailable — fall through to location.reload() */ }
location.reload();
}
// Clear stale db_events.event IDB data on IDAA session start.
@@ -116,7 +127,13 @@ if (browser) {
// Show a manual reset button if the spinner is still visible after this many ms.
// Handles the case where site_cfg_json loads without novi_idaa_api_key (stale cache)
// or the Novi API call hangs — the user would otherwise be stuck with no escape.
const VERIFY_TIMEOUT_MS = 8000;
//
// WHY 35s: worst-case auto-retry cycle is 27s (12s first timeout + 3s wait + 12s retry).
// If the auto-retries succeed or fail within that window, the spinner is already gone
// (content shown or error panel shown) before this fires. The escape hatch only appears
// for the rare case where the Novi API is slow-but-not-timing-out, or site_cfg_json
// never loads. Previously 8s — fired mid-flight and caused premature Reset & Retry clicks.
const VERIFY_TIMEOUT_MS = 35_000;
let verifying_timed_out: boolean = $state(false);
@@ -131,7 +148,7 @@ $effect(() => {
}
});
const VERIFIED_TTL_MS_DEFAULT = 45 * 60 * 1000; // 25 minutes
const VERIFIED_TTL_MS_DEFAULT = 45 * 60 * 1000; // 45 minutes
// Effect 1: Set URL origin and params
$effect(() => {