diff --git a/.github/scripts/patch-v1770-foundation.mjs b/.github/scripts/patch-v1770-foundation.mjs new file mode 100644 index 0000000..6b52924 --- /dev/null +++ b/.github/scripts/patch-v1770-foundation.mjs @@ -0,0 +1,72 @@ +import fs from 'node:fs'; + +const VERSION='17.7.0'; +const RELEASE='20260908-v17-7-0-architecture-foundation'; +const read=f=>fs.readFileSync(f,'utf8'); +const write=(f,s)=>fs.writeFileSync(f,s); +function once(s,a,b,label){const n=s.split(a).length-1;if(n!==1)throw new Error(`${label}: expected 1 match, got ${n}`);return s.replace(a,b)} + +let perf=read('public/core/performance.js'); +perf=perf.replace(/const VERSION='17\.6\.9';\n const RELEASE='20260908-v17-6-9-offer-pdf-tabs-gallery';/,`const VERSION='${VERSION}';\n const RELEASE='${RELEASE}';`); +perf=once(perf, +` function loadHotfix(){`, +` function loadDataLayer(){ + if(window.CateriumDataV1770||document.getElementById('cateriumDataV1770Script'))return; + const script=document.createElement('script');script.id='cateriumDataV1770Script';script.src=\`core/data-layer-v1770.js?v=${'${RELEASE}'}\`;script.async=false;script.onerror=()=>console.error('[Caterium] Не загрузился data-layer-v1770.js');document.head.appendChild(script); + } + function loadServerAutomation(){ + if(window.CateriumServerAutomationV1770||document.getElementById('cateriumServerAutomationV1770Script'))return; + const script=document.createElement('script');script.id='cateriumServerAutomationV1770Script';script.src=\`core/server-automation-v1770.js?v=${'${RELEASE}'}\`;script.async=true;script.onerror=()=>console.error('[Caterium] Не загрузился server-automation-v1770.js');document.head.appendChild(script); + } + function loadHotfix(){`, 'performance loaders'); +perf=once(perf, +` loadHotfix();loadOpsUX();loadUXFix();loadDeveloperUX();loadOfferWorkspace();scan(document);startMemoryTimer();`, +` loadDataLayer();loadServerAutomation();loadHotfix();loadOpsUX();loadUXFix();loadDeveloperUX();loadOfferWorkspace();scan(document);startMemoryTimer();`, 'performance start loaders'); +perf=once(perf, +`window.SunPerformance={VERSION,scanImages:()=>scan(document),refreshDeveloperMemory:(force=true)=>enhanceDeveloperMemory({force}),loadHotfix,loadOpsUX,loadUXFix,loadDeveloperUX,loadOfferWorkspace,disconnect:()=>`, +`window.SunPerformance={VERSION,scanImages:()=>scan(document),refreshDeveloperMemory:(force=true)=>enhanceDeveloperMemory({force}),loadDataLayer,loadServerAutomation,loadHotfix,loadOpsUX,loadUXFix,loadDeveloperUX,loadOfferWorkspace,disconnect:()=>`, 'performance exports'); +write('public/core/performance.js',perf); + +let ux=read('public/core/ux-fixes-v1764.js'); +ux=once(ux, +` const signed=Boolean(cloud?.getSession?.()?.user); + if(!signed)return true; + if(typeof cloud?.hasPermission==='function')return cloud.hasPermission('orders.edit')||cloud.hasPermission('app.write');`, +` const signed=Boolean(cloud?.getSession?.()?.user); + if(!signed)return true; + if(window.CateriumServerAutomationV1770?.enabled)return false; + if(typeof cloud?.hasPermission==='function')return cloud.hasPermission('orders.edit')||cloud.hasPermission('app.write');`, 'disable browser auto completion for cloud users'); +write('public/core/ux-fixes-v1764.js',ux); + +let runtime=read('public/app-runtime.js'); +runtime=runtime.replace(/const VERSION = '17\.6\.5';\n const RELEASE = 'v17\.6\.5 Stability';/,`const VERSION = '${VERSION}';\n const RELEASE = 'v17.7.0 Architecture Foundation';`); +write('public/app-runtime.js',runtime); + +let index=read('public/index.html'); +index=index.split('20260908-v17-6-9-offer-pdf-tabs-gallery').join(RELEASE); +write('public/index.html',index); + +let sw=read('public/service-worker.js'); +sw=sw.replace(/const CACHE='sun-catering-pwa-v\d+-[^']+';\nconst VERSION='[^']+';/,`const CACHE='sun-catering-pwa-v75-${RELEASE}';\nconst VERSION='${RELEASE}';`); +sw=once(sw, +"`./core/sun-safe.js?v=${VERSION}`,`./core/performance.js?v=${VERSION}`", +"`./core/sun-safe.js?v=${VERSION}`,`./core/performance.js?v=${VERSION}`,`./core/data-layer-v1770.js?v=${VERSION}`,`./core/server-automation-v1770.js?v=${VERSION}`", +'service worker foundation modules'); +write('public/service-worker.js',sw); + +const pkg=JSON.parse(read('package.json'));pkg.version=VERSION;pkg.scripts['check:syntax']=pkg.scripts['check:syntax'].replace('node --check public/core/performance.js','node --check public/core/performance.js && node --check public/core/data-layer-v1770.js && node --check public/core/server-automation-v1770.js');write('package.json',JSON.stringify(pkg,null,2)+'\n'); +const lock=JSON.parse(read('package-lock.json'));lock.version=VERSION;if(lock.packages?.[''])lock.packages[''].version=VERSION;write('package-lock.json',JSON.stringify(lock,null,2)+'\n'); + +const manifestPath='docs/release-manifest.json';const manifest=JSON.parse(read(manifestPath));Object.assign(manifest,{version:'v17.7.0',release:RELEASE,pwaCache:`v75-${RELEASE}`,architectureFoundation:true,dataLayer:'core/data-layer-v1770.js',serverOrderAutomation:true,serverOrderAutomationCron:'every minute',serverOrderTimezoneColumn:true,browserOrderAutomationCloudDisabled:true,errorTelemetryRejectsLocalFile:true,errorTelemetryServerDedupMinutes:5,errorTelemetryRetentionDays:30,stabilityLoggerVersion:VERSION,legacyStateKept:true,normalizedMirror:true,notes:'Architecture foundation: explicit data layer, server-side order automation with legacy/cloud compatibility, telemetry hygiene, current stability version, regression checks.'});write(manifestPath,JSON.stringify(manifest,null,2)+'\n'); + +write('docs/releases/V17.7.0-CHANGES.txt',`Caterium v17.7.0 — Architecture Foundation\nDate: 2026-09-08\n\n1. Introduces core/data-layer-v1770.js as the first explicit application data layer. Orders and storage access can migrate away from direct globals/localStorage without a rewrite.\n2. Order auto-completion is now a server business rule. PostgreSQL cron runs every minute and marks due orders fully paid/completed.\n3. The server updates both normalized sun_v17_orders and the legacy sun_app_state sunOrders payload so existing clients remain compatible during migration.\n4. Signed-in cloud clients no longer execute browser-side auto-completion; the old code remains only as local/offline fallback.\n5. Client server-automation module can request an immediate run on startup/focus and applies changed normalized orders through the data layer.\n6. Error telemetry rejects file:// events, deduplicates identical events for five minutes, and retains only 30 days. Historical file:// events are removed.\n7. Stability logger version is synchronized to 17.7.0.\n8. PWA cache v75 includes data-layer and server-automation modules.\n9. This is phase 1 of the architecture migration; legacy state remains intentionally enabled until subsequent domain-by-domain extraction is complete.\n`); + +let checks=read('tests/release-check.mjs'); +checks += `\ncheck(pkg.version==='17.7.0','package version is v17.7.0');\ncheck(index.includes('${RELEASE}'),'index cache bust is v17.7.0');\ncheck(sw.includes('v75-${RELEASE}')&&sw.includes('data-layer-v1770.js')&&sw.includes('server-automation-v1770.js'),'PWA caches architecture foundation modules');\ncheck(fs.existsSync(path.join(root,'public/core/data-layer-v1770.js'))&&fs.existsSync(path.join(root,'public/core/server-automation-v1770.js')),'data layer and server automation modules exist');\ncheck(ux.includes('CateriumServerAutomationV1770?.enabled'),'cloud browser auto completion is disabled when server automation is active');\ncheck(runtime.includes("const VERSION = '17.7.0'")&&runtime.includes("v17.7.0 Architecture Foundation"),'stability logger reports v17.7.0');\ncheck(fs.existsSync(path.join(root,'ops/sql/SUPABASE-V17.7.0-SERVER-ORDER-AUTOMATION.sql'))&&fs.existsSync(path.join(root,'ops/sql/SUPABASE-V17.7.0-ERROR-TELEMETRY-HYGIENE.sql')),'v17.7.0 server migrations are versioned');\n`; +write('tests/release-check.mjs',checks); + +let spec=read('tests/app.spec.mjs'); +spec += `\n\ntest('v17.7.0 data layer can update orders without direct UI globals', async ({ page }) => {\n await page.goto('/index.html',{waitUntil:'domcontentloaded'});\n const source=fs.readFileSync(path.join(process.cwd(),'public','core','data-layer-v1770.js'),'utf8');await page.addScriptTag({content:source});\n await page.evaluate(()=>localStorage.setItem('sunOrders',JSON.stringify([{id:77,status:'Новый',total:1000}])));\n const result=await page.evaluate(()=>{const before=window.CateriumDataV1770.orders.get(77);window.CateriumDataV1770.orders.update(77,o=>({...o,status:'Тест'}));return {before:before.status,after:window.CateriumDataV1770.orders.get(77).status,version:window.CateriumDataV1770.VERSION}});\n expect(result).toEqual({before:'Новый',after:'Тест',version:'17.7.0'});\n});\n\ntest('v17.7.0 server automation applies returned normalized orders through data layer', async ({ page }) => {\n await page.goto('/index.html',{waitUntil:'domcontentloaded'});\n await page.evaluate(()=>{window.__applied=[];window.CateriumDataV1770={isSupportReadOnly:()=>false,diagnostics:{measure:async(_n,fn)=>fn()},orders:{applyServerChanges:(orders)=>window.__applied.push(...orders)}};window.CateriumData=window.CateriumDataV1770;window.SunCloudV2={getSession:()=>({user:{id:'u'}}),getWorkspace:()=>({id:'w'}),getClient:()=>({rpc:async()=>({data:{changed:1,orders:[{id:8,status:'Отдан заказчику'}]},error:null})})};});\n const source=fs.readFileSync(path.join(process.cwd(),'public','core','server-automation-v1770.js'),'utf8');await page.addScriptTag({content:source});\n await page.waitForFunction(()=>Boolean(window.CateriumServerAutomationV1770));await page.evaluate(()=>window.CateriumServerAutomationV1770.run({force:true}));\n expect(await page.evaluate(()=>window.__applied)).toEqual([{id:8,status:'Отдан заказчику'}]);\n});\n`; +write('tests/app.spec.mjs',spec); + +console.log('Applied Caterium v17.7.0 architecture foundation patch');