From eb325a8412498bdcfa07803870179055f18a0984 Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Mon, 3 Aug 2026 00:47:00 +0530 Subject: [PATCH] fix: recover stale service worker clients --- app/docs.test.ts | 6 +++++- public/pwa-recover.js | 37 +++++++++++++++++++++++++++++++++++++ wrnexus.config.ts | 5 ++++- 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 public/pwa-recover.js diff --git a/app/docs.test.ts b/app/docs.test.ts index ddc5179b..cc48add1 100644 --- a/app/docs.test.ts +++ b/app/docs.test.ts @@ -135,7 +135,11 @@ test("site includes core guides and production configuration", () => { expect(config).toContain( '"style-src": ["\'self\'", "\'unsafe-inline\'", "https://fonts.googleapis.com"]', ); - expect(config).toContain('cacheName: "wrnexus-pwa-v2"'); + expect(config).toContain('cacheName: "wrnexus-pwa-v3"'); + expect(config).toContain("head: ''"); + const recovery = readFileSync(join(root, "public", "pwa-recover.js"), "utf8"); + expect(recovery).toContain('updateViaCache: "none"'); + expect(recovery).toContain("registration.update()"); expect(config).toContain('pattern: "^https://wrnexusjs\\\\.dev/"'); }); diff --git a/public/pwa-recover.js b/public/pwa-recover.js new file mode 100644 index 00000000..fc9283e3 --- /dev/null +++ b/public/pwa-recover.js @@ -0,0 +1,37 @@ +/* global location, navigator, sessionStorage, window */ +(function () { + if (!("serviceWorker" in navigator)) return; + + var version = "docs-v3"; + var workerUrl = "/sw.js?v=" + encodeURIComponent(version); + if (window.trustedTypes) { + try { + workerUrl = window.trustedTypes + .createPolicy("wrnexus-pwa-recovery", { + createScriptURL: function (value) { + return value; + }, + }) + .createScriptURL(workerUrl); + } catch { + // A previously-created policy can make creation fail; the same-origin + // string remains valid when Trusted Types enforcement is not active. + } + } + + var reloading = false; + navigator.serviceWorker.addEventListener("controllerchange", function () { + var key = "wrnexus-pwa-controller-" + version; + if (reloading || sessionStorage.getItem(key)) return; + reloading = true; + sessionStorage.setItem(key, "1"); + location.reload(); + }); + + navigator.serviceWorker + .register(workerUrl, { updateViaCache: "none" }) + .then(function (registration) { + return registration.update(); + }) + .catch(function () {}); +})(); diff --git a/wrnexus.config.ts b/wrnexus.config.ts index 040d25d9..6441c442 100644 --- a/wrnexus.config.ts +++ b/wrnexus.config.ts @@ -1,6 +1,9 @@ import type { AppConfig } from "@wrnexus/styles"; const config: AppConfig = { + // Repair clients that are still controlled by an older cached service worker. + // This can be removed after every preview client has advanced beyond v3. + head: '', mobile: { enabled: true, appId: "com.example.wrnexusjs", @@ -15,7 +18,7 @@ const config: AppConfig = { pwa: { name: "WRNexusJS Documentation", shortName: "WRNexusJS Docs", - cacheName: "wrnexus-pwa-v2", + cacheName: "wrnexus-pwa-v3", runtimeCaching: [ { pattern: "^https://wrnexusjs\\.dev/",