From df7c8fa76838840a4e1fa58be5f90e85f74fd24d Mon Sep 17 00:00:00 2001 From: pavlov346346-source Date: Wed, 9 Sep 2026 10:34:25 +0300 Subject: [PATCH] Add temporary v17.7.2 release patch script --- ops/v1772-patch.mjs | 115 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 ops/v1772-patch.mjs diff --git a/ops/v1772-patch.mjs b/ops/v1772-patch.mjs new file mode 100644 index 0000000..1f30dfa --- /dev/null +++ b/ops/v1772-patch.mjs @@ -0,0 +1,115 @@ +import fs from 'node:fs'; + +const read=p=>fs.readFileSync(p,'utf8'); +const write=(p,s)=>fs.writeFileSync(p,s); +const mustReplace=(s,from,to,label)=>{ + const count=s.split(from).length-1; + if(!count) throw new Error(`Missing marker: ${label}`); + return s.split(from).join(to); +}; + +const release='20260909-v17-7-2-clients-foundation'; +const cache='sun-catering-pwa-v77-20260909-v17-7-2-clients-foundation'; + +{ + const p='public/core/performance.js'; let s=read(p); + s=mustReplace(s,"const VERSION='17.7.1';","const VERSION='17.7.2';",'performance version'); + s=mustReplace(s,"const RELEASE='20260909-v17-7-1-data-layer-adoption';",`const RELEASE='${release}';`,'performance release'); + s=mustReplace(s,"if(window.CateriumDataV1771||document.getElementById('cateriumDataV1771Script'))return;\n const script=document.createElement('script');script.id='cateriumDataV1771Script';script.src=`core/data-layer-v1771.js?v=${RELEASE}`;script.async=false;script.onerror=()=>console.error('[Caterium] Не загрузился data-layer-v1771.js');document.head.appendChild(script);", + "if(window.CateriumDataV1772||document.getElementById('cateriumDataV1772Script'))return;\n const script=document.createElement('script');script.id='cateriumDataV1772Script';script.src=`core/data-layer-v1772.js?v=${RELEASE}`;script.async=false;script.onerror=()=>console.error('[Caterium] Не загрузился data-layer-v1772.js');document.head.appendChild(script);", + 'data layer loader'); + write(p,s); +} + +{ + const p='public/service-worker.js'; let s=read(p); + s=mustReplace(s,"const CACHE='sun-catering-pwa-v76-20260909-v17-7-1-data-layer-adoption';",`const CACHE='${cache}';`,'sw cache'); + s=mustReplace(s,"const VERSION='20260909-v17-7-1-data-layer-adoption';",`const VERSION='${release}';`,'sw version'); + s=mustReplace(s,'data-layer-v1771.js','data-layer-v1772.js','sw data layer'); + write(p,s); +} + +{ + const p='public/index.html'; let s=read(p); + s=mustReplace(s,'20260909-v17-7-1-data-layer-adoption',release,'index release'); + write(p,s); +} + +{ + const p='public/app-runtime.js'; let s=read(p); + s=mustReplace(s,"const VERSION = '17.7.1'","const VERSION = '17.7.2'",'runtime version'); + s=mustReplace(s,'v17.7.1 Data Layer Adoption','v17.7.2 Clients Foundation','runtime release label'); + write(p,s); +} + +{ + const p='public/legacy/bootstrap.js'; let s=read(p); + s=mustReplace(s,"function dataLayer(){return window.CateriumDataV1771||window.CateriumData||window.CateriumDataV1770||null}","function dataLayer(){return window.CateriumDataV1772||window.CateriumDataV1771||window.CateriumData||window.CateriumDataV1770||null}",'legacy data layer alias'); + write(p,s); +} + +{ + const p='package.json'; const j=JSON.parse(read(p)); + j.version='17.7.2'; + j.scripts['check:syntax']=j.scripts['check:syntax'].replace('public/core/data-layer-v1771.js','public/core/data-layer-v1772.js'); + write(p,JSON.stringify(j,null,2)+'\n'); +} +{ + const p='package-lock.json'; const j=JSON.parse(read(p)); + j.version='17.7.2'; if(j.packages?.['']) j.packages[''].version='17.7.2'; + write(p,JSON.stringify(j,null,2)+'\n'); +} + +{ + const p='docs/release-manifest.json'; const j=JSON.parse(read(p)); + Object.assign(j,{ + version:'v17.7.2',release,pwaCache:'v77-20260909-v17-7-2-clients-foundation',stabilityLoggerVersion:'17.7.2', + dataLayerPhase:3,clientDataLayer:true,clientLegacyDoubleWrite:true,clientCanonicalIdentity:'phone > normalized name > order id fallback', + clientNormalizedRpc:'sun_v17_save_client_v1772',clientLegacyRowsPreserved:true, + notes:'Client foundation: canonical client identity, loyalty and communication data routed through Caterium Data Layer with legacy localStorage compatibility and additive normalized server writes.' + }); + write(p,JSON.stringify(j,null,2)+'\n'); +} + +{ + const p='tests/static-security.mjs'; let s=read(p); + s=mustReplace(s,"dataLayer=readPub('core/data-layer-v1771.js')","dataLayer=readPub('core/data-layer-v1772.js')",'static data layer file'); + s=s.split('v17-7-1-data-layer-adoption').join('v17-7-2-clients-foundation'); + s=s.split('data-layer-v1771.js').join('data-layer-v1772.js'); + s=s.split("const VERSION='17.7.1'").join("const VERSION='17.7.2'"); + s=s.replace("if(!dataLayer.includes(\"const VERSION='17.7.2'\")||!dataLayer.includes('ordersRepo')||!dataLayer.includes('catalogRepo')||!dataLayer.includes('applyServerOrders')||!dataLayer.includes('CateriumDataV1770=api'))fail('v17.7.1 data layer missing');else ok('v17.7.1 data layer present');", + "if(!dataLayer.includes(\"const VERSION='17.7.2'\")||!dataLayer.includes('ordersRepo')||!dataLayer.includes('catalogRepo')||!dataLayer.includes('clientsRepo')||!dataLayer.includes('sun_v17_save_client_v1772')||!dataLayer.includes('CateriumDataV1771=api'))fail('v17.7.2 data layer missing');else ok('v17.7.2 data layer present');"); + write(p,s); +} + +{ + const p='tests/release-check.mjs'; let s=read(p); + s=mustReplace(s,"dataLayer=read('core/data-layer-v1771.js')","dataLayer=read('core/data-layer-v1772.js')",'release data layer file'); + s=s.split('v17-7-1-data-layer-adoption').join('v17-7-2-clients-foundation'); + s=s.split('data-layer-v1771.js').join('data-layer-v1772.js'); + s=s.split("pkg.version==='17.7.1'").join("pkg.version==='17.7.2'"); + s=s.split("const VERSION = '17.7.1'").join("const VERSION = '17.7.2'"); + s=s.split("const VERSION='17.7.1'").join("const VERSION='17.7.2'"); + s=s.split('through v17.7.1').join('through v17.7.2'); + s=s.replace("['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.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']"); + s=s.replace("check(dataLayer.includes(\"const VERSION='17.7.2'\")&&dataLayer.includes('catalogRepo')&&dataLayer.includes('CateriumDataV1770=api'),'v17.7.1 data layer exposes order/catalog repositories with compatibility alias');", + "check(dataLayer.includes(\"const VERSION='17.7.2'\")&&dataLayer.includes('catalogRepo')&&dataLayer.includes('clientsRepo')&&dataLayer.includes('CateriumDataV1771=api'),'v17.7.2 data layer exposes order/catalog/client repositories with compatibility aliases');"); + s=s.replace("check(releaseManifest.dataLayerPhase===2&&releaseManifest.dataLayerLegacyOrderWrites===true&&releaseManifest.dataLayerLegacyCatalogWrites===true,'release manifest records data layer phase 2');", + "check(releaseManifest.dataLayerPhase===3&&releaseManifest.clientDataLayer===true&&releaseManifest.clientLegacyDoubleWrite===true,'release manifest records client data layer phase 3');"); + write(p,s); +} + +{ + const p='tests/app.spec.mjs'; let s=read(p); + s=s.split("'data-layer-v1771.js','CateriumDataV1771'").join("'data-layer-v1772.js','CateriumDataV1772'"); + s=s.split('window.CateriumDataV1771').join('window.CateriumDataV1772'); + s=s.split("version:'17.7.1'").join("version:'17.7.2'"); + if(!s.includes("v17.7.2 client data layer uses phone then normalized name identity")){ + s += `\n\ntest('v17.7.2 client data layer uses phone then normalized name identity', async ({ page }) => {\n await page.addInitScript(()=>{\n localStorage.setItem('sunOrders',JSON.stringify([{id:1,contact:' Иван Петров ',phone:'',address:'A',total:1000,lines:[]},{id:2,contact:'иван петров',phone:'',address:'B',total:2000,lines:[]},{id:3,contact:'Анна',phone:'+7 (999) 123-45-67',total:3000,lines:[]}]))\n localStorage.setItem('sunClientLoyaltyV1',JSON.stringify({'n:иван петров':{enabled:true,fixedDiscount:5}}));\n localStorage.setItem('sunClientCommunicationV1',JSON.stringify({'p:79991234567':{preferred:'telegram'}}));\n });\n await page.goto('/index.html',{waitUntil:'domcontentloaded'});\n await injectCore(page,'data-layer-v1772.js','CateriumDataV1772');\n const result=await page.evaluate(()=>{\n const d=window.CateriumDataV1772,clients=d.clients.list();\n return {version:d.VERSION,nameKey:d.clients.keyFromValues('', ' Иван Петров '),phoneKey:d.clients.keyFromValues('+7 (999) 123-45-67','Анна'),ivan:clients.find(x=>x.key==='n:иван петров'),anna:clients.find(x=>x.key==='p:79991234567'),alias:window.CateriumDataV1771===d};\n });\n expect(result.version).toBe('17.7.2');\n expect(result.nameKey).toBe('n:иван петров');\n expect(result.phoneKey).toBe('p:79991234567');\n expect(result.ivan.orderCount).toBe(2);\n expect(result.ivan.totalSpent).toBe(3000);\n expect(result.ivan.loyalty.fixedDiscount).toBe(5);\n expect(result.anna.communication.preferred).toBe('telegram');\n expect(result.alias).toBeTruthy();\n});\n`; + } + write(p,s); +} + +write('docs/releases/V17.7.2-CHANGES.txt',`Caterium v17.7.2 — Clients Foundation\n\n- Added a client repository to Caterium Data Layer.\n- Canonical client identity: phone digits, then normalized name, then order ID only as a fallback.\n- Loyalty and communication stores remain backward-compatible in localStorage while being adopted by the client repository.\n- Added additive normalized client RPC sun_v17_save_client_v1772 with workspace, subscription, feature and permission checks plus optimistic version protection.\n- Existing legacy client rows are preserved for rollback safety.\n- No client UI redesign in this release.\n`); + +console.log('v17.7.2 release patch applied');