import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; import assert from 'node:assert/strict'; import { publishFiles } from '../work/board-deploy-20261106-r1/package/scripts/publish-board.mjs'; const base=path.resolve('work/board-deploy-20261106-r1'); const pkg=path.join(base,'package'),sourceDir=path.join(pkg,'payload'),manifestPath=path.join(pkg,'deploy/board-files.json'); const manifest=JSON.parse(fs.readFileSync(manifestPath)); const targetDir=fs.mkdtempSync(path.join(base,'static-publish-test-')); for(const f of manifest.files){const p=path.join(targetDir,f.path);fs.mkdirSync(path.dirname(p),{recursive:true});fs.copyFileSync(path.join(sourceDir,f.path),p);} fs.copyFileSync(path.join(base,'production-index.html'),path.join(targetDir,'index.html')); const nav=path.join(targetDir,'src/layout/kf-nav.js'); fs.copyFileSync(path.join(base,'production-before/src/layout/kf-nav.js'),nav); fs.unlinkSync(path.join(targetDir,'src/core/library.js')); const snapshot=()=>Object.fromEntries(['index.html',...manifest.files.map(f=>f.path)].map(p=>{const f=path.join(targetDir,p);return[p,fs.existsSync(f)?crypto.createHash('sha256').update(fs.readFileSync(f)).digest('hex'):null];})); const options={sourceDir,manifestPath,targetDir},before=snapshot(); const plan=publishFiles(options); assert.equal(plan.readOnly,true);assert.equal(plan.filesChecked,71);assert.equal(plan.changes.length,2);assert.deepEqual(snapshot(),before); let thrown; try{publishFiles({...options,apply:true},{beforeWrite:p=>{if(p==='src/layout/kf-nav.js')throw Error('simulated filesystem failure');}});}catch(e){thrown=e;} assert.equal(thrown?.rollbackComplete,true);assert.deepEqual(snapshot(),before); fs.writeFileSync(nav,'unknown concurrent revision'); assert.throws(()=>publishFiles({...options,apply:true}),{code:'UNKNOWN_TARGET_CONTENT'}); assert.equal(fs.readFileSync(nav,'utf8'),'unknown concurrent revision'); fs.copyFileSync(path.join(base,'production-before/src/layout/kf-nav.js'),nav); const applied=publishFiles({...options,apply:true}); assert.equal(applied.filesystemVerified,true);assert.equal(applied.homepageModified,false);assert.ok(!applied.backup.startsWith(targetDir+path.sep)); const stamp=fs.statSync(nav).mtimeMs,after=snapshot(); assert.equal(publishFiles({...options,apply:true}).changes.length,0);assert.equal(fs.statSync(nav).mtimeMs,stamp);assert.deepEqual(snapshot(),after); fs.writeFileSync(path.join(targetDir,'index.html'),'changed homepage'); assert.throws(()=>publishFiles(options),{code:'HOMEPAGE_MISMATCH'}); const result={ok:true,checks:['dry run writes nothing','failure restores changed and newly created files','unknown target revision is preserved','apply verifies all 71 files and preserves homepage','repeat is a no-op preserving mtime','changed homepage is refused'],productionWrites:0}; fs.writeFileSync(path.join(base,'static-publisher-validation.json'),JSON.stringify(result,null,2)); console.log(JSON.stringify(result));