// ============================================================ // SERVICE WORKER — Cache shell, network-first for API // Provides offline fallback for app shell while keeping // API calls always fresh (critical for medical data accuracy) // ============================================================ var CACHE_NAME = 'pedscribe-v12'; var SHELL_ASSETS = [ '/', '/index.html', '/css/styles.css', '/js/app.js', '/js/auth.js', '/manifest.json' ]; // Install: precache app shell self.addEventListener('install', function(event) { event.waitUntil( caches.open(CACHE_NAME).then(function(cache) { return cache.addAll(SHELL_ASSETS); }).then(function() { return self.skipWaiting(); }) ); }); // Activate: clear old caches self.addEventListener('activate', function(event) { event.waitUntil( caches.keys().then(function(names) { return Promise.all( names.filter(function(name) { return name !== CACHE_NAME; }) .map(function(name) { return caches.delete(name); }) ); }).then(function() { return self.clients.claim(); }) ); }); // Fetch: network-first for API, cache-first for static assets self.addEventListener('fetch', function(event) { var url = new URL(event.request.url); // Only handle same-origin requests if (url.origin !== self.location.origin) return; // API calls — always network, never cache (medical data must be fresh) if (url.pathname.startsWith('/api/')) { event.respondWith(fetch(event.request)); return; } // Component HTML — network-first with cache fallback if (url.pathname.startsWith('/components/')) { event.respondWith( fetch(event.request).then(function(response) { var clone = response.clone(); caches.open(CACHE_NAME).then(function(cache) { cache.put(event.request, clone); }); return response; }).catch(function() { return caches.match(event.request); }) ); return; } // Static assets (JS, CSS, icons) — network-first so code updates apply immediately if (url.pathname.match(/\.(js|css|png|ico|woff2?)$/)) { event.respondWith( fetch(event.request).then(function(response) { var clone = response.clone(); caches.open(CACHE_NAME).then(function(cache) { cache.put(event.request, clone); }); return response; }).catch(function() { return caches.match(event.request); }) ); return; } // HTML pages — network-first event.respondWith( fetch(event.request).then(function(response) { var clone = response.clone(); caches.open(CACHE_NAME).then(function(cache) { cache.put(event.request, clone); }); return response; }).catch(function() { return caches.match(event.request) || caches.match('/index.html'); }) ); });