2025-06-04 10:03:22 +02:00

25 lines
7.5 KiB
JavaScript

const CACHE_NAME='myp-platform-cache-v1';const STATIC_CACHE='myp-static-v1';const DYNAMIC_CACHE='myp-dynamic-v1';const ASSETS_TO_CACHE=['/','/dashboard','/static/css/tailwind.min.css','/static/css/tailwind-dark.min.css','/static/js/ui-components.js','/static/js/offline-app.js','/static/icons/mercedes-logo.svg','/static/icons/icon-144x144.png','/static/favicon.ico'];const STATIC_PATTERNS=[/\.css$/,/\.js$/,/\.svg$/,/\.png$/,/\.ico$/,/\.woff2?$/];const API_PATTERNS=[/^\/api\//,/^\/auth\//,/^\/api\/jobs/,/^\/api\/printers/,/^\/api\/stats/];self.addEventListener('install',(event)=>{console.log('Service Worker: Installing...');event.waitUntil(caches.open(STATIC_CACHE).then((cache)=>{console.log('Service Worker: Caching static files');return cache.addAll(ASSETS_TO_CACHE);}).then(()=>{console.log('Service Worker: Static files cached');return self.skipWaiting();}).catch((error)=>{console.error('Service Worker: Error caching static files',error);}));});self.addEventListener('activate',(event)=>{console.log('Service Worker: Activating...');event.waitUntil(caches.keys().then((cacheNames)=>{return Promise.all(cacheNames.map((cacheName)=>{if(cacheName!==STATIC_CACHE&&cacheName!==DYNAMIC_CACHE){console.log('Service Worker: Deleting old cache',cacheName);return caches.delete(cacheName);}}));}).then(()=>{console.log('Service Worker: Activated');return self.clients.claim();}));});self.addEventListener('fetch',(event)=>{const{request}=event;const url=new URL(request.url);if(request.method!=='GET'||(url.protocol!=='http:'&&url.protocol!=='https:')){return;}
event.respondWith(fetch(request).then((response)=>{if(response&&response.status===200&&isStaticFile(url.pathname)&&(url.protocol==='http:'||url.protocol==='https:')){const responseClone=response.clone();caches.open(STATIC_CACHE).then((cache)=>{cache.put(request,responseClone);}).catch(err=>{console.warn('Failed to cache response:',err);});}
return response;}).catch(()=>{return caches.match(request);}));});function isStaticFile(pathname){return STATIC_PATTERNS.some(pattern=>pattern.test(pathname));}
function isAPIRequest(pathname){return API_PATTERNS.some(pattern=>pattern.test(pathname));}
function isPageRequest(request){return request.mode==='navigate';}
const STATIC_FILES=['/','/static/css/tailwind.min.css','/static/css/tailwind-dark.min.css','/static/js/ui-components.js','/static/js/offline-app.js','/login','/dashboard'];const API_CACHE_PATTERNS=[/^\/api\/dashboard/,/^\/api\/printers/,/^\/api\/jobs/,/^\/api\/stats/];async function handleStaticFile(request){try{const cachedResponse=await caches.match(request);if(cachedResponse){return cachedResponse;}
const networkResponse=await fetch(request);if(networkResponse.ok){const cache=await caches.open(STATIC_CACHE);cache.put(request,networkResponse.clone());}
return networkResponse;}catch(error){console.error('Service Worker: Error handling static file',error);const cachedResponse=await caches.match(request);if(cachedResponse){return cachedResponse;}
return new Response('Offline - Datei nicht verfügbar',{status:503,statusText:'Service Unavailable'});}}
async function handleAPIRequest(request){const url=new URL(request.url);if(url.protocol==='chrome-extension:'){try{return await fetch(request);}catch(error){console.error('Failed to fetch from chrome-extension:',error);return new Response(JSON.stringify({error:'Fehler beim Zugriff auf chrome-extension',offline:true}),{status:400,headers:{'Content-Type':'application/json'}});}}
try{const networkResponse=await fetch(request);if(networkResponse.ok){if(request.method==='GET'&&shouldCacheAPIResponse(url.pathname)){const cache=await caches.open(DYNAMIC_CACHE);cache.put(request,networkResponse.clone());}
return networkResponse;}
throw new Error(`HTTP ${networkResponse.status}`);}catch(error){console.log('Service Worker: Network failed for API request, trying cache');const cachedResponse=await caches.match(request);if(cachedResponse){const response=cachedResponse.clone();response.headers.set('X-Served-By','ServiceWorker-Cache');return response;}
return new Response(JSON.stringify({error:'Offline - Daten nicht verfügbar',offline:true,timestamp:new Date().toISOString()}),{status:503,statusText:'Service Unavailable',headers:{'Content-Type':'application/json','X-Served-By':'ServiceWorker-Offline'}});}}
async function handlePageRequest(request){try{const networkResponse=await fetch(request);if(networkResponse.ok){const cache=await caches.open(DYNAMIC_CACHE);cache.put(request,networkResponse.clone());return networkResponse;}
throw new Error(`HTTP ${networkResponse.status}`);}catch(error){console.log('Service Worker: Network failed for page request, trying cache');const cachedResponse=await caches.match(request);if(cachedResponse){return cachedResponse;}
return caches.match('/offline.html')||new Response('<html><body><h1>Offline</h1><p>Sie sind momentan offline. Bitte überprüfen Sie Ihre Internetverbindung.</p></body></html>',{status:200,headers:{'Content-Type':'text/html'}});}}
function shouldCacheAPIResponse(pathname){return API_CACHE_PATTERNS.some(pattern=>pattern.test(pathname));}
self.addEventListener('sync',(event)=>{console.log('Service Worker: Background sync triggered',event.tag);if(event.tag==='background-sync'){event.waitUntil(doBackgroundSync());}});async function doBackgroundSync(){try{const pendingRequests=await getPendingRequests();for(const request of pendingRequests){try{await fetch(request.url,request.options);await removePendingRequest(request.id);console.log('Service Worker: Synced request',request.url);}catch(error){console.error('Service Worker: Failed to sync request',request.url,error);}}}catch(error){console.error('Service Worker: Background sync failed',error);}}
async function getPendingRequests(){return[];}
async function removePendingRequest(id){console.log('Service Worker: Removing pending request',id);}
self.addEventListener('push',(event)=>{console.log('Service Worker: Push notification received');const options={body:'Sie haben neue Benachrichtigungen',icon:'/static/icons/icon-192x192.png',badge:'/static/icons/badge-72x72.png',vibrate:[100,50,100],data:{dateOfArrival:Date.now(),primaryKey:1},actions:[{action:'explore',title:'Anzeigen',icon:'/static/icons/checkmark.png'},{action:'close',title:'Schließen',icon:'/static/icons/xmark.png'}]};event.waitUntil(self.registration.showNotification('MYP Platform',options));});self.addEventListener('notificationclick',(event)=>{console.log('Service Worker: Notification clicked');event.notification.close();if(event.action==='explore'){event.waitUntil(clients.openWindow('/dashboard'));}});self.addEventListener('message',(event)=>{console.log('Service Worker: Message received',event.data);if(event.data&&event.data.type==='SKIP_WAITING'){self.skipWaiting();}
if(event.data&&event.data.type==='CACHE_URLS'){event.waitUntil(cacheUrls(event.data.urls));}});async function cacheUrls(urls){try{const cache=await caches.open(DYNAMIC_CACHE);await cache.addAll(urls);console.log('Service Worker: URLs cached',urls);}catch(error){console.error('Service Worker: Error caching URLs',error);}}
self.addEventListener('periodicsync',(event)=>{console.log('Service Worker: Periodic sync triggered',event.tag);if(event.tag==='content-sync'){event.waitUntil(syncContent());}});async function syncContent(){try{const endpoints=['/api/dashboard','/api/jobs'];for(const endpoint of endpoints){try{const response=await fetch(endpoint);if(response.ok){const cache=await caches.open(DYNAMIC_CACHE);cache.put(endpoint,response.clone());}}catch(error){console.error('Service Worker: Error syncing',endpoint,error);}}}catch(error){console.error('Service Worker: Content sync failed',error);}}
console.log('Service Worker: Script loaded');