const CACHE_NAME = 'offline-cache-v1' const ASSETS = [ '/', '/index.html', '/styles.css', '/styles3.css', '/tempo.md', '/bell.png', '/bell.svg', '/by-sa.png', '/cc-by-sa-legalcode.txt', '/symbols.txt' ] self.addEventListener('install', e => { console.log('installing sw') e.waitUntil(caches.open(CACHE_NAME).then(cache => cache.addAll(ASSETS))) self.skipWaiting() }) self.addEventListener('activate', e => { console.log('sw activated') e.waitUntil(self.clients.claim()) }) const checkChange = (r1, r2) => { const h1 = r1.headers const h2 = r2.headers if (h1.get('etag') && h2.get('etag')) return h1.get('etag') !== h2.get('etag') if (h1.get('last-modified') && h2.get('last-modified')) return h1.get('last-modified') !== h2.get('last-modified') return h1.get('content-length') !== h2.get('content-length') } self.addEventListener('fetch', e => { const url = new URL(e.request.url) const isTarget = ASSETS.includes(url.pathname) || url.pathname.startsWith('/fonts/') if (!isTarget) return e.respondWith((async () => { const cache = await caches.open(CACHE_NAME) const cachedResponse = await cache.match(e.request) const networkFetch = fetch(e.request, { cache: 'no-cache' }).then(async networkResponse => { if (!networkResponse.ok) return networkResponse const freshCopy = networkResponse.clone() let changed = false if (cachedResponse) { changed = checkChange(cachedResponse, networkResponse) } else { console.log(`fetch ${url.pathname}`) } await cache.put(e.request, freshCopy) if (changed) { console.log(`content changed, signaling refresh: ${url.pathname}`) const clients = await self.clients.matchAll() clients.forEach(client => { client.postMessage({ type: 'REFRESH', url: url.pathname }) }) } return networkResponse }).catch(err => { console.error(`failed ${url.pathname}:`, err) }) if (cachedResponse) { console.log(`cache ${url.pathname}`) e.waitUntil(networkFetch) return cachedResponse } return networkFetch })()) })