1const CACHE_VERSION = "bhapi-v1"; 2const STATIC_CACHE = `static-${CACHE_VERSION}`; 3const RUNTIME_CACHE = `runtime-${CACHE_VERSION}`; 4 5const STATIC_EXTENSIONS = /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot)$/; 6 7const OFFLINE_PAGE = "/offline.html"; 8 9// Install: precache the offline fallback page 10self.addEventListener("install", (event) => { 11 event.waitUntil( 12 caches 13 .open(STATIC_CACHE) 14 .then((cache) => cache.add(OFFLINE_PAGE)) 15 .then(() => self.skipWaiting()) 16 ); 17}); 18 19// Activate: clean up old caches 20self.addEventListener("activate", (event) => { 21 event.waitUntil( 22 caches 23 .keys() 24 .then((keys) => 25 Promise.all( 26 keys 27 .filter( 28 (key) => key !== STATIC_CACHE && key !== RUNTIME_CACHE 29 ) 30 .map((key) => caches.delete(key)) 31 ) 32 ) 33 .then(() => self.clients.claim()) 34 ); 35}); 36 37// Fetch: cache-first for static assets, network-first for API calls 38self.addEventListener("fetch", (event) => { 39 const { request } = event; 40 const url = new URL(request.url); 41 42 // Only handle GET requests 43 if (request.method !== "GET") return; 44 45 // Skip cross-origin requests 46 if (url.origin !== self.location.origin) return; 47 48 // Network-first for API calls 49 if (url.pathname.startsWith("/api/")) { 50 event.respondWith(networkFirst(request)); 51 return; 52 } 53 54 // Cache-first for static assets 55 if (STATIC_EXTENSIONS.test(url.pathname)) { 56 event.respondWith(cacheFirst(request)); 57 return; 58 } 59 60 // Network-first for HTML navigation (pages) 61 event.respondWith(networkFirst(request)); 62}); 63 64async function cacheFirst(request) { 65 const cached = await caches.match(request); 66 if (cached) return cached; 67 68 try { 69 const response = await fetch(request); 70 if (response.ok) { 71 const cache = await caches.open(STATIC_CACHE); 72 cache.put(request, response.clone()); 73 } 74 return response; 75 } catch { 76 return new Response("", { status: 408, statusText: "Offline" }); 77 } 78} 79 80async function networkFirst(request) { 81 try { 82 const response = await fetch(request); 83 if (response.ok) { 84 const cache = await caches.open(RUNTIME_CACHE); 85 cache.put(request, response.clone()); 86 } 87 return response; 88 } catch { 89 const cached = await caches.match(request); 90 if (cached) return cached; 91 92 // For navigation requests, show offline page 93 if (request.mode === "navigate") { 94 const offlinePage = await caches.match(OFFLINE_PAGE); 95 if (offlinePage) return offlinePage; 96 } 97 98 return new Response("", { status: 408, statusText: "Offline" }); 99 } 100}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.