@kehto/paja 0.17.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -15
- package/dist/browser-host.js +16978 -16392
- package/dist/browser-host.js.map +1 -1
- package/dist/{chunk-ESE55K3Q.js → chunk-YX6C2UU7.js} +143 -24
- package/dist/chunk-YX6C2UU7.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +132 -4
- package/dist/index.js +13 -1
- package/package.json +5 -5
- package/dist/chunk-ESE55K3Q.js.map +0 -1
package/README.md
CHANGED
|
@@ -57,6 +57,15 @@ Any dev server works as long as it answers `Origin: null` with
|
|
|
57
57
|
and logs a `paja.target.cors.error` entry in the message log, plus a console
|
|
58
58
|
warning, when the target would block the sandboxed frame.
|
|
59
59
|
|
|
60
|
+
Every drawer section is a flush, independent native accordion: **Pointer** (in
|
|
61
|
+
runtime-pointer mode), **Interfaces**, **ACL**, **Signer**, **Resource servers**,
|
|
62
|
+
then **Messages** last. Headers support Enter/Space, visible keyboard focus and
|
|
63
|
+
state chevrons; bodies keep their padding and live controls when hidden. Sections
|
|
64
|
+
start expanded unless a validated origin-local boolean preference says otherwise.
|
|
65
|
+
The collapsed map uses `kehto:paja:sidebar-sections:v1`, separately from whole-drawer
|
|
66
|
+
visibility and resource server values. Storage failures leave session-only toggles
|
|
67
|
+
usable; collapsing never reloads the running app or discards unsaved drafts.
|
|
68
|
+
|
|
60
69
|
The console shows supported interfaces with per-domain injection toggles,
|
|
61
70
|
runtime ACL controls, signer controls, and a filterable message log with visible
|
|
62
71
|
error details. It starts expanded and collapses to the left with the chevron
|
|
@@ -193,6 +202,34 @@ and hinted-author/publisher server lists first, then the active shell user's
|
|
|
193
202
|
published list, the current window's verified pointer-manifest servers, and
|
|
194
203
|
finally configured runtime fallbacks.
|
|
195
204
|
|
|
205
|
+
## Local `index.html` files
|
|
206
|
+
|
|
207
|
+
In runtime-pointer mode, Paja can also open a napplet straight from disk. Use
|
|
208
|
+
**Open file…** next to **Load**, or drop an `index.html` anywhere on the Paja
|
|
209
|
+
page (not onto a running napplet frame, which receives its own drag events).
|
|
210
|
+
The file opens in a new runtime tab named after the file.
|
|
211
|
+
|
|
212
|
+
- **Identity comes from the bytes.** Paja hashes the exact file bytes (`sha256`)
|
|
213
|
+
and derives `aggregateHash` as the NIP-5A aggregate over the single
|
|
214
|
+
`/index.html` path entry. That is the same derivation the resolver checks for a
|
|
215
|
+
published single-file napplet, so editing the file gives it a new identity. The
|
|
216
|
+
`dTag` comes from the NIP-5D publishing metadata
|
|
217
|
+
`<meta name="napplet-id" content="…">`. Without it, Paja uses
|
|
218
|
+
`local-<file-stem>`.
|
|
219
|
+
- **Same loading path as verified pointers.** Paja registers the identity before
|
|
220
|
+
the frame runs. It injects the Class-1 CSP (with `connect-src 'none'`, since a
|
|
221
|
+
local file has no relay or Blossom hints) and then the runtime-owned
|
|
222
|
+
`window.napplet` prelude, including mandatory `shell`. The bytes go in through
|
|
223
|
+
`srcdoc` under the same `allow-scripts` sandbox.
|
|
224
|
+
- **Development only and unverified.** A local file has no signed manifest. It
|
|
225
|
+
never enters the installed napplet catalog, never becomes an intent delivery
|
|
226
|
+
target, has no share link, and is not restored after a page reload.
|
|
227
|
+
- **Self-contained single-file HTML only.** A `srcdoc` document has no base URL,
|
|
228
|
+
and the CSP denies network loads, so relative `<script src>`, stylesheets, and
|
|
229
|
+
images do not load. Paja lists relative references it finds in the status line
|
|
230
|
+
and the message log. Build with an inlining bundler (for example
|
|
231
|
+
`vite-plugin-singlefile`). Opening a folder or zip of assets is not supported.
|
|
232
|
+
|
|
196
233
|
## Installed intent handlers and delivery
|
|
197
234
|
|
|
198
235
|
Paja keeps resolver-verified pointer and manifest facts in an installed catalog,
|
|
@@ -201,7 +238,10 @@ the catalog record; an explicit artifact removal removes it. Closing, reloading,
|
|
|
201
238
|
or replacing a frame never makes an installed handler unavailable, so a cold
|
|
202
239
|
target can still be selected and started later.
|
|
203
240
|
|
|
204
|
-
Intent selection considers only exact compatible contracts from that catalog.
|
|
241
|
+
Intent selection considers only exact compatible contracts from that catalog. Required or optional INC declarations are eligible only when
|
|
242
|
+
INC is available in the target's host-resolved environment. Missing optional INC
|
|
243
|
+
still permits frame loading. Nameless root/snapshot artifacts may also run, but
|
|
244
|
+
are excluded from the dTag-keyed intent catalog.
|
|
205
245
|
Paja can use a compatible user default, ask its host chooser when more than one
|
|
206
246
|
candidate is available, or reject an ambiguity. An explicit handler d-tag is
|
|
207
247
|
accepted only when it is an installed compatible handler and the invoking sender
|
|
@@ -211,12 +251,21 @@ arbitrary running frame.
|
|
|
211
251
|
When Paja receives an invocation, it selects and opens or reuses a verified
|
|
212
252
|
target. The controller waits for the target generation's
|
|
213
253
|
registered `MessageEvent.source` to establish its real `shell.ready` session;
|
|
214
|
-
it checks that generation is still current, sends one target-only `
|
|
254
|
+
it checks that generation is still current, sends one target-only `intent.deliver`
|
|
215
255
|
with the selected queryless convention, and returns the final handled target
|
|
216
256
|
identity. A superseded target/source, failed open/readiness, or terminal send is
|
|
217
257
|
handled by the controller's replacement/retry/terminal policy and produces a
|
|
218
258
|
canonical failed `IntentResult`.
|
|
219
259
|
|
|
260
|
+
Reusing a handler tab activates it and remembers the new active tab. Paja's stage
|
|
261
|
+
shows exactly one tab, so a delivered intent always selects the handler tab:
|
|
262
|
+
`behavior.focus` is a hint, and honoring `false` as "deliver into the hidden
|
|
263
|
+
tab" would report a handled intent whose surface the user never sees. Reuse
|
|
264
|
+
still leaves the caller's tab open, so nothing is replaced. Newly created
|
|
265
|
+
handler tabs behave the same way. Pointer installation logs declared
|
|
266
|
+
archetypes and required domains; Paja warns when archetypes lack `inc`, which
|
|
267
|
+
its current convention delivery policy requires.
|
|
268
|
+
|
|
220
269
|
`@napplet/shim@0.30.0` supplies no generic shell API. Kehto deliberately keeps
|
|
221
270
|
its host-owned mandatory `window.napplet.shell` prelude: it installs the live
|
|
222
271
|
receiver before the one bare `shell.ready`, caches the first `shell.init`, and
|
|
@@ -309,6 +358,25 @@ pubkey without `signEvent` is read-only. This implements the draft
|
|
|
309
358
|
|
|
310
359
|
## NAP-RESOURCE schemes
|
|
311
360
|
|
|
361
|
+
The development sidebar's **Resource servers** textarea adds read-only Blossom
|
|
362
|
+
lookup origins in both target-URL and runtime-pointer modes. Enter one public
|
|
363
|
+
HTTPS origin per line (`cdn.example` is shorthand for `https://cdn.example`)
|
|
364
|
+
and press **Save**. Blanks are ignored and equivalent origins are deduplicated
|
|
365
|
+
in first-seen order. A bad line rejects the whole save without changing the
|
|
366
|
+
active or saved list; credentials, paths, queries, fragments, HTTP and obvious
|
|
367
|
+
local/private hosts are rejected. Saving blank clears only these extras.
|
|
368
|
+
|
|
369
|
+
Valid saves apply to subsequent Blossom requests across all running tabs,
|
|
370
|
+
without reloading their frames. The list persists in the host origin's
|
|
371
|
+
`localStorage`; if storage fails, it remains usable **session-only**, and the
|
|
372
|
+
status warns that an older saved list may return after reload. Extras are
|
|
373
|
+
appended after existing request/event/user/window/configured defaults. The
|
|
374
|
+
combined eight-server cap remains: extras may not be reached if earlier
|
|
375
|
+
candidates fill it. This setting does not change upload destinations,
|
|
376
|
+
per-napplet NAP-CONFIG, initial pointer/artifact loading, direct HTTP(S) resource
|
|
377
|
+
URLs, or napplet CSP/network grants. Browser CORS and the DNS limitation below
|
|
378
|
+
still apply.
|
|
379
|
+
|
|
312
380
|
Paja's developer-runtime policy accepts arbitrary `http:` and `https:` resource
|
|
313
381
|
URLs so a normal remote image does not look broken merely because its origin was
|
|
314
382
|
not pre-granted. Paja resolves those URLs with browser `fetch`, omits credentials
|
|
@@ -316,33 +384,68 @@ and referrer data, caps responses at 10 MiB, and classifies MIME from returned
|
|
|
316
384
|
bytes. Its byte classifier recognizes checksum-valid Game Boy ROM headers as
|
|
317
385
|
`application/vnd.nintendo.gb-rom`; it never trusts a server-supplied media type.
|
|
318
386
|
Browser network and CORS rules still apply: an unreadable response is the
|
|
319
|
-
canonical `network-error
|
|
320
|
-
|
|
387
|
+
canonical `network-error`. HTTP(S) and locally decoded `data:` bytes must have a
|
|
388
|
+
recognized type; opaque invalid-UTF-8 or NUL-bearing binary remains rejected.
|
|
389
|
+
Only capped, SHA-256-verified canonical Blossom resources may return unknown
|
|
390
|
+
opaque bytes as `application/octet-stream`. Recognized formats retain their
|
|
391
|
+
sniffed MIME. SVG, HTML, XML and script prefixes remain blocked, even with NUL or
|
|
392
|
+
invalid-UTF-8 suffixes; upstream headers never override classification.
|
|
393
|
+
Byte-identifiable UTF-16 markup is checked by decoding the complete capped
|
|
394
|
+
buffer; identifiable UTF-32 document signatures are conservatively rejected.
|
|
395
|
+
This encoding guard is not a general markup parser.
|
|
321
396
|
|
|
322
397
|
`data:` remains locally decoded. `blossom:` is a separate, content-addressed
|
|
323
398
|
boundary and is advertised because each request may provide server locations
|
|
324
|
-
without a host default.
|
|
325
|
-
|
|
399
|
+
without a host default. For example, reads accept
|
|
400
|
+
`blossom:<hash>.gbc?xs=cdn.example&as=<pubkey>&sz=32768` and
|
|
401
|
+
`blossom:sha256:<hash>.gbc?xs=cdn.example&sz=32768`.
|
|
402
|
+
Repeated `xs` and `as` are supported without an observed event. Paja accepts only
|
|
403
|
+
public-looking HTTPS origin hints (scheme-less domains use HTTPS), discards
|
|
404
|
+
invalid/private literals, and deduplicates them. Unlike BUD-10's suggested HTTP
|
|
405
|
+
retry, URI hints never enable public HTTP. For a Blossom URL
|
|
326
406
|
previously returned to the same napplet window by `outbox.getEvent`,
|
|
327
407
|
`outbox.query`, or `outbox.subscribe`, Paja retains bounded event context
|
|
328
|
-
without prefetching bytes. Resolution tries request
|
|
329
|
-
event-local server hints first, then lazily queries hinted authors' and the
|
|
408
|
+
without prefetching bytes. Resolution tries explicit request servers, URI `xs`,
|
|
409
|
+
and event-local server hints first, then lazily queries URI `as`, event-hinted authors' and the
|
|
330
410
|
event publisher's newest BUD-03 kind `10063` lists through the verified
|
|
331
411
|
NIP-65-aware OUTBOX router, then queries the active shell user's BUD-03 list
|
|
332
412
|
through that same router, then uses the current window's verified
|
|
333
|
-
pointer-manifest servers, followed by upload-runtime fallbacks
|
|
413
|
+
pointer-manifest servers, followed by upload-runtime fallbacks and saved extra
|
|
414
|
+
resource servers. The user-list
|
|
334
415
|
lookup works independently of upload mode; an upload runtime may reuse the same
|
|
335
416
|
servers when present. ROM-specific event and publisher locations retain
|
|
336
|
-
priority over the user/runtime fallbacks.
|
|
337
|
-
|
|
338
|
-
|
|
417
|
+
priority over the user/runtime fallbacks. URI length is capped at 8192 characters;
|
|
418
|
+
retained unique `xs`, the complete author lookup list, and combined server
|
|
419
|
+
candidates are each capped at eight. Both prefixes require exactly 64 hex
|
|
420
|
+
characters, with an optional single ASCII-alphanumeric extension preserved in
|
|
421
|
+
`GET /<hash>.<ext>`; no query hints reach the blob server. Extensions and upstream
|
|
422
|
+
headers never establish MIME. Fragments, path injection, malformed escapes/authors,
|
|
423
|
+
and invalid or repeated `sz` fail with `invalid-request` before discovery.
|
|
424
|
+
`sz` must be a positive decimal safe integer; sizes above 10 MiB fail `too-large`.
|
|
425
|
+
Paja checks a numeric Content-Length before reading and always checks actual
|
|
426
|
+
bytes against `sz`; a size or hash mismatch is `decode-failed` unless fallback succeeds.
|
|
427
|
+
Hash-only event context stays window-scoped, without transferring extension/size
|
|
428
|
+
or retaining request hints. Byte caches retain the original URL and identity scope;
|
|
429
|
+
public author lists reuse five-minute cache/single-flight lookups, with incomplete misses retryable.
|
|
430
|
+
|
|
431
|
+
[BUD-10 at `b5bd280`](https://github.com/hzrd149/blossom/blob/b5bd2801d1763aa635fc8fea7a76597e0eb18990/buds/10.md)
|
|
432
|
+
requires lowercase hashes and an extension (default `.bin`) for emitted references.
|
|
433
|
+
Extensionless reads, mixed-case hashes, and the `sha256:` alias are deliberately
|
|
434
|
+
retained local compatibility, not a full BUD-10 conformance claim. Upload URI
|
|
435
|
+
generation is unchanged. Paja refuses redirects, verifies SHA-256 and byte MIME,
|
|
436
|
+
and permits plain-HTTP
|
|
339
437
|
transport only for configured loopback development defaults. Browser-only Paja
|
|
340
438
|
cannot pin DNS results, so production runtimes must add the draft's DNS-time
|
|
341
439
|
private-address checks. The current
|
|
342
440
|
[NAP-RESOURCE draft at `fa6bcc6`](https://github.com/napplet/naps/blob/fa6bcc6935aa19e7b70ab2a2c721dafca77c78e1/naps/NAP-RESOURCE.md)
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
441
|
+
was rechecked for this MIME policy against PR #80's exact head. The opaque
|
|
442
|
+
fallback preserves byte sniffing, hash verification, complete Blob delivery,
|
|
443
|
+
ordered independent bulk results, and the prohibition on raw SVG delivery.
|
|
444
|
+
This is bounded conformance, not full draft compliance: existing developer HTTP
|
|
445
|
+
policy, DNS enforcement, SVG rejection instead of rasterization, and request
|
|
446
|
+
server-hint differences remain outside this change. The draft defines no
|
|
447
|
+
wire-level Blossom server-hint field. Retaining verified manifest servers per
|
|
448
|
+
window is therefore Paja host policy, informed by the current
|
|
346
449
|
[NIP-5D draft at `24711d9`](https://github.com/nostr-protocol/nips/blob/24711d9c47bbdd07908bf1d52bf677d9cbc530f0/5D.md),
|
|
347
450
|
which defines manifest `server` tags. The existing request-server compatibility
|
|
348
451
|
path comes from the earlier NAP-RESOURCE draft at `9511232`, with the merged package implementation
|
|
@@ -355,3 +458,13 @@ Full package docs: [`docs/packages/paja.md`](../../docs/packages/paja.md).
|
|
|
355
458
|
Getting started: [`docs/how-tos/paja-getting-started.md`](../../docs/how-tos/paja-getting-started.md).
|
|
356
459
|
Local authoring how-to: [`docs/how-tos/paja-local-authoring.md`](../../docs/how-tos/paja-local-authoring.md).
|
|
357
460
|
Generated API module: `docs/api/modules/_kehto_paja.html` (run `pnpm docs:api`).
|
|
461
|
+
|
|
462
|
+
## NIP-5D event compatibility
|
|
463
|
+
|
|
464
|
+
Current manifests use a direct artifact `x` hash, plain-text `content`, independent
|
|
465
|
+
`z`/`i` routing declarations, and required `R` / optional `O` domains. Kehto also
|
|
466
|
+
accepts legacy aggregate events through an isolated compatibility adapter.
|
|
467
|
+
Existing `aggregateHash` host/cache/ACL fields carry the verified artifact hash
|
|
468
|
+
for current events; legacy identities keep their original aggregate. Both paths
|
|
469
|
+
verify signatures and bytes before runtime injection and `srcdoc` execution.
|
|
470
|
+
For the schema and removal boundary, see [event migration](https://kehto.github.io/web/docs/migrations/NIP-5D-EVENT-SCHEMA.html).
|