///
// Claude Chat PWA — Service Worker
// Cache-First fuer statische Assets, Network-First fuer API-Calls
declare const self: ServiceWorkerGlobalScope;
const CACHE_NAME = 'claude-chat-v1';
// Statische Assets die gecacht werden sollen
const STATIC_ASSETS = [
'/',
'/favicon.png',
'/manifest.json',
];
// ============ Install — Statische Assets vorladen ============
self.addEventListener('install', (event: ExtendableEvent) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(STATIC_ASSETS);
})
);
// Sofort aktivieren, nicht auf alte Tabs warten
self.skipWaiting();
});
// ============ Activate — Alte Caches loeschen ============
self.addEventListener('activate', (event: ExtendableEvent) => {
event.waitUntil(
caches.keys().then((names) => {
return Promise.all(
names
.filter((name) => name !== CACHE_NAME)
.map((name) => caches.delete(name))
);
})
);
// Sofort alle Clients uebernehmen
self.clients.claim();
});
// ============ Fetch — Caching-Strategie ============
self.addEventListener('fetch', (event: FetchEvent) => {
const url = new URL(event.request.url);
// WebSocket-Requests ignorieren
if (url.protocol === 'ws:' || url.protocol === 'wss:') {
return;
}
// API-Calls: Network-First mit Cache-Fallback
if (url.pathname.startsWith('/api/')) {
event.respondWith(networkFirst(event.request));
return;
}
// Statische Assets: Cache-First mit Network-Fallback
event.respondWith(cacheFirst(event.request));
});
/** Cache-First: Zuerst im Cache suchen, dann Netzwerk */
async function cacheFirst(request: Request): Promise {
const cached = await caches.match(request);
if (cached) return cached;
try {
const response = await fetch(request);
// Erfolgreiche Responses cachen
if (response.ok) {
const cache = await caches.open(CACHE_NAME);
cache.put(request, response.clone());
}
return response;
} catch {
// Offline-Fallback fuer HTML-Seiten
if (request.headers.get('accept')?.includes('text/html')) {
const cached = await caches.match('/');
if (cached) return cached;
}
return new Response('Offline', { status: 503 });
}
}
/** Network-First: Zuerst Netzwerk versuchen, dann Cache */
async function networkFirst(request: Request): Promise {
try {
const response = await fetch(request);
// Erfolgreiche GET-Responses cachen
if (response.ok && request.method === 'GET') {
const cache = await caches.open(CACHE_NAME);
cache.put(request, response.clone());
}
return response;
} catch {
const cached = await caches.match(request);
if (cached) return cached;
return new Response(JSON.stringify({ error: 'Offline' }), {
status: 503,
headers: { 'Content-Type': 'application/json' },
});
}
}
export {};