From 338dbe6c1f56df2bbf218fd8119a4080b8b13ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Wed, 29 Jul 2026 13:46:15 +0200 Subject: [PATCH] fix(01-06): purge owned PWA caches on session end - delete current and legacy HealthLog static page and data caches - preserve unrelated CacheStorage namespaces during activation and logout - keep IndexedDB query-cache removal in the session-end boundary --- public/sw.js | 13 ++++++++++++- src/lib/pwa/query-persister.ts | 10 +++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/public/sw.js b/public/sw.js index fd60ece14..499698631 100644 --- a/public/sw.js +++ b/public/sw.js @@ -51,6 +51,16 @@ const PAGE_CACHE = `healthlog-pages-${CACHE_VERSION}`; // next paint. Network-first restores read-after-write freshness while keeping // the offline fallback. const DATA_CACHE = `healthlog-data-${CACHE_VERSION}`; +// Keep this ownership contract aligned with +// `clearOfflineCachesForSessionEnd()` in `query-persister.ts`. Cache cleanup +// must cover every current/legacy HealthLog cache without deleting unrelated +// CacheStorage namespaces owned by another app on the same origin. +const HEALTHLOG_CACHE_NAME_RE = /^healthlog-(?:static|pages|data)-/; +const CURRENT_HEALTHLOG_CACHES = new Set([ + STATIC_CACHE, + PAGE_CACHE, + DATA_CACHE, +]); const MAX_STATIC_ENTRIES = 150; const MAX_PAGE_ENTRIES = 30; const MAX_DATA_ENTRIES = 60; @@ -136,7 +146,8 @@ self.addEventListener("activate", (event) => { keys .filter( (k) => - k !== STATIC_CACHE && k !== PAGE_CACHE && k !== DATA_CACHE, + HEALTHLOG_CACHE_NAME_RE.test(k) && + !CURRENT_HEALTHLOG_CACHES.has(k), ) .map((k) => caches.delete(k)), ), diff --git a/src/lib/pwa/query-persister.ts b/src/lib/pwa/query-persister.ts index 3fc3e2067..805b44f04 100644 --- a/src/lib/pwa/query-persister.ts +++ b/src/lib/pwa/query-persister.ts @@ -39,6 +39,10 @@ const STORE = "kv"; const KEY = "react-query"; const VERSION_KEY = "react-query-version"; const MAX_AGE_MS = 24 * 60 * 60 * 1000; // discard anything older than a day +// Keep this ownership contract aligned with `public/sw.js`. Session-end +// cleanup removes every current/legacy HealthLog cache family while leaving +// unrelated CacheStorage namespaces on the same origin untouched. +const HEALTHLOG_CACHE_NAME_RE = /^healthlog-(?:static|pages|data)-/; /** * Upper bound on the serialized snapshot. The allowlist already caps WHAT is @@ -326,11 +330,7 @@ export async function clearOfflineCachesForSessionEnd(): Promise { const keys = await caches.keys(); await Promise.all( keys - .filter( - (k) => - k.startsWith("healthlog-data-") || - k.startsWith("healthlog-pages-"), - ) + .filter((k) => HEALTHLOG_CACHE_NAME_RE.test(k)) .map((k) => caches.delete(k)), ); } catch {