Poll workspace revision through the authorized state RPC
This commit is contained in:
parent
71bc56b0cd
commit
7807bf4f8f
@ -11,7 +11,7 @@
|
|||||||
"serverReady": true,
|
"serverReady": true,
|
||||||
"workspaceAutoDiscovery": true,
|
"workspaceAutoDiscovery": true,
|
||||||
"invitesTemporarilyDisabled": false,
|
"invitesTemporarilyDisabled": false,
|
||||||
"pwaCache": "v104-20260918-russia-proxy",
|
"pwaCache": "v105-20260918-russia-proxy-rpc",
|
||||||
"fullOfferDescriptions": true,
|
"fullOfferDescriptions": true,
|
||||||
"dynamicOfferRows": true,
|
"dynamicOfferRows": true,
|
||||||
"pdfOfferDescriptionFix": true,
|
"pdfOfferDescriptionFix": true,
|
||||||
|
|||||||
@ -25,6 +25,8 @@ Updates use HTTP: a revision-only request every 20 seconds while visible, and
|
|||||||
chat refresh every 10 seconds. Unchanged bases are not downloaded again. Requests
|
chat refresh every 10 seconds. Unchanged bases are not downloaded again. Requests
|
||||||
from the previous account are discarded. Typing/online indicators require a
|
from the previous account are discarded. Typing/online indicators require a
|
||||||
future WebSocket-capable proxy and are not advertised by the HTTP mode.
|
future WebSocket-capable proxy and are not advertised by the HTTP mode.
|
||||||
|
Revision reads project `revision` from the existing `sun_fetch_app_state` RPC;
|
||||||
|
direct table access remains revoked. No database grants or schema changes are required.
|
||||||
|
|
||||||
This covers application data and media. Optional map/geocoding providers remain
|
This covers application data and media. Optional map/geocoding providers remain
|
||||||
external and do not gate login or order loading. If the login page itself cannot
|
external and do not gate login or order loading. If the login page itself cannot
|
||||||
|
|||||||
@ -3363,7 +3363,9 @@ window.SUN_LEGACY_CATALOG_V175=[];
|
|||||||
try{
|
try{
|
||||||
// Poll only the revision; download/merge the full base only after a change.
|
// Poll only the revision; download/merge the full base only after a change.
|
||||||
// The same RLS and authorization apply as to the previous socket channel.
|
// The same RLS and authorization apply as to the previous socket channel.
|
||||||
const {data,error}=await client.from('sun_app_state').select('revision').eq('workspace_id',startedWorkspace).maybeSingle();
|
// Direct table reads are intentionally revoked in production. PostgREST
|
||||||
|
// projects just revision from the existing, tenant-checked RPC result.
|
||||||
|
const {data,error}=await client.rpc('sun_fetch_app_state',{p_workspace:startedWorkspace}).select('revision').maybeSingle();
|
||||||
if(error)throw error;
|
if(error)throw error;
|
||||||
const baseline=await getBaseline();
|
const baseline=await getBaseline();
|
||||||
if(current()&&data&&Number(data.revision)!==Number(baseline?.revision))await syncNow({quiet:true});
|
if(current()&&data&&Number(data.revision)!==Number(baseline?.revision))await syncNow({quiet:true});
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
(()=>{
|
(()=>{
|
||||||
'use strict';
|
'use strict';
|
||||||
const VERSION='17.7.3';
|
const VERSION='17.7.3';
|
||||||
const RELEASE='20260918-russia-proxy';
|
const RELEASE='20260918-russia-proxy-rpc';
|
||||||
|
|
||||||
const hasStoredSession=()=>{try{return Object.keys(localStorage).some(k=>/^sb-.*-auth-token$/i.test(k)&&String(localStorage.getItem(k)||'').length>20)}catch(_){return false}};
|
const hasStoredSession=()=>{try{return Object.keys(localStorage).some(k=>/^sb-.*-auth-token$/i.test(k)&&String(localStorage.getItem(k)||'').length>20)}catch(_){return false}};
|
||||||
function installAuthBoot(){
|
function installAuthBoot(){
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
|||||||
const CACHE='sun-catering-pwa-v104-20260918-russia-proxy';
|
const CACHE='sun-catering-pwa-v105-20260918-russia-proxy-rpc';
|
||||||
const VERSION='20260918-russia-proxy';
|
const VERSION='20260918-russia-proxy-rpc';
|
||||||
const CORE=[
|
const CORE=[
|
||||||
'./vendor/supabase-2.112.4.min.js',
|
'./vendor/supabase-2.112.4.min.js',
|
||||||
`./core/help-center.js?v=${VERSION}`,`./core/help-center.css?v=${VERSION}`,`./help/knowledge-v1.json?v=${VERSION}`,
|
`./core/help-center.js?v=${VERSION}`,`./core/help-center.css?v=${VERSION}`,`./help/knowledge-v1.json?v=${VERSION}`,
|
||||||
|
|||||||
@ -24,17 +24,17 @@ test('revision polling reads only changed bases and ignores the previous account
|
|||||||
const result=await page.evaluate(async()=>{
|
const result=await page.evaluate(async()=>{
|
||||||
let revision=1,readCount=0,resolveRevision;const calls=[];
|
let revision=1,readCount=0,resolveRevision;const calls=[];
|
||||||
const payload={format:'sun-cloud-v2',version:2,storage:{sunOrders:{t:'j',v:[]}}};
|
const payload={format:'sun-cloud-v2',version:2,storage:{sunOrders:{t:'j',v:[]}}};
|
||||||
const query={select(fields){calls.push(fields);return this},eq(key,value){calls.push([key,value]);return this},async maybeSingle(){readCount++;return revision===99?new Promise(r=>resolveRevision=r):{data:{revision}}}};
|
const query={select(fields){calls.push(fields);return this},async maybeSingle(){readCount++;return revision===99?new Promise(r=>resolveRevision=r):{data:{revision}}},then(resolve){calls.push('full-state');return Promise.resolve({data:[{revision,payload}]}).then(resolve)}};
|
||||||
const c={from(table){calls.push(table);return query},async rpc(name){calls.push(name);return {data:[{revision,payload}]}}};
|
const c={from(){throw new Error('Direct table access denied')},rpc(name,args){calls.push(name);if(name==='sun_fetch_app_state'){calls.push(args.p_workspace);return query}return Promise.resolve({data:[{revision,payload}]})}};
|
||||||
SunCloudV2.testInit(c);await SunCloudV2.testBaseline({revision:1,payload});
|
SunCloudV2.testInit(c);await SunCloudV2.testBaseline({revision:1,payload});
|
||||||
await SunCloudV2.testPoll();const unchanged=calls.splice(0);
|
await SunCloudV2.testPoll();const unchanged=calls.splice(0);
|
||||||
revision=2;await SunCloudV2.testPoll();const changed=calls.splice(0);
|
revision=2;await SunCloudV2.testPoll();const changed=calls.splice(0);
|
||||||
revision=99;const pending=SunCloudV2.testPoll();await SunCloudV2.testPoll();SunCloudV2.testLeave();resolveRevision({data:{revision:99}});await pending;
|
revision=99;const pending=SunCloudV2.testPoll();await SunCloudV2.testPoll();SunCloudV2.testLeave();resolveRevision({data:{revision:99}});await pending;
|
||||||
return {unchanged,changed,late:calls,readCount};
|
return {unchanged,changed,late:calls,readCount};
|
||||||
});
|
});
|
||||||
expect(result.unchanged).toEqual(['sun_app_state','revision',['workspace_id','company']]);
|
expect(result.unchanged).toEqual(['sun_fetch_app_state','company','revision']);
|
||||||
expect(result.changed).toContain('sun_fetch_app_state');
|
expect(result.changed).toContain('full-state');
|
||||||
expect(result.late).not.toContain('sun_fetch_app_state');expect(result.readCount).toBe(3);
|
expect(result.late).not.toContain('full-state');expect(result.readCount).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Safari without streaming uploads can send login and binary bodies through fallback',async({page})=>{
|
test('Safari without streaming uploads can send login and binary bodies through fallback',async({page})=>{
|
||||||
@ -223,6 +223,7 @@ test('a failed company load replaces the stale login form with an actionable ret
|
|||||||
});
|
});
|
||||||
|
|
||||||
for(const primaryFails of [false,true])test('real SDK loads orders with foreign services blocked, primary failure='+primaryFails,async({page})=>{
|
for(const primaryFails of [false,true])test('real SDK loads orders with foreign services blocked, primary failure='+primaryFails,async({page})=>{
|
||||||
|
await page.clock.install();
|
||||||
const userId='11111111-1111-4111-8111-111111111111',workspaceId='22222222-2222-4222-8222-222222222222',expires=Math.floor(Date.now()/1000)+3600;
|
const userId='11111111-1111-4111-8111-111111111111',workspaceId='22222222-2222-4222-8222-222222222222',expires=Math.floor(Date.now()/1000)+3600;
|
||||||
const user={id:userId,aud:'authenticated',role:'authenticated',email:'test@example.invalid',email_confirmed_at:new Date().toISOString(),app_metadata:{provider:'email'},user_metadata:{}};
|
const user={id:userId,aud:'authenticated',role:'authenticated',email:'test@example.invalid',email_confirmed_at:new Date().toISOString(),app_metadata:{provider:'email'},user_metadata:{}};
|
||||||
const token=[{alg:'HS256',typ:'JWT'},{sub:userId,role:'authenticated',aud:'authenticated',exp:expires,iat:expires-3600,aal:'aal1'},'test'].map(x=>typeof x==='string'?x:Buffer.from(JSON.stringify(x)).toString('base64url')).join('.');
|
const token=[{alg:'HS256',typ:'JWT'},{sub:userId,role:'authenticated',aud:'authenticated',exp:expires,iat:expires-3600,aal:'aal1'},'test'].map(x=>typeof x==='string'?x:Buffer.from(JSON.stringify(x)).toString('base64url')).join('.');
|
||||||
@ -230,10 +231,12 @@ for(const primaryFails of [false,true])test('real SDK loads orders with foreign
|
|||||||
page.on('console',m=>{if(m.type()==='warning')warnings.push(m.text())});page.on('websocket',ws=>sockets.push(ws.url()));
|
page.on('console',m=>{if(m.type()==='warning')warnings.push(m.text())});page.on('websocket',ws=>sockets.push(ws.url()));
|
||||||
await page.route('https://**',r=>{foreign.push(r.request().url());return r.abort()});
|
await page.route('https://**',r=>{foreign.push(r.request().url());return r.abort()});
|
||||||
const handle=async route=>{
|
const handle=async route=>{
|
||||||
const request=route.request(),url=new URL(request.url()),path=url.searchParams.get('__caterium_path')||url.pathname;seen.push({host:url.host,path,method:request.method()});
|
const request=route.request(),url=new URL(request.url()),path=url.searchParams.get('__caterium_path')||url.pathname;seen.push({host:url.host,path,method:request.method(),select:url.searchParams.get('select')});
|
||||||
const headers={'access-control-allow-origin':'*'};
|
const headers={'access-control-allow-origin':'*'};
|
||||||
if(request.method()==='OPTIONS')return route.fulfill({status:204,headers});
|
if(request.method()==='OPTIONS')return route.fulfill({status:204,headers});
|
||||||
if(primaryFails&&url.pathname==='/api/index.php')return route.fulfill({status:200,contentType:'text/html',body:'',headers});
|
if(primaryFails&&url.pathname==='/api/index.php')return route.fulfill({status:200,contentType:'text/html',body:'',headers});
|
||||||
|
if(path==='/rest/v1/sun_app_state')return route.fulfill({status:403,contentType:'application/json',body:'{"message":"direct table access revoked"}',headers});
|
||||||
|
if(path.endsWith('/sun_fetch_app_state')&&url.searchParams.get('select')==='revision')return route.fulfill({status:200,contentType:'application/json',body:'{"revision":1}',headers});
|
||||||
let body=null;
|
let body=null;
|
||||||
if(path==='/auth/v1/token')body={access_token:token,refresh_token:'test-refresh',token_type:'bearer',expires_in:3600,expires_at:expires,user};
|
if(path==='/auth/v1/token')body={access_token:token,refresh_token:'test-refresh',token_type:'bearer',expires_in:3600,expires_at:expires,user};
|
||||||
else if(path==='/auth/v1/user')body=user;
|
else if(path==='/auth/v1/user')body=user;
|
||||||
@ -249,6 +252,9 @@ for(const primaryFails of [false,true])test('real SDK loads orders with foreign
|
|||||||
await expect(page.locator('#sunCloudAuthGateV3')).toHaveCount(0,{timeout:20000});await expect(page.locator('body > header')).toBeVisible();
|
await expect(page.locator('#sunCloudAuthGateV3')).toHaveCount(0,{timeout:20000});await expect(page.locator('body > header')).toBeVisible();
|
||||||
expect(await page.evaluate(()=>window.SunCloudV2.getWorkspace()?.id)).toBe(workspaceId);
|
expect(await page.evaluate(()=>window.SunCloudV2.getWorkspace()?.id)).toBe(workspaceId);
|
||||||
await expect.poll(()=>page.evaluate(()=>JSON.parse(localStorage.getItem('sunOrders')||'[]').map(o=>o.id))).toContain('proxy-order');
|
await expect.poll(()=>page.evaluate(()=>JSON.parse(localStorage.getItem('sunOrders')||'[]').map(o=>o.id))).toContain('proxy-order');
|
||||||
|
await page.clock.fastForward(21000);
|
||||||
|
await expect.poll(()=>seen.filter(s=>s.path.endsWith('/sun_fetch_app_state')&&s.select==='revision').length).toBeGreaterThan(0);
|
||||||
|
expect(seen.some(s=>s.path==='/rest/v1/sun_app_state')).toBe(false);
|
||||||
expect(seen.some(s=>s.path==='/auth/v1/token'&&s.host!=='api.caterium.ru')).toBe(true);
|
expect(seen.some(s=>s.path==='/auth/v1/token'&&s.host!=='api.caterium.ru')).toBe(true);
|
||||||
expect(seen.some(s=>s.host==='api.caterium.ru')).toBe(primaryFails);
|
expect(seen.some(s=>s.host==='api.caterium.ru')).toBe(primaryFails);
|
||||||
expect(foreign).toEqual([]);expect(sockets).toEqual([]);
|
expect(foreign).toEqual([]);expect(sockets).toEqual([]);
|
||||||
|
|||||||
@ -14,8 +14,8 @@ check(!index.includes('offer-gallery-data.js'),'blocking Base64 gallery absent')
|
|||||||
check((runtime.match(/\/Type \/Catalog/g)||[]).length===0,'runtime contains no PDF binary writer');
|
check((runtime.match(/\/Type \/Catalog/g)||[]).length===0,'runtime contains no PDF binary writer');
|
||||||
check(read('core/pdf-engine.js').includes('595.28')&&read('core/pdf-engine.js').includes('841.89'),'PDF engine uses A4 MediaBox');
|
check(read('core/pdf-engine.js').includes('595.28')&&read('core/pdf-engine.js').includes('841.89'),'PDF engine uses A4 MediaBox');
|
||||||
check([...index.matchAll(/@page\{([^}]*)\}/g)].every(m=>/size:A4/i.test(m[1])),'compact @page rules use A4');
|
check([...index.matchAll(/@page\{([^}]*)\}/g)].every(m=>/size:A4/i.test(m[1])),'compact @page rules use A4');
|
||||||
check(sw.includes('v104-20260918-russia-proxy')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js')&&sw.includes('offer-workspace-v1769.js'),'service worker cache is v17.7.3');
|
check(sw.includes('v105-20260918-russia-proxy-rpc')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js')&&sw.includes('offer-workspace-v1769.js'),'service worker cache is v17.7.3');
|
||||||
check(index.includes('20260918-russia-proxy')&&index.includes('classic-offer-pdf-v1767.js')&&!index.includes('20260907-v17-6-0-stability-security'),'index cache-busting points to v17.7.3');
|
check(index.includes('20260918-russia-proxy-rpc')&&index.includes('classic-offer-pdf-v1767.js')&&!index.includes('20260907-v17-6-0-stability-security'),'index cache-busting points to v17.7.3');
|
||||||
check(performance.includes('SunAttachmentGuard')&&performance.includes('TARGET=2*1024*1024'),'chat photo auto-compression is versioned');
|
check(performance.includes('SunAttachmentGuard')&&performance.includes('TARGET=2*1024*1024'),'chat photo auto-compression is versioned');
|
||||||
check(performance.includes("rpc('sun_dev_dashboard')")&&performance.includes('server_size')&&performance.includes('storage_size'),'Developer Console server/storage counters are versioned');
|
check(performance.includes("rpc('sun_dev_dashboard')")&&performance.includes('server_size')&&performance.includes('storage_size'),'Developer Console server/storage counters are versioned');
|
||||||
check(performance.includes('MEMORY_REFRESH_MS=30000')&&performance.includes('MEMORY_TIMEOUT_MS=8000')&&performance.includes('memoryPromise'),'Developer Console memory refresh is bounded');
|
check(performance.includes('MEMORY_REFRESH_MS=30000')&&performance.includes('MEMORY_TIMEOUT_MS=8000')&&performance.includes('memoryPromise'),'Developer Console memory refresh is bounded');
|
||||||
@ -39,7 +39,7 @@ check(!/sb_secret_[A-Za-z0-9_-]{20,}|service_role\s*[:=]\s*["'][A-Za-z0-9._-]{30
|
|||||||
check(lock.version===pkg.version&&lock.packages?.['']?.version===pkg.version,'package.json and package-lock.json versions match');
|
check(lock.version===pkg.version&&lock.packages?.['']?.version===pkg.version,'package.json and package-lock.json versions match');
|
||||||
check(releaseManifest.version===`v${pkg.version}`,'release manifest version matches package.json');
|
check(releaseManifest.version===`v${pkg.version}`,'release manifest version matches package.json');
|
||||||
check(releaseManifest.channel==='production','release manifest channel is production');
|
check(releaseManifest.channel==='production','release manifest channel is production');
|
||||||
check(String(releaseManifest.pwaCache||'').includes('v104-20260918-russia-proxy'),'release manifest points to current PWA cache');
|
check(String(releaseManifest.pwaCache||'').includes('v105-20260918-russia-proxy-rpc'),'release manifest points to current PWA cache');
|
||||||
check(['17.6.2','17.6.3','17.6.4','17.6.5','17.6.6','17.6.7','17.6.8','17.6.9','17.7.0','17.7.1','17.7.2','17.7.3'].every(v=>fs.existsSync(path.join(root,`docs/releases/V${v}-CHANGES.txt`))),'release notes exist through v17.7.3');
|
check(['17.6.2','17.6.3','17.6.4','17.6.5','17.6.6','17.6.7','17.6.8','17.6.9','17.7.0','17.7.1','17.7.2','17.7.3'].every(v=>fs.existsSync(path.join(root,`docs/releases/V${v}-CHANGES.txt`))),'release notes exist through v17.7.3');
|
||||||
check(runtime.includes('CLOUD_RPC_TIMEOUT_MS=45000')&&runtime.includes('CLOUD_CONFLICT_MAX_RETRIES=4')&&runtime.includes('retryCount'),'cloud sync has timeout and capped exponential conflict retries');
|
check(runtime.includes('CLOUD_RPC_TIMEOUT_MS=45000')&&runtime.includes('CLOUD_CONFLICT_MAX_RETRIES=4')&&runtime.includes('retryCount'),'cloud sync has timeout and capped exponential conflict retries');
|
||||||
check(runtime.includes("const VERSION = '17.7.3'")&&runtime.includes('ERROR_DEDUPE_MS=5*60*1000')&&runtime.includes('mirrorBusy=false')&&runtime.includes('backupBusy=false'),'stability logger uses current version, dedupe and single-flight guards');
|
check(runtime.includes("const VERSION = '17.7.3'")&&runtime.includes('ERROR_DEDUPE_MS=5*60*1000')&&runtime.includes('mirrorBusy=false')&&runtime.includes('backupBusy=false'),'stability logger uses current version, dedupe and single-flight guards');
|
||||||
@ -65,8 +65,8 @@ check(offerWorkspace.includes('PDF и предпросмотр')&&offerWorkspace
|
|||||||
check(offerWorkspace.includes('SunClassicOfferPDFV1767')&&offerWorkspace.includes('finalGallery=galleryFor'),'custom gallery is injected into PDF renderer');
|
check(offerWorkspace.includes('SunClassicOfferPDFV1767')&&offerWorkspace.includes('finalGallery=galleryFor'),'custom gallery is injected into PDF renderer');
|
||||||
check(releaseManifest.offerWorkspaceTabs===true&&releaseManifest.offerTemplatesSeparateTab===true&&releaseManifest.offerTwoCustomGalleryPhotos===true,'release manifest records offer workspace changes');
|
check(releaseManifest.offerWorkspaceTabs===true&&releaseManifest.offerTemplatesSeparateTab===true&&releaseManifest.offerTwoCustomGalleryPhotos===true,'release manifest records offer workspace changes');
|
||||||
check(pkg.version==='17.7.3','package version is v17.7.3');
|
check(pkg.version==='17.7.3','package version is v17.7.3');
|
||||||
check(index.includes('20260918-russia-proxy'),'index cache bust is v17.7.3');
|
check(index.includes('20260918-russia-proxy-rpc'),'index cache bust is v17.7.3');
|
||||||
check(sw.includes('v104-20260918-russia-proxy')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js'),'PWA caches v17.7.3 client foundation modules');
|
check(sw.includes('v105-20260918-russia-proxy-rpc')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js'),'PWA caches v17.7.3 client foundation modules');
|
||||||
check(fs.existsSync(path.join(root,'public/core/data-layer-v1773.js'))&&fs.existsSync(path.join(root,'public/core/server-automation-v1770.js')),'data layer and server automation modules exist');
|
check(fs.existsSync(path.join(root,'public/core/data-layer-v1773.js'))&&fs.existsSync(path.join(root,'public/core/server-automation-v1770.js')),'data layer and server automation modules exist');
|
||||||
check(ux.includes('CateriumServerAutomationV1770?.enabled'),'cloud browser auto completion is disabled when server automation is active');
|
check(ux.includes('CateriumServerAutomationV1770?.enabled'),'cloud browser auto completion is disabled when server automation is active');
|
||||||
check(runtime.includes("const VERSION = '17.7.3'")&&runtime.includes("v17.7.3 Clients Server Read"),'stability logger reports v17.7.3');
|
check(runtime.includes("const VERSION = '17.7.3'")&&runtime.includes("v17.7.3 Clients Server Read"),'stability logger reports v17.7.3');
|
||||||
|
|||||||
@ -28,8 +28,8 @@ if(current!==113)fail(`current catalog photo count ${current}, expected 113`);el
|
|||||||
if(legacyCount!==60)fail(`legacy catalog photo count ${legacyCount}, expected 60`);else ok('60 legacy catalog photos');
|
if(legacyCount!==60)fail(`legacy catalog photo count ${legacyCount}, expected 60`);else ok('60 legacy catalog photos');
|
||||||
const gallery=fs.readdirSync(path.join(pub,'offer-gallery')).filter(x=>/\.jpg$/i.test(x));
|
const gallery=fs.readdirSync(path.join(pub,'offer-gallery')).filter(x=>/\.jpg$/i.test(x));
|
||||||
if(gallery.length!==2)fail(`offer gallery contains ${gallery.length} jpg files, expected 2`);else ok('offer gallery trimmed');
|
if(gallery.length!==2)fail(`offer gallery contains ${gallery.length} jpg files, expected 2`);else ok('offer gallery trimmed');
|
||||||
if(!sw.includes('20260918-russia-proxy')||!sw.includes('login-signature-v1776.js')||!sw.includes('data-layer-v1773.js')||!sw.includes('server-automation-v1770.js')||!sw.includes('offer-workspace-v1769.js')||sw.includes('offer-gallery-data.js'))fail('service worker cache is stale');else ok('PWA cache updated for login refresh');
|
if(!sw.includes('20260918-russia-proxy-rpc')||!sw.includes('login-signature-v1776.js')||!sw.includes('data-layer-v1773.js')||!sw.includes('server-automation-v1770.js')||!sw.includes('offer-workspace-v1769.js')||sw.includes('offer-gallery-data.js'))fail('service worker cache is stale');else ok('PWA cache updated for login refresh');
|
||||||
if(html.includes('20260907-v17-6-0-stability-security')||html.includes('20260909-v17-7-3-clients-server-read')||!html.includes('20260918-russia-proxy')||!html.includes('classic-offer-pdf-v1767.js'))fail('index still serves stale core asset version');else ok('index cache-busting is current');
|
if(html.includes('20260907-v17-6-0-stability-security')||html.includes('20260909-v17-7-3-clients-server-read')||!html.includes('20260918-russia-proxy-rpc')||!html.includes('classic-offer-pdf-v1767.js'))fail('index still serves stale core asset version');else ok('index cache-busting is current');
|
||||||
if(!performance.includes('SunAttachmentGuard')||!performance.includes('MAX_SIDE=2048'))fail('chat photo compression guard missing');else ok('chat photo compression guard present');
|
if(!performance.includes('SunAttachmentGuard')||!performance.includes('MAX_SIDE=2048'))fail('chat photo compression guard missing');else ok('chat photo compression guard present');
|
||||||
if(!performance.includes("rpc('sun_dev_dashboard')")||!performance.includes('storage_size')||!performance.includes('server_size'))fail('Developer Console memory counters missing');else ok('Developer Console memory counters present');
|
if(!performance.includes("rpc('sun_dev_dashboard')")||!performance.includes('storage_size')||!performance.includes('server_size'))fail('Developer Console memory counters missing');else ok('Developer Console memory counters present');
|
||||||
if(performance.includes('records.forEach(r=>r.addedNodes.forEach(n=>{if(n.nodeType===1)scan(n)}));enhanceDeveloperMemory()'))fail('Developer Console memory refresh is still coupled to MutationObserver');else ok('Developer Console memory refresh loop removed');
|
if(performance.includes('records.forEach(r=>r.addedNodes.forEach(n=>{if(n.nodeType===1)scan(n)}));enhanceDeveloperMemory()'))fail('Developer Console memory refresh is still coupled to MutationObserver');else ok('Developer Console memory refresh loop removed');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user