1const CACHE = 'ecocard-public-v1' 2const OFFLINE = '/offline.html' 3 4self.addEventListener('install', (event) => { 5 event.waitUntil(caches.open(CACHE).then((cache) => cache.addAll([OFFLINE, '/images/ecocard_favicon.png']))) 6 self.skipWaiting() 7}) 8 9self.addEventListener('activate', (event) => { 10 event.waitUntil(caches.keys().then((keys) => Promise.all(keys.filter((key) => key !== CACHE).map((key) => caches.delete(key))))) 11 self.clients.claim() 12}) 13 14function isPrivate(url) { 15 return url.pathname.startsWith('/api/') || url.pathname.startsWith('/dash') || url.pathname.startsWith('/admin') || url.pathname.startsWith('/superuser') || url.pathname.startsWith('/portal') 16} 17 18self.addEventListener('fetch', (event) => { 19 if (event.request.method !== 'GET') return 20 const url = new URL(event.request.url) 21 if (url.origin !== self.location.origin || isPrivate(url)) return 22 if (event.request.mode === 'navigate') { 23 event.respondWith(fetch(event.request).catch(() => caches.match(OFFLINE))) 24 return 25 } 26 if (url.pathname.startsWith('/_next/static/') || url.pathname.startsWith('/images/')) { 27 event.respondWith(caches.match(event.request).then((cached) => cached || fetch(event.request).then((response) => { 28 if (response.ok) caches.open(CACHE).then((cache) => cache.put(event.request, response.clone())) 29 return response 30 }
30))) 31 } 32}) 33 34self.addEventListener('push', (event) => { 35 let payload = { title: 'Ecocard', body: 'Você tem uma nova atualização.', url: '/dash/notificacoes' } 36 try { payload = { ...payload, ...event.data.json() } } catch {} 37 event.waitUntil(self.registration.showNotification(payload.title, { body: payload.body, icon: '/images/ecocard_favicon.png', badge: '/images/ecocard_favicon.png', data: { url: payload.url }, tag: payload.tag })) 38}) 39 40self.addEventListener('notificationclick', (event) => { 41 event.notification.close() 42 const target = new URL(event.notification.data?.url || '/dash/notificacoes', self.location.origin).href 43 event.waitUntil(clients.matchAll({ type: 'window', includeUncontrolled: true }).then((windows) => { 44 const existing = windows.find((client) => client.url === target) 45 return existing ? existing.focus() : clients.openWindow(target) 46 })) 47})
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.