/** * BattleWords Service Worker * Enables PWA functionality: offline caching, install prompt, etc. * * Security Note: This file contains no secrets or sensitive data. * It only caches public assets for offline access. */ const CACHE_NAME = 'battlewords-v0.2.29'; const RUNTIME_CACHE = 'battlewords-runtime'; // Assets to cache on install (minimal for faster install) const PRECACHE_URLS = [ '/', '/app/static/manifest.json', '/app/static/icon-192.png', '/app/static/icon-512.png' ]; // Install event - cache essential files self.addEventListener('install', event => { console.log('[ServiceWorker] Installing...'); event.waitUntil( caches.open(CACHE_NAME) .then(cache => { console.log('[ServiceWorker] Precaching app shell'); return cache.addAll(PRECACHE_URLS); }) .then(() => self.skipWaiting()) // Activate immediately ); }); // Activate event - clean up old caches self.addEventListener('activate', event => { console.log('[ServiceWorker] Activating...'); event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(cacheName => { if (cacheName !== CACHE_NAME && cacheName !== RUNTIME_CACHE) { console.log('[ServiceWorker] Deleting old cache:', cacheName); return caches.delete(cacheName); } }) ); }).then(() => self.clients.claim()) // Take control immediately ); }); // Fetch event - network first, fall back to cache self.addEventListener('fetch', event => { // Skip non-GET requests if (event.request.method !== 'GET') { return; } // Skip chrome-extension and other non-http requests if (!event.request.url.startsWith('http')) { return; } event.respondWith( caches.open(RUNTIME_CACHE).then(cache => { return fetch(event.request) .then(response => { // Cache successful responses for future offline access if (response.status === 200) { cache.put(event.request, response.clone()); } return response; }) .catch(() => { // Network failed, try cache return caches.match(event.request).then(cachedResponse => { if (cachedResponse) { console.log('[ServiceWorker] Serving from cache:', event.request.url); return cachedResponse; } // No cache available, return offline page or error return new Response('Offline - Please check your connection', { status: 503, statusText: 'Service Unavailable', headers: new Headers({ 'Content-Type': 'text/plain' }) }); }); }); }) ); }); // Message event - handle commands from the app self.addEventListener('message', event => { if (event.data.action === 'skipWaiting') { self.skipWaiting(); } });