/* Foodlinkk PWA service worker v6 */ const CACHE = 'foodlinkk-shell-v6'; const PRECACHE = [ '/', '/static/manifest.json', '/static/css/mobile.css?v=6', '/static/css/app-sidebar-neo.css?v=12', '/static/css/palantir-theme.css?v=4', '/static/icons/icon-192.png', '/static/icons/icon-512.png', '/static/icons/apple-touch-icon.png', ]; self.addEventListener('install', (event) => { self.skipWaiting(); event.waitUntil( caches.open(CACHE).then((cache) => cache.addAll(PRECACHE).catch(() => undefined)) ); }); 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()) ); }); self.addEventListener('fetch', (event) => { const req = event.request; if (req.method !== 'GET') return; const url = new URL(req.url); if (url.origin !== self.location.origin) return; // API / live data: always network if (url.pathname.startsWith('/api') || url.pathname.includes('/ws')) return; // Navigations: network-first, fallback to cache if (req.mode === 'navigate') { event.respondWith( fetch(req) .then((res) => { const copy = res.clone(); caches.open(CACHE).then((c) => c.put('/', copy)).catch(() => undefined); return res; }) .catch(() => caches.match('/') || caches.match(req)) ); return; } // Static assets: stale-while-revalidate if (url.pathname.startsWith('/static/')) { event.respondWith( caches.match(req).then((cached) => { const net = fetch(req) .then((res) => { if (res && res.ok) { const copy = res.clone(); caches.open(CACHE).then((c) => c.put(req, copy)).catch(() => undefined); } return res; }) .catch(() => cached); return cached || net; }) ); } });