// Cairn's service worker: the app's own files come from this cache, so the board opens with no signal. Each load // also fetches a fresh copy in the background for next time. /api/ is never cached: app.js keeps the board itself. // Bump VERSION when the list of files changes. const VERSION = "cairn-1"; const SHELL = ["./", "app.js", "manifest.webmanifest", "icon-192.png", "icon-512.png", "fonts/B612Mono-Regular.ttf", "fonts/B612Mono-Bold.ttf"]; self.addEventListener("install", e => { e.waitUntil(caches.open(VERSION).then(c => c.addAll(SHELL)).then(() => self.skipWaiting())); }); self.addEventListener("activate", e => { e.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(k => k !== VERSION).map(k => caches.delete(k)))) .then(() => self.clients.claim())); }); self.addEventListener("fetch", e => { const url = new URL(e.request.url); if (e.request.method !== "GET" || url.origin !== location.origin || url.pathname.includes("/api/")) return; const key = e.request.mode === "navigate" ? "./" : e.request; e.respondWith(caches.open(VERSION).then(async cache => { const hit = await cache.match(key); const fresh = fetch(e.request).then(r => { if (r.ok) cache.put(key, r.clone()); return r; }); if (hit) { e.waitUntil(fresh.catch(() => {})); return hit; } return fresh; })); });