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('
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