const CACHE_NAME = "roast-planner-static-v3"; const APP_SHELL = [ "/", "/landing.html", "/app.css", "/worksheet.css", "/manifest.webmanifest", "/icon.svg", "/js/main.js", "/js/landing.js", "/js/admin.js", "/js/prefill-ui.js", "/js/alog-ui.js", "/js/print.js", "/shared/fields.js", "/shared/ledger.js", "/shared/time.js", "/shared/reference-data.js", "/shared/curve.js", ]; self.addEventListener("install", (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => cache.addAll(APP_SHELL)), ); self.skipWaiting(); }); self.addEventListener("activate", (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all( keys .filter((key) => key !== CACHE_NAME) .map((key) => caches.delete(key)), ), ), ); self.clients.claim(); }); self.addEventListener("fetch", (event) => { const { request } = event; let url; try { url = new URL(request.url); } catch { return; } if ( request.method !== "GET" || url.origin !== self.location.origin || url.pathname.startsWith("/api/") ) return; if (request.mode === "navigate") { // Never serve authenticated application HTML from cache after logout. event.respondWith( fetch(request).catch(() => caches.match("/landing.html")), ); return; } // Prefer fresh JavaScript and styles so installed clients receive UI/security updates // immediately; use the cache only when offline. event.respondWith( fetch(request) .then((response) => { if (response.ok) caches .open(CACHE_NAME) .then((cache) => cache.put(request, response.clone())); return response; }) .catch(() => caches.match(request)), ); });