Files
canteen-asset-tracker/static/sw.js
T
shawn 120f52a29a chore: bump service worker cache to v8 to force refresh
Old cached index.html was likely serving stale JS on mobile devices.
v8 purge ensures all clients fetch the latest code on next load.
2026-06-01 23:09:17 -04:00

124 lines
4.5 KiB
JavaScript

// ═══════════════════════════════════════════════════════════════════════════
// Canteen Asset Tracker — Service Worker
// Caches app shell + CDN deps. Network-first for API, cache fallback for static.
// ═══════════════════════════════════════════════════════════════════════════
const CACHE_NAME = 'canteen-v8';
// App shell — core resources needed to boot the PWA
const APP_SHELL = [
'/',
'/index.html',
];
// CDN resources we want cached for offline resilience
const CDN_URLS = [
'https://cdn.jsdelivr.net/npm/@zxing/library@0.20.0/umd/index.min.js',
'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css',
'https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.css',
'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',
'https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.js',
'https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js',
];
// ── Install: pre-cache app shell + CDN resources ──────────────────────────
self.addEventListener('install', (event) => {
console.log('[SW] Install — caching app shell + CDN assets');
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll([...APP_SHELL, ...CDN_URLS]).catch((err) => {
console.warn('[SW] Some resources failed to cache (non-fatal):', err.message);
});
})
);
// Activate immediately — don't wait for old SW to release
self.skipWaiting();
});
// ── Activate: purge old caches ────────────────────────────────────────────
self.addEventListener('activate', (event) => {
console.log('[SW] Activate — purging old caches');
event.waitUntil(
caches.keys().then((keys) => {
return Promise.all(
keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k))
);
})
);
// Take control of all clients immediately
self.clients.claim();
});
// ── Fetch: network-first for everything, cache fallback ───────────────────
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
// Navigation requests: network-first, fallback to cached index.html
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request)
.then((response) => {
// Cache the latest version
const clone = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
return response;
})
.catch(() => {
return caches.match(event.request).then((cached) => cached || caches.match('/'));
})
);
return;
}
// API GET calls: network-first, cache fallback (offline reads)
// API POST/PUT/DELETE: pass through — main thread handles offline queuing
if (url.pathname.startsWith('/api/')) {
if (event.request.method === 'GET') {
event.respondWith(
fetch(event.request)
.then((response) => {
if (response.ok) {
const clone = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
}
return response;
})
.catch(() => caches.match(event.request))
);
}
// Non-GET API calls: pass through — main thread queues offline writes
return;
}
// Static assets (local + CDN): network-first, cache fallback
event.respondWith(
fetch(event.request)
.then((response) => {
if (response.ok) {
const clone = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
}
return response;
})
.catch(() => {
return caches.match(event.request);
})
);
});
// ── Message handler: allow main thread to trigger queue sync ──────────────
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SYNC_QUEUE') {
// Forward sync request to all controlled clients
self.clients.matchAll().then((clients) => {
clients.forEach((client) => {
client.postMessage({ type: 'PROCESS_OFFLINE_QUEUE' });
});
});
}
});