1const CACHE_VERSION = "dailyprayer-uk-pwa-v2026-08-24-church1"; 2const LIVE_CACHE = "dailyprayer-uk-live-v2026-08-24-church1"; 3const OFFLINE_URL = "/app/offline.html"; 4const APP_SHELL = [ 5 "/app/", 6 "/app/index.html", 7 "/app/styles.css?v=20260824-church1", 8 "/app/app.js?v=20260824-church1", 9 "/app/manifest.webmanifest", 10 OFFLINE_URL, 11 "/app/assets/dailyprayer-logo.png", 12 "/app/assets/dailyprayer-icon-180.png", 13 "/app/assets/dailyprayer-icon-192.png", 14 "/app/assets/dailyprayer-icon-512.png", 15 "/app/assets/dailyprayer-icon-maskable-512.png" 16]; 17 18self.addEventListener("install", (event) => { 19 event.waitUntil( 20 caches.open(CACHE_VERSION) 21 .then((cache) => cache.addAll(APP_SHELL)) 22 .then(() => self.skipWaiting()) 23 ); 24}); 25 26self.addEventListener("activate", (event) => { 27 event.waitUntil( 28 caches.keys() 29 .then((names) => Promise.all( 30 names 31 .filter((name) => name !== CACHE_VERSION && name !== LIVE_CACHE) 32 .map((name) => caches.delete(name)) 33 )) 34 .then(() => self.clients.claim()) 35 ); 36}); 37 38self.addEventListener("message", (event) => { 39 if (event.data && event.data.type === "SKIP_WAITING") { 40 self.skipWaiting(); 41 } 42}); 43 44const isAudioStream = (request) => { 45 const accept = request.headers.get("accept") || ""; 46 return accept.includes("audio") || request.url.includes("streamer.radio.co"); 47}; 48 49const networkFirst = async (request) => { 50 const cache = await caches.open(LIVE_CACHE); 51 try { 52 const response = await fetch(request); 53 if (response && response.ok) { 54 cache.put(request, response.clone()); 55 } 56 return response; 57 } catch (error) { 58 return cache.match(request); 59 } 60}; 61 62const shellFirst = async (request) => { 63 const cached = await caches.match(request); 64 if (cached) return cached; 65 66 try { 67 const response = await fetch(request); 68 if (response && response.ok && request.method === "GET") { 69 const cache = await caches.open(CACHE_VERSION); 70 cache.put(request, response.clone()); 71 } 72 return response; 73 } catch (error) { 74 return caches.match(OFFLINE_URL); 75 } 76}; 77 78self.addEventListener("fetch", (event) => { 79 const { request } = event; 80 if (request.method !== "GET" || isAudioStream(request)) return; 81 82 const url = new URL(request.url); 83 84 if (request.mode === "navigate") { 85 event.respondWith( 86 fetch(request) 87 .then((response) => { 88 const copy = response.clone(); 89 caches.open(CACHE_VERSION).then((cache) => cache.put("/app/", copy)); 90 return response; 91 }) 92 .catch(() => caches.match("/app/").then((response) => response || caches.match(OFFLINE_URL))) 93 ); 94 return; 95 } 96 97 if (url.origin === self.location.origin && (url.pathname.startsWith("/wp-json/") || url.pathname.startsWith("/app/api/"))) { 98 event.respondWith(networkFirst(request).then((response) => response || caches.match(OFFLINE_URL))); 99 return; 100 } 101 102 if (url.origin === self.location.origin && url.pathname.startsWith("/app/")) { 103 event.respondWith(shellFirst(request)); 104 } 105});
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.