// CERTifAI Service Worker — network-first with offline fallback cache. // Static assets (CSS, JS, WASM, fonts) use cache-first for speed. // API and navigation requests always try the network first. const CACHE_NAME = "certifai-v1"; // Pre-cache the app shell on install self.addEventListener("install", (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => cache.addAll([ "/", "/dashboard", "/assets/logo.svg", "/assets/favicon.svg", ]) ) ); self.skipWaiting(); }); // Clean up old caches on activate self.addEventListener("activate", (event) => { event.waitUntil( caches.keys().then((keys) => Promise.all( keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k)) ) ) ); self.clients.claim(); }); self.addEventListener("fetch", (event) => { const url = new URL(event.request.url); // Skip non-GET and API requests (let them go straight to network) if (event.request.method !== "GET" || url.pathname.startsWith("/api/")) { return; } // Cache-first for static assets (hashed filenames make this safe) const isStatic = /\.(js|wasm|css|ico|svg|png|jpg|woff2?)(\?|$)/.test(url.pathname); if (isStatic) { event.respondWith( caches.match(event.request).then((cached) => cached || fetch(event.request).then((resp) => { const clone = resp.clone(); caches.open(CACHE_NAME).then((c) => c.put(event.request, clone)); return resp; }) ) ); return; } // Network-first for navigation / HTML event.respondWith( fetch(event.request) .then((resp) => { const clone = resp.clone(); caches.open(CACHE_NAME).then((c) => c.put(event.request, clone)); return resp; }) .catch(() => caches.match(event.request)) ); });