// Spendlight service worker. Makes the home-screen app open instantly and // show its shell offline. It never touches /api: household data is always // fetched fresh and never stored here. const SHELL = 'spendlight-shell'; const ASSETS = 'spendlight-assets'; const MAX_ASSETS = 80; self.addEventListener('install', () => self.skipWaiting()); self.addEventListener('activate', (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all(keys.filter((k) => k !== SHELL && k !== ASSETS).map((k) => caches.delete(k)))) .then(() => self.clients.claim()), ); }); self.addEventListener('fetch', (event) => { const request = event.request; const url = new URL(request.url); if (request.method !== 'GET' || url.origin !== self.location.origin || url.pathname.startsWith('/api/')) return; // Pages: always try the network first so a new version shows up at once. if (request.mode === 'navigate') { event.respondWith( fetch(request) .then((response) => { if (response.ok) { const copy = response.clone(); caches.open(SHELL).then((cache) => cache.put('/', copy)); } return response; }) .catch(() => caches.match('/').then((cached) => cached || Response.error())), ); return; } // Versioned files never change, so a cached copy is always right. if (url.pathname.startsWith('/assets/')) { event.respondWith( caches.open(ASSETS).then(async (cache) => { const cached = await cache.match(request); if (cached) return cached; const response = await fetch(request); if (response.ok) { await cache.put(request, response.clone()); const keys = await cache.keys(); if (keys.length > MAX_ASSETS) await Promise.all(keys.slice(0, keys.length - MAX_ASSETS).map((k) => cache.delete(k))); } return response; }), ); } });