const CACHE = 'premier-gunner-v6'; const SHELL = [ '/', '/index.html', '/login.html', '/css/styles.css', '/js/app.js', '/js/api.js', '/js/dashboard.js', '/vendor/chart.umd.min.js', '/manifest.webmanifest', '/icons/logo.svg', '/icons/favicon.svg', '/icons/icon-192.png', '/icons/icon-512.png', ]; self.addEventListener('install', (e) => { // Pre-cache the new shell, but do NOT skipWaiting automatically — we wait // until the page tells us to (via the "Refresh" banner) so the update is // controlled and the user is never interrupted mid-action. e.waitUntil(caches.open(CACHE).then((c) => c.addAll(SHELL))); }); self.addEventListener('activate', (e) => { e.waitUntil( caches.keys().then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))) .then(() => self.clients.claim()) ); }); // The page posts this when the user taps "Refresh" on the update banner. self.addEventListener('message', (e) => { if (e.data && e.data.type === 'SKIP_WAITING') self.skipWaiting(); }); self.addEventListener('fetch', (e) => { const url = new URL(e.request.url); if (e.request.method !== 'GET') return; // Never cache the API — always go to network so data stays fresh and auth works. if (url.pathname.startsWith('/api/')) return; e.respondWith( caches.match(e.request).then((cached) => { const network = fetch(e.request).then((res) => { if (res.ok && url.origin === location.origin) { const copy = res.clone(); caches.open(CACHE).then((c) => c.put(e.request, copy)); } return res; }).catch(() => cached); return cached || network; }) ); });