diora-web/static/js/sw.js
Marwin Schulz b0ce463cca
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 15s
Debug books: show visible status at each load stage, bump SW to v7
Each step in loadBookList now updates the visible UI so the exact
failure point is obvious without opening DevTools.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 12:28:00 +01:00

83 lines
2.5 KiB
JavaScript

/**
* diora service worker — caches the app shell for offline use.
*/
const CACHE = 'diora-v7';
const PODCAST_CACHE = 'diora-podcast-v1';
const SHELL = [
'/static/css/app.css',
'/static/js/app.js',
'/static/manifest.json',
];
// Install: pre-cache the app shell
self.addEventListener('install', function (event) {
event.waitUntil(
caches.open(CACHE).then(function (cache) {
return cache.addAll(SHELL);
})
);
// Activate immediately without waiting for old tabs to close
self.skipWaiting();
});
// Activate: remove stale caches from previous versions
self.addEventListener('activate', function (event) {
event.waitUntil(
caches.keys().then(function (keys) {
return Promise.all(
keys.filter(function (key) { return key !== CACHE && key !== PODCAST_CACHE; })
.map(function (key) { return caches.delete(key); })
);
}).then(function () {
return self.clients.claim();
})
);
});
// Fetch: serve from cache, fall back to network
self.addEventListener('fetch', function (event) {
// Only handle GET requests; let POST/SSE etc. pass through
if (event.request.method !== 'GET') return;
const url = new URL(event.request.url);
// Bypass for API/mutation endpoints
if (url.pathname.startsWith('/radio/sse/') ||
url.pathname.startsWith('/radio/record/') ||
url.pathname.startsWith('/radio/affiliate/') ||
url.pathname.startsWith('/admin/') ||
url.pathname.startsWith('/podcasts/progress/') ||
url.pathname.startsWith('/podcasts/queue/') ||
url.pathname === '/podcasts/feeds/add' ||
url.pathname.startsWith('/podcasts/feeds/add') ||
url.pathname.includes('/remove') ||
url.pathname.startsWith('/podcasts/feeds/refresh')) {
return;
}
// Podcast audio: serve from podcast cache first, then network
if (event.request.destination === 'audio') {
event.respondWith(
caches.open(PODCAST_CACHE).then(function (cache) {
return cache.match(event.request).then(function (cached) {
if (cached) return cached;
return fetch(event.request).then(function (response) {
return response;
});
});
})
);
return;
}
// Cache-first only for pre-defined shell assets; everything else hits the network
const isShell = SHELL.some(function (s) { return url.pathname === s; });
if (isShell) {
event.respondWith(
caches.match(event.request).then(function (cached) {
return cached || fetch(event.request);
})
);
}
});