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.
// Actual napplet.soy + public CVM/RTC. Two separate browser processes; disposable
// NIP-07 test signer, with real signatures and deliberately delayed approval.
import { chromium, executable, installTestIdentity } from './browser-support.mjs';
import { readFile, writeFile } from 'node:fs/promises';
import { execFileSync } from 'node:child_process';
import assert from 'node:assert/strict';
const readyFile='.napplet-space/publication-ready.json';
const old=JSON.parse(execFileSync('soyli',['status','--json'],{encoding:'utf8'}));
const context=JSON.parse(await readFile('.napplet-space/soy-backend.json','utf8'));
const backend=JSON.parse(await readFile('.napplet-space/active-backend-before.json','utf8'));
const browsers=[],players=[],checks=[],limitations=[],dialogs=[],approvals=[];
const check=(name,value)=>{assert.ok(value,name);checks.push(name);console.log('PASS',name);};
const startApp=async(p,url)=>{
await p.page.goto(url,{waitUntil:'domcontentloaded'});
await p.page.getByRole('button',{name:'Start Napcraft',exact:true}).click({timeout:45000});
const iframe=p.page.locator('iframe[title="Napcraft"]');await iframe.waitFor();
p.frame=await(await iframe.elementHandle()).contentFrame();
await p.frame.locator('#app[data-ready=true]').waitFor({timeout:45000});
};
const signIn=async p=>{
await p.page.getByRole('button',{name:'Connect',exact:true}).click();
await p.page.getByRole('button',{name:'Connect browser extension',exact:true}).click();
await p.page.getByRole('button',{name:'Connect',exact:true}).waitFor({state:'hidden'});
};
const panelText=async p=>(await p.page.locator('body').innerText()).slice(-7000);
// Public host labels differ from soyLI preview. Only approve these two observed
// capability dialogs; never social publishing, uploads or arbitrary connections.
const approvePlayer=(p,index)=>{
let stop=false;
const done=(async()=>{while(!stop&&!p.page.isClosed()){
try {
const network=p.page.getByRole('dialog',{name:'Allow network connection',exact:true});
if(await network.isVisible()) {
const message=await network.innerText();
assert.match(message,/saved worlds and actions in worlds on backend 60517f645482/);
const entry={player:index,type:'backend consent',message,opened:Date.now()};
const first=!dialogs.some(d=>d.player===0&&d.type==='backend consent');dialogs.push(entry);
if(index===0&&first)await new Promise(r=>setTimeout(r,20000));
entry.stillOpen=await network.isVisible();entry.accepted=Date.now();
await network.getByRole('button',{name:'Connect',exact:true}).click();
console.log('PUBLIC APPROVAL',index,entry.accepted-entry.opened);
}
const peer=p.page.getByRole('dialog',{name:'Allow multiplayer connections',exact:true});
if(await peer.isVisible())await peer.getByRole('button',{name:'Allow',exact:true}).click();
}catch(error){if(!stop){console.log('Approval driver error',String(error));throw error;}}
await new Promise(r=>setTimeout(r,100));
}})();
done.catch(()=>{});
return {stop:()=>{stop=true},done};
};
const saved=(p,n)=>p.frame.waitForFunction(n=>Number(document.querySelector('canvas').dataset.confirmedEdits)===n&&document.querySelector('#app').dataset.pending==='0',n,{timeout:45000});
let legacy, publication;
try {
for(let i=0;i<2;i++) {
const browser=await chromium.launch({executablePath:executable,headless:true,args:['--disable-background-timer-throttling','--disable-renderer-backgrounding']});browsers.push(browser);
const page=await browser.newPage({viewport:{width:1200,height:900}});
const options={signDelayMs:0};const signer=i===0?await installTestIdentity(page,options):undefined;
const player={page,options,signer};players.push(player);approvals.push(approvePlayer(player,i));
}
const [a,b]=players;
const baselineUrl=process.env.NAPCRAFT_BASELINE_URL || old.snapshotUrl;
await startApp(b,baselineUrl);
legacy={target:{module:{napplet:context.napplet,name:'worlds'},release:backend.active},operation:'createWorld',input:{name:'Earlier interrupted test request'},requestId:crypto.randomUUID(),expiresAt:Math.floor(Date.now()/1000)-86400};
await b.frame.evaluate(value=>window.napplet.storage.setItem('napcraft-pending-v1',value),JSON.stringify(legacy));
console.log('READY: representative unfinished request saved in the old public build. Waiting for publication-ready.json.');
const deadline=Date.now()+20*60*1000;
while(Date.now()<deadline) {
try{publication=JSON.parse(await readFile(readyFile,'utf8'));break;}catch{}
await new Promise(r=>setTimeout(r,1000));
}
assert.ok(publication,'Publication signal arrived');
await startApp(b,publication.snapshotUrl);
const recovered=await b.frame.evaluate(()=>window.napplet.storage.getItem('napcraft-pending-v1'));
if(recovered!==JSON.stringify(legacy)) {
assert.equal(recovered,null,'New build has an empty storage scope');
await startApp(b,baselineUrl);
const original=await b.frame.evaluate(()=>window.napplet.storage.getItem('napcraft-pending-v1'));
check('previous public release retains its exact pending request',original===JSON.stringify(legacy));
limitations.push('Host storage is build-scoped: the updated app cannot read the previous build recovery request. Returning to the pinned previous release still finds it.');
console.log('PLATFORM LIMIT',limitations.at(-1));
await startApp(b,publication.snapshotUrl);
// Separate, explicit same-build legacy-state test. This does NOT migrate
// real player data or assert that cross-build migration works.
await b.frame.evaluate(value=>window.napplet.storage.setItem('napcraft-pending-v1',value),JSON.stringify(legacy));
await startApp(b,publication.snapshotUrl);
} else check('old public-build recovery request survives the new release',true);
await b.frame.locator('#recover').click();await b.frame.locator('#keepSave').click();
const kept=await b.frame.evaluate(async()=>JSON.parse(await window.napplet.storage.getItem('napcraft-kept-saves-v1')));
check('legacy-shaped request in current public build is explicitly preserved',JSON.stringify(kept[0].intent)===JSON.stringify(legacy));
await a.page.goto(publication.snapshotUrl);await signIn(a);
await a.page.getByRole('button',{name:'Start Napcraft',exact:true}).click();
a.frame=await(await a.page.locator('iframe[title="Napcraft"]').elementHandle()).contentFrame();await a.frame.locator('#app[data-ready=true]').waitFor();
a.options.signDelayMs=25000;
await a.frame.locator('#create').click();await a.frame.locator('#name').fill('Napcraft public consent check');await a.frame.locator('#confirmCreate').click();
// Account binding can be followed by a separate peer-connection grant.
await a.frame.locator('#share').waitFor({timeout:120000});
check('public host approval accepted after a 20-second wait',dialogs.some(d=>d.player===0&&d.stillOpen&&d.accepted-d.opened>=20000));
const signatures=a.signer.signing;
check('public backend accepts delayed extension signing',signatures.some(s=>s.finished-s.start>=25000));
console.log('Public world created. Host text:',await panelText(a));
a.options.signDelayMs=0;
await a.frame.locator('#share').click();const code=await a.frame.locator('#shareCode').inputValue();await a.frame.locator('#close').click();
await b.frame.locator('#join').click();await b.frame.locator('#code').fill(code);await b.frame.locator('#confirmJoin').click();await b.frame.locator('#share').waitFor({timeout:60000});
await Promise.all(players.map(p=>p.frame.waitForFunction(()=>document.querySelector('canvas').dataset.peerCount==='1',null,{timeout:60000})));
check('two independent public browsers see each other',true);
await a.frame.locator('#place').click();await Promise.all(players.map(p=>saved(p,1)));
await b.frame.locator('#remove').click();await Promise.all(players.map(p=>saved(p,2)));
check('both public players edits are confirmed and shared',true);
for(const p of players) {
await startApp(p,publication.snapshotUrl);
await p.frame.locator('#join').click();await p.frame.locator('#code').fill(code);await p.frame.locator('#confirmJoin').click();await saved(p,2);
}
check('public world survives both browser reloads',true);
await a.page.locator('iframe[title="Napcraft"]').screenshot({path:'.napplet-space/promotion/public-final.png'});
await writeFile('.napplet-space/public-consent-results.json',JSON.stringify({passed:true,checks,limitations,dialogs,baselineUrl,code,publication,signing:signatures,browserProcesses:2,transport:'website-selected public ICE; no local TURN substitution'},null,2));
} catch(error) {
for(const [i,p] of players.entries()) {
console.log('PUBLIC FAILURE',i,await panelText(p).catch(()=>''));
if(p.frame)console.log('APP FAILURE',i,await p.frame.locator('body').innerText().catch(()=>''));
await p.page.screenshot({path:`.napplet-space/promotion/public-failure-${i}.png`}).catch(()=>{});
}
await writeFile('.napplet-space/public-consent-results.json',JSON.stringify({passed:false,checks,limitations,dialogs,error:String(error),publication},null,2));
throw error;
} finally {approvals.forEach(a=>a.stop());await Promise.all(browsers.map(b=>b.close()));await Promise.allSettled(approvals.map(a=>a.done));}
