@kehto/shell 0.11.1 → 0.13.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 +14 -2
- package/dist/index.d.ts +89 -312
- package/dist/index.js +44 -134
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -53,6 +53,18 @@ bridge.runtime.registerService(
|
|
|
53
53
|
### Hooks adapter
|
|
54
54
|
- `adaptHooks` — convert a `ShellAdapter` + `BrowserDeps` into the canonical `RuntimeAdapter` hook bag consumed by `@kehto/runtime`
|
|
55
55
|
|
|
56
|
+
### Diagnostics
|
|
57
|
+
- `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.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const bridge = createShellBridge({
|
|
61
|
+
...myShellAdapter,
|
|
62
|
+
onUnroutedMessage: ({ type, origin, reason }) => {
|
|
63
|
+
console.warn(`[shell] dropped ${type ?? '<unknown>'} from ${origin}: ${reason}`);
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
56
68
|
### Shell init
|
|
57
69
|
- `buildShellCapabilities` — construct the current draft `ShellCapabilities` payload emitted during the `shell.ready` / `shell.init` handshake
|
|
58
70
|
|
|
@@ -85,10 +97,10 @@ bridge.runtime.registerService(
|
|
|
85
97
|
- `TopicKey`, `TopicValue` — typed topic lookup helpers
|
|
86
98
|
|
|
87
99
|
### Types
|
|
88
|
-
Exported for host-app integration: `ShellAdapter`, `ShellCapabilities`, `RelayPoolHooks`, `RelayPoolLike`, `RelayConfigHooks`, `WindowManagerHooks`, `AuthHooks`, `ConfigHooks`, `HotkeyHooks`, `WorkerRelayHooks`, `WorkerRelayLike`, `CryptoHooks`, `DmHooks`, `SessionEntry`, `NappKeyEntry` (deprecated), `AclEntry`, `AclCheckEvent`, `ServiceDescriptor`, `ServiceHandler`, `ServiceRegistry`, `NostrEvent`, `NostrFilter`, `NappletMessage`, `ConsentRequest`, and per-proxy `*Deps`/`*Proxy` interfaces.
|
|
100
|
+
Exported for host-app integration: `ShellAdapter`, `ShellCapabilities`, `RelayPoolHooks`, `RelayPoolLike`, `RelayConfigHooks`, `WindowManagerHooks`, `AuthHooks`, `ConfigHooks`, `HotkeyHooks`, `WorkerRelayHooks`, `WorkerRelayLike`, `CryptoHooks`, `DmHooks`, `SessionEntry`, `NappKeyEntry` (deprecated), `AclEntry`, `AclCheckEvent`, `UnroutedMessageInfo`, `ServiceDescriptor`, `ServiceHandler`, `ServiceRegistry`, `NostrEvent`, `NostrFilter`, `NappletMessage`, `ConsentRequest`, and per-proxy `*Deps`/`*Proxy` interfaces.
|
|
89
101
|
|
|
90
102
|
### Enforcement re-exports (from @kehto/runtime)
|
|
91
|
-
`createEnforceGate`, `
|
|
103
|
+
`createEnforceGate`, `createNapEnforceGate`, `formatDenialReason`, plus `EnforceResult`, `EnforceConfig`, `NapEnforceConfig`, `IdentityResolver`, `AclChecker`, `NapMessage`.
|
|
92
104
|
|
|
93
105
|
### Compat re-exports (DRIFT-CORE-06)
|
|
94
106
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Capability,
|
|
2
|
-
export { ALL_CAPABILITIES, AclChecker, Capability, ConsentRequest, EnforceConfig, EnforceResult, IdentityResolver,
|
|
1
|
+
import { Capability, ServiceRegistry, RuntimeConfigOverrides, ConsentRequest, Runtime, SessionEntry, PendingUpdate, RuntimeAdapter } from '@kehto/runtime';
|
|
2
|
+
export { ALL_CAPABILITIES, AclChecker, Capability, ConsentRequest, EnforceConfig, EnforceResult, IdentityResolver, NapEnforceConfig, NapMessage, NappKeyEntry, PendingUpdate, ServiceDescriptor, ServiceHandler, ServiceRegistry, SessionEntry, createEnforceGate, createNapEnforceGate, formatDenialReason } from '@kehto/runtime';
|
|
3
3
|
import { NappletMessage, NostrEvent, NostrFilter } from '@napplet/core';
|
|
4
4
|
export { NappletMessage, NostrEvent, NostrFilter, TOPICS, TopicKey, TopicValue } from '@napplet/core';
|
|
5
5
|
import { Theme } from '@napplet/nap/theme/types';
|
|
@@ -165,6 +165,17 @@ interface IntentHooks {
|
|
|
165
165
|
/** True when the host has an intent resolver wired and ready to dispatch. */
|
|
166
166
|
isAvailable(): boolean;
|
|
167
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Optional host override for the static shell.init capability handshake.
|
|
170
|
+
*
|
|
171
|
+
* Hosts normally advertise the default Kehto NAP surface. Development hosts may
|
|
172
|
+
* temporarily suppress domains to simulate smaller or policy-constrained shell
|
|
173
|
+
* environments while still using the production shell-ready path.
|
|
174
|
+
*/
|
|
175
|
+
interface CapabilityHooks {
|
|
176
|
+
/** Bare capability domains to remove from domains, naps, and protocols. */
|
|
177
|
+
readonly disabledDomains?: readonly string[];
|
|
178
|
+
}
|
|
168
179
|
/**
|
|
169
180
|
* Event emitted on every ACL enforcement check.
|
|
170
181
|
* @example
|
|
@@ -188,36 +199,51 @@ interface AclCheckEvent {
|
|
|
188
199
|
/** The triggering message, if available. Accepts NIP-01 arrays or NIP-5D NappletMessage envelopes. */
|
|
189
200
|
message?: NappletMessage | unknown[];
|
|
190
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Diagnostic payload reported when {@link ShellAdapter.onUnroutedMessage} fires —
|
|
204
|
+
* i.e. when `ShellBridge.handleMessage` drops an incoming postMessage because it
|
|
205
|
+
* cannot be routed to a registered napplet window.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* hooks.onUnroutedMessage = (info: UnroutedMessageInfo) => {
|
|
210
|
+
* console.warn(`[shell] dropped ${info.type ?? '<unknown>'} from ${info.origin}: ${info.reason}`);
|
|
211
|
+
* };
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
interface UnroutedMessageInfo {
|
|
215
|
+
/**
|
|
216
|
+
* The dropped message's `type` field when `event.data` is an object with a
|
|
217
|
+
* string `type`; `undefined` for malformed/non-envelope payloads.
|
|
218
|
+
*/
|
|
219
|
+
type?: string;
|
|
220
|
+
/** The `MessageEvent.origin` of the dropped message. */
|
|
221
|
+
origin: string;
|
|
222
|
+
/**
|
|
223
|
+
* Why the message was dropped:
|
|
224
|
+
* - `no-source-window` — the `MessageEvent` had no `source` window to identify the sender.
|
|
225
|
+
* - `unregistered-window` — the source `Window` is not in `originRegistry` (the
|
|
226
|
+
* sending iframe was never registered, or a `srcdoc` reload swapped its
|
|
227
|
+
* `contentWindow` to a new object that no longer matches the registry key).
|
|
228
|
+
*/
|
|
229
|
+
reason: 'no-source-window' | 'unregistered-window';
|
|
230
|
+
}
|
|
191
231
|
/**
|
|
192
232
|
* Static capability set sent to napplet iframes through the shell.ready /
|
|
193
233
|
* shell.init handshake. Used by hosted `window.napplet.shell.supports()` for
|
|
194
234
|
* synchronous capability queries after the shim consumes shell.init.
|
|
195
235
|
*
|
|
196
|
-
* Per canonical NIP-5D (
|
|
197
|
-
* two namespaces:
|
|
236
|
+
* Per canonical NIP-5D (https://github.com/nostr-protocol/nips/pull/2303/),
|
|
237
|
+
* supports() distinguishes two namespaces:
|
|
198
238
|
*
|
|
199
|
-
* - Bare names
|
|
200
|
-
*
|
|
201
|
-
* `supports('identity')`.
|
|
239
|
+
* - Bare names for NAP-capability lookups, resolved against the `naps`
|
|
240
|
+
* array — e.g. `supports('relay')`, `supports('identity')`.
|
|
202
241
|
* - The `perm:<permission>` prefix for sandbox-permission lookups, resolved
|
|
203
242
|
* against the `sandbox` array — e.g. `supports('perm:popups')`,
|
|
204
243
|
* `supports('perm:modals')`.
|
|
205
244
|
*
|
|
206
245
|
* The two namespaces do not cross: a bare-name lookup never matches a sandbox
|
|
207
|
-
* entry and a `perm:`-prefixed lookup never matches a
|
|
208
|
-
*
|
|
209
|
-
* ## Dual-emit (back-compat window — D2/D3, ALIGN-01..04)
|
|
210
|
-
*
|
|
211
|
-
* Both `naps` and `nubs` are emitted in the shell.init payload for one
|
|
212
|
-
* back-compat release:
|
|
213
|
-
*
|
|
214
|
-
* - `naps` (PRIMARY) — NAP vocabulary: bare domain `inc`, protocol IDs
|
|
215
|
-
* `inc:NAP-01..inc:NAP-06`. Consumed by `@napplet/shim >=0.9.0`.
|
|
216
|
-
* Contains NO unaliased `ifc` or `NUB-NN` identifiers.
|
|
217
|
-
* - `nubs` (LEGACY) — retains the original `ifc` / `ifc:NUB-01..06` /
|
|
218
|
-
* `ifc:NAP-01` vocabulary for `@napplet/nub` and `<=0.8.x` shims.
|
|
219
|
-
*
|
|
220
|
-
* The dual-emit is intentional; removal is tracked as CLEANUP-01.
|
|
246
|
+
* entry and a `perm:`-prefixed lookup never matches a NAP entry.
|
|
221
247
|
*
|
|
222
248
|
* ## Conformant NAP-SHELL shape (TERM-03 — @napplet/core@0.12 / @napplet/shim@0.13)
|
|
223
249
|
*
|
|
@@ -230,8 +256,8 @@ interface AclCheckEvent {
|
|
|
230
256
|
* - `supports('inc','NAP-01')`→ true iff `capabilities.protocols['inc']`
|
|
231
257
|
* includes `'NAP-01'`
|
|
232
258
|
*
|
|
233
|
-
* `domains` and `protocols` are emitted as a SUPERSET ALONGSIDE the
|
|
234
|
-
* `naps`/`
|
|
259
|
+
* `domains` and `protocols` are emitted as a SUPERSET ALONGSIDE the
|
|
260
|
+
* `naps`/`sandbox` fields (TERM-05 back-compat). The 0.13 shim has NO
|
|
235
261
|
* special `perm:` logic — `supports('perm:popups')` is an ordinary bare-domain
|
|
236
262
|
* membership check, so kehto's `perm:`-prefixed sandbox entries are folded into
|
|
237
263
|
* `domains` (empty by default, preserving the default-empty sandbox behavior).
|
|
@@ -262,38 +288,25 @@ interface ShellCapabilities {
|
|
|
262
288
|
protocols: Record<string, string[]>;
|
|
263
289
|
/**
|
|
264
290
|
* NAP-vocabulary domain entries the shell handles (PRIMARY — consumed by
|
|
265
|
-
* `@napplet/shim >=0.9.0`). Bare domain `inc` (the NAP rename of `
|
|
291
|
+
* `@napplet/shim >=0.9.0`). Bare domain `inc` (the NAP rename of `inc`)
|
|
266
292
|
* plus protocol IDs `inc:NAP-01..inc:NAP-06`. Conditional entries:
|
|
267
293
|
* `relay`, `outbox` prepended when a relay pool is wired; `upload` appended
|
|
268
294
|
* when an upload backend is wired; `intent` appended when an intent
|
|
269
295
|
* dispatcher is available.
|
|
270
296
|
*
|
|
271
|
-
* Contains NO `
|
|
297
|
+
* Contains NO `NAP-NN` protocol strings (those live in `protocols`).
|
|
272
298
|
*/
|
|
273
299
|
naps: string[];
|
|
274
|
-
/**
|
|
275
|
-
* Legacy NUB domain entries the shell handles (retained for one back-compat
|
|
276
|
-
* release — consumed by `@napplet/nub` and `@napplet/shim <=0.8.x`).
|
|
277
|
-
* Vocabulary: `ifc`, `ifc:NUB-01..06`, `ifc:NAP-01`, bare domain names.
|
|
278
|
-
* Contents are unchanged from the pre-0.9.0 release; `naps` is the primary
|
|
279
|
-
* field for new shims. Removal tracked as CLEANUP-01.
|
|
280
|
-
*
|
|
281
|
-
* Entries are bare domain names — `'relay'`, `'identity'`, etc. They MUST NOT
|
|
282
|
-
* carry the `perm:` prefix; that prefix is reserved for the `sandbox` array.
|
|
283
|
-
* Napplets query NUB support via `supports('<domain>')` (or, equivalently,
|
|
284
|
-
* `supports('nub:<domain>')`).
|
|
285
|
-
*/
|
|
286
|
-
nubs: string[];
|
|
287
300
|
/**
|
|
288
301
|
* Sandbox permissions under the `perm:<permission>` namespace. Each entry
|
|
289
302
|
* MUST begin with the literal prefix `'perm:'` — e.g. `'perm:popups'`,
|
|
290
303
|
* `'perm:modals'`, `'perm:downloads'`. Napplets call
|
|
291
304
|
* `shell.supports('perm:<permission>')` to check sandbox entitlements.
|
|
292
305
|
*
|
|
293
|
-
* The `perm:` prefix is what separates sandbox permissions from
|
|
306
|
+
* The `perm:` prefix is what separates sandbox permissions from NAP
|
|
294
307
|
* capabilities; bare-name entries here violate the NIP-5D contract and will
|
|
295
|
-
* be unreachable through `supports()` (see
|
|
296
|
-
*
|
|
308
|
+
* be unreachable through `supports()` (see the living NIP-5D at
|
|
309
|
+
* https://github.com/nostr-protocol/nips/pull/2303/). NAP-capability lookups (on `naps`) retain the bare-name
|
|
297
310
|
* convention and do NOT use the `perm:` prefix.
|
|
298
311
|
*/
|
|
299
312
|
sandbox: string[];
|
|
@@ -337,24 +350,30 @@ interface ShellAdapter {
|
|
|
337
350
|
* concrete service via `registerService('intent')`.
|
|
338
351
|
*/
|
|
339
352
|
intent?: IntentHooks;
|
|
353
|
+
/**
|
|
354
|
+
* Optional capability advertisement override. Omitted by production hosts.
|
|
355
|
+
*/
|
|
356
|
+
capabilities?: CapabilityHooks;
|
|
340
357
|
/** Called on every ACL enforcement check. Both allows and denials are reported. */
|
|
341
358
|
onAclCheck?: (event: AclCheckEvent) => void;
|
|
359
|
+
/**
|
|
360
|
+
* Called when `ShellBridge.handleMessage` drops an incoming postMessage because
|
|
361
|
+
* it cannot be routed to a registered napplet window (no source window, or the
|
|
362
|
+
* source `Window` is not in `originRegistry`). Observe-only — the message is
|
|
363
|
+
* still dropped; this hook exists so otherwise-silent drops are diagnosable
|
|
364
|
+
* (the FEED-02 / hyprgate#21 class of "a napplet's messages vanish" bug).
|
|
365
|
+
*/
|
|
366
|
+
onUnroutedMessage?: (info: UnroutedMessageInfo) => void;
|
|
342
367
|
/** Called when aggregate hash verification fails (computed != declared). */
|
|
343
368
|
onHashMismatch?: (dTag: string, claimed: string, computed: string) => void;
|
|
344
369
|
/**
|
|
345
370
|
* Called at iframe creation for NIP-5D napplets.
|
|
346
|
-
* Returns identity metadata for originRegistry.register()
|
|
347
|
-
*
|
|
348
|
-
* the permissive default (D2). Returning null overall means "not NIP-5D /
|
|
349
|
-
* skip registration" (unchanged semantics from v1.6).
|
|
350
|
-
*
|
|
351
|
-
* BREAKING v1.7: previously `{ dTag, aggregateHash } | null`; now requires
|
|
352
|
-
* `class` in the non-null branch. See .changeset/class-01-breaking-hook.md.
|
|
371
|
+
* Returns identity metadata for originRegistry.register(). Returning null
|
|
372
|
+
* means "not NIP-5D / skip registration".
|
|
353
373
|
*/
|
|
354
374
|
onNip5dIframeCreate?: (windowId: string) => {
|
|
355
375
|
dTag: string;
|
|
356
376
|
aggregateHash: string;
|
|
357
|
-
class: NappletClass;
|
|
358
377
|
} | null;
|
|
359
378
|
/**
|
|
360
379
|
* Optional service extensions. Each key is a service name (e.g., 'audio',
|
|
@@ -381,146 +400,6 @@ interface ShellAdapter {
|
|
|
381
400
|
getConfigOverrides?(): RuntimeConfigOverrides;
|
|
382
401
|
}
|
|
383
402
|
|
|
384
|
-
/**
|
|
385
|
-
* connect-store.ts — NUB-CONNECT grant registry keyed on (dTag, aggregateHash).
|
|
386
|
-
*
|
|
387
|
-
* Mirrors acl-store.ts pattern: module-level singleton, localStorage persistence,
|
|
388
|
-
* composite-key Map. Grants are per-napplet-build: changing the aggregateHash
|
|
389
|
-
* (a rebuild) invalidates prior grants (CONNECT-06) — the composite key makes
|
|
390
|
-
* this structural, not policy-driven.
|
|
391
|
-
*
|
|
392
|
-
* Default policy is RESTRICTIVE (opposite of aclStore): unknown (dTag, hash, origin)
|
|
393
|
-
* combinations return `false` from check() — napplets must be explicitly granted
|
|
394
|
-
* origins via grant(). This is the NUB-CONNECT security invariant.
|
|
395
|
-
*
|
|
396
|
-
* @see packages/shell/src/types/internal-connect.ts for the wire types.
|
|
397
|
-
* @see docs/policies/SHELL-CONNECT-POLICY.md (Plan 39-05) for the full policy.
|
|
398
|
-
*/
|
|
399
|
-
/**
|
|
400
|
-
* Public interface for the NUB-CONNECT grant store singleton.
|
|
401
|
-
*
|
|
402
|
-
* All methods are keyed on (dTag, aggregateHash). A rebuild with a new
|
|
403
|
-
* aggregateHash is a distinct identity — CONNECT-06 hash-upgrade semantics
|
|
404
|
-
* are structurally guaranteed: check(dTag, newHash, origin) returns false
|
|
405
|
-
* because newHash has no entry in the store.
|
|
406
|
-
*/
|
|
407
|
-
interface ConnectStore {
|
|
408
|
-
/**
|
|
409
|
-
* Check whether an origin has been granted for a specific (dTag, aggregateHash).
|
|
410
|
-
*
|
|
411
|
-
* Returns false for unknown (dTag, aggregateHash) pairs — RESTRICTIVE default.
|
|
412
|
-
* Returns false for unknown origins even if the (dTag, hash) pair exists.
|
|
413
|
-
*
|
|
414
|
-
* @param dTag - The napplet's dTag identifier
|
|
415
|
-
* @param aggregateHash - The napplet's build aggregate hash
|
|
416
|
-
* @param origin - The origin to check (e.g., 'https://relay.example.com')
|
|
417
|
-
* @returns true if origin is in the grant set; false otherwise
|
|
418
|
-
*/
|
|
419
|
-
check(dTag: string, aggregateHash: string, origin: string): boolean;
|
|
420
|
-
/**
|
|
421
|
-
* Get all granted origins for a (dTag, aggregateHash) pair.
|
|
422
|
-
*
|
|
423
|
-
* Returns an empty array for unknown (dTag, aggregateHash) pairs.
|
|
424
|
-
*
|
|
425
|
-
* @param dTag - The napplet's dTag identifier
|
|
426
|
-
* @param aggregateHash - The napplet's build aggregate hash
|
|
427
|
-
* @returns Readonly array of granted origin strings; empty if not granted
|
|
428
|
-
*/
|
|
429
|
-
getOrigins(dTag: string, aggregateHash: string): readonly string[];
|
|
430
|
-
/**
|
|
431
|
-
* Grant a set of origins to a (dTag, aggregateHash) pair.
|
|
432
|
-
*
|
|
433
|
-
* Deduplicates and sorts origins for idempotent CSP header output (Plan 39-03).
|
|
434
|
-
* Replaces any existing grant for the same (dTag, aggregateHash) pair.
|
|
435
|
-
* Persists to localStorage automatically.
|
|
436
|
-
*
|
|
437
|
-
* @param dTag - The napplet's dTag identifier
|
|
438
|
-
* @param aggregateHash - The napplet's build aggregate hash
|
|
439
|
-
* @param origins - Origins to grant (e.g., ['https://relay.example.com', 'wss://relay2.example.com'])
|
|
440
|
-
*/
|
|
441
|
-
grant(dTag: string, aggregateHash: string, origins: readonly string[]): void;
|
|
442
|
-
/**
|
|
443
|
-
* Revoke all granted origins for a (dTag, aggregateHash) pair.
|
|
444
|
-
*
|
|
445
|
-
* After revocation, check() returns false and getOrigins() returns [].
|
|
446
|
-
* Persists to localStorage automatically.
|
|
447
|
-
*
|
|
448
|
-
* @param dTag - The napplet's dTag identifier
|
|
449
|
-
* @param aggregateHash - The napplet's build aggregate hash
|
|
450
|
-
*/
|
|
451
|
-
revoke(dTag: string, aggregateHash: string): void;
|
|
452
|
-
/**
|
|
453
|
-
* Get all current grants across all (dTag, aggregateHash) pairs.
|
|
454
|
-
*
|
|
455
|
-
* Used by the Vite CSP plugin (Plan 39-03) to build the connect-src
|
|
456
|
-
* header for each napplet on dev-server startup.
|
|
457
|
-
*
|
|
458
|
-
* @returns Readonly array of all grants
|
|
459
|
-
*/
|
|
460
|
-
getAllGrants(): ReadonlyArray<{
|
|
461
|
-
dTag: string;
|
|
462
|
-
aggregateHash: string;
|
|
463
|
-
origins: readonly string[];
|
|
464
|
-
}>;
|
|
465
|
-
/**
|
|
466
|
-
* Persist the current store state to localStorage under 'napplet:connect'.
|
|
467
|
-
*
|
|
468
|
-
* Tolerates unavailable localStorage (e.g., SSR, private browsing with
|
|
469
|
-
* storage disabled). Called automatically by grant() and revoke().
|
|
470
|
-
*/
|
|
471
|
-
persist(): void;
|
|
472
|
-
/**
|
|
473
|
-
* Load the store state from localStorage.
|
|
474
|
-
*
|
|
475
|
-
* Validates shape before populating; clears store on corrupt data.
|
|
476
|
-
* Should be called once on shell startup before handling any napplet messages.
|
|
477
|
-
*/
|
|
478
|
-
load(): void;
|
|
479
|
-
/**
|
|
480
|
-
* Clear all grants and remove the localStorage entry.
|
|
481
|
-
*
|
|
482
|
-
* Best-effort localStorage removal (tolerates unavailability).
|
|
483
|
-
*/
|
|
484
|
-
clear(): void;
|
|
485
|
-
}
|
|
486
|
-
/**
|
|
487
|
-
* NUB-CONNECT grant store singleton.
|
|
488
|
-
*
|
|
489
|
-
* Module-level instance — import and use directly. Persists under localStorage
|
|
490
|
-
* key 'napplet:connect'. Call `connectStore.load()` on shell startup to restore
|
|
491
|
-
* persisted grants from a previous session.
|
|
492
|
-
*
|
|
493
|
-
* @example
|
|
494
|
-
* ```ts
|
|
495
|
-
* import { connectStore } from '@kehto/shell';
|
|
496
|
-
*
|
|
497
|
-
* // On shell startup:
|
|
498
|
-
* connectStore.load();
|
|
499
|
-
*
|
|
500
|
-
* // On consent approval:
|
|
501
|
-
* connectStore.grant(dTag, aggregateHash, ['https://relay.example.com']);
|
|
502
|
-
*
|
|
503
|
-
* // In Vite CSP plugin (Plan 39-03):
|
|
504
|
-
* const origins = connectStore.getOrigins(dTag, aggregateHash);
|
|
505
|
-
* ```
|
|
506
|
-
*/
|
|
507
|
-
declare const connectStore: ConnectStore;
|
|
508
|
-
/**
|
|
509
|
-
* Compose the canonical `<dTag>:<aggregateHash>` composite key used by the
|
|
510
|
-
* connect-store. Exported for consumers that need to key their own maps by
|
|
511
|
-
* the same identity (e.g., Vite CSP plugin — Plan 39-03).
|
|
512
|
-
*
|
|
513
|
-
* @param dTag - The napplet's dTag identifier
|
|
514
|
-
* @param aggregateHash - The napplet's build aggregate hash
|
|
515
|
-
* @returns Composite key string in `<dTag>:<aggregateHash>` format
|
|
516
|
-
*
|
|
517
|
-
* @example
|
|
518
|
-
* ```ts
|
|
519
|
-
* const key = connectGrantKey('chat', 'abc123'); // 'chat:abc123'
|
|
520
|
-
* ```
|
|
521
|
-
*/
|
|
522
|
-
declare function connectGrantKey(dTag: string, aggregateHash: string): string;
|
|
523
|
-
|
|
524
403
|
/**
|
|
525
404
|
* Shell-side message bridge that handles NIP-5D communication with napplet iframes.
|
|
526
405
|
*
|
|
@@ -548,7 +427,7 @@ interface ShellBridge {
|
|
|
548
427
|
*
|
|
549
428
|
* shell.ready messages are handled locally: the bridge responds with shell.init
|
|
550
429
|
* containing the capability set and registered service list. All other envelopes
|
|
551
|
-
* are delegated to the runtime's
|
|
430
|
+
* are delegated to the runtime's NAP domain dispatch.
|
|
552
431
|
*
|
|
553
432
|
* @param event - The raw MessageEvent from window.addEventListener('message', ...)
|
|
554
433
|
* @example
|
|
@@ -559,7 +438,7 @@ interface ShellBridge {
|
|
|
559
438
|
handleMessage(event: MessageEvent): void;
|
|
560
439
|
/**
|
|
561
440
|
* Inject a shell-originated event into subscription delivery. Under NIP-5D,
|
|
562
|
-
* shell-originated events are forwarded to napplets as
|
|
441
|
+
* shell-originated events are forwarded to napplets as inc.event envelope
|
|
563
442
|
* messages. The runtime's injectEvent() handles the per-session routing.
|
|
564
443
|
*
|
|
565
444
|
* v1.10 hard-removed the v1.8 soft-rename compatibility branch for the
|
|
@@ -640,45 +519,7 @@ interface ShellBridge {
|
|
|
640
519
|
* and manifestCache.
|
|
641
520
|
*/
|
|
642
521
|
readonly runtime: Runtime;
|
|
643
|
-
/**
|
|
644
|
-
* Access the NUB-CONNECT grant store. Per-napplet connect grants are
|
|
645
|
-
* keyed on (dTag, aggregateHash) and persisted under localStorage key
|
|
646
|
-
* 'napplet:connect'. Public API surface for the Vite CSP middleware
|
|
647
|
-
* (Plan 39-03) and the consent flow (Plan 39-04).
|
|
648
|
-
*
|
|
649
|
-
* Default policy is RESTRICTIVE: check() returns false for any origin
|
|
650
|
-
* not explicitly granted. Call load() on shell startup to restore
|
|
651
|
-
* persisted grants from a previous session.
|
|
652
|
-
*
|
|
653
|
-
* @see SHELL-CONNECT-POLICY.md for the full policy.
|
|
654
|
-
*/
|
|
655
|
-
readonly connectStore: ConnectStore;
|
|
656
522
|
}
|
|
657
|
-
/**
|
|
658
|
-
* Create a ShellBridge instance with dependency injection via hooks.
|
|
659
|
-
*
|
|
660
|
-
* Internally creates a Runtime from @kehto/runtime and adapts the
|
|
661
|
-
* browser-oriented ShellAdapter into environment-agnostic RuntimeAdapter.
|
|
662
|
-
*
|
|
663
|
-
* @param hooks - Host application provides relay pool, auth, config, etc.
|
|
664
|
-
* @returns A ShellBridge instance ready to handle napplet messages
|
|
665
|
-
* @example
|
|
666
|
-
* ```ts
|
|
667
|
-
* import { createShellBridge, type ShellAdapter } from '@kehto/shell';
|
|
668
|
-
*
|
|
669
|
-
* const hooks: ShellAdapter = {
|
|
670
|
-
* relayPool: myRelayPoolHooks,
|
|
671
|
-
* relayConfig: myRelayConfigHooks,
|
|
672
|
-
* windowManager: myWindowManagerHooks,
|
|
673
|
-
* auth: myAuthHooks,
|
|
674
|
-
* config: myConfigHooks,
|
|
675
|
-
* hotkeys: myHotkeyHooks,
|
|
676
|
-
* workerRelay: myWorkerRelayHooks,
|
|
677
|
-
* crypto: myCryptoHooks,
|
|
678
|
-
* };
|
|
679
|
-
* const bridge = createShellBridge(hooks);
|
|
680
|
-
* ```
|
|
681
|
-
*/
|
|
682
523
|
declare function createShellBridge(hooks: ShellAdapter): ShellBridge;
|
|
683
524
|
|
|
684
525
|
/**
|
|
@@ -1221,27 +1062,23 @@ declare function adaptHooks(shellHooks: ShellAdapter, deps: BrowserDeps): Runtim
|
|
|
1221
1062
|
/**
|
|
1222
1063
|
* Build the shell's static capability set from adapter configuration.
|
|
1223
1064
|
*
|
|
1224
|
-
* Returns
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1227
|
-
*
|
|
1065
|
+
* Returns the conformant NAP-SHELL `domains`/`protocols` shape (consumed by
|
|
1066
|
+
* `@napplet/shim >=0.13` via `@napplet/nap@0.12`'s `createShellEnvironment` +
|
|
1067
|
+
* `makeSupports`) alongside the flat `naps` array (consumed by
|
|
1068
|
+
* `@napplet/shim >=0.9.0`) and the `sandbox` array.
|
|
1228
1069
|
*
|
|
1229
1070
|
* ### naps array (NAP vocabulary)
|
|
1230
|
-
* Bare domain `inc`
|
|
1071
|
+
* Bare domain `inc` + `inc:NAP-01..inc:NAP-06`.
|
|
1231
1072
|
* Conditional: `relay`+`outbox` prepended when hooks.relayPool;
|
|
1232
1073
|
* `upload` appended when hooks.upload;
|
|
1233
1074
|
* `intent` appended when hooks.intent.isAvailable().
|
|
1234
|
-
* Contains NO `ifc` or `NUB-NN` identifiers.
|
|
1235
|
-
*
|
|
1236
|
-
* ### nubs array (legacy vocabulary)
|
|
1237
|
-
* Bare domain `ifc`, `ifc:NUB-01..06`, `ifc:NAP-01`.
|
|
1238
|
-
* Same conditional appends as naps, using legacy vocabulary.
|
|
1239
1075
|
*
|
|
1240
1076
|
* Sandbox permissions are left empty by default — host apps may extend after
|
|
1241
1077
|
* construction. Sandbox entries (and any host-app extensions) MUST use the
|
|
1242
1078
|
* canonical `perm:<permission>` form — e.g. `'perm:popups'`, `'perm:modals'`,
|
|
1243
1079
|
* `'perm:downloads'`. Napplets rely on the `perm:` prefix to distinguish
|
|
1244
|
-
* sandbox permissions from
|
|
1080
|
+
* sandbox permissions from NAP-capability lookups; see the living NIP-5D at
|
|
1081
|
+
* https://github.com/nostr-protocol/nips/pull/2303/
|
|
1245
1082
|
*
|
|
1246
1083
|
* ### domains array + protocols map (conformant NAP-SHELL — @napplet/core@0.12)
|
|
1247
1084
|
* The structured shape the released `@napplet/shim@0.13` actually reads via
|
|
@@ -1255,26 +1092,23 @@ declare function adaptHooks(shellHooks: ShellAdapter, deps: BrowserDeps): Runtim
|
|
|
1255
1092
|
* - `protocols` — `{ inc: ['NAP-01'..'NAP-06'] }`, derived from
|
|
1256
1093
|
* `NAP_INC_PROTOCOLS` by stripping the `inc:` prefix.
|
|
1257
1094
|
*
|
|
1258
|
-
* Emitted as a SUPERSET alongside `naps`/`
|
|
1095
|
+
* Emitted as a SUPERSET alongside `naps`/`sandbox` (TERM-05 back-compat).
|
|
1259
1096
|
*
|
|
1260
1097
|
* @param hooks - The ShellAdapter provided by the host app
|
|
1261
1098
|
* @returns ShellCapabilities with domains/protocols (conformant 0.13 shape) plus
|
|
1262
|
-
* naps (NAP vocab)
|
|
1099
|
+
* naps (NAP vocab) and sandbox (perm:-prefixed) arrays
|
|
1263
1100
|
* @example
|
|
1264
1101
|
* ```ts
|
|
1265
1102
|
* const caps = buildShellCapabilities(hooks);
|
|
1266
|
-
* // caps.domains => ['relay','outbox','identity','storage','inc','theme','keys','media','notify','config','resource','
|
|
1103
|
+
* // caps.domains => ['relay','outbox','identity','storage','inc','theme','keys','media','notify','config','resource','cvm']
|
|
1267
1104
|
* // (relay + outbox present when hooks.relayPool is provided; 'upload'/'intent'
|
|
1268
1105
|
* // appended under their hooks; perm:<x> sandbox entries appended when extended)
|
|
1269
1106
|
* // caps.protocols => { inc: ['NAP-01','NAP-02','NAP-03','NAP-04','NAP-05','NAP-06'] }
|
|
1270
|
-
* // caps.naps => ['relay','outbox','identity','storage','inc','theme','keys','media','notify','config','resource','
|
|
1107
|
+
* // caps.naps => ['relay','outbox','identity','storage','inc','theme','keys','media','notify','config','resource','cvm',
|
|
1271
1108
|
* // 'inc:NAP-01','inc:NAP-02','inc:NAP-03','inc:NAP-04','inc:NAP-05','inc:NAP-06']
|
|
1272
1109
|
* // (relay + outbox present when hooks.relayPool is provided; 'upload'
|
|
1273
1110
|
* // appended when hooks.upload is provided; 'intent' appended when
|
|
1274
|
-
* // hooks.intent.isAvailable() is true
|
|
1275
|
-
* // caps.nubs => ['relay','outbox','identity','storage','ifc','theme','keys','media','notify','config','resource','connect','class','cvm',
|
|
1276
|
-
* // 'ifc:NAP-01','ifc:NUB-01','ifc:NUB-02','ifc:NUB-03','ifc:NUB-04','ifc:NUB-05','ifc:NUB-06']
|
|
1277
|
-
* // (legacy vocabulary, unchanged for back-compat)
|
|
1111
|
+
* // hooks.intent.isAvailable() is true)
|
|
1278
1112
|
* // caps.sandbox => [] // host app may extend with 'perm:popups', etc.
|
|
1279
1113
|
* ```
|
|
1280
1114
|
*/
|
|
@@ -1738,15 +1572,15 @@ declare function createNotifyProxy(deps: NotifyProxyDeps): NotifyProxy;
|
|
|
1738
1572
|
|
|
1739
1573
|
/**
|
|
1740
1574
|
* keys-forwarder.ts — Shell-side host keydown listener that forwards events
|
|
1741
|
-
* to registered napplets as `keys.forward` envelopes (Plan 12-11,
|
|
1575
|
+
* to registered napplets as `keys.forward` envelopes (Plan 12-11, NAP-05
|
|
1742
1576
|
* shell-side half).
|
|
1743
1577
|
*
|
|
1744
1578
|
* Per `@napplet/nap/keys`, `keys.forward` is fire-and-forget (no result
|
|
1745
|
-
* envelope, no correlation id). Field names follow the
|
|
1579
|
+
* envelope, no correlation id). Field names follow the nap convention:
|
|
1746
1580
|
* `{ ctrl, alt, shift, meta }` — NOT the DOM-style `ctrlKey`/etc.
|
|
1747
1581
|
*
|
|
1748
1582
|
* Capability gate: only forwards to napplets whose ACL grants the
|
|
1749
|
-
* `keys:forward` capability (per Plan 12-10 `
|
|
1583
|
+
* `keys:forward` capability (per Plan 12-10 `resolveCapabilitiesNap` 'keys'
|
|
1750
1584
|
* case). The caller wires the cap-lookup via the `hasKeysForwardCap` dep so
|
|
1751
1585
|
* this module stays free of any direct ACL-store dependency.
|
|
1752
1586
|
*
|
|
@@ -1831,63 +1665,6 @@ interface KeysForwarder {
|
|
|
1831
1665
|
*/
|
|
1832
1666
|
declare function createKeysForwarder(deps: KeysForwarderDeps): KeysForwarder;
|
|
1833
1667
|
|
|
1834
|
-
/**
|
|
1835
|
-
* @file internal-connect.ts
|
|
1836
|
-
*
|
|
1837
|
-
* Kehto-internal shell-side connect-store + consent-flow types. Per
|
|
1838
|
-
* PROJECT.md Decision #31, this is NOT a staging-ground duplicate of upstream
|
|
1839
|
-
* `@napplet/nap/connect`: upstream exports a napplet-side accessor interface
|
|
1840
|
-
* (`NappletConnect = { granted, origins }`) plus the shared
|
|
1841
|
-
* `normalizeConnectOrigin` pure validator. Kehto's types here describe the
|
|
1842
|
-
* shell's grant-store records (`ConnectGrant`, `ConnectGrantKey`,
|
|
1843
|
-
* `ConsentResult`), used by the connect-store singleton and the Vite CSP
|
|
1844
|
-
* plugin's consent flow.
|
|
1845
|
-
*
|
|
1846
|
-
* The two surfaces are complementary: upstream's accessor type ships at the
|
|
1847
|
-
* napplet boundary; kehto's grant-store types live shell-side. No retirement
|
|
1848
|
-
* planned. For canonical origin validation (kehto has no local impl;
|
|
1849
|
-
* Decision #32), consume `@napplet/nap/connect`'s `normalizeConnectOrigin`
|
|
1850
|
-
* directly.
|
|
1851
|
-
*
|
|
1852
|
-
* Downstream consumers (Phase 39 `connect-store.ts`, Vite CSP middleware,
|
|
1853
|
-
* consent flow UI) import from this module.
|
|
1854
|
-
*/
|
|
1855
|
-
/**
|
|
1856
|
-
* Grant key composed from the napplet's dTag and build aggregateHash. A hash
|
|
1857
|
-
* upgrade invalidates prior grants (CONNECT-06).
|
|
1858
|
-
*/
|
|
1859
|
-
interface ConnectGrantKey {
|
|
1860
|
-
dTag: string;
|
|
1861
|
-
aggregateHash: string;
|
|
1862
|
-
}
|
|
1863
|
-
/**
|
|
1864
|
-
* A persisted connect grant. Stored in the shell connect-store singleton,
|
|
1865
|
-
* surfaced as the CSP `connect-src` origin list for the corresponding napplet.
|
|
1866
|
-
*/
|
|
1867
|
-
interface ConnectGrant {
|
|
1868
|
-
/** Composite key `"<dTag>:<aggregateHash>"` under which this grant is stored. */
|
|
1869
|
-
key: string;
|
|
1870
|
-
/** The set of origins (WebSocket and HTTPS) the napplet is granted to connect to. */
|
|
1871
|
-
origins: readonly string[];
|
|
1872
|
-
/** Epoch millis when the grant was approved by the user. */
|
|
1873
|
-
grantedAt: number;
|
|
1874
|
-
}
|
|
1875
|
-
/**
|
|
1876
|
-
* Consent flow outcome. `'dismiss'` resolves to deny (MUST NOT default to allow).
|
|
1877
|
-
* `'timeout'` also resolves to deny.
|
|
1878
|
-
*/
|
|
1879
|
-
type ConsentResult = 'approve' | 'deny' | 'dismiss' | 'timeout';
|
|
1880
|
-
/**
|
|
1881
|
-
* Inbound consent request from a napplet requesting connect access to one or
|
|
1882
|
-
* more origins.
|
|
1883
|
-
*/
|
|
1884
|
-
interface ConnectConsentRequest {
|
|
1885
|
-
dTag: string;
|
|
1886
|
-
aggregateHash: string;
|
|
1887
|
-
/** Origins the napplet is asking to be granted access to. */
|
|
1888
|
-
requestedOrigins: readonly string[];
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
1668
|
/**
|
|
1892
1669
|
* @file internal-resource.ts
|
|
1893
1670
|
*
|
|
@@ -1897,8 +1674,8 @@ interface ConnectConsentRequest {
|
|
|
1897
1674
|
* field names (kehto's `requestId` vs upstream `id`; kehto's `bodyBase64` vs
|
|
1898
1675
|
* upstream `blob` + `mime`), different message-type names
|
|
1899
1676
|
* (`ResourceBytesRequest` vs `ResourceBytesMessage`), and disjoint error
|
|
1900
|
-
* vocabularies (kehto:
|
|
1901
|
-
*
|
|
1677
|
+
* vocabularies (kehto: 4 codes `{denied, canceled, network-error, invalid-url}`;
|
|
1678
|
+
* upstream: 8 codes `{not-found, blocked-by-policy,
|
|
1902
1679
|
* timeout, too-large, unsupported-scheme, decode-failed, network-error,
|
|
1903
1680
|
* quota-exceeded}`).
|
|
1904
1681
|
*
|
|
@@ -1954,7 +1731,7 @@ interface ResourceBytesResult {
|
|
|
1954
1731
|
* Canonical typed-error codes for RESOURCE-03 cancel correlation + H-03
|
|
1955
1732
|
* ungranted-origin refusal.
|
|
1956
1733
|
*/
|
|
1957
|
-
type ResourceErrorCode = 'denied' | 'canceled' | 'network-error' | 'invalid-url'
|
|
1734
|
+
type ResourceErrorCode = 'denied' | 'canceled' | 'network-error' | 'invalid-url';
|
|
1958
1735
|
/**
|
|
1959
1736
|
* Outbound: error result — used for both grant-refusal (RESOURCE-01) and
|
|
1960
1737
|
* cancel-correlation (RESOURCE-03) cases.
|
|
@@ -1974,4 +1751,4 @@ type ResourceInbound = ResourceBytesRequest | ResourceCancelRequest;
|
|
|
1974
1751
|
*/
|
|
1975
1752
|
type ResourceOutbound = ResourceBytesResult | ResourceBytesError;
|
|
1976
1753
|
|
|
1977
|
-
export { type AclCheckEvent, type AclEntry, type AudioSource, type AuthHooks, type BrowserDeps, type
|
|
1754
|
+
export { type AclCheckEvent, type AclEntry, type AudioSource, type AuthHooks, type BrowserDeps, type CapabilityHooks, type ConfigHooks, type CryptoHooks, type DmHooks, type HotkeyHooks, type IdentityProxy, type IdentityProxyDeps, type IntentHooks, type KeysForwarder, type KeysForwarderDeps, type KeysForwarderOriginRegistry, type KeysForwarderSessionRegistry, type KeysProxy, type KeysProxyDeps, type ManifestCacheEntry, type MediaProxy, type MediaProxyDeps, type NotifyProxy, type NotifyProxyDeps, type ProxyOriginRegistry, type RelayConfigHooks, type RelayPoolHooks, type RelayPoolLike, type ResourceBytesError, type ResourceBytesRequest, type ResourceBytesResult, type ResourceCancelRequest, type ResourceErrorCode, type ResourceInbound, type ResourceOutbound, type ResourceRequestId, type ShellAdapter, type ShellBridge, type ShellCapabilities, type ThemeProxy, type ThemeProxyDeps, type UnroutedMessageInfo, type UploadBackendLike, type UploadHooks, type WindowManagerHooks, type WorkerRelayHooks, type WorkerRelayLike, adaptHooks, audioManager, buildShellCapabilities, createIdentityProxy, createKeysForwarder, createKeysProxy, createMediaProxy, createNotifyProxy, createShellBridge, createThemeProxy, manifestCache, nappKeyRegistry, originRegistry, sessionRegistry };
|