const CACHE_NAME = 'vibetorrent-v1'; const ASSETS_TO_CACHE = [ '/', '/index.html', '/manifest.json', '/icon-192.png', '/icon-512.png' ]; // Install event - cache assets self.addEventListener('install', (event) => { console.log('[Service Worker] Installing...'); event.waitUntil( caches.open(CACHE_NAME).then((cache) => { console.log('[Service Worker] Caching static assets'); return cache.addAll(ASSETS_TO_CACHE); }).then(() => { console.log('[Service Worker] Skip waiting'); return self.skipWaiting(); }) ); }); // Activate event - clean old caches self.addEventListener('activate', (event) => { console.log('[Service Worker] Activating...'); event.waitUntil( caches.keys().then((cacheNames) => { return Promise.all( cacheNames.map((key) => { if (key !== CACHE_NAME) { console.log('[Service Worker] Deleting old cache:', key); return caches.delete(key); } }) ); }).then(() => { console.log('[Service Worker] Claiming clients'); return self.clients.claim(); }) ); }); // Fetch event - network first, cache fallback for API calls self.addEventListener('fetch', (event) => { const url = new URL(event.request.url); // Network-first strategy for API calls if (url.pathname.startsWith('/api/')) { event.respondWith( fetch(event.request) .catch(() => { // Could return cached API response or offline page return new Response( JSON.stringify({ error: 'Offline' }), { headers: { 'Content-Type': 'application/json' } } ); }) ); return; } // Cache-first strategy for static assets event.respondWith( caches.match(event.request).then((response) => { return response || fetch(event.request).then((fetchResponse) => { // Optionally cache new requests if (fetchResponse && fetchResponse.status === 200) { const responseToCache = fetchResponse.clone(); caches.open(CACHE_NAME).then((cache) => { cache.put(event.request, responseToCache); }); } return fetchResponse; }); }) ); }); // Notification click event - focus or open app self.addEventListener('notificationclick', (event) => { console.log('[Service Worker] Notification clicked:', event.notification.tag); event.notification.close(); event.waitUntil( clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => { // If app is already open, focus it for (let client of clientList) { if (client.url === '/' && 'focus' in client) { return client.focus(); } } // Otherwise open new window if (clients.openWindow) { return clients.openWindow('/'); } }) ); }); // Push notification event (for future use) self.addEventListener('push', (event) => { console.log('[Service Worker] Push received'); const data = event.data ? event.data.json() : {}; const options = { body: data.message || 'New notification', icon: '/icon-192.png', badge: '/icon-192.png', tag: data.tag || 'vibetorrent-notification', requireInteraction: false, }; event.waitUntil( self.registration.showNotification(data.title || 'VibeTorrent', options) ); });