const CACHE_PREFIX = "pi-web"; const CACHE_VERSION = new URL(self.location.href).searchParams.get("v") || "dev"; const STATIC_CACHE = `${CACHE_PREFIX}-static-${CACHE_VERSION}`; const OFFLINE_URL = "/offline.html"; const PRECACHE_URLS = [ OFFLINE_URL, "/manifest.webmanifest", "/icons/icon-192.png", "/icons/icon-512.png", "/icons/apple-touch-icon.png", ]; self.addEventListener("install", (event) => { event.waitUntil( caches .open(STATIC_CACHE) .then((cache) => cache.addAll(PRECACHE_URLS)) .then(() => self.skipWaiting()), ); }); self.addEventListener("activate", (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all( keys .filter((key) => key.startsWith(`${CACHE_PREFIX}-`) && key !== STATIC_CACHE) .map((key) => caches.delete(key)), ), ) .then(() => self.clients.claim()), ); }); self.addEventListener("fetch", (event) => { const { request } = event; if (request.method !== "GET") return; const url = new URL(request.url); if (url.origin !== self.location.origin) return; // Session data and live agent traffic must always come from the local server. if (url.pathname.startsWith("/api/") || url.pathname === "/sw.js") return; if (request.mode === "navigate") { event.respondWith( fetch(request).catch(async () => { const fallback = await caches.match(OFFLINE_URL); return fallback ?? Response.error(); }), ); return; } const isStaticAsset = url.pathname.startsWith("/_next/static/") || PRECACHE_URLS.includes(url.pathname); if (isStaticAsset) { event.respondWith(cacheFirst(request)); } }); async function cacheFirst(request) { const cached = await caches.match(request); if (cached) return cached; const response = await fetch(request); if (response.ok && response.type === "basic") { const cache = await caches.open(STATIC_CACHE); await cache.put(request, response.clone()); } return response; }