Back to Napcraft
SOURCE / PINNED RELEASE

Made of little things.

Napcraft

Release
ee47ac6a25df…
Author-recorded commit
410dea87e109…
License
LICENSE
Author’s source reference
nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-52f9e22f5ce

Archive hash verified: 9e6e0cabb18d0d46…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

tests/shared-editor.test.mjs
import test from 'node:test';
import assert from 'node:assert/strict';
import {readFileSync} from 'node:fs';
import path from 'node:path';
import {runInNewContext} from 'node:vm';
import ts from 'typescript';
const cache = new Map();
function load(file) {
  file = path.resolve(file);
  if (cache.has(file)) return cache.get(file);
  const exports = {}; cache.set(file,exports);
  const source = ts.transpileModule(readFileSync(file,'utf8'),{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2022}}).outputText;
  runInNewContext(source,{exports,structuredClone,setTimeout,clearTimeout,Date,crypto,require:name=>load(path.resolve(path.dirname(file),name+'.ts'))});
  return exports;
}
const {SharedEditor} = load('src/shared-editor.ts');
const {BackendCallError} = load('docs/examples/backend-client.ts');
const {practiceWorld} = load('src/world.ts');
const target={module:{napplet:'test',name:'worlds'},release:'a'.repeat(64),instance:'island'};
const edit={x:9,y:3,z:10,expected:0,block:4};
const wait=ms=>new Promise(r=>setTimeout(r,ms));
async function until(f) { for(let i=0;i<200;i++) {if(f())return;await wait(2);}throw Error('condition timeout'); }
function deferred(){let resolve,reject;const promise=new Promise((a,b)=>{resolve=a;reject=b;});return {promise,resolve,reject};}
function fixture({journal,world=practiceWorld(),revision=0,gate,lose=false,reject=false,compact=false}={}) {
  let state=structuredClone(world),rev=revision,view,edits=0,lost=false;
  const receipts=new Map(),history=[],saved=[],notices=[];
  const api={
    intent:(target,operation,input)=>({target,operation,input,requestId:crypto.randomUUID(),expiresAt:Math.floor(Date.now()/1000)+240}),
    async invoke(intent) {
      history.push(structuredClone(intent));
      if(intent.operation==='readWorld')return {result:structuredClone(state),revision:rev};
      if(intent.operation==='readUpdates') return {result:{from:intent.input.after,edits:state.edits,locked:state.locked,reset:false,changes:[]},revision:rev};
      if(gate)await gate.promise;
      if(reject)throw new BackendCallError('CONFLICT',true,'CONFLICT');
      if(receipts.has(intent.requestId))return structuredClone(receipts.get(intent.requestId));
      const batch=intent.operation==='editBlocks'?intent.input.edits:[intent.input];
      const changes=[];
      for(const e of batch){state.blocks[e.x+e.z*18+e.y*324]=e.block;state.edits++;edits++;changes.push({...e,n:state.edits});}
      const r={revision:++rev,result:intent.operation==='editBlocks'?{from:intent.input.after,edits:state.edits,locked:state.locked,reset:false,changes}:structuredClone(state)};
      receipts.set(intent.requestId,structuredClone(r));
      if(lose&&!lost){lost=true;throw new BackendCallError('lost reply',false);}
      return r;
    },
    async call(){if(gate)await gate.promise;return {revision:rev};},
  };
  const editor=new SharedEditor(target,world,revision,compact,api,{change:v=>view=v,persist:async j=>saved.push(structuredClone(j)),saved:()=>{},notice:n=>notices.push(n)},journal ? {actor:"a".repeat(64),...journal} : undefined,"a".repeat(64));
  editor.start();
  return {editor,api,history,saved,notices,view:()=>view,edits:()=>edits,state:()=>state,receipts};
}
test('immediate feedback, bounded queue and no dropped input during a background read',async()=>{
  const gate=deferred(),f=fixture({gate});
  try{
    f.editor.sync(); // query in progress must not disable editing
    for(let i=0;i<24;i++)assert.equal(f.editor.enqueue({...edit,expected:i%2?4:0,block:i%2?0:4}),true);
    assert.equal(f.view().pending,24); assert.equal(f.view().world.edits,24);
    assert.equal(f.view().confirmedEdits,0);
    assert.equal(f.editor.enqueue(edit),false);
    gate.resolve(); await until(()=>f.view().pending===0);
    assert.equal(f.edits(),24);
  }finally{f.editor.dispose();}
});
test('atomic batches drain a rapid queue without one network round trip per input',async()=>{
  const gate=deferred(),f=fixture({gate,compact:true});
  try{
    for(let i=0;i<12;i++)f.editor.enqueue({...edit,expected:i%2?4:0,block:i%2?0:4});
    gate.resolve(); await until(()=>f.view().pending===0);
    assert.equal(f.edits(),12);
    assert.equal(f.history.filter(x=>x.operation==='editBlocks').length,3); // 1 in flight, then 8, then 3
  }finally{f.editor.dispose();}
});
test('lost commit response retries exact ID, expiry and payload and never duplicates a block',async()=>{
  const f=fixture({lose:true});
  try{
    f.editor.enqueue(edit); await until(()=>f.editor.uncertain);
    assert.equal(f.view().pending,1); assert.equal(f.edits(),1);
    const journal=f.saved.filter(Boolean).at(-1);
    assert.deepEqual(journal.active.intent,f.history[0]);
    f.editor.retry(); await until(()=>f.view().pending===0);
    assert.equal(f.edits(),1); assert.deepEqual(f.history[0],f.history[1]);
    assert.equal(f.view().world.edits,1); assert.equal(f.view().confirmedEdits,1);
  }finally{f.editor.dispose();}
});
test('definitive conflict cancels dependent predictions and refreshes before new input',async()=>{
  const gate=deferred(),f=fixture({gate,reject:true});
  try{
    f.editor.enqueue(edit); f.editor.enqueue({...edit,y:4});
    f.state().blocks[9+10*18+3*324]=6;
    gate.resolve(); await until(()=>f.view().pending===0&&!f.editor.hasWork);
    assert.equal(f.view().world.edits,0);
    assert.equal(f.history.filter(x=>x.operation==='editBlock').length,1);
    assert.ok(f.history.some(x=>x.operation==='readWorld'));
  }finally{f.editor.dispose();}
});
test('expired uncertain intent refreshes without manufacturing a new command',async()=>{
  const intent={target,operation:'editBlock',input:edit,requestId:'expired',expiresAt:1};
  const f=fixture({journal:{target,queue:[edit],active:{intent,count:1}}});
  try{
    await until(()=>!f.editor.hasWork);
    assert.equal(f.history.filter(x=>x.operation==='editBlock').length,0);
    assert.equal(f.view().world.edits,0);
    assert.ok(f.notices.some(x=>x.includes('expired')));
  }finally{f.editor.dispose();}
});
test('recovered cached receipt cannot roll back a newer snapshot after reload',async()=>{
  const intent={target,operation:'editBlock',input:edit,requestId:'committed',expiresAt:Math.floor(Date.now()/1000)+240};
  const world=practiceWorld(); world.edits=3;world.blocks[9+10*18+3*324]=6;
  const f=fixture({world,revision:3,journal:{target,queue:[edit],active:{intent,count:1}}});
  f.receipts.set('committed',{revision:1,result:{...world,edits:1}});
  try{await until(()=>!f.editor.hasWork);assert.equal(f.view().world.edits,3);assert.equal(f.view().revision,3);assert.equal(f.edits(),0);}finally{f.editor.dispose();}
});
test('closing session ignores late completions; forged refresh floods are bounded',async()=>{
  const gate=deferred(),f=fixture({gate});
  f.editor.enqueue(edit);await until(()=>f.history.length===1);
  const view=f.view(),writes=f.saved.length;
  f.editor.dispose();gate.resolve();await wait(10);
  assert.equal(f.view(),view);assert.equal(f.saved.length,writes);
  const other=fixture();try{
    for(let i=0;i<100;i++)other.editor.sync(true);
    await wait(10);
    assert.equal(other.history.filter(i=>i.operation==='readWorld').length,1);
    assert.equal(other.view().world.edits,0);
  }finally{other.editor.dispose();}
});
test('instance contention refreshes and revalidates an independent edit before a new intent',async()=>{
  const f=fixture(),invoke=f.api.invoke;
  let rejected;
  f.api.invoke=async intent=>{
    if(intent.operation==='editBlock'&&!rejected){rejected=structuredClone(intent);throw new BackendCallError('instance busy',true,'CONFLICT');}
    return invoke(intent);
  };
  try{
    f.editor.enqueue(edit);await until(()=>!f.editor.hasWork);
    assert.equal(f.edits(),1);
    const retry=f.history.find(i=>i.operation==='editBlock');
    assert.notEqual(retry.requestId,rejected.requestId);
    assert.ok(f.history.findIndex(i=>i.operation==='readWorld')<f.history.indexOf(retry));
  }finally{f.editor.dispose();}
});

test('coalesced peer hints retain the final refresh of a fast save burst',async()=>{
  const f=fixture();
  try {
    f.editor.sync(true); await wait(10);
    f.state().edits=1;f.state().blocks[9+10*18+3*324]=4;
    for(let i=0;i<100;i++)f.editor.sync(true);
    await wait(550);
    assert.equal(f.history.filter(i=>i.operation==='readWorld').length,2);
    assert.equal(f.view().world.edits,1);
  }finally{f.editor.dispose();}
});
test('a recovered receipt from another transport cannot replay an ABA edit',async()=>{
  const intent={target,operation:'editBlock',input:edit,requestId:'old-guest',expiresAt:Math.floor(Date.now()/1000)+240};
  const f=fixture({journal:{actor:'b'.repeat(64),target,queue:[edit],active:{intent,count:1}}});
  try{await until(()=>!f.editor.hasWork);assert.equal(f.edits(),0,'another actor cannot replay even when the cell became empty again');}finally{f.editor.dispose();}
});