diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index ca1cf020..f853289b 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -60,6 +60,7 @@ let flag_clear_idb: boolean = $state(false); let flag_clear_local: boolean = $state(false); let flag_clear_sess: boolean = $state(false); let flag_reload: boolean = $state(false); +let flag_hard_reload: boolean = $state(false); let flag_new_ver: boolean = $state(false); let flag_expired: boolean = $state(false); @@ -72,6 +73,7 @@ let api_error_msg = $derived($ae_loc?.account_name || 'API Server Unreachable'); let show_connection_details = $state(true); let last_reload_time = 0; +let sw_heal_in_flight = false; // Shallow equality guard — avoids triggering Svelte store updates when the merged // object is functionally identical to the current one. Comparing JSON.stringify on @@ -139,8 +141,11 @@ $effect(() => { // B. Version & Sanity Check if (new_loc.ver && $ae_sess.ver && new_loc.ver !== $ae_sess.ver) { if (!flag_new_ver) { - console.log('ROOT: Version mismatch detected'); + console.log( + 'ROOT: Version mismatch detected; clearing stale service workers and caches before reload' + ); flag_new_ver = true; + flag_hard_reload = true; flag_reload = true; } } @@ -189,6 +194,15 @@ $effect(() => { if (flag_clear_local) clear_local(); if (flag_clear_sess) clear_sess(); + if (flag_hard_reload) { + flag_hard_reload = false; + console.log('ROOT: Executing hard reload after service worker heal'); + void clear_stale_service_worker_state().finally(() => { + location.reload(); + }); + return; + } + console.log('ROOT: Executing throttled reload'); invalidateAll(); }); @@ -252,6 +266,35 @@ function clear_sess() { sessionStorage.clear(); } +async function clear_stale_service_worker_state() { + if (!browser || sw_heal_in_flight) return; + sw_heal_in_flight = true; + + try { + if ('serviceWorker' in navigator) { + const registrations = await navigator.serviceWorker.getRegistrations(); + for (const registration of registrations) { + await registration.unregister(); + } + } + } catch (err) { + console.warn('ROOT: Service worker unregister failed during heal:', err); + } + + try { + if ('caches' in window) { + const cache_keys = await caches.keys(); + for (const cache_key of cache_keys) { + await caches.delete(cache_key); + } + } + } catch (err) { + console.warn('ROOT: Cache cleanup failed during heal:', err); + } finally { + sw_heal_in_flight = false; + } +} + // 4. EXTERNAL INTERFACES EFFECT $effect(() => { if (!browser) return;