Files
canteen-asset-tracker/static/sw.js
T
shawn 72003e2742 fix: GPS chip visibility and Leaflet Draw geofencing
- Removed hardcoded display:none from GPS center chip on map tab
- Chip now shows when GPS position is obtained in startVisitTracking
- Added leaflet-draw CSS and JS to HTML head
- Added draw control (polygon, rectangle, circle) to map init
- Emits geofenceDrawn custom event for external hooks
2026-05-22 11:50:44 -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-v3';
// 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' });
});
});
}
});