// Caches RainViewer radar tile images so the last-seen frames stay visible // once the network is actually gone — nothing else here. No app-shell // precaching: the app itself is served by the same local server that's // already the offline resource in the van, so there's no "app unreachable // but should still work" scenario to solve, unlike the radar tiles (a // third-party CDN). const CACHE_VERSION = "v1"; const RADAR_CACHE = `radar-tiles-${CACHE_VERSION}`; // ponytail: a rough cap, not real LRU/expiry — trims oldest-by-insertion via // Cache API iteration order (stable in practice, not spec-guaranteed). // Revisit with timestamp-based expiry if storage actually becomes a // problem; 400 tiles is at most a few MB either way. const MAX_RADAR_TILES = 400; function isRadarTile(url) { return url.hostname.endsWith("rainviewer.com") && url.pathname.includes("/v2/radar/"); } self.addEventListener("install", (event) => { self.skipWaiting(); }); self.addEventListener("activate", (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all(keys.filter((key) => key !== RADAR_CACHE).map((key) => caches.delete(key)))) .then(() => self.clients.claim()), ); }); self.addEventListener("fetch", (event) => { const url = new URL(event.request.url); if (!isRadarTile(url)) return; event.respondWith(networkFallingBackToCache(event.request)); }); // Network first (frame ids rotate as new radar sweeps come in, so a cached // tile can go stale) — cache is only the answer once the network actually // fails, not a shortcut when it's merely slow. async function networkFallingBackToCache(request) { const cache = await caches.open(RADAR_CACHE); try { const response = await fetch(request); if (response.ok) { cache.put(request, response.clone()); trimRadarCache(cache); } return response; } catch (err) { const cached = await cache.match(request); if (cached) return cached; throw err; } } async function trimRadarCache(cache) { const keys = await cache.keys(); if (keys.length <= MAX_RADAR_TILES) return; await Promise.all(keys.slice(0, keys.length - MAX_RADAR_TILES).map((key) => cache.delete(key))); }