// Served from / (not /static/) so its scope covers /admin/today/. const CACHE = "osiris-v1"; self.addEventListener("install", (event) => { self.skipWaiting(); }); self.addEventListener("activate", (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all(keys.filter((key) => key !== CACHE).map((key) => caches.delete(key))) ) .then(() => self.clients.claim()) ); }); self.addEventListener("fetch", (event) => { const { request } = event; // Never touch writes or the API: a stale or replayed dose would be a lie. if (request.method !== "GET" || new URL(request.url).pathname.startsWith("/api/")) { return; } // Static assets change rarely: serve from cache, refresh in the background. if (new URL(request.url).pathname.startsWith("/static/")) { event.respondWith( caches.open(CACHE).then(async (cache) => { const cached = await cache.match(request); const network = fetch(request) .then((response) => { if (response.ok) cache.put(request, response.clone()); return response; }) .catch(() => cached); return cached || network; }) ); return; } // Pages: always prefer the live version, fall back to the last one seen so the // app still opens (read-only) with no signal. event.respondWith( fetch(request) .then((response) => { if (response.ok) { const copy = response.clone(); caches.open(CACHE).then((cache) => cache.put(request, copy)); } return response; }) .catch(async () => { const cached = await caches.match(request); return ( cached || new Response( "" + "" + "

Offline

Osiris needs a connection to load. Try again once you're back online.

", { headers: { "Content-Type": "text/html; charset=utf-8" } } ) ); }) ); });