// Minimal service worker: offline shell only. No data caching. const CACHE = 'ticketing-shell-v1'; const SHELL = ['/', '/icon.svg', '/manifest.webmanifest']; self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE).then((cache) => cache.addAll(SHELL)), ); self.skipWaiting(); }); self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))), ), ); self.clients.claim(); }); self.addEventListener('fetch', (event) => { const req = event.request; if (req.method !== 'GET') return; const url = new URL(req.url); // Never cache API calls — they must always hit the server if (url.pathname.startsWith('/api/')) return; // Network-first for navigation, fall back to cached shell if (req.mode === 'navigate') { event.respondWith( fetch(req) .then((res) => { const clone = res.clone(); caches.open(CACHE).then((c) => c.put('/', clone)); return res; }) .catch(() => caches.match('/')), ); return; } // Cache-first for static assets if (url.origin === self.location.origin) { event.respondWith( caches.match(req).then((cached) => { if (cached) return cached; return fetch(req).then((res) => { if (res.ok && res.type === 'basic') { const clone = res.clone(); caches.open(CACHE).then((c) => c.put(req, clone)); } return res; }); }), ); } });