From f36f6aeee141de58366025c550c11fe29f407d78 Mon Sep 17 00:00:00 2001 From: Jonathan Sykes Date: Thu, 2 Jul 2026 13:40:36 +0800 Subject: [PATCH] fix: only treat a waiting service worker as an update when a controller exists --- frontend/app.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/frontend/app.js b/frontend/app.js index 27ac065..362112e 100755 --- a/frontend/app.js +++ b/frontend/app.js @@ -3021,16 +3021,25 @@ async function registerServiceWorker() { const reg = await navigator.serviceWorker.register('/sw.js', { updateViaCache: 'none' }); _swReg = reg; + // A waiting worker only means "update pending" when this page is already + // controlled by a previous SW. On a FIRST install (fresh visit, or right + // after Settings → Force refresh unregisters everything) the brand-new + // worker passes through the `installed`/waiting state for a moment before + // activating — with no controller that is not an update, and showing the + // banner for it is exactly the "Update available keeps coming back after + // Refresh UI" loop. + const hasController = () => !!navigator.serviceWorker.controller; + // If a new SW is already waiting (e.g. user refreshed after an update), // show the dialog right away. - if (reg.waiting) { showUpdateBanner(); return; } + if (reg.waiting && hasController()) { showUpdateBanner(); return; } // Listen for a new SW installing after the page is open. reg.addEventListener('updatefound', () => { const sw = reg.installing; if (!sw) return; sw.addEventListener('statechange', () => { - if (sw.state === 'installed' && reg.waiting) showUpdateBanner(); + if (sw.state === 'installed' && reg.waiting && hasController()) showUpdateBanner(); }); });