From 981ca827a29f14d015533878348efd62bdfcc249 Mon Sep 17 00:00:00 2001 From: Hermes Date: Mon, 17 Aug 2026 16:17:36 +0200 Subject: [PATCH] =?UTF-8?q?fix(sw):=20stop=20unbounded=20cache=20growth=20?= =?UTF-8?q?=E2=80=94=20delete=20stale=20caches=20on=20activate,=20cache=20?= =?UTF-8?q?only=20static=20assets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - activate: delete ALL caches except current STATIC/RUNTIME (was keeping every previous construction-delivery-* cache forever → 3GB storage, 30-40s caches.match) - fetch: only cache same-origin static assets (js/css/img/fonts); API/data and cross-origin requests go straight to network, never cached - bump to v115 --- public/service-worker.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/public/service-worker.js b/public/service-worker.js index b53129f..06aed83 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -1,10 +1,15 @@ const isLocalhost = self.location.hostname === "localhost" || self.location.hostname === "127.0.0.1"; if (!isLocalhost) { - const STATIC_CACHE = "construction-delivery-static-v114"; - const RUNTIME_CACHE = "construction-delivery-runtime-v114"; + const STATIC_CACHE = "construction-delivery-static-v115"; + const RUNTIME_CACHE = "construction-delivery-runtime-v115"; const APP_SHELL_URLS = ["/", "/client", "/index.html", "/manifest.webmanifest", "/icons/icon-192.png", "/icons/icon-512.png"]; + // Only these are treated as cacheable static assets. Everything else + // (API/data requests, cross-origin) goes straight to the network and is + // NEVER written to cache — prevents unbounded cache growth. + const ASSET_EXT = /\.(js|mjs|css|png|jpe?g|gif|svg|webp|ico|woff2?|ttf|eot|webmanifest)$/i; + self.addEventListener("install", (event) => { event.waitUntil( caches.open(STATIC_CACHE).then((cache) => cache.addAll(APP_SHELL_URLS)).then(() => self.skipWaiting()), @@ -38,6 +43,7 @@ if (!isLocalhost) { const requestUrl = new URL(event.request.url); const isSameOrigin = requestUrl.origin === self.location.origin; + // Navigation: network-first, fall back to cached index.html when offline. if (event.request.mode === "navigate") { event.respondWith( fetch(event.request) @@ -54,7 +60,9 @@ if (!isLocalhost) { return; } - if (!isSameOrigin) { + // Only cache same-origin static assets (hashed build files, images, fonts). + // API/data requests and cross-origin calls are never cached. + if (!isSameOrigin || !ASSET_EXT.test(requestUrl.pathname)) { return; }