const CACHE_NAME = 'tsl-embedded-pwa-v12'; const APP_SHELL = [ '/', '/admin.html', '/setup.html', '/manifest.webmanifest', '/css/app.css', '/css/setup.css', '/js/app.js', '/js/setup.js', '/js/pwa.js', '/components/status-card.js', '/components/uptime-card.js', '/components/led-card.js', '/components/add-card.js', '/icons/icon.svg', '/icons/icon-192.png', '/icons/icon-512.png' ]; self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(APP_SHELL)) .then(() => self.skipWaiting()) ); }); self.addEventListener('activate', event => { event.waitUntil( caches.keys() .then(names => Promise.all(names.filter(name => name !== CACHE_NAME).map(name => caches.delete(name)))) .then(() => self.clients.claim()) ); }); self.addEventListener('fetch', event => { const requestUrl = new URL(event.request.url); if (requestUrl.origin !== location.origin || requestUrl.pathname.startsWith('/api/')) return; if (event.request.mode === 'navigate') { event.respondWith(fetch(event.request).catch(() => caches.match('/admin.html'))); return; } event.respondWith( caches.match(event.request).then(cached => cached || fetch(event.request).then(response => { if (!response || response.status !== 200 || event.request.method !== 'GET') return response; const copy = response.clone(); caches.open(CACHE_NAME).then(cache => cache.put(event.request, copy)); return response; })) ); });