From 5d1e5ec791fc76f85c1893639eefe978461d7f14 Mon Sep 17 00:00:00 2001 From: Jonathan Sykes Date: Thu, 8 Oct 2026 00:03:14 +0800 Subject: [PATCH] Verify explicit activation and legacy incremental migration --- frontend/asset-worker.test.js | 2 +- frontend/sw-update.js | 8 +++- frontend/sw-update.test.js | 6 +++ frontend/sw.js | 10 ++--- perf/baseline.mjs | 5 +++ perf/migration.mjs | 71 ++++++++++++++++++++++++++++++++--- perf/proxy.mjs | 10 ++++- 7 files changed, 96 insertions(+), 16 deletions(-) diff --git a/frontend/asset-worker.test.js b/frontend/asset-worker.test.js index 667c887..193a31a 100644 --- a/frontend/asset-worker.test.js +++ b/frontend/asset-worker.test.js @@ -9,4 +9,4 @@ function environment(){ return {storage,m,skips,dispatch,request}; } test('install does not activate or publish; CACHE_STATUS is honest; activation commits and exact requests self-heal',async()=>{const e=environment();await e.dispatch('install');assert.equal(e.skips.length,0);const cache=await e.storage.open(core.CACHE);assert.equal(await core.state(cache),null);let reply;await e.dispatch('message',{data:{type:'CACHE_STATUS'},ports:[{postMessage:r=>reply=r}]});assert.equal(reply.ready,true);await e.dispatch('activate');assert.equal((await core.state(cache)).current.buildTag,'next');assert.equal((await e.request('/playlist/x','navigate')).headers.get('X-Asset-Hash'),'index');await cache.delete('/app.js?v=app');await e.dispatch('message',{data:{type:'CACHE_STATUS'},ports:[{postMessage:r=>reply=r}]});assert.equal(reply.ready,false);assert.equal(reply.missing,1);assert.equal(reply.version,'next');assert.equal((await e.request('/app.js')).headers.get('X-Asset-Hash'),'app');assert.ok(await cache.match('/app.js?v=app'));assert.equal(await cache.match('/app.js?v=stale'),undefined);assert.equal((await e.request('/app.js?v=stale')).status,409);}); -test('reported playback defers explicit activation until pause; install never calls skipWaiting',async()=>{const e=environment(),source={id:'p'};await e.dispatch('message',{source,data:{type:'PLAYING',value:true}});await e.dispatch('message',{source,data:{type:'SKIP_WAITING'}});assert.equal(e.skips.length,0);await e.dispatch('message',{source,data:{type:'PLAYING',value:false}});assert.equal(e.skips.length,1);}); +test('reported playback defers explicit activation until pause; install never calls skipWaiting',async()=>{const e=environment(),source={id:'p'};await e.dispatch('message',{data:{type:'SKIP_WAITING'}});assert.equal(e.skips.length,0);await e.dispatch('message',{source,data:{type:'PLAYING',value:true}});await e.dispatch('message',{source,data:{type:'SKIP_WAITING'}});assert.equal(e.skips.length,0);await e.dispatch('message',{source,data:{type:'PLAYING',value:false}});assert.equal(e.skips.length,1);}); diff --git a/frontend/sw-update.js b/frontend/sw-update.js index e4b195e..d40de07 100644 --- a/frontend/sw-update.js +++ b/frontend/sw-update.js @@ -1,7 +1,7 @@ /* ============================================================================ * sw-update — makes "Refresh UI" actually land the new build. * - * Framework-free and dependency-free on purpose (same pattern as + * Framework-free, with a shared sync core and a legacy fallback (same pattern as * async-guard.js): * • Loads as a plain