48 lines
1.6 KiB
JavaScript
48 lines
1.6 KiB
JavaScript
// Puzzle Trainer — Service Worker
|
|
const CACHE = "pt-v2";
|
|
const SHELL = ["/", "/queens", "/tango", "/zip", "/sudoku", "/patches", "/stats", "/settings"];
|
|
|
|
self.addEventListener("install", e => {
|
|
e.waitUntil(
|
|
caches.open(CACHE).then(c => c.addAll(SHELL)).then(() => self.skipWaiting())
|
|
);
|
|
});
|
|
|
|
self.addEventListener("activate", e => {
|
|
e.waitUntil(
|
|
caches.keys().then(keys =>
|
|
Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k)))
|
|
).then(() => self.clients.claim())
|
|
);
|
|
});
|
|
|
|
self.addEventListener("fetch", e => {
|
|
// Only handle same-origin GET requests
|
|
if (e.request.method !== "GET") return;
|
|
const url = new URL(e.request.url);
|
|
if (url.origin !== self.location.origin) return;
|
|
|
|
// Network-first for HTML pages (fresh content), cache-first for assets
|
|
const isPage = e.request.mode === "navigate" || e.request.headers.get("accept")?.includes("text/html");
|
|
const isAsset = url.pathname.startsWith("/_next/static/");
|
|
|
|
if (isAsset) {
|
|
// Cache-first for static assets (they're content-hashed)
|
|
e.respondWith(
|
|
caches.match(e.request).then(cached => cached || fetch(e.request).then(res => {
|
|
if (res.ok) caches.open(CACHE).then(c => c.put(e.request, res.clone()));
|
|
return res;
|
|
}))
|
|
);
|
|
} else if (isPage) {
|
|
// Network-first for pages, fallback to cache
|
|
e.respondWith(
|
|
fetch(e.request)
|
|
.then(res => {
|
|
if (res.ok) caches.open(CACHE).then(c => c.put(e.request, res.clone()));
|
|
return res;
|
|
})
|
|
.catch(() => caches.match(e.request).then(cached => cached || caches.match("/")))
|
|
);
|
|
}
|
|
});
|