Spaces:
Running
Running
| const STATIC_CACHE = 'static-v3'; | |
| const DYNAMIC_CACHE = 'dynamic-v3'; | |
| const isHttpGet = (req) => { | |
| try { | |
| if (!req || req.method !== 'GET') return false; | |
| const u = new URL(req.url); | |
| return (u.protocol === 'http:' || u.protocol === 'https:'); | |
| } catch { return false; } | |
| }; | |
| const isSameOrigin = (req) => { | |
| try { return new URL(req.url).origin === self.location.origin; } catch { return false; } | |
| }; | |
| self.addEventListener('install', (event) => { | |
| event.waitUntil((async () => { | |
| const cache = await caches.open(STATIC_CACHE); | |
| await cache.addAll(['/','/index.html','/vite.svg']); | |
| })()); | |
| self.skipWaiting(); | |
| }); | |
| self.addEventListener('activate', (event) => { | |
| event.waitUntil((async () => { | |
| // If you enabled navigationPreload in page code, either keep it: | |
| // await self.registration.navigationPreload.enable(); | |
| // or disable to remove the warning: | |
| try { await self.registration.navigationPreload.disable(); } catch {} | |
| const names = await caches.keys(); | |
| await Promise.all(names.map((n) => (n === STATIC_CACHE || n === DYNAMIC_CACHE) ? null : caches.delete(n))); | |
| await self.clients.claim(); | |
| })()); | |
| }); | |
| self.addEventListener('fetch', (event) => { | |
| const req = event.request; | |
| // Ignore non-http(s) or non-GET (extensions, blob:, data:, etc.) | |
| if (!isHttpGet(req)) return; | |
| const url = new URL(req.url); | |
| // Handle navigations (SPA shell) + optional preload | |
| if (req.mode === 'navigate') { | |
| event.respondWith((async () => { | |
| // If preload is enabled, prefer it | |
| const pre = await event.preloadResponse; | |
| if (pre) return pre; | |
| try { | |
| const net = await fetch(req); | |
| return net; | |
| } catch { | |
| const cached = await caches.match('/index.html'); | |
| return cached || Response.error(); | |
| } | |
| })()); | |
| return; | |
| } | |
| // API: network-first, cache successful same-origin GETs | |
| if (url.pathname.startsWith('/api/')) { | |
| event.respondWith((async () => { | |
| try { | |
| const resp = await fetch(req); | |
| if (resp.ok && isSameOrigin(req)) { | |
| try { | |
| const c = await caches.open(DYNAMIC_CACHE); | |
| await c.put(req, resp.clone()); | |
| } catch {} | |
| } | |
| return resp; | |
| } catch { | |
| const cached = await caches.match(req); | |
| return cached || Response.error(); | |
| } | |
| })()); | |
| return; | |
| } | |
| // Assets (script/style/image/font): cache-first | |
| const dest = req.destination; | |
| const isAsset = dest === 'script' || dest === 'style' || dest === 'image' || dest === 'font'; | |
| if (isAsset) { | |
| event.respondWith((async () => { | |
| const hit = await caches.match(req); | |
| if (hit) return hit; | |
| const resp = await fetch(req); | |
| if (resp.ok && isSameOrigin(req)) { | |
| try { | |
| const c = await caches.open(STATIC_CACHE); | |
| await c.put(req, resp.clone()); | |
| } catch {} | |
| } | |
| return resp; | |
| })()); | |
| return; | |
| } | |
| // Default: network-first with safe cache | |
| event.respondWith((async () => { | |
| try { | |
| const resp = await fetch(req); | |
| if (resp.ok && isSameOrigin(req)) { | |
| try { | |
| const c = await caches.open(DYNAMIC_CACHE); | |
| await c.put(req, resp.clone()); | |
| } catch {} | |
| } | |
| return resp; | |
| } catch { | |
| const cached = await caches.match(req); | |
| return cached || Response.error(); | |
| } | |
| })()); | |
| }); | |