import fs from 'node:fs/promises'; import http from 'node:http'; import crypto from 'node:crypto'; import assert from 'node:assert/strict'; import ts from 'typescript'; import {chromium} from 'playwright'; const root=process.cwd(); const output=root+'/results'; await fs.mkdir(output,{recursive:true}); const sourceRoot=root+'/'; const before=await fs.readFile(sourceRoot+'source-before.ts.txt','utf8'); const after=await fs.readFile(sourceRoot+'source-after.ts.txt','utf8'); const hash=s=>crypto.createHash('sha256').update(s).digest('hex'); const manifest=JSON.parse(await fs.readFile(sourceRoot+'source-manifest.json','utf8')); assert.equal(hash(before),manifest.historicalVariants.gitBlob);assert.equal(hash(after),manifest.currentSHA256); const compile=s=>ts.transpileModule(s,{compilerOptions:{target:ts.ScriptTarget.ES2022,module:ts.ModuleKind.ES2022}}).outputText; const routes={ '/before.js':compile(before.replace("indexedDB.open('layer-studio',1)","indexedDB.open(globalThis.__BENCH_DB__,1)")), '/after.js':compile(after), '/document.ts':"export function validateDoc(){throw Error('Load validation is outside this experiment');}", '/config/profile.ts':"export const PROFILE={get workspaceDatabase(){return globalThis.__BENCH_DB__},workspaceFormat:'slohero-vector-workspace'};" }; const server=http.createServer((req,res)=>{const pathname=new URL(req.url,'http://localhost').pathname;if(pathname==='/'){res.setHeader('Content-Type','text/html');res.end('Snapshot preprocessing measurement

Isolated local experiment.

');return;}if(routes[pathname]){res.setHeader('Content-Type','application/javascript');res.end(routes[pathname]);}else{res.statusCode=404;res.end('Not found');}}); await new Promise(r=>server.listen(0,'127.0.0.1',r)); const context=await chromium.launchPersistentContext(root+'/benchmark-browser-profile',{headless:true,viewport:{width:1280,height:900}}); try{ const page=context.pages()[0];await page.goto('http://127.0.0.1:'+server.address().port); const result=await page.evaluate(async()=>{ const startedAt=new Date().toISOString(),sizes=[100,1000,5000,20000],warmups=3,repetitions=20,rows=[],groups=[],ownedDatabases=[]; const validator=v=>{if(!v||!Number.isInteger(v.revision)||typeof v.label!=='string')throw Error('Invalid session');return v;}; function payload(count){return {version:1,activeId:'bench',tabs:[{id:'bench',doc:{revision:1,label:'synthetic path points',points:Array.from({length:count},(_,i)=>({x:i/8,y:(i%127)/16,pressure:(i%11)/10}))}}],savedAt:1,revision:1,label:'synthetic path points'};} async function read(name){const db=await new Promise((ok,no)=>{const r=indexedDB.open(name,1);r.onsuccess=()=>ok(r.result);r.onerror=()=>no(r.error);});try{return await new Promise((ok,no)=>{const r=db.transaction('documents').objectStore('documents').get('workspace');r.onsuccess=()=>ok(r.result);r.onerror=()=>no(r.error);});}finally{db.close();}} for(const count of sizes){ const modes={}; for(const mode of ['before','after']){ const database='si-journal-bench-'+mode+'-'+crypto.randomUUID();ownedDatabases.push(database);globalThis.__BENCH_DB__=database; const mod=await import('/'+mode+'.js?group='+crypto.randomUUID()),store=mode==='after'?mod.createWorkspaceStore(validator):null; modes[mode]={database,save:mode==='after'?v=>store.save(v):mod.saveWorkspace}; } let bytes; for(let index=-warmups;index=0)rows.push({mode,points:count,trial:index+1,payloadBytes:bytes,syncMs:t1-t0,completionMs:t2-t0,observedRevision:saved.revision,documentRevision:saved.tabs[0].doc.revision}); } groups.push({points:count,payloadBytes:bytes}); } for(const name of ownedDatabases){if(!name.startsWith('si-journal-bench-'))throw Error('Unsafe cleanup target');await new Promise((ok,no)=>{const r=indexedDB.deleteDatabase(name);r.onsuccess=ok;r.onerror=()=>no(r.error);r.onblocked=()=>no(Error('Experiment cleanup blocked'));});} return {startedAt,endedAt:new Date().toISOString(),userAgent:navigator.userAgent,hardwareConcurrency:navigator.hardwareConcurrency,crossOriginIsolated,warmups,repetitions,groups,rows,ownedDatabasesDeleted:ownedDatabases.length}; }); assert.equal(result.rows.length,160); const report={...result,protocol:'Synthetic ordinary-object DTOs; points generated before timing; byte size is UTF-8 JSON outside timing; each implementation uses its own instance and unique DB per size; three warm-up requests per size and implementation; twenty retained requests; implementation order alternates; synchronous save() return and transaction completion measured with performance.now(); mutations occur after the synchronous timing window; reads and payload generation are excluded; baseline and Si differ in envelope, validation and number of written slots, so this is not a pure structuredClone microbenchmark or an end-to-end editor benchmark.',sourceSHA256:{before:hash(before),after:hash(after)},pointCounts:[100,1000,5000,20000],summaryStatistics:'Median and interquartile range; descriptive, not confidence intervals; no outlier removal',passed:true}; await fs.writeFile(output+'/benchmark-raw.json',JSON.stringify(report,null,2)); const header=['mode','points','trial','payloadBytes','syncMs','completionMs','observedRevision','documentRevision']; await fs.writeFile(output+'/benchmark-raw.csv',header.join(',')+'\n'+result.rows.map(r=>header.map(k=>r[k]).join(',')).join('\n')+'\n'); console.log(JSON.stringify({passed:true,samples:result.rows.length,groups:result.groups,startedAt:result.startedAt,endedAt:result.endedAt,browser:result.userAgent,databasesDeleted:result.ownedDatabasesDeleted})); }finally{await context.close();await new Promise(r=>server.close(r));}