const CACHE_NAME = 'quartiles-pwa-v1'; const STATIC_ASSETS = [ '/', '/index.html', '/manifest.webmanifest', '/icon.svg' ]; // Install: Cache initial shell assets self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME).then(cache => { return cache.addAll(STATIC_ASSETS); }).then(() => self.skipWaiting()) ); }); // Activate: Clean up old cache versions self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(keys => { return Promise.all( keys.map(key => { if (key !== CACHE_NAME) { return caches.delete(key); } }) ); }).then(() => self.clients.claim()) ); }); // Fetch: Stale-While-Revalidate for local assets, Network-First for HTML navigation self.addEventListener('fetch', event => { const request = event.request; const url = new URL(request.url); // Only handle GET requests if (request.method !== 'GET') return; // Version checks must always hit the network (never cached) if (url.origin === location.origin && url.pathname === '/version.json') return; // Handle HTML navigation requests (Offline support) if (request.mode === 'navigate') { event.respondWith( fetch(request) .then(response => { if (response && response.status === 200) { const responseClone = response.clone(); caches.open(CACHE_NAME).then(cache => cache.put(request, responseClone)); } return response; }) .catch(() => caches.match('/index.html') || caches.match('/')) ); return; } // Same-origin static assets or Google Fonts: Stale-While-Revalidate if (url.origin === location.origin || url.hostname.includes('googleapis.com') || url.hostname.includes('gstatic.com')) { event.respondWith( caches.match(request).then(cachedResponse => { const fetchPromise = fetch(request) .then(networkResponse => { if (networkResponse && networkResponse.status === 200) { const responseClone = networkResponse.clone(); caches.open(CACHE_NAME).then(cache => cache.put(request, responseClone)); } return networkResponse; }) .catch(() => cachedResponse); return cachedResponse || fetchPromise; }) ); } });