// sw.js -- service worker d'Ustagammon : l'application hors ligne. // // Copyright (C) 2026 les auteurs d'Ustagammon. // Licence : GPLv3 ou ultérieure (voir LICENSE). // // À l'installation, tous les fichiers du site (dont les 8,7 Mo de données du // moteur) sont mis en cache ; ensuite, chaque fichier est servi depuis ce // cache, sans réseau. VERSION et FILES sont écrits en tête de ce fichier par // scripts/service-worker.sh au moment de make site. // // Mise à jour : à chaque publication, VERSION change, donc ce fichier. Le // navigateur installe alors la nouvelle version, qui télécharge tout dans un // nouveau cache, puis attend : la version en place garde la main, et son // cache, tant que le joueur n'a pas accepté la mise à jour. Une page ouverte // continue donc de trouver tous ses fichiers. L'application affiche le // bandeau « Nouvelle version disponible » (app/src/ui/updates.ts) ; « Mettre // à jour » envoie le message « skip-waiting » : la nouvelle version prend // la main, efface l'ancien cache, et la page se recharge. À la toute // première installation, aucune version n'est en place : elle prend la main // sans attendre. /* global VERSION, FILES */ const CACHE = `ustagammon-${VERSION}`; self.addEventListener("install", (event) => { event.waitUntil( (async () => { const cache = await caches.open(CACHE); // no-cache : revalider auprès du serveur, jamais une copie // périmée du cache HTTP du navigateur. await cache.addAll(FILES.map((file) => new Request(file, { cache: "no-cache" }))); })(), ); }); // L'accord du joueur (même nom que SKIP_WAITING dans updates.ts). self.addEventListener("message", (event) => { if (event.data?.type === "skip-waiting") { void self.skipWaiting(); } }); self.addEventListener("activate", (event) => { event.waitUntil( (async () => { for (const name of await caches.keys()) { if (name !== CACHE) { await caches.delete(name); } } await self.clients.claim(); })(), ); }); self.addEventListener("fetch", (event) => { const request = event.request; if (request.method !== "GET" || new URL(request.url).origin !== self.location.origin) { return; } event.respondWith( (async () => { const cached = await caches.match(request, { cacheName: CACHE, ignoreSearch: true, ignoreVary: true, }); return cached ?? fetch(request); })(), ); });