// Service worker for the Neuron PWA powered by el. // // Caching strategy: // /pkg/ — WASM runtime files, cache-first (content-addressed, change on version bump) // *.elc — compiled bytecode, stale-while-revalidate (instant load, background update) // // The WASM runtime is fetched once and cached indefinitely. // Engram programs (.elc) are served from cache immediately, then refreshed in // the background so the next load gets the newest version — no user action needed. const CACHE_NAME = 'engram-v1'; const WASM_CACHE = 'engram-wasm-v1'; // Files to pre-cache during service worker installation. const PRECACHE = [ '/pkg/el_wasm_bg.wasm', '/pkg/el_wasm.js', ]; self.addEventListener('install', event => { event.waitUntil( caches.open(WASM_CACHE).then(cache => cache.addAll(PRECACHE)) ); // Take control immediately — don't wait for existing tabs to close. self.skipWaiting(); }); self.addEventListener('fetch', event => { const url = new URL(event.request.url); // WASM runtime files: cache-first. // These are large and rarely change; the version bump forces a new URL. if (url.pathname.startsWith('/pkg/')) { event.respondWith( caches.match(event.request).then(cached => cached || fetch(event.request).then(response => { caches.open(WASM_CACHE).then(cache => cache.put(event.request, response.clone()) ); return response; }) ) ); return; } // Compiled bytecode (.elc): stale-while-revalidate. // Respond immediately from cache, update in background. if (url.pathname.endsWith('.elc')) { event.respondWith( caches.open(CACHE_NAME).then(async cache => { const cached = await cache.match(event.request); const fetchPromise = fetch(event.request).then(response => { cache.put(event.request, response.clone()); return response; }); return cached || fetchPromise; }) ); return; } }); self.addEventListener('activate', event => { // Purge old cache versions to reclaim storage. event.waitUntil( caches.keys().then(keys => Promise.all( keys .filter(k => k !== CACHE_NAME && k !== WASM_CACHE) .map(k => caches.delete(k)) ) ) ); // Claim all clients immediately. self.clients.claim(); });