const CACHE_NAME = 'aethex-connect-v1'; const ASSETS_TO_CACHE = [ '/', '/index.html', '/manifest.json', ]; // Install event self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => { console.log('Caching app shell'); return cache.addAll(ASSETS_TO_CACHE).catch(err => { console.log('Cache addAll error:', err); // Don't fail installation if some assets can't be cached }); }) ); self.skipWaiting(); }); // Activate event self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((cacheNames) => { return Promise.all( cacheNames.map((cacheName) => { if (cacheName !== CACHE_NAME) { console.log('Deleting old cache:', cacheName); return caches.delete(cacheName); } }) ); }) ); self.clients.claim(); }); // Fetch event - Network first, fallback to cache self.addEventListener('fetch', (event) => { const { request } = event; // Skip non-GET requests if (request.method !== 'GET') { return; } // API requests - network first if (request.url.includes('/api/')) { event.respondWith( fetch(request) .then((response) => { if (!response || response.status !== 200) { return response; } const responseClone = response.clone(); caches.open(CACHE_NAME).then((cache) => { cache.put(request, responseClone); }); return response; }) .catch(() => { return caches.match(request); }) ); } else { // Static assets - cache first event.respondWith( caches.match(request).then((response) => { if (response) { return response; } return fetch(request).then((response) => { if (!response || response.status !== 200 || response.type === 'error') { return response; } const responseClone = response.clone(); caches.open(CACHE_NAME).then((cache) => { cache.put(request, responseClone); }); return response; }); }) ); } }); // Background sync for offline messages self.addEventListener('sync', (event) => { if (event.tag === 'sync-messages') { event.waitUntil(syncMessages()); } }); async function syncMessages() { try { const db = await openIndexedDB(); const messages = await getPendingMessages(db); for (const message of messages) { try { await fetch('/api/messages', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(message), }); await deletePendingMessage(db, message.id); } catch (error) { console.error('Failed to sync message:', error); } } } catch (error) { console.error('Sync error:', error); } } function openIndexedDB() { return new Promise((resolve, reject) => { const request = indexedDB.open('aethex-connect', 1); request.onerror = () => reject(request.error); request.onsuccess = () => resolve(request.result); }); } function getPendingMessages(db) { return new Promise((resolve, reject) => { const transaction = db.transaction(['pendingMessages'], 'readonly'); const store = transaction.objectStore('pendingMessages'); const request = store.getAll(); request.onerror = () => reject(request.error); request.onsuccess = () => resolve(request.result); }); } function deletePendingMessage(db, id) { return new Promise((resolve, reject) => { const transaction = db.transaction(['pendingMessages'], 'readwrite'); const store = transaction.objectStore('pendingMessages'); const request = store.delete(id); request.onerror = () => reject(request.error); request.onsuccess = () => resolve(); }); }