Spaces:
Build error
Build error
File size: 5,565 Bytes
aff7a19 5657d91 aff7a19 f4791ec 0d2f09e 5657d91 0d2f09e 4d25967 5657d91 4d25967 5657d91 4d25967 5f08495 aff7a19 beba5b2 aff7a19 4d25967 aff7a19 5657d91 aff7a19 4d25967 aff7a19 4d25967 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | // 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") ||
// Prefixes below verified against every @router.get/post/put/delete
// decorator in api/routes/*.py -- 14 of these were named in the audit
// report; adversarial, affidavit, benami, conflict, debate, linguistic,
// policy, procurement, sources, timeline, forensics, self-learning,
// case-memory, resolve.
path.startsWith("/timeline") ||
path.startsWith("/forensics") ||
path.startsWith("/benami") ||
path.startsWith("/procurement") ||
path.startsWith("/conflict") ||
path.startsWith("/linguistic") ||
path.startsWith("/policy") ||
path.startsWith("/self-learning") ||
path.startsWith("/case-memory") ||
path.startsWith("/affidavit") ||
path.startsWith("/adversarial") ||
path.startsWith("/debate") ||
path.startsWith("/resolve") ||
path.startsWith("/sources") ||
// Not named in the audit report -- found by extracting every real
// route path and diffing against the allowlist directly, rather than
// relying on the report's own count. None of these are nested under
// any prefix above: export.py's /verify/{hash} and
// investigation.py's /connection-map and /node-evidence/{id} were
// never nested under /export or /investigate despite living in those
// files; multilingual.py's /languages, /translate, /ui-labels are
// separate top-level paths that don't literally start with
// "/multilingual" at all (only /search/multilingual and
// /risk/multilingual/{id} do, and those are already covered by the
// /search and /risk entries above).
path.startsWith("/verify") ||
path.startsWith("/connection-map") ||
path.startsWith("/node-evidence") ||
path.startsWith("/languages") ||
path.startsWith("/translate") ||
path.startsWith("/ui-labels");
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;
});
})
);
});
|