@kehto/shell 0.16.7 → 0.18.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 +99 -15
- package/dist/index.d.ts +146 -621
- package/dist/index.js +593 -215
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @kehto/shell
|
|
2
2
|
|
|
3
|
-
Browser adapter over @kehto/runtime — ShellBridge
|
|
3
|
+
Browser adapter over @kehto/runtime — ShellBridge and domain proxies.
|
|
4
4
|
|
|
5
5
|
> **Alpha status:** Kehto is an early runtime implementation for a draft NIP-5D
|
|
6
6
|
> protocol. NAP contracts and injected-domain behavior are still draft; treat
|
|
@@ -12,6 +12,13 @@ Browser adapter over @kehto/runtime — ShellBridge, domain proxies, keys-forwar
|
|
|
12
12
|
pnpm add @kehto/shell
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
## Published Napplet Compatibility
|
|
16
|
+
|
|
17
|
+
`@kehto/shell` publishes against `@napplet/core` and `@napplet/nap`
|
|
18
|
+
`>=0.29.0 <0.30.0`. The installed core/nap 0.29.0 contracts are from source
|
|
19
|
+
`dd7b3a728eb9c838b7218fcec7bb7bb00e7cc88b` and release
|
|
20
|
+
`60889f1c2476e063500c7ab6624af6abe0dbcbe5`.
|
|
21
|
+
|
|
15
22
|
## Overview
|
|
16
23
|
|
|
17
24
|
`@kehto/shell` is the browser-specific integration layer for kehto. It wraps `@kehto/runtime` with the window/postMessage transport, localStorage persistence hooks, an audio manager, and the five canonical per-domain proxies defined by NIP-5D.
|
|
@@ -21,11 +28,64 @@ The primary entry point is `createShellBridge()` — it owns the postMessage lis
|
|
|
21
28
|
Current draft behaviors this package enforces:
|
|
22
29
|
|
|
23
30
|
- The shell does not inject a host-provided nostr object into napplets — NIP-5D explicitly forbids napplet-visible signing. Napplets call `relay.publish` / `relay.publishEncrypted` and the shell mediates the signing flow internally (NIP-44 default, NIP-04 opt-in for encrypted envelopes).
|
|
24
|
-
- `injectNappletNamespacePrelude()` implements the
|
|
25
|
-
-
|
|
26
|
-
- Five optional per-domain proxies — `createIdentityProxy`, `createThemeProxy`, `createKeysProxy`, `createMediaProxy`, `createNotifyProxy` — can be composed between napplet and runtime to intercept
|
|
27
|
-
-
|
|
28
|
-
- `buildShellCapabilities()` advertises `dm` when the host adapter provides `hooks.dm
|
|
31
|
+
- `injectNappletNamespacePrelude()` implements the NIP-5D injected-domain bootstrap and mandatory NAP-SHELL shim: hosts prepend it to `srcdoc` outside verified artifact bytes, install the parent-bound `shell.init` receiver, emit one `shell.ready`, and expose callable NAP interfaces before authored scripts run. Optional namespaces are filtered to the bare-domain allowlist; `shell` is always retained. Published core 0.29.0 and shim 0.27.0 omit generic mandatory shell, so Kehto retains this host-owned prelude under NAP-SHELL `5ac0490461ca6fec2f0d2e45b4835cf9bc08de24` until an upstream correction is reviewed.
|
|
32
|
+
- `window.napplet.shell.supports(domain)` answers synchronously and locally from the cached first `shell.init` environment. It returns `false` before `shell.init`, for unknown values, and for domains that are not live and granted to that napplet; it never sends a support-query message.
|
|
33
|
+
- Five optional per-domain proxies — `createIdentityProxy`, `createThemeProxy`, `createKeysProxy`, `createMediaProxy`, `createNotifyProxy` — can be composed between napplet and runtime to intercept request traffic per NAP. They are NOT wired by default. Identity/theme proxy `emit()` compatibility members fail closed; hosts must deliver automatic changes through `ShellBridge.publishIdentityChanged()` / `publishTheme()`, which enforce live session, granted domain, and current ACL.
|
|
34
|
+
- `keys.forward` is napplet-to-shell only. Active napplets suppress locally-bound keys from `keys.bindings` before forwarding; shell-initiated action triggers use `keys.action`.
|
|
35
|
+
- `buildShellCapabilities()` advertises only live domains (including `dm` when the host adapter provides `hooks.dm`); disabled domains are absent from the delivered `domains` and named services snapshots.
|
|
36
|
+
|
|
37
|
+
### NAP-INC binding and channel contract
|
|
38
|
+
|
|
39
|
+
The injected INC binding follows merged
|
|
40
|
+
[`naps/NAP-INC.md`](https://github.com/napplet/naps/blob/6461e4b37c29dc09a20dff35d9515889c4433874/naps/NAP-INC.md)
|
|
41
|
+
on `napplet/naps` master
|
|
42
|
+
`6461e4b37c29dc09a20dff35d9515889c4433874`. The specification remains marked
|
|
43
|
+
draft, but its merged path is the protocol authority.
|
|
44
|
+
|
|
45
|
+
The released package projection and `window.napplet.inc` binding own
|
|
46
|
+
query-to-text-payload
|
|
47
|
+
transposition: it converts a convention URI query before emitting a stable,
|
|
48
|
+
exact queryless topic identity. Subscriptions reject query-bearing identities.
|
|
49
|
+
The binding never creates a normalized query-bearing wire/discovery identity,
|
|
50
|
+
does not do prefix/wildcard/query-aware matching or service-over-INC prefix
|
|
51
|
+
dispatch, and does not infer payload kinds. Runtime delivery supplies the
|
|
52
|
+
**runtime-attested dTag**; no caller sender is accepted, topic source exclusion
|
|
53
|
+
is runtime-owned, and IDs and payloads are opaque.
|
|
54
|
+
|
|
55
|
+
Merged NAP-INC delivers one `IncEvent` to `on(topic, callback)`. Released
|
|
56
|
+
`@napplet/nap@0.29.0` instead declares and implements a
|
|
57
|
+
`(payload, NostrEvent)` callback. The protected binding follows the NAP;
|
|
58
|
+
package-based consumers must bridge that upstream callback drift.
|
|
59
|
+
|
|
60
|
+
For channels, runtime ACL checks are open-only rather than per-message. The
|
|
61
|
+
target `inc.channel.opened` before the opener result creates an equivalent target
|
|
62
|
+
handle; `channel.onOpened` exposes it, while symmetric handles expose `on` and
|
|
63
|
+
`onClosed`. The binding retains inbound, early, and terminal lifecycle state in
|
|
64
|
+
order, closes on bounded overflow, and treats teardown as deterministic.
|
|
65
|
+
`channel.list()` is informational only. The downstream tracker is
|
|
66
|
+
[`kehto/web#203`](https://github.com/kehto/web/issues/203), with its [upstream
|
|
67
|
+
resolution reply](https://github.com/kehto/web/issues/203#issuecomment-5060904495);
|
|
68
|
+
the prior opener-only interpretation is obsolete.
|
|
69
|
+
|
|
70
|
+
### NAP-INTENT binding and delivery
|
|
71
|
+
|
|
72
|
+
Phase 104 implements the draft [NAP-INTENT PR #91 at
|
|
73
|
+
`a718915ddefa2f03a0126579601f59d8bd86f7c4`](https://github.com/napplet/naps/pull/91).
|
|
74
|
+
The protected `window.napplet.intent` binding normalizes URI invocation into
|
|
75
|
+
exact `archetype`, `action`, queryless `convention`, and optional payload
|
|
76
|
+
fields. It rejects fragments, malformed/repeated queries, query plus explicit
|
|
77
|
+
payload, mismatched normalized fields, and caller-supplied sender data.
|
|
78
|
+
|
|
79
|
+
Only parent-originated result, change, and delivery envelopes settle the
|
|
80
|
+
binding. Incoming no-ID `intent.deliver` values are retained until an
|
|
81
|
+
`onDelivery` handler is registered. The runtime, not the source, attests the
|
|
82
|
+
sender dTag; an accepted result records retained responsibility and does not
|
|
83
|
+
expose target window, handled, protocol, retry, or lifecycle state.
|
|
84
|
+
|
|
85
|
+
Phase 105 completed released `@napplet/*` package adoption and persistent live
|
|
86
|
+
Paja/playground catalogs and target controllers. The Phase 104 Paja simulator
|
|
87
|
+
and playground catalog builder are historical exact-contract consumers; preserve
|
|
88
|
+
archived planning rather than presenting it as active guidance.
|
|
29
89
|
|
|
30
90
|
## Quick Start
|
|
31
91
|
|
|
@@ -41,7 +101,7 @@ const bridge = createShellBridge({
|
|
|
41
101
|
|
|
42
102
|
// Register a reference service against the underlying runtime.
|
|
43
103
|
bridge.runtime.registerService(
|
|
44
|
-
'
|
|
104
|
+
'notify',
|
|
45
105
|
createNotificationService({ onChange: updateBadge }),
|
|
46
106
|
);
|
|
47
107
|
```
|
|
@@ -68,24 +128,42 @@ const bridge = createShellBridge({
|
|
|
68
128
|
```
|
|
69
129
|
|
|
70
130
|
### Shell init
|
|
71
|
-
- `buildShellCapabilities` — construct the
|
|
131
|
+
- `buildShellCapabilities` — construct the immutable domain-only `ShellCapabilities` payload emitted during the `shell.ready` / `shell.init` handshake
|
|
132
|
+
- `resolveShellEnvironment(hooks, identity)` — host-integrator-only utility that narrows the live environment for a trusted creation-time identity before `shell.init`; it is not installed on `window.napplet` and is not a shim-facing napplet API
|
|
72
133
|
- `injectNappletNamespacePrelude` — insert a host-owned NIP-5D `window.napplet` callable-domain prelude into verified HTML before authored scripts
|
|
73
134
|
- `renderNappletNamespacePrelude` — render only the bootstrap `<script>` for hosts that already own HTML insertion
|
|
74
135
|
|
|
75
136
|
### Domain proxies (NIP-5D composition seams)
|
|
76
|
-
- `createIdentityProxy` — intercept
|
|
77
|
-
- `createThemeProxy` — intercept `theme.get
|
|
137
|
+
- `createIdentityProxy` — intercept identity read requests; direct `emit()` is prohibited
|
|
138
|
+
- `createThemeProxy` — intercept `theme.get`; direct `emit()` is prohibited
|
|
78
139
|
- `createKeysProxy` — intercept `keys.bind/unbind/bindings`
|
|
79
140
|
- `createMediaProxy` — intercept `media.*` playback control
|
|
80
|
-
- `createNotifyProxy` — intercept `notify.send/list/read/dismiss`
|
|
81
141
|
|
|
82
|
-
###
|
|
83
|
-
|
|
142
|
+
### Protected identity and theme delivery
|
|
143
|
+
|
|
144
|
+
The injected identity/theme bindings follow NAP-IDENTITY and NAP-THEME at
|
|
145
|
+
`napplet/naps` master `5ac0490461ca6fec2f0d2e45b4835cf9bc08de24`.
|
|
146
|
+
They are readonly protected objects: identity exposes supported reads and
|
|
147
|
+
`onChanged`, while theme exposes `get` and `onChanged` only. Results and
|
|
148
|
+
automatic changes are accepted only when their `MessageEvent.source` is
|
|
149
|
+
`window.parent`; direct-domain and whole-namespace assignment cannot replace
|
|
150
|
+
the canonical operations.
|
|
151
|
+
|
|
152
|
+
`ShellBridge` delivers `identity.changed` and `theme.changed` exactly once per
|
|
153
|
+
eligible recipient: a live authenticated `shell.ready` session, its frozen
|
|
154
|
+
environment includes the relevant domain, and its current recipient read
|
|
155
|
+
capability is still granted. Identity sign-out is `pubkey: ""`. Theme updates
|
|
156
|
+
arrive only after the service has stored the complete color state. These are
|
|
157
|
+
automatic change messages, not NAP-INC/intent delivery and not a subscription
|
|
158
|
+
protocol. Kehto's denied/unavailable theme read policy is a complete fixed
|
|
159
|
+
normal result without `error`, deliberately avoiding a mixed theme/error
|
|
160
|
+
payload.
|
|
161
|
+
- `createNotifyProxy` — intercept `notify.send/list/read/dismiss`
|
|
84
162
|
|
|
85
163
|
### Session / origin registry
|
|
86
164
|
- `sessionRegistry` — canonical windowId ↔ verified-napplet registry singleton
|
|
87
165
|
- `nappKeyRegistry` — deprecated alias for `sessionRegistry`
|
|
88
|
-
- `originRegistry` — origin-to-windowId map used by proxies and
|
|
166
|
+
- `originRegistry` — origin-to-windowId map used by proxies and bridge broadcasts
|
|
89
167
|
- `PendingUpdate` — type for pending aggregate-hash change prompts
|
|
90
168
|
|
|
91
169
|
### Manifest cache
|
|
@@ -101,7 +179,13 @@ const bridge = createShellBridge({
|
|
|
101
179
|
- `TopicKey`, `TopicValue` — typed topic lookup helpers
|
|
102
180
|
|
|
103
181
|
### Types
|
|
104
|
-
Exported for host-app integration: `ShellAdapter`, `ShellCapabilities`, `RelayPoolHooks`, `RelayPoolLike`, `RelayConfigHooks`, `WindowManagerHooks`, `AuthHooks`, `ConfigHooks`, `HotkeyHooks`, `WorkerRelayHooks`, `WorkerRelayLike`, `CryptoHooks`, `DmHooks`, `UploadHooks`, `IntentHooks`, `LinkHooks`, `CommonHooks`, `ListsHooks`, `SerialHooks`, `BleHooks`, `WebrtcHooks`, `SessionEntry`, `NappKeyEntry` (deprecated), `AclEntry`, `AclCheckEvent`, `UnroutedMessageInfo`, `ServiceDescriptor`, `ServiceHandler`, `ServiceRegistry`, `NostrEvent`, `NostrFilter`, `NappletMessage`, `ConsentRequest`, and per-proxy `*Deps`/`*Proxy` interfaces.
|
|
182
|
+
Exported for host-app integration: `ShellAdapter`, `ShellCapabilities`, `CapabilityHooks`, `OriginIdentity`, `RelayPoolHooks`, `RelayPoolLike`, `RelayConfigHooks`, `WindowManagerHooks`, `AuthHooks`, `ConfigHooks`, `HotkeyHooks`, `WorkerRelayHooks`, `WorkerRelayLike`, `CryptoHooks`, `DmHooks`, `UploadHooks`, `IntentHooks`, `LinkHooks`, `CommonHooks`, `ListsHooks`, `SerialHooks`, `BleHooks`, `WebrtcHooks`, `SessionEntry`, `NappKeyEntry` (deprecated), `AclEntry`, `AclCheckEvent`, `UnroutedMessageInfo`, `ServiceDescriptor`, `ServiceHandler`, `ServiceRegistry`, `NostrEvent`, `NostrFilter`, `NappletMessage`, `ConsentRequest`, and per-proxy `*Deps`/`*Proxy` interfaces.
|
|
183
|
+
|
|
184
|
+
`RelayPoolLike.publish()` may return `Promise<void>` when transport acceptance
|
|
185
|
+
is asynchronous. The shell adapter forwards that promise so the runtime does
|
|
186
|
+
not acknowledge or buffer an event before the relay operation settles.
|
|
187
|
+
`RelayPoolHooks.publishToScopedRelay()` may likewise return
|
|
188
|
+
`Promise<boolean>` so asynchronous hosts report the settled outcome.
|
|
105
189
|
|
|
106
190
|
### Enforcement re-exports (from @kehto/runtime)
|
|
107
191
|
`createEnforceGate`, `createNapEnforceGate`, `formatDenialReason`, plus `EnforceResult`, `EnforceConfig`, `NapEnforceConfig`, `IdentityResolver`, `AclChecker`, `NapMessage`.
|