/* global self, caches, URL, Response */ const CACHE_NAME = 'flynn-webchat-v5'; const token = new URL(self.location.href).searchParams.get('token'); const withToken = (path) => { if (!token) { return path; } const sep = path.includes('?') ? '&' : '?'; return `${path}${sep}token=${encodeURIComponent(token)}`; }; const OFFLINE_ASSETS = ['/', '/index.html', '/style.css', '/app.js', '/manifest.webmanifest'].map(withToken); self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME) .then((cache) => cache.addAll(OFFLINE_ASSETS)) .catch(() => undefined), ); self.skipWaiting(); }); self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((keys) => Promise.all( keys .filter((key) => key !== CACHE_NAME) .map((key) => caches.delete(key)), )), ); self.clients.claim(); }); self.addEventListener('fetch', (event) => { if (event.request.method !== 'GET') { return; } const requestUrl = new URL(event.request.url); const isNavigation = event.request.mode === 'navigate'; const isStaticAsset = requestUrl.origin === self.location.origin && (requestUrl.pathname.startsWith('/lib/') || requestUrl.pathname.startsWith('/pages/') || requestUrl.pathname === '/app.js' || requestUrl.pathname === '/style.css' || requestUrl.pathname === '/index.html' || requestUrl.pathname === '/manifest.webmanifest'); event.respondWith((async () => { try { const networkResponse = await fetch(event.request); if (isNavigation || isStaticAsset) { const cache = await caches.open(CACHE_NAME); await cache.put(event.request, networkResponse.clone()); } return networkResponse; } catch { const cached = await caches.match(event.request, { ignoreSearch: true }); if (cached) { return cached; } if (isNavigation) { const fallback = await caches.match('/index.html', { ignoreSearch: true }); if (fallback) { return fallback; } } return new Response('Offline', { status: 503 }); } })()); }); self.addEventListener('push', (event) => { let payload = { title: 'Flynn', body: 'You have a new update.', }; try { const parsed = event.data?.json(); if (parsed && typeof parsed === 'object') { payload = { ...payload, ...parsed, }; } } catch { const text = event.data?.text(); if (text) { payload.body = text; } } event.waitUntil(self.registration.showNotification(payload.title, { body: payload.body, tag: payload.tag || 'flynn-webchat', renotify: false, data: payload.data || {}, })); }); self.addEventListener('notificationclick', (event) => { event.notification.close(); event.waitUntil((async () => { const clients = await self.clients.matchAll({ type: 'window', includeUncontrolled: true }); if (clients.length > 0) { await clients[0].focus(); return; } await self.clients.openWindow('/#/chat'); })()); });