const CACHE_NAME = 'ims-v1' self.addEventListener('install', () => { self.skipWaiting() }) self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(keys => Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k))) ) ) self.clients.claim() }) self.addEventListener('fetch', event => { const url = new URL(event.request.url) // Only handle same-origin GET requests if ( event.request.method !== 'GET' || url.origin !== self.location.origin || !url.pathname.startsWith('/') ) { return } // Skip API routes — always go to network if (url.pathname.startsWith('/api/')) return // Cache-first for immutable Next.js static assets if (url.pathname.startsWith('/_next/static/')) { event.respondWith( caches.match(event.request).then(cached => { if (cached) return cached return fetch(event.request).then(res => { if (res.ok) { const clone = res.clone() caches.open(CACHE_NAME).then(c => c.put(event.request, clone)) } return res }) }) ) return } // Network-first for pages — fall back to cache when offline event.respondWith( fetch(event.request) .then(res => { if (res.ok) { const clone = res.clone() caches.open(CACHE_NAME).then(c => c.put(event.request, clone)) } return res }) .catch(() => caches.match(event.request)) ) })