1const CACHE_NAME = 'just-pray-v3' 2const CAMPAIGN_PATH = '/come-pray' 3 4self.addEventListener('install', () => { 5 self.skipWaiting() 6}) 7 8self.addEventListener('activate', (event) => { 9 event.waitUntil( 10 caches 11 .keys() 12 .then((keys) => 13 Promise.all( 14 keys 15 .filter((key) => key.startsWith('just-pray-') && key !== CACHE_NAME) 16 .map((key) => caches.delete(key)) 17 ) 18 ) 19 .then(() => self.clients.claim()) 20 ) 21}) 22 23self.addEventListener('fetch', (event) => { 24 if (event.request.method !== 'GET') return 25 26 const url = new URL(event.request.url) 27 const isCampaignPage = url.origin === self.location.origin && (url.pathname === CAMPAIGN_PATH || url.pathname === '/just-pray') 28 const isDailyContent = 29 url.origin === self.location.origin && 30 url.pathname.startsWith('/api/just-pray/day/') 31 32 if (!isCampaignPage && !isDailyContent) return 33 34 event.respondWith( 35 fetch(event.request) 36 .then((response) => { 37 if (response.ok) { 38 const copy = response.clone() 39 caches.open(CACHE_NAME).then((cache) => cache.put(event.request, copy)) 40 } 41 return response 42 }) 43 .catch(async () => { 44 const cached = await caches.match(event.request) 45 if (cached) return cached 46 47 if (isCampaignPage) { 48 return new Response( 49 '<!doctype html><html lang="en"><meta name="viewport" content="width=device-width"><title>Come Pray</title><body style="font:18px system-ui;padding:40px;color:#12324a"><h1>Come Pray</h1><p>You are offline. Reconnect to open the campaign, or return to a prayer day you have opened before.</p></body></html>', 50 { headers: { 'Content-Type': 'text/html' } } 51 ) 52 } 53 54 return new Response(JSON.stringify({ error: 'This day is not available offline yet.' }), { 55 status: 503, 56 headers: { 'Content-Type': 'application/json' }, 57 }) 58 }) 59 ) 60}) 61 62self.addEventListener('push', (event) => { 63 const data = event.data?.json() || {} 64 event.waitUntil( 65 self.registration.showNotification(data.title || 'Come Pray', { 66 body: data.body || 'Take one minute to pray before your day begins.', 67 icon: '/thelight-logo.png', 68 badge: '/thelight-logo.png', 69 tag: data.tag || 'just-pray-reminder', 70 data: { url: data.url || CAMPAIGN_PATH }, 71 renotify: false, 72 }) 73 ) 74}) 75 76self.addEventListener('notificationclick', (event) => { 77 event.notification.close() 78 const target = new URL(event.notification.data?.url || CAMPAIGN_PATH, self.location.origin).href 79 event.waitUntil( 80 self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clients) => { 81 const existing = clients.find((client) => client.url.startsWith(self.location.origin)) 82 if (existing) { 83 existing.navigate(target) 84 return existing.focus() 85 } 86 return self.clients.openWindow(target) 87 }) 88 ) 89})
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.