95 lines
2.9 KiB
JavaScript
95 lines
2.9 KiB
JavaScript
// ============================================================
|
|
// 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_VERSION = 'dev';
|
|
try { CACHE_VERSION = new URL(self.location.href).searchParams.get('v') || CACHE_VERSION; } catch(e) {}
|
|
var CACHE_NAME = 'pedscribe-' + CACHE_VERSION;
|
|
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');
|
|
})
|
|
);
|
|
});
|