/* ===================================================================== LinguaClub service worker ===================================================================== Strategy: cache-first for anything already visited, with a background network refresh each time (stale-while-revalidate), so pages open instantly once cached and quietly stay up to date. Nothing is precached by name here, since the site keeps growing with new tools and games; instead, every page a member actually opens gets cached automatically the first time, so it's available offline from then on. Bump CACHE_VERSION whenever site files change in a way that should force old cached copies to be replaced. ===================================================================== */ const CACHE_VERSION = 'linguaclub-v18'; const CORE_ASSETS = [ 'index.html', 'manifest.json', 'icons/icon-192.png', 'icons/icon-512.png', 'icons/apple-touch-icon.png' ]; self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_VERSION).then((cache) => cache.addAll(CORE_ASSETS)).catch(() => { /* offline during install, or a core asset is missing; not fatal */ }) ); self.skipWaiting(); }); self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((names) => Promise.all(names.filter((n) => n !== CACHE_VERSION).map((n) => caches.delete(n))) ) ); self.clients.claim(); }); self.addEventListener('fetch', (event) => { const req = event.request; // Only handle GET requests on our own origin; let everything else // (fonts.googleapis.com, POSTs, etc.) go straight to the network. if (req.method !== 'GET' || new URL(req.url).origin !== self.location.origin) return; event.respondWith( caches.open(CACHE_VERSION).then(async (cache) => { const cached = await cache.match(req); const networkFetch = fetch(req) .then((res) => { if (res && res.status === 200) cache.put(req, res.clone()); return res; }) .catch(() => null); // Serve the cached copy immediately if we have one, refreshing // it in the background; otherwise wait for the network, and if // that fails too on a page navigation, fall back to the cached // home page rather than showing a browser error screen. if (cached) { networkFetch; return cached; } const fresh = await networkFetch; if (fresh) return fresh; if (req.mode === 'navigate') { const fallback = await cache.match('index.html'); if (fallback) return fallback; } return new Response('Offline and not yet cached.', { status: 503, statusText: 'Offline' }); }) ); });