// VIBN Service Worker — PWA shell (production). Must always resolve respondWith to a Response. const CACHE = 'vibn-v1'; self.addEventListener('install', (e) => { e.waitUntil( caches.open(CACHE).then((cache) => cache.addAll(['/', '/manifest.json'])) ); self.skipWaiting(); }); self.addEventListener('activate', () => self.clients.claim()); self.addEventListener('fetch', (e) => { const { request } = e; const url = new URL(request.url); // Let the browser handle Next.js RSC, Turbopack/HMR, and dev endpoints — do not intercept. if ( url.pathname.startsWith('/_next/') || url.pathname.includes('__nextjs') || url.search.includes('_rsc=') ) { return; } if (url.pathname.startsWith('/api/')) { return; } if ( request.destination === 'image' || request.destination === 'font' || url.pathname.startsWith('/_next/static/') ) { e.respondWith( caches.match(request).then((cached) => { if (cached) return cached; return fetch(request).then((res) => { const clone = res.clone(); caches.open(CACHE).then((c) => c.put(request, clone)); return res; }); }) ); return; } // Network-first; cache fallback must be a real Response (undefined breaks FetchEvent). e.respondWith( fetch(request) .catch(() => caches.match(request)) .then((cachedOrFailed) => { if (cachedOrFailed instanceof Response) return cachedOrFailed; return new Response('Offline', { status: 503, statusText: 'Service Unavailable', headers: { 'Content-Type': 'text/plain' }, }); }) ); });