Spaces:
Running
Running
| // BharatGraph Service Worker v5 | |
| // BUG-28 FIX: API responses were cached indefinitely | |
| // NEW-A5 FIX: host === "hf.space" never matches -- HF uses *.hf.space subdomains | |
| // SW-01 FIX: use relative paths so caching works on GitHub Pages | |
| const CACHE = "bharatgraph-v6"; | |
| const STATIC = [ | |
| "./", | |
| "./index.html", | |
| "./css/design-system.css", | |
| "./css/components.css", | |
| "./js/router.js", | |
| "./js/api.js", | |
| "./js/components.js", | |
| "./js/graph.js", | |
| "./js/timeline.js", | |
| "./js/evidence_panel.js", | |
| "./js/app.js" | |
| ]; | |
| self.addEventListener("install", e => { | |
| e.waitUntil( | |
| caches.open(CACHE) | |
| .then(c => c.addAll(STATIC)) | |
| .catch(() => {}) // never block install on cache failure | |
| ); | |
| self.skipWaiting(); | |
| }); | |
| self.addEventListener("activate", e => { | |
| e.waitUntil( | |
| caches.keys() | |
| .then(keys => Promise.all( | |
| keys.filter(k => k !== CACHE).map(k => caches.delete(k)) | |
| )) | |
| .then(() => self.clients.claim()) | |
| ); | |
| }); | |
| self.addEventListener("fetch", e => { | |
| const reqUrl = new URL(e.request.url); | |
| const host = reqUrl.hostname; | |
| const path = reqUrl.pathname; | |
| // NEW-A5 FIX: HuggingFace Spaces run on *.hf.space subdomains. | |
| // The previous check `host === "hf.space"` never matched because the actual | |
| // hostname is e.g. "abinazebinoly-bharatgraph.hf.space" -- use endsWith(). | |
| // BUG-28 FIX: all API paths must be network-first, never cached. | |
| const isHfSpace = host.endsWith(".hf.space") || host === "hf.space"; | |
| const isApiPath = path.startsWith("/search") || | |
| path.startsWith("/profile") || | |
| path.startsWith("/risk") || | |
| path.startsWith("/graph") || | |
| path.startsWith("/biography") || | |
| path.startsWith("/investigate") || | |
| path.startsWith("/admin") || | |
| path.startsWith("/stats") || | |
| path.startsWith("/health") || | |
| path.startsWith("/ws/") || | |
| path.startsWith("/runtime") || | |
| path.startsWith("/multilingual") || | |
| path.startsWith("/export"); | |
| const isLocalApi = host === "localhost" || host === "127.0.0.1"; | |
| const isApi = isHfSpace || (isLocalApi && isApiPath); | |
| if (isApi) { | |
| // Network-first: always go to network, fall back to error JSON | |
| e.respondWith( | |
| fetch(e.request).catch(() => | |
| new Response( | |
| JSON.stringify({ error: "API temporarily unavailable" }), | |
| { status: 503, headers: { "Content-Type": "application/json" } } | |
| ) | |
| ) | |
| ); | |
| return; | |
| } | |
| // Static assets: cache-first | |
| e.respondWith( | |
| caches.match(e.request).then(cached => { | |
| if (cached) return cached; | |
| return fetch(e.request).then(response => { | |
| if (!response || response.status !== 200 || response.type !== "basic") { | |
| return response; | |
| } | |
| const clone = response.clone(); | |
| caches.open(CACHE).then(c => c.put(e.request, clone)); | |
| return response; | |
| }); | |
| }) | |
| ); | |
| }); | |