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/directory-layout.mjs
// Fixture records exercise layout and untrusted titles only, not network delivery.
import {chromium,executable,frameOf,fitFrame} from './browser-support.mjs';
import assert from 'node:assert/strict';
import {writeFile} from 'node:fs/promises';
const browser=await chromium.launch({executablePath:executable,headless:true});
const checks=[];
try{
  const page=await browser.newPage({viewport:{width:1200,height:900},hasTouch:true});await page.goto(process.env.NAPCRAFT_URL);const frame=await frameOf(page);
  await frame.evaluate(async()=>{
    const policy=await new Promise(resolve=>window.napplet.shell.onReady(e=>resolve(e.capabilities.appData)));
    const scope=policy.scope,author='a'.repeat(64);
    const events=Array.from({length:5},(_,i)=>({event:{kind:30078,id:String(i+1).repeat(64),pubkey:author,sig:'f'.repeat(128),created_at:100+i,tags:[['d',`soy.app-data/1:${scope}:worlds:fixture${i}`],['s',scope],['c','worlds'],['L','soy.app-data/1'],['l','napcraft.world-directory','soy.app-data/1'],['v','1']],content:JSON.stringify({schema:'napcraft.world-directory',version:1,title:i===4?'<img src=x onerror=alert(1)>':'Fixture island '+i,previous:null,deleted:false,data:{code:'NC1-'+btoa(JSON.stringify(['b'.repeat(64),'fixture'+i])).replace(/=+$/,'')}})}}));
    window.napplet.outbox.query=async()=>({events,incomplete:false});
  });
  await frame.locator('.directory-refresh').click();await frame.locator('.world-row').nth(4).waitFor();assert.equal(await frame.locator('.world-row img').count(),0);checks.push('untrusted title renders as text, not markup');
  for(const [w,h] of [[200,160],[320,560],[900,600],[1440,900],[390,844],[360,640],[844,390]]){
    await fitFrame(page,w,h);
    if(w<300||h<340)assert.ok(await frame.locator('.tiny').isVisible());
    else{
      const button=frame.locator('.world-join').last();await button.scrollIntoViewIfNeeded();
      const bounds=await button.evaluate(e=>{const b=e.getBoundingClientRect();return {left:b.left,right:b.right,top:b.top,bottom:b.bottom,width:b.width,height:b.height,vw:innerWidth,vh:innerHeight}});
      assert.ok(bounds.left>=0&&bounds.right<=bounds.vw&&bounds.top>=0&&bounds.bottom<=bounds.vh&&bounds.height>=44&&bounds.width>=44,JSON.stringify(bounds));
      await frame.locator('#worldSearch').fill('Fixture island 1');assert.equal(await frame.locator('.world-row').count(),1);await frame.locator('#worldSearch').fill('');
    }
    checks.push(`${w}x${h} directory reachable with touch-sized Join controls`);
    await page.locator('#stage iframe').screenshot({path:`.napplet-space/promotion/directory-fixture-${w}x${h}.png`});
  }
  await frame.evaluate(()=>{window.napplet.outbox.query=async()=>({events:[],incomplete:true})});await frame.locator('.directory-refresh').click();await frame.locator('.directory-status').filter({hasText:'Some listings could not be checked'}).waitFor();checks.push('incomplete response is not labelled empty');
  await writeFile('.napplet-space/directory-layout.json',JSON.stringify({passed:true,checks,scope:'fixture data in real hosted frame; not relay evidence'},null,2));console.log('PASS',checks);
}finally{await browser.close()}