/* Service Worker: App-Shell cachen (Offline + schneller Start). Version bei jeder Template-/Asset-Änderung bumpen (SHELL_VERSION), damit alte Caches beim Activate bereinigt werden. */ const SHELL_VERSION = 'v1'; const SHELL_CACHE = 'essen-shell-' + SHELL_VERSION; const SHELL = [ '/', '/manifest.webmanifest', '/js/htmx.min.js', '/js/sortable.min.js', '/icons/icon-192.png', '/icons/icon-512.png', ]; self.addEventListener('install', (event) => { event.waitUntil( caches .open(SHELL_CACHE) .then((cache) => cache.addAll(SHELL)) .then(() => self.skipWaiting()) ); }); self.addEventListener('activate', (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all( keys .filter((key) => key.startsWith('essen-shell-') && key !== SHELL_CACHE) .map((key) => caches.delete(key)) ) ) .then(() => self.clients.claim()) ); }); self.addEventListener('fetch', (event) => { const url = new URL(event.request.url); if (event.request.method !== 'GET' || url.origin !== self.location.origin) { return; } // Navigations: erst Netzwerk (frische Deploys!), dann Cache (Offline). if (event.request.mode === 'navigate') { event.respondWith( fetch(event.request) .then((response) => { const kopie = response.clone(); caches.open(SHELL_CACHE).then((cache) => cache.put(event.request, kopie)); return response; }) .catch(() => caches.match(event.request).then((treffer) => treffer || caches.match('/')) ) ); return; } // Statische Assets: Cache-first (unveränderlich pro Version). if ( url.pathname.startsWith('/js/') || url.pathname.startsWith('/icons/') || url.pathname === '/manifest.webmanifest' ) { event.respondWith( caches.match(event.request).then( (treffer) => treffer || fetch(event.request).then((response) => { const kopie = response.clone(); caches.open(SHELL_CACHE).then((cache) => cache.put(event.request, kopie)); return response; }) ) ); } });