const CACHE_NAME = "rave-budget-control-v1"; const APP_SHELL = ["/", "/login", "/icon.svg", "/manifest.webmanifest"]; self.addEventListener("install", (event) => { event.waitUntil( caches .open(CACHE_NAME) .then((cache) => cache.addAll(APP_SHELL)) .then(() => self.skipWaiting()) ); }); self.addEventListener("activate", (event) => { event.waitUntil( caches.keys().then((cacheNames) => Promise.all(cacheNames.filter((cacheName) => cacheName !== CACHE_NAME).map((cacheName) => caches.delete(cacheName))) ) ); }); self.addEventListener("fetch", (event) => { const { request } = event; const url = new URL(request.url); if (request.method !== "GET" || url.pathname.startsWith("/api")) { return; } event.respondWith( fetch(request) .then((response) => { const responseClone = response.clone(); caches.open(CACHE_NAME).then((cache) => { cache.put(request, responseClone); }); return response; }) .catch(async () => { const cached = await caches.match(request); return cached ?? caches.match("/"); }) ); }); self.addEventListener("push", (event) => { const payload = event.data?.json() ?? {}; const title = payload.title || "RFP Finanzen"; const options = { body: payload.body || "Es gibt eine neue Benachrichtigung.", icon: "/icon-192.png", badge: "/icon-192.png", tag: payload.tag || "rfp-finance", data: { url: payload.url || "/" } }; event.waitUntil(self.registration.showNotification(title, options)); }); self.addEventListener("notificationclick", (event) => { event.notification.close(); const targetUrl = new URL(event.notification.data?.url || "/", self.location.origin); event.waitUntil( clients.matchAll({ type: "window", includeUncontrolled: true }).then(async (clientList) => { for (const client of clientList) { const clientUrl = new URL(client.url); if (clientUrl.origin === targetUrl.origin && "focus" in client) { if ("navigate" in client) { await client.navigate(targetUrl.href).catch(() => null); } return client.focus(); } } if (clients.openWindow) { return clients.openWindow(targetUrl.href); } return undefined; }) ); });