Repository navigation
Conversation
Derive one binding per extension mock from its NAP API Surface and Wire Protocol tables at the exact ref the mock records, so a host can expose mocked domains to napplets. Drift tests pin the table to the mock routes, push capabilities, and spec refs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-in binding NappletNamespacePreludeOptions.bindings lets a host expose a draft NAP (for example one served by @kehto/mocks) as callable window.napplet.<domain> methods over the private NIP-5D port, with pushes via on(event) and named handlers. Tables are validated host-side and never replace built-in domains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paja registers deterministic mocks for blossom, capture, catalog, class, display, git, hashtree, location, mesh, motion, navigation, nzb, pow, soulseek, system, torrent, value and worker, adds them to each frame's environment (through the same disable and grant policy) and exposes them to napplets with the generated wire-table bindings. The Interfaces panel marks each mocked interface with one symbol and a legend line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Document the generated mock bindings, the shell's table-driven bindings and Paja's mocked interfaces (with the wire-table spec-gap decision), add changesets, cover the class assignment hook, and add a Paja Playwright spec that calls mocked NAPs through window.napplet and checks the marker/legend. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Paja now hosts every NAP it has no real backend for, using
@kehto/mocks. Napplets can actually call those interfaces throughwindow.napplet.<domain>, and the Interfaces panel marks them as mocked with a single◌and one legend line, so the panel doesn't grow.The newly mocked domains are blossom, capture, catalog, class, display, git, hashtree, location, mesh, motion, navigation, nzb, pow, soulseek, system, torrent, value and worker.
Screenshots
These are taken from the Playwright spec
tests/e2e/paja-mocked-naps.spec.tsagainst a real Paja host. The images live on thepr-assets/paja-mocked-napsref, not in this branch.Interfaces panel: mocked interfaces get the
◌prefix and a dashed border, and the legend sits under the toggles.A napplet calling mocked NAPs: the probe napplet calls
torrent.capabilities(),torrent.add(magnet),torrent.jobs(),git.open(),system.naps()andcatalog.get(), sees a mappeddeniedrejection fromlocation.current(), and receives the mockedclass.assignedpush.What changed
Advertising a domain alone wasn't enough. The NIP-5D prelude owns the only port, so an unknown domain showed up as an empty
{}, and@napplet/nap0.37 only ships the 26 domains Paja already implements. So this PR touches three packages:@kehto/mocks(minor): addsMOCK_NAPPLET_BINDINGS, one napplet-facing table perextensionmock.scripts/generate-napplet-bindings.mjsgenerates it from each NAP's API Surface and Wire Protocol tables at the exact ref the mock records (bindings:generate, plusbindings:checkto detect drift). The binding rules:location.requestPermission→location.permission).on(event)and the namedonXhandlers.@kehto/shell(minor): addsNappletNamespacePreludeOptions.bindings(NappletDomainBinding), which turns those tables into methods over the private port. Tables are validated host-side byserializeDomainBindings, which throwsTypeError. They only reach exposed domains, never replace a domain inNAPPLET_PRELUDE_BUILT_IN_DOMAINS, and come out frozen and protected from napplet reassignment.@kehto/paja(minor): registers the 18 seeded mocks and appends the enabled ones to the frame environment. They go through the same disabled-domain andresolveEnvironmentgrant policy, which also gives the runtime's extension routing itsisDomainAllowedgrant. Paja passes the bindings to the prelude and sends the mockedclass.assignedaftershell.ready. In the Interfaces panel each mocked toggle gets◌,data-mocked="true", a title note, and the legend line. Mocked domains are on by default and toggle or--capabilitylike any other interface. New exports:PAJA_MOCKED_DOMAINS,PAJA_MOCKED_MARK,isPajaMockedDomain,PajaMockedDomain.Docs are updated in the package READMEs,
docs/packages/{mocks,shell,paja}.md, the Paja getting-started how-to, and both mock skills. Changesets are included for all three packages.NAP refs checked
The binding tables come from the same draft heads the mocks are pinned to (all open
napplet/napsPRs):5e74daa4438b37611020ae53482827982c2e1b5ca73bf8de6799770624d2039cbf9a47223069a9459a4b179e3a426fe4d85b4252892ed8d443a112dbbc99787ee468764d0a54af9abindings:checkagainst those refs reports the committed file as current.The wire envelopes are conformant. The JavaScript shape is a spec-gap decision, documented in
docs/packages/shell.md. NIP-5D leaves each domain's API to its NAP, and these drafts pin the wire table, so Kehto binds what the table expresses. That has some consequences:pow.mine(jobId, template, target, options)is one example;mesh.subscribe(subId, filters, ttl)is another.location.state/latest,motion.state/latest) and local helpers (blossom.parseUri,pow.formatHashRate) aren't bound. They're listed in each table'sgaps.valueresult), which the generator encodes as a single override.shell.ready.Verification
pnpm build: greenpnpm type-check: greenpnpm test:unit: 234 files, 2887 tests passingpnpm docs:check: green (typedoc with--treatWarningsAsErrors)pnpm --filter @kehto/mocks bindings:check: "napplet-bindings.ts is current."npx playwright test): 120 passed, 1 skipped (pre-existing), including the 3 newpaja-mocked-napsspecs. They cover the marker/legend, real calls with fixture data plus an error mapping plus a class push, and disablingtorrentremoving it fromwindow.napplet.main(c815e65f), with the same 7 pre-existing warnings (browser-host.ts,runtime/types.ts,cvm-nostr-transport.ts, long Paja functions). This PR adds no findings. I didn't get it to 100 because those warnings are in files this change doesn't own.Known gaps / out of scope
bindings: MOCK_NAPPLET_BINDINGS; seeskills/use-nap-mocks.mesh.subscribe.result, which isn't routed toon(). The NAP folds them into the subscription'scloseddelivery, and the mock never refuses.🤖 Generated with Claude Code