diff --git a/public/sw.js b/public/sw.js index b2f35e4..45fff96 100644 --- a/public/sw.js +++ b/public/sw.js @@ -1,8 +1,13 @@ -const CACHE_NAME = 'api-mediaplayer-v1' +const CACHE_NAME = 'api-mediaplayer-v2' const MEDIA_CACHE_NAME = 'api-mediaplayer-media-v2' const ASSETS = ['/', '/index.html', '/manifest.json', '/no-image.svg'] const MAX_MEDIA_CACHE_ITEMS = 12 +function isNavigationRequest(request, acceptHeader) { + if (!request) return false + return request.mode === 'navigate' || acceptHeader.includes('text/html') +} + function getRangeBounds(rangeHeader, size) { const match = /^bytes=(\d*)-(\d*)$/i.exec(rangeHeader || '') if (!match) return null @@ -83,6 +88,33 @@ async function handleMediaRequest(event) { return networkResponse } +async function updateShellCache(cache, response) { + if (!response || !response.ok || response.status !== 200) return + + await Promise.allSettled([ + cache.put('/index.html', response.clone()), + cache.put('/', response.clone()), + ]) +} + +async function handleShellRequest(event) { + const appCache = await caches.open(CACHE_NAME) + + try { + const networkResponse = await fetch(event.request) + event.waitUntil(updateShellCache(appCache, networkResponse.clone())) + return networkResponse + } catch { + const cachedIndex = await appCache.match('/index.html').catch(() => null) + if (cachedIndex) return cachedIndex + + const cachedRoot = await appCache.match('/').catch(() => null) + if (cachedRoot) return cachedRoot + + return new Response('Network error', { status: 502, statusText: 'Bad Gateway' }) + } +} + self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => { @@ -122,6 +154,11 @@ self.addEventListener('fetch', (event) => { return } + if (isNavigationRequest(event.request, acceptHeader)) { + event.respondWith(handleShellRequest(event)) + return + } + event.respondWith((async () => { try { const cached = await caches.match(event.request).catch(() => null) diff --git a/src/serviceWorker.ts b/src/serviceWorker.ts index b6c4cf6..f56dfeb 100644 --- a/src/serviceWorker.ts +++ b/src/serviceWorker.ts @@ -1,9 +1,36 @@ export function registerServiceWorker() { if ('serviceWorker' in navigator) { window.addEventListener('load', () => { + let refreshing = false + + navigator.serviceWorker.addEventListener('controllerchange', () => { + if (refreshing) return + refreshing = true + window.location.reload() + }) + navigator.serviceWorker .register('/sw.js') - .then((reg) => console.log('Service worker registered:', reg)) + .then((reg) => { + console.log('Service worker registered:', reg) + + void reg.update().catch(() => undefined) + + if (reg.waiting) { + reg.waiting.postMessage({ type: 'SKIP_WAITING' }) + } + + reg.addEventListener('updatefound', () => { + const installingWorker = reg.installing + if (!installingWorker) return + + installingWorker.addEventListener('statechange', () => { + if (installingWorker.state === 'installed' && navigator.serviceWorker.controller) { + installingWorker.postMessage({ type: 'SKIP_WAITING' }) + } + }) + }) + }) .catch((err) => console.log('Service worker registration failed:', err)) }) }