const CACHE = 'microlearn-shell-v2' const OFFLINE_URL = '/offline.html' const SHELL = ['/', OFFLINE_URL, '/manifest.webmanifest', '/icons/app-icon.svg'] self.addEventListener('install', event => event.waitUntil(caches.open(CACHE).then(cache => cache.addAll(SHELL)))) self.addEventListener('activate', event => event.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(key => key !== CACHE).map(key => caches.delete(key)))).then(() => self.clients.claim()))) self.addEventListener('message', event => { if (event.data?.type === 'SKIP_WAITING') void self.skipWaiting() }) function isCacheableAsset(url) { if (url.origin !== self.location.origin) return false return url.pathname.startsWith('/assets/') || url.pathname.startsWith('/icons/') || url.pathname.startsWith('/brand/') || url.pathname === '/manifest.webmanifest' || url.pathname.startsWith('/favicon') || url.pathname === '/apple-touch-icon.png' } self.addEventListener('fetch', event => { const request = event.request const url = new URL(request.url) if (request.method !== 'GET' || url.origin !== self.location.origin || url.pathname.startsWith('/api/') || url.pathname.startsWith('/storage/')) return if (request.mode === 'navigate') { event.respondWith(fetch(request).catch(async () => (await caches.match('/')) ?? (await caches.match(OFFLINE_URL)))) return } if (!isCacheableAsset(url)) return event.respondWith(caches.match(request).then(cached => cached ?? fetch(request).then(response => { if (response.ok) void caches.open(CACHE).then(cache => cache.put(request, response.clone())) return response }))) })