/* Baustelle PWA Service Worker. * Cache-Strategie: * - App-Shell (HTML/CSS/JS): cache-first, network update * - API-Calls: network-first, kein offline-cache (da auth-pflichtig) */ const CACHE = 'baustelle-v5'; const SHELL = [ './', './index.html', './share.html', './app.css', './app.js', './manifest.webmanifest', './lib/idb.js', './lib/api.js', './lib/offline.js', './lib/router.js', './icons/icon-192.png', './icons/icon-512.png', ]; // Web Share Target: eingehende POSTs an share.html abfangen und in IDB zwischenspeichern async function handleShareTarget(request) { const fd = await request.formData(); const files = fd.getAll('photos'); if (files.length) { const db = await new Promise((res, rej) => { const req = indexedDB.open('baustelle-pwa-v1', 1); req.onupgradeneeded = () => { const d = req.result; if (!d.objectStoreNames.contains('kv')) d.createObjectStore('kv'); if (!d.objectStoreNames.contains('queue')) d.createObjectStore('queue', { keyPath: 'id', autoIncrement: true }); }; req.onsuccess = () => res(req.result); req.onerror = () => rej(req.error); }); const tx = db.transaction('kv', 'readwrite'); tx.objectStore('kv').put(files.map(f => ({ name: f.name, type: f.type, data: f })), 'shared_files'); await new Promise(res => tx.oncomplete = res); } return Response.redirect('./share.html', 303); } self.addEventListener('install', (e) => { e.waitUntil(caches.open(CACHE).then(c => c.addAll(SHELL).catch(() => null))); self.skipWaiting(); }); self.addEventListener('activate', (e) => { e.waitUntil( caches.keys().then(keys => Promise.all( keys.filter(k => k !== CACHE).map(k => caches.delete(k)) )) ); self.clients.claim(); }); self.addEventListener('fetch', (e) => { const url = new URL(e.request.url); // Web Share Target: POST auf share.html abfangen if (e.request.method === 'POST' && url.pathname.endsWith('/share.html')) { e.respondWith(handleShareTarget(e.request)); return; } // API-Requests: nicht cachen, durchreichen if (url.pathname.includes('/custom/bericht/api/')) { return; // default network } // App-Shell: cache-first if (e.request.method === 'GET' && url.origin === location.origin) { e.respondWith( caches.match(e.request).then(hit => { if (hit) { // Background-Update fetch(e.request).then(r => { if (r.ok) caches.open(CACHE).then(c => c.put(e.request, r.clone())); }).catch(() => null); return hit; } return fetch(e.request).then(r => { if (r.ok) { const clone = r.clone(); caches.open(CACHE).then(c => c.put(e.request, clone)); } return r; }); }) ); } });