/// /// /// /// // Offline-first: the app shell and static assets are cached on install. // GitHub API calls are never cached (sync needs live data). import { build, files, version } from '$service-worker'; const sw = self as unknown as ServiceWorkerGlobalScope; const CACHE = `papure-${version}`; const ASSETS = [...build, ...files, '/']; sw.addEventListener('install', (event) => { event.waitUntil( caches .open(CACHE) // Bypass the HTTP cache: hashed assets are cached as immutable, so a bad // response (e.g. a wrong MIME type) would otherwise be copied in forever. .then((c) => c.addAll(ASSETS.map((url) => new Request(url, { cache: 'reload' })))) .then(() => sw.skipWaiting()) ); }); sw.addEventListener('activate', (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))) .then(() => sw.clients.claim()) ); }); sw.addEventListener('fetch', (event) => { const req = event.request; if (req.method !== 'GET') return; const url = new URL(req.url); if (url.origin !== sw.location.origin) return; // Navigations: network first, fall back to the cached shell (SPA). if (req.mode === 'navigate') { event.respondWith( fetch(req).catch(async () => (await caches.match('/')) ?? Response.error()) ); return; } // Assets: cache first (they're versioned or fixed). event.respondWith( caches.match(req).then( (hit) => hit ?? fetch(req).then((res) => { if (res.ok && ASSETS.includes(url.pathname)) { const copy = res.clone(); void caches.open(CACHE).then((c) => c.put(req, copy)); } return res; }) ) ); });