puzzle-trainer/public/sw.js
2026-05-23 01:05:21 +00:00

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("/")))
);
}
});