/* Baby Tracker — shell-only service worker Precaches static UI assets. Never caches API / Supabase / config. */ const CACHE = 'baby-shell-v1'; const PRECACHE = [ './', './index.html', './manifest.webmanifest', './src/styles/main.css', './src/js/config.js', './src/js/utils.js', './src/js/db.js', './src/js/charts.js', './src/js/toast.js', './src/js/app.js', './icons/icon.svg', './icons/apple-touch-icon.svg' ]; self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE) .then((cache) => cache.addAll(PRECACHE)) .then(() => self.skipWaiting()) .catch(() => self.skipWaiting()) ); }); self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))) ).then(() => self.clients.claim()) ); }); function isShellRequest(url) { // Only same-origin static assets if (url.origin !== self.location.origin) return false; const path = url.pathname; if (path.endsWith('.html') || path.endsWith('/') || path.endsWith('.css') || path.endsWith('.js') || path.endsWith('.svg') || path.endsWith('.webmanifest') || path.endsWith('.ico') || path.endsWith('.png')) { // Never cache remote config path if hosted same-origin under /api if (path.includes('/api/')) return false; return true; } return false; } self.addEventListener('fetch', (event) => { const req = event.request; if (req.method !== 'GET') return; let url; try { url = new URL(req.url); } catch { return; } // Pass through cross-origin (CDN, Supabase, APIs) if (url.origin !== self.location.origin) return; if (!isShellRequest(url)) return; // Network-first for HTML so deploys show up; cache-first for static assets const isHTML = url.pathname.endsWith('.html') || url.pathname.endsWith('/'); if (isHTML) { event.respondWith( fetch(req).then((res) => { const copy = res.clone(); caches.open(CACHE).then((c) => c.put(req, copy)).catch(() => {}); return res; }).catch(() => caches.match(req).then((r) => r || caches.match('./index.html'))) ); return; } event.respondWith( caches.match(req).then((cached) => { const network = fetch(req).then((res) => { if (res && res.ok) { const copy = res.clone(); caches.open(CACHE).then((c) => c.put(req, copy)).catch(() => {}); } return res; }).catch(() => cached); return cached || network; }) ); });