// Bump this on every release that changes the app shell or the vendored // engine build — it's the only thing that invalidates old caches, since // none of the cached URLs below are content-hashed by us. const CACHE_VERSION = "v2"; const SHELL_CACHE = `shell-${CACHE_VERSION}`; const ENGINE_CACHE = `engine-${CACHE_VERSION}`; const SHELL_ASSETS = [ "/", "/play/", "/manifest.webmanifest", "/icons/icon-192.png", "/icons/icon-512.png", ]; self.addEventListener("install", (event) => { event.waitUntil( caches .open(SHELL_CACHE) .then((cache) => cache.addAll(SHELL_ASSETS)) .then(() => self.skipWaiting()), ); }); self.addEventListener("activate", (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all( keys .filter((key) => key !== SHELL_CACHE && key !== ENGINE_CACHE) .map((key) => caches.delete(key)), ), ) .then(() => self.clients.claim()), ); }); self.addEventListener("fetch", (event) => { const url = new URL(event.request.url); if (event.request.method !== "GET" || url.origin !== self.location.origin) return; // The engine's .wasm/.data/.js are large and effectively immutable per // release (they aren't content-hashed), so once fetched they're served // straight from cache — cache-busting happens by bumping CACHE_VERSION. if (url.pathname.startsWith("/vendor/vpinball-wasm/")) { event.respondWith( caches.open(ENGINE_CACHE).then((cache) => cache.match(event.request).then( (hit) => hit ?? fetch(event.request).then((response) => { cache.put(event.request, response.clone()); return response; }), ), ), ); return; } event.respondWith( caches.match(event.request).then( (hit) => hit ?? fetch(event.request).then((response) => { if (response.ok) { const clone = response.clone(); caches.open(SHELL_CACHE).then((cache) => cache.put(event.request, clone)); } return response; }), ), ); });