// famapp service worker — app-shell pattern // Caches a minimal offline fallback on install. // Navigation requests: network-first with offline fallback. // Next.js static chunks: cache-first. // API routes: network-only (pass through). const CACHE = "famapp-shell-v1"; const OFFLINE = "/offline.html"; // --- install: precache offline shell --- self.addEventListener("install", (event) => { event.waitUntil( caches.open(CACHE).then((cache) => cache.add(OFFLINE)) ); self.skipWaiting(); }); // --- activate: evict old caches --- self.addEventListener("activate", (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))) ) ); self.clients.claim(); }); // --- fetch --- self.addEventListener("fetch", (event) => { const { request } = event; if (request.method !== "GET") return; const url = new URL(request.url); // API routes — always go to network, never cache. if (url.pathname.startsWith("/api/")) return; // NextAuth — network-only. if (url.pathname.startsWith("/api/auth/")) return; // Next.js immutable static assets — cache-first. if (url.pathname.startsWith("/_next/static/")) { event.respondWith( caches.match(request).then( (cached) => cached ?? fetch(request).then((res) => { const clone = res.clone(); caches.open(CACHE).then((c) => c.put(request, clone)); return res; }) ) ); return; } // Navigation requests — network-first, serve offline shell if unreachable. if (request.mode === "navigate") { event.respondWith( fetch(request).catch(() => caches.match(OFFLINE)) ); return; } });