@kehto/shell 0.26.0 → 0.27.0
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 +47 -9
- package/dist/index.d.ts +168 -20
- package/dist/index.js +277 -91
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -14,8 +14,10 @@ pnpm add @kehto/shell
|
|
|
14
14
|
|
|
15
15
|
## Published Napplet Compatibility
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
`>=0.32.0 <0.
|
|
17
|
+
Peers admit `@napplet/core` `>=0.32.0 <0.38.0` and `@napplet/nap`
|
|
18
|
+
`>=0.32.0 <0.37.0`, so the nap 0.35.x line that ships the `llm` subpath (and the
|
|
19
|
+
core 0.36.x line nap 0.35.1 requires) installs without peer conflicts; development
|
|
20
|
+
and tests stay on the baseline 0.32.0 line. The installed core 0.32.0 / nap 0.32.0 contracts follow
|
|
19
21
|
NAP-INTENT authority `5ac0490461ca6fec2f0d2e45b4835cf9bc08de24`, napplet/web#199
|
|
20
22
|
source `3037200c932488f14f7f369b8583c39c9c16510a` / merge
|
|
21
23
|
`b3f0007867eac109fa4917fac9c285d3b7cc6155`, and Version Packages #198 release
|
|
@@ -23,9 +25,9 @@ source `dc1d24153c759152b6ba31a6ec9bea967798f2df`.
|
|
|
23
25
|
|
|
24
26
|
## Overview
|
|
25
27
|
|
|
26
|
-
`@kehto/shell` is the browser-specific integration layer for kehto. It wraps `@kehto/runtime` with the window
|
|
28
|
+
`@kehto/shell` is the browser-specific integration layer for kehto. It wraps `@kehto/runtime` with the NIP-5D port-bound transport (one window-level `napplet.hello`, then a dedicated `MessagePort`), localStorage persistence hooks, an audio manager, and the five canonical per-domain proxies defined by NIP-5D.
|
|
27
29
|
|
|
28
|
-
The primary entry point is `createShellBridge()` — it owns the
|
|
30
|
+
The primary entry point is `createShellBridge()` — it owns the `napplet.hello` listener and port binding, the NAP-SHELL `shell.ready` / `shell.init` handshake, manifest verification, and every dispatch back into the runtime engine.
|
|
29
31
|
|
|
30
32
|
ACL persistence uses the browser's `localStorage` key `napplet:acl`. A failed
|
|
31
33
|
write is intentionally reported through `bridge.runtime.aclState.persist()` or
|
|
@@ -101,6 +103,38 @@ remain bounded compatibility adapters and warn once per iframe with
|
|
|
101
103
|
`KEHTO_COMPAT_INTENT_OBJECT_INVOKE`. Their removal conditions are tracked in
|
|
102
104
|
[compatibility](https://github.com/kehto/web/blob/main/docs/compatibility.md).
|
|
103
105
|
|
|
106
|
+
### NIP-5D port-bound transport
|
|
107
|
+
|
|
108
|
+
NIP-5D ([nostr-protocol/nips#2303 at `51ef0cd`](https://github.com/nostr-protocol/nips/blob/51ef0cd33a5694784306f3260d90b1872545fdee/5D.md))
|
|
109
|
+
binds napplet identity to a `MessagePort`, not the iframe `Window`. A `Window`
|
|
110
|
+
survives same-frame navigation, but the port lives only in the verified document:
|
|
111
|
+
|
|
112
|
+
- The injected prelude opens a `MessageChannel` before napplet scripts run,
|
|
113
|
+
keeps one port private, and sends the other once in a window-level
|
|
114
|
+
`{ type: 'napplet.hello' }` (`NAPPLET_HELLO`). Every NAP message then travels
|
|
115
|
+
over that port in both directions.
|
|
116
|
+
- `ShellBridge.handleMessage` accepts the hello only from the `contentWindow` of
|
|
117
|
+
an iframe registered in `originRegistry`, carrying exactly one port. It binds
|
|
118
|
+
the registered `(dTag, aggregateHash)` to the port. Shell senders use
|
|
119
|
+
`originRegistry.postToNapplet(windowId, message)` or `getNappletTarget(windowId)`,
|
|
120
|
+
never `iframeWindow.postMessage`.
|
|
121
|
+
- A second hello, any other window-level message, a hello without exactly one
|
|
122
|
+
port, a second iframe `load`, or the port closing revokes the napplet. The
|
|
123
|
+
bridge closes the port, revokes its sessions, subscriptions and environment,
|
|
124
|
+
and calls `ShellAdapter.onNappletRevoked({ windowId, reason, detail })`. The
|
|
125
|
+
host must remove that frame. `ShellBridge.revokeNapplet(windowId)` revokes on
|
|
126
|
+
demand.
|
|
127
|
+
- `ShellBridge.observeFrame(frame, windowId)` watches for the second load. Call
|
|
128
|
+
it after the frame is in the DOM and before assigning `srcdoc`.
|
|
129
|
+
- `originRegistry.register()` throws for a `Window` that already handed over (or
|
|
130
|
+
lost) its port. Create a fresh iframe for every reload or navigation.
|
|
131
|
+
- `ShellAdapter.onNappletMessage(windowId, message)` observes each port envelope
|
|
132
|
+
before dispatch, for logging or readiness tracking.
|
|
133
|
+
|
|
134
|
+
Napplets hosted with this prelude must not also import `@napplet/shim`, because
|
|
135
|
+
the shim sends a second hello. The retired window-level transport is recorded as
|
|
136
|
+
`NIP5D_WINDOW_TRANSPORT_RETIRED` in the [compatibility register](https://github.com/kehto/web/blob/main/docs/compatibility.md).
|
|
137
|
+
|
|
104
138
|
## Quick Start
|
|
105
139
|
|
|
106
140
|
```ts
|
|
@@ -123,13 +157,16 @@ bridge.runtime.registerService(
|
|
|
123
157
|
## Public API
|
|
124
158
|
|
|
125
159
|
### Bridge factory
|
|
126
|
-
- `createShellBridge` — primary entry point; returns a `ShellBridge` (exposed `runtime`, `shell.ready`, lifecycle hooks)
|
|
160
|
+
- `createShellBridge` — primary entry point; returns a `ShellBridge` (exposed `runtime`, `shell.ready`, lifecycle hooks, `observeFrame`, `revokeNapplet`)
|
|
161
|
+
- `NAPPLET_HELLO` — the NIP-5D port handoff message type
|
|
127
162
|
- `ShellBridge` — interface type for the returned bridge
|
|
128
163
|
|
|
129
164
|
### Hooks adapter
|
|
130
165
|
- `adaptHooks` — convert a `ShellAdapter` + `BrowserDeps` into the canonical `RuntimeAdapter` hook bag consumed by `@kehto/runtime`
|
|
131
166
|
|
|
132
167
|
### Diagnostics
|
|
168
|
+
- `ShellAdapter.onNappletRevoked?(revocation)` — called once when the bridge revokes a NIP-5D binding (`NappletRevocation`: `{ windowId, reason, detail }`, `reason` one of `NappletRevocationReason`). The host must remove the frame.
|
|
169
|
+
- `ShellAdapter.onNappletMessage?(windowId, message)` — observe-only; called for each NAP envelope received on a bound port before dispatch.
|
|
133
170
|
- `ShellAdapter.onUnroutedMessage?(info)` — optional observe-only hook fired when `ShellBridge.handleMessage` drops an incoming postMessage it can't route to a registered napplet window. `info` is an `UnroutedMessageInfo` (`{ type?, origin, reason }`) where `reason` is `'no-source-window'` or `'unregistered-window'`. The message is still dropped — this exists so otherwise-silent drops (e.g. an intent/`srcdoc` iframe whose `contentWindow` was never registered in `originRegistry`, or was swapped by a reload) are diagnosable instead of vanishing. Host can `console.warn` inside its own hook; the bridge adds no console output and swallows hook errors so routing is never broken.
|
|
134
171
|
|
|
135
172
|
```ts
|
|
@@ -218,14 +255,15 @@ payload.
|
|
|
218
255
|
### Session / origin registry
|
|
219
256
|
- `sessionRegistry` — canonical windowId ↔ verified-napplet registry singleton
|
|
220
257
|
- `nappKeyRegistry` — deprecated alias for `sessionRegistry`
|
|
221
|
-
- `originRegistry` —
|
|
258
|
+
- `originRegistry` — iframe `Window` → windowId/identity map; also holds each window's bound NIP-5D port (`bindPort`, `getPort`, `postToNapplet`, `getNappletTarget`, `isSpent`)
|
|
259
|
+
- `NappletMessageTarget` — port-backed outbound target passed to `RelayPoolHooks.openScopedRelay`
|
|
222
260
|
- `PendingUpdate` — type for pending aggregate-hash change prompts
|
|
223
261
|
|
|
224
262
|
Environment snapshots belong to one source registration. To retire a window,
|
|
225
263
|
call `bridge.runtime.destroyWindow(windowId)`,
|
|
226
264
|
`bridge.runtime.sessionRegistry.unregister(windowId)`, and
|
|
227
265
|
`originRegistry.unregister(windowId)`. When registering a replacement under the
|
|
228
|
-
same window ID, provide its snapshot with `originRegistry.setEnvironment()` or
|
|
266
|
+
same window ID (always a fresh iframe — a spent `Window` cannot be re-registered), provide its snapshot with `originRegistry.setEnvironment()` or
|
|
229
267
|
let the bridge call `resolveShellEnvironment()` for current host defaults. A
|
|
230
268
|
retired registration's cached domains and service names are discarded even when
|
|
231
269
|
the runtime session was already removed. This applies before any domain dispatch,
|
|
@@ -303,11 +341,11 @@ for outer URL encoding, review, routing, and verified launcher behavior.
|
|
|
303
341
|
|
|
304
342
|
## GAMEPAD integration
|
|
305
343
|
|
|
306
|
-
This non-normative guidance defers to the living [NAP-GAMEPAD](https://github.com/napplet/naps/pull/108). Services export `createGamepadService` and `browserGamepadOptions`; shell exports `denyNappletControllerAccess`. Paja
|
|
344
|
+
This non-normative guidance defers to the living [NAP-GAMEPAD](https://github.com/napplet/naps/pull/108). Services export `createGamepadService` and `browserGamepadOptions`; shell exports `denyNappletControllerAccess`. Paja registers one host reader and deny native gamepad/HID/USB paths before frame execution. Source-bound subscriptions receive immediate full snapshots; only the visible host's input owner gets live controls. Focus loss supplies neutral controls and timestamp zero; unsubscribe, window destruction, and service removal release polling. Non-browser or denied native readers report the proposal's unavailable reasons. See [Controller input](https://github.com/kehto/web/blob/main/docs/gamepad.md).
|
|
307
345
|
|
|
308
346
|
## LLM integration
|
|
309
347
|
|
|
310
|
-
This non-normative guidance defers to the living [NAP-LLM](https://github.com/napplet/naps/pull/134) (checked at `3e10939`). Services export `createLlmService`, `LlmServiceError`, the provider mappers and `LLM_PROVIDER_PRESETS`; shell exports `getShellDomainState` and the `LlmHooks` adapter field; acl exports `llm:generate`. The runtime routes `llm.*` to one registered service and answers every sanctioned request with exactly one `llm.<op>.result`, shaping missing-service and ACL failures as `{ code: 'unsupported' }`. Hosts implement `LlmConnectionHost`; the service enforces schema, handle ownership, consent before submission, duplicate ids, cancellation and deadline races, ordered deltas and safe errors. Advertisement stays binary on the wire while hosts report a third `unconfigured` state until the user adds a connection. See [Language models](https://github.com/kehto/web/blob/main/docs/llm.md).
|
|
348
|
+
This non-normative guidance defers to the living [NAP-LLM](https://github.com/napplet/naps/pull/134) (checked at `3e10939`). Services export `createLlmService`, `LlmServiceError`, the provider mappers and `LLM_PROVIDER_PRESETS`; shell exports `getShellDomainState` and the `LlmHooks` adapter field; acl exports `llm:generate`. The runtime routes `llm.*` to one registered service and answers every sanctioned request with exactly one `llm.<op>.result`, shaping missing-service and ACL failures as `{ code: 'unsupported' }`. Hosts implement `LlmConnectionHost`; the service enforces schema, handle ownership, a per-window live-handle bound (`maxHandlesPerWindow`), consent before submission, duplicate ids, cancellation and deadline races, ordered deltas and safe errors, and passes `select`/`authorize` a `{ signal }` that withdraws stale prompts. `createHttpLlmProvider({ stream: true })` streams provider output into `llm.delta`. Advertisement stays binary on the wire while hosts report a third `unconfigured` state until the user adds a connection. See [Language models](https://github.com/kehto/web/blob/main/docs/llm.md).
|
|
311
349
|
|
|
312
350
|
## UUID support on HTTP origins
|
|
313
351
|
|
package/dist/index.d.ts
CHANGED
|
@@ -6,14 +6,30 @@ import { Theme } from '@napplet/nap/theme/types';
|
|
|
6
6
|
import { ResourceBytesItem, ResourceBytesRequest as ResourceBytesRequest$1, ResourceInfo } from '@napplet/nap/resource/types';
|
|
7
7
|
export { ResourceInfo } from '@napplet/nap/resource/types';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Minimal outbound target for one napplet. NIP-5D carries every NAP message
|
|
11
|
+
* over the port bound by `napplet.hello`, so this never wraps the iframe
|
|
12
|
+
* `Window`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* originRegistry.getNappletTarget('napp-1')?.postMessage({ type: 'relay.eose', subId });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
interface NappletMessageTarget {
|
|
20
|
+
/** Post one NAP envelope over the bound port. Dropped when no port is bound. */
|
|
21
|
+
postMessage(message: unknown): void;
|
|
22
|
+
}
|
|
9
23
|
/** NIP-5D identity metadata associated with a registered iframe window. */
|
|
10
24
|
interface OriginIdentity {
|
|
11
25
|
readonly dTag: string;
|
|
12
26
|
readonly aggregateHash: string;
|
|
13
27
|
}
|
|
14
28
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
29
|
+
* Registry mapping each shell-created iframe Window to its windowId, verified
|
|
30
|
+
* NIP-5D identity, and the `MessagePort` bound by its single `napplet.hello`.
|
|
31
|
+
* The Window is only used to authenticate the hello; all NAP traffic uses the
|
|
32
|
+
* bound port (NIP-5D, nostr-protocol/nips#2303).
|
|
17
33
|
*
|
|
18
34
|
* @example
|
|
19
35
|
* ```ts
|
|
@@ -26,6 +42,11 @@ interface OriginIdentity {
|
|
|
26
42
|
interface OriginRegistry {
|
|
27
43
|
register(win: Window, windowId: string, identity?: OriginIdentity): void;
|
|
28
44
|
unregister(windowId: string): void;
|
|
45
|
+
bindPort(windowId: string, port: MessagePort): boolean;
|
|
46
|
+
getPort(windowId: string): MessagePort | undefined;
|
|
47
|
+
postToNapplet(windowId: string, message: unknown): boolean;
|
|
48
|
+
getNappletTarget(windowId: string): NappletMessageTarget | null;
|
|
49
|
+
isSpent(win: Window): boolean;
|
|
29
50
|
getWindowId(win: Window): string | undefined;
|
|
30
51
|
getIframeWindow(windowId: string): Window | null;
|
|
31
52
|
getAllWindowIds(): string[];
|
|
@@ -73,7 +94,7 @@ interface RelayPoolHooks {
|
|
|
73
94
|
/** Untrack and clean up a subscription. */
|
|
74
95
|
untrackSubscription(subKey: string): void;
|
|
75
96
|
/** Open a scoped relay connection (NIP-29 groups). */
|
|
76
|
-
openScopedRelay(windowId: string, relayUrl: string, subId: string, filters: NostrFilter[],
|
|
97
|
+
openScopedRelay(windowId: string, relayUrl: string, subId: string, filters: NostrFilter[], target: NappletMessageTarget): void;
|
|
77
98
|
/** Close a scoped relay connection. */
|
|
78
99
|
closeScopedRelay(windowId: string): void;
|
|
79
100
|
/**
|
|
@@ -348,6 +369,33 @@ interface UnroutedMessageInfo {
|
|
|
348
369
|
*/
|
|
349
370
|
reason: 'no-source-window' | 'unregistered-window';
|
|
350
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Why a NIP-5D napplet binding was revoked.
|
|
374
|
+
* - `window-message` — a window-level message other than the one `napplet.hello`.
|
|
375
|
+
* - `second-hello` — a second `napplet.hello` from the same iframe.
|
|
376
|
+
* - `invalid-hello` — a `napplet.hello` without exactly one transferred port.
|
|
377
|
+
* - `second-load` — the iframe loaded a second document (navigation or reload).
|
|
378
|
+
* - `port-closed` — the bound port closed or failed to deserialize a message.
|
|
379
|
+
* - `host` — the host revoked the binding itself.
|
|
380
|
+
*/
|
|
381
|
+
type NappletRevocationReason = 'window-message' | 'second-hello' | 'invalid-hello' | 'second-load' | 'port-closed' | 'host';
|
|
382
|
+
/**
|
|
383
|
+
* Passed to {@link ShellAdapter.onNappletRevoked} after the shell closed the
|
|
384
|
+
* port and revoked the identity binding, sessions and grants of one frame.
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```ts
|
|
388
|
+
* hooks.onNappletRevoked = ({ windowId }) => frames.get(windowId)?.remove();
|
|
389
|
+
* ```
|
|
390
|
+
*/
|
|
391
|
+
interface NappletRevocation {
|
|
392
|
+
/** The revoked window. Its identity can never be re-bound to the same iframe. */
|
|
393
|
+
readonly windowId: string;
|
|
394
|
+
/** What the shell observed. */
|
|
395
|
+
readonly reason: NappletRevocationReason;
|
|
396
|
+
/** Human-readable detail for diagnostics. Never includes message payloads. */
|
|
397
|
+
readonly detail: string;
|
|
398
|
+
}
|
|
351
399
|
/**
|
|
352
400
|
* Static capability set sent to napplet iframes through the shell.ready /
|
|
353
401
|
* shell.init handshake. Optional runtime domain presence is injected before
|
|
@@ -461,6 +509,24 @@ interface ShellAdapter {
|
|
|
461
509
|
* (the FEED-02 / hyprgate#21 class of "a napplet's messages vanish" bug).
|
|
462
510
|
*/
|
|
463
511
|
onUnroutedMessage?: (info: UnroutedMessageInfo) => void;
|
|
512
|
+
/**
|
|
513
|
+
* Called once when the shell revokes a NIP-5D napplet binding: a second
|
|
514
|
+
* `napplet.hello`, any other window-level message, an invalid hello, a
|
|
515
|
+
* second iframe `load` (see `ShellBridge.observeFrame`), the port closing,
|
|
516
|
+
* or `ShellBridge.revokeNapplet`. The shell has already closed the port and
|
|
517
|
+
* revoked the identity binding, sessions and grants. NIP-5D requires the
|
|
518
|
+
* host to remove the iframe here; it MAY create a fresh iframe from the
|
|
519
|
+
* verified bytes but MUST NOT reuse this one.
|
|
520
|
+
*/
|
|
521
|
+
onNappletRevoked?: (revocation: NappletRevocation) => void;
|
|
522
|
+
/**
|
|
523
|
+
* Observe-only: called with each NAP envelope received on a napplet's bound
|
|
524
|
+
* NIP-5D port, before the shell dispatches it. NIP-5D moves NAP traffic off
|
|
525
|
+
* window-level `message` events, so hosts that logged or tracked readiness
|
|
526
|
+
* from those events use this hook instead. It cannot change or drop the
|
|
527
|
+
* message; host hook errors are swallowed.
|
|
528
|
+
*/
|
|
529
|
+
onNappletMessage?: (windowId: string, message: NappletMessage) => void;
|
|
464
530
|
/** Called when aggregate hash verification fails (computed != declared). */
|
|
465
531
|
onHashMismatch?: (dTag: string, claimed: string, computed: string) => void;
|
|
466
532
|
/**
|
|
@@ -497,14 +563,36 @@ interface ShellAdapter {
|
|
|
497
563
|
getConfigOverrides?(): RuntimeConfigOverrides;
|
|
498
564
|
}
|
|
499
565
|
|
|
566
|
+
/**
|
|
567
|
+
* NIP-5D port-bound transport for ShellBridge (nostr-protocol/nips#2303 at
|
|
568
|
+
* 51ef0cd33a5694784306f3260d90b1872545fdee, packaged by napplet/web#302).
|
|
569
|
+
*
|
|
570
|
+
* A napplet's injected bootstrap transfers one MessagePort in a single
|
|
571
|
+
* window-level `napplet.hello`. The shell binds the registered identity to
|
|
572
|
+
* that port, dispatches NAP only from it, and revokes the binding on any
|
|
573
|
+
* evidence that the verified document was replaced.
|
|
574
|
+
*
|
|
575
|
+
* @module
|
|
576
|
+
*/
|
|
577
|
+
|
|
578
|
+
/** The NIP-5D port handoff message type (nostr-protocol/nips#2303). */
|
|
579
|
+
declare const NAPPLET_HELLO = "napplet.hello";
|
|
580
|
+
|
|
500
581
|
/**
|
|
501
582
|
* Shell-side message bridge that handles NIP-5D communication with napplet iframes.
|
|
502
583
|
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
584
|
+
* NIP-5D binds napplet identity to a `MessagePort`, not to the iframe Window:
|
|
585
|
+
* the injected bootstrap transfers one port to the shell in a single
|
|
586
|
+
* window-level `napplet.hello`. The bridge accepts that hello only from the
|
|
587
|
+
* `contentWindow` of a registered iframe carrying exactly one port, binds the
|
|
588
|
+
* frame's verified `(dTag, aggregateHash)` to the port, and then processes NAP
|
|
589
|
+
* envelopes only from that port and replies only over it. A second hello, any
|
|
590
|
+
* other window-level message, an invalid hello, a second iframe `load`
|
|
591
|
+
* ({@link ShellBridge.observeFrame}) or the port closing revokes the binding,
|
|
592
|
+
* its sessions and grants, and asks the host to remove the frame through
|
|
593
|
+
* `ShellAdapter.onNappletRevoked`. The shell.ready/shell.init capability
|
|
594
|
+
* handshake is handled locally within the bridge and never forwarded to the
|
|
595
|
+
* runtime.
|
|
508
596
|
*
|
|
509
597
|
* @example
|
|
510
598
|
* ```ts
|
|
@@ -516,15 +604,19 @@ interface ShellAdapter {
|
|
|
516
604
|
*/
|
|
517
605
|
interface ShellBridge {
|
|
518
606
|
/**
|
|
519
|
-
* Handle
|
|
607
|
+
* Handle a window-level message from a napplet iframe.
|
|
520
608
|
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
609
|
+
* The only window-level message a napplet may send is its single
|
|
610
|
+
* `napplet.hello` carrying exactly one `MessagePort`. The bridge binds that
|
|
611
|
+
* port and receives every later NAP envelope from it. Any other window-level
|
|
612
|
+
* message from a registered iframe, a second hello, or a hello without
|
|
613
|
+
* exactly one port revokes the frame. Messages from unregistered sources are
|
|
614
|
+
* dropped.
|
|
524
615
|
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
616
|
+
* On the bound port, only NIP-5D envelope objects (plain objects with a
|
|
617
|
+
* `.type` string) are accepted. shell.ready is handled locally (the bridge
|
|
618
|
+
* answers with shell.init over the port); all other envelopes are delegated
|
|
619
|
+
* to the runtime's NAP domain dispatch.
|
|
528
620
|
*
|
|
529
621
|
* @param event - The raw MessageEvent from window.addEventListener('message', ...)
|
|
530
622
|
* @example
|
|
@@ -605,6 +697,36 @@ interface ShellBridge {
|
|
|
605
697
|
* @param pubkey - Current user's hex pubkey, or empty string when signed out.
|
|
606
698
|
*/
|
|
607
699
|
publishIdentityChanged(pubkey: string): void;
|
|
700
|
+
/**
|
|
701
|
+
* Watch a napplet iframe for a second `load`, which NIP-5D treats as
|
|
702
|
+
* evidence that the verified document was replaced. Call after the frame is
|
|
703
|
+
* in the DOM and before assigning its `srcdoc`/`src`.
|
|
704
|
+
*
|
|
705
|
+
* @param frame - The shell-created napplet iframe
|
|
706
|
+
* @param windowId - The windowId registered for this frame
|
|
707
|
+
* @returns A function that stops watching
|
|
708
|
+
* @example
|
|
709
|
+
* ```ts
|
|
710
|
+
* document.body.append(frame);
|
|
711
|
+
* originRegistry.register(frame.contentWindow!, windowId, identity);
|
|
712
|
+
* const stop = bridge.observeFrame(frame, windowId);
|
|
713
|
+
* frame.srcdoc = verifiedSrcdoc;
|
|
714
|
+
* ```
|
|
715
|
+
*/
|
|
716
|
+
observeFrame(frame: Pick<HTMLIFrameElement, 'addEventListener' | 'removeEventListener'>, windowId: string): () => void;
|
|
717
|
+
/**
|
|
718
|
+
* Revoke one napplet binding: close its port, unregister it, destroy its
|
|
719
|
+
* sessions and subscriptions, and call `ShellAdapter.onNappletRevoked` so
|
|
720
|
+
* the host removes the frame. No-op for unknown windows.
|
|
721
|
+
*
|
|
722
|
+
* @param windowId - The window to revoke
|
|
723
|
+
* @param reason - Why the binding is revoked (defaults to `host`)
|
|
724
|
+
* @example
|
|
725
|
+
* ```ts
|
|
726
|
+
* bridge.revokeNapplet(windowId);
|
|
727
|
+
* ```
|
|
728
|
+
*/
|
|
729
|
+
revokeNapplet(windowId: string, reason?: NappletRevocationReason): void;
|
|
608
730
|
/**
|
|
609
731
|
* Access the underlying runtime instance for advanced use cases.
|
|
610
732
|
* Provides direct access to the runtime's sessionRegistry, aclState,
|
|
@@ -612,6 +734,31 @@ interface ShellBridge {
|
|
|
612
734
|
*/
|
|
613
735
|
readonly runtime: Runtime;
|
|
614
736
|
}
|
|
737
|
+
/**
|
|
738
|
+
* Create a ShellBridge instance with dependency injection via hooks.
|
|
739
|
+
*
|
|
740
|
+
* Internally creates a Runtime from @kehto/runtime and adapts the
|
|
741
|
+
* browser-oriented ShellAdapter into environment-agnostic RuntimeAdapter.
|
|
742
|
+
*
|
|
743
|
+
* @param hooks - Host application provides relay pool, auth, config, etc.
|
|
744
|
+
* @returns A ShellBridge instance ready to handle napplet messages
|
|
745
|
+
* @example
|
|
746
|
+
* ```ts
|
|
747
|
+
* import { createShellBridge, type ShellAdapter } from '@kehto/shell';
|
|
748
|
+
*
|
|
749
|
+
* const hooks: ShellAdapter = {
|
|
750
|
+
* relayPool: myRelayPoolHooks,
|
|
751
|
+
* relayConfig: myRelayConfigHooks,
|
|
752
|
+
* windowManager: myWindowManagerHooks,
|
|
753
|
+
* auth: myAuthHooks,
|
|
754
|
+
* config: myConfigHooks,
|
|
755
|
+
* hotkeys: myHotkeyHooks,
|
|
756
|
+
* workerRelay: myWorkerRelayHooks,
|
|
757
|
+
* crypto: myCryptoHooks,
|
|
758
|
+
* };
|
|
759
|
+
* const bridge = createShellBridge(hooks);
|
|
760
|
+
* ```
|
|
761
|
+
*/
|
|
615
762
|
declare function createShellBridge(hooks: ShellAdapter): ShellBridge;
|
|
616
763
|
|
|
617
764
|
/**
|
|
@@ -1054,11 +1201,12 @@ declare function getShellDomainState(hooks: ShellAdapter, domain: string): Shell
|
|
|
1054
1201
|
* Minimal origin-registry contract used by per-domain proxies.
|
|
1055
1202
|
*
|
|
1056
1203
|
* Accepts the `@kehto/shell` singleton `originRegistry` as well as any test
|
|
1057
|
-
* double with a matching `
|
|
1204
|
+
* double with a matching `postToNapplet` method. NIP-5D carries every NAP
|
|
1205
|
+
* message over the port bound by `napplet.hello`, never the iframe Window.
|
|
1058
1206
|
*/
|
|
1059
1207
|
interface ProxyOriginRegistry {
|
|
1060
|
-
/**
|
|
1061
|
-
|
|
1208
|
+
/** Send one envelope over the window's bound NIP-5D port; `false` when unbound. */
|
|
1209
|
+
postToNapplet(windowId: string, message: unknown): boolean;
|
|
1062
1210
|
}
|
|
1063
1211
|
/**
|
|
1064
1212
|
* Dependencies for `createIdentityProxy`.
|
|
@@ -1074,7 +1222,7 @@ interface ProxyOriginRegistry {
|
|
|
1074
1222
|
interface IdentityProxyDeps {
|
|
1075
1223
|
/** The runtime engine that owns identity.* dispatch (Plan 12-03). */
|
|
1076
1224
|
runtime: Runtime;
|
|
1077
|
-
/** Origin registry
|
|
1225
|
+
/** Origin registry that delivers envelopes over each window's bound port. */
|
|
1078
1226
|
originRegistry: ProxyOriginRegistry;
|
|
1079
1227
|
}
|
|
1080
1228
|
/**
|
|
@@ -1616,4 +1764,4 @@ type ResourceInbound = ResourceInfoRequest | ResourceBytesRequest | ResourceByte
|
|
|
1616
1764
|
*/
|
|
1617
1765
|
type ResourceOutbound = ResourceInfoResult | ResourceInfoError | ResourceBytesResult | ResourceBytesError | ResourceBytesManyResult | ResourceBytesManyError;
|
|
1618
1766
|
|
|
1619
|
-
export { type AclCheckEvent, type AclEntry, type AclStore, type AudioManager, type AudioSource, type AuthHooks, type BleHooks, type BrowserDeps, type CapabilityHooks, type CommonHooks, type ConfigHooks, type CryptoHooks, type DmHooks, type HotkeyHooks, type IdentityProxy, type IdentityProxyDeps, type IntentHooks, type KeysProxy, type KeysProxyDeps, type LinkHooks, type ListsHooks, type LlmHooks, type ManifestCache, type ManifestCacheEntry, type MediaProxy, type MediaProxyDeps, type NappletCspDirective, type NappletCspDirectives, type NappletCspOptions, type NappletNamespacePreludeOptions, type NappletSrcdocOptions, type NormalizedIntentUri, type NotifyProxy, type NotifyProxyDeps, type OriginIdentity, type OriginRegistry, type ProxyOriginRegistry, type RelayConfigHooks, type RelayPoolHooks, type RelayPoolLike, type ResourceBytesError, type ResourceBytesManyError, type ResourceBytesManyItem, type ResourceBytesManyRequest, type ResourceBytesManyResult, type ResourceBytesRequest, type ResourceBytesResult, type ResourceCancelRequest, type ResourceErrorCode, type ResourceInbound, type ResourceInfoError, type ResourceInfoRequest, type ResourceInfoResult, type ResourceOutbound, type ResourceRequestId, type SerialHooks, type SessionRegistry, type ShellAdapter, type ShellBridge, type ShellCapabilities, type ShellDomainState, type ShellEnvironment, type ThemeProxy, type ThemeProxyDeps, type UnroutedMessageInfo, type UploadBackendLike, type UploadHooks, type WebrtcHooks, type WindowManagerHooks, type WorkerRelayHooks, type WorkerRelayLike, adaptHooks, audioManager, buildNappletCsp, buildShellCapabilities, createIdentityProxy, createKeysProxy, createMediaProxy, createNotifyProxy, createShellBridge, createThemeProxy, denyNappletControllerAccess, getShellDomainState, injectNappletCsp, injectNappletNamespacePrelude, manifestCache, nappKeyRegistry, normalizeIntentUri, originRegistry, prepareNappletSrcdoc, renderNappletCspMeta, renderNappletNamespacePrelude, resolveShellEnvironment, sessionRegistry };
|
|
1767
|
+
export { type AclCheckEvent, type AclEntry, type AclStore, type AudioManager, type AudioSource, type AuthHooks, type BleHooks, type BrowserDeps, type CapabilityHooks, type CommonHooks, type ConfigHooks, type CryptoHooks, type DmHooks, type HotkeyHooks, type IdentityProxy, type IdentityProxyDeps, type IntentHooks, type KeysProxy, type KeysProxyDeps, type LinkHooks, type ListsHooks, type LlmHooks, type ManifestCache, type ManifestCacheEntry, type MediaProxy, type MediaProxyDeps, NAPPLET_HELLO, type NappletCspDirective, type NappletCspDirectives, type NappletCspOptions, type NappletMessageTarget, type NappletNamespacePreludeOptions, type NappletRevocation, type NappletRevocationReason, type NappletSrcdocOptions, type NormalizedIntentUri, type NotifyProxy, type NotifyProxyDeps, type OriginIdentity, type OriginRegistry, type ProxyOriginRegistry, type RelayConfigHooks, type RelayPoolHooks, type RelayPoolLike, type ResourceBytesError, type ResourceBytesManyError, type ResourceBytesManyItem, type ResourceBytesManyRequest, type ResourceBytesManyResult, type ResourceBytesRequest, type ResourceBytesResult, type ResourceCancelRequest, type ResourceErrorCode, type ResourceInbound, type ResourceInfoError, type ResourceInfoRequest, type ResourceInfoResult, type ResourceOutbound, type ResourceRequestId, type SerialHooks, type SessionRegistry, type ShellAdapter, type ShellBridge, type ShellCapabilities, type ShellDomainState, type ShellEnvironment, type ThemeProxy, type ThemeProxyDeps, type UnroutedMessageInfo, type UploadBackendLike, type UploadHooks, type WebrtcHooks, type WindowManagerHooks, type WorkerRelayHooks, type WorkerRelayLike, adaptHooks, audioManager, buildNappletCsp, buildShellCapabilities, createIdentityProxy, createKeysProxy, createMediaProxy, createNotifyProxy, createShellBridge, createThemeProxy, denyNappletControllerAccess, getShellDomainState, injectNappletCsp, injectNappletNamespacePrelude, manifestCache, nappKeyRegistry, normalizeIntentUri, originRegistry, prepareNappletSrcdoc, renderNappletCspMeta, renderNappletNamespacePrelude, resolveShellEnvironment, sessionRegistry };
|