@kehto/shell 0.11.1 → 0.12.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 +74 -312
- package/dist/index.js +27 -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';
|
|
@@ -188,36 +188,51 @@ interface AclCheckEvent {
|
|
|
188
188
|
/** The triggering message, if available. Accepts NIP-01 arrays or NIP-5D NappletMessage envelopes. */
|
|
189
189
|
message?: NappletMessage | unknown[];
|
|
190
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Diagnostic payload reported when {@link ShellAdapter.onUnroutedMessage} fires —
|
|
193
|
+
* i.e. when `ShellBridge.handleMessage` drops an incoming postMessage because it
|
|
194
|
+
* cannot be routed to a registered napplet window.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```ts
|
|
198
|
+
* hooks.onUnroutedMessage = (info: UnroutedMessageInfo) => {
|
|
199
|
+
* console.warn(`[shell] dropped ${info.type ?? '<unknown>'} from ${info.origin}: ${info.reason}`);
|
|
200
|
+
* };
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
interface UnroutedMessageInfo {
|
|
204
|
+
/**
|
|
205
|
+
* The dropped message's `type` field when `event.data` is an object with a
|
|
206
|
+
* string `type`; `undefined` for malformed/non-envelope payloads.
|
|
207
|
+
*/
|
|
208
|
+
type?: string;
|
|
209
|
+
/** The `MessageEvent.origin` of the dropped message. */
|
|
210
|
+
origin: string;
|
|
211
|
+
/**
|
|
212
|
+
* Why the message was dropped:
|
|
213
|
+
* - `no-source-window` — the `MessageEvent` had no `source` window to identify the sender.
|
|
214
|
+
* - `unregistered-window` — the source `Window` is not in `originRegistry` (the
|
|
215
|
+
* sending iframe was never registered, or a `srcdoc` reload swapped its
|
|
216
|
+
* `contentWindow` to a new object that no longer matches the registry key).
|
|
217
|
+
*/
|
|
218
|
+
reason: 'no-source-window' | 'unregistered-window';
|
|
219
|
+
}
|
|
191
220
|
/**
|
|
192
221
|
* Static capability set sent to napplet iframes through the shell.ready /
|
|
193
222
|
* shell.init handshake. Used by hosted `window.napplet.shell.supports()` for
|
|
194
223
|
* synchronous capability queries after the shim consumes shell.init.
|
|
195
224
|
*
|
|
196
|
-
* Per canonical NIP-5D (
|
|
197
|
-
* two namespaces:
|
|
225
|
+
* Per canonical NIP-5D (https://github.com/nostr-protocol/nips/pull/2303/),
|
|
226
|
+
* supports() distinguishes two namespaces:
|
|
198
227
|
*
|
|
199
|
-
* - Bare names
|
|
200
|
-
*
|
|
201
|
-
* `supports('identity')`.
|
|
228
|
+
* - Bare names for NAP-capability lookups, resolved against the `naps`
|
|
229
|
+
* array — e.g. `supports('relay')`, `supports('identity')`.
|
|
202
230
|
* - The `perm:<permission>` prefix for sandbox-permission lookups, resolved
|
|
203
231
|
* against the `sandbox` array — e.g. `supports('perm:popups')`,
|
|
204
232
|
* `supports('perm:modals')`.
|
|
205
233
|
*
|
|
206
234
|
* 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.
|
|
235
|
+
* entry and a `perm:`-prefixed lookup never matches a NAP entry.
|
|
221
236
|
*
|
|
222
237
|
* ## Conformant NAP-SHELL shape (TERM-03 — @napplet/core@0.12 / @napplet/shim@0.13)
|
|
223
238
|
*
|
|
@@ -230,8 +245,8 @@ interface AclCheckEvent {
|
|
|
230
245
|
* - `supports('inc','NAP-01')`→ true iff `capabilities.protocols['inc']`
|
|
231
246
|
* includes `'NAP-01'`
|
|
232
247
|
*
|
|
233
|
-
* `domains` and `protocols` are emitted as a SUPERSET ALONGSIDE the
|
|
234
|
-
* `naps`/`
|
|
248
|
+
* `domains` and `protocols` are emitted as a SUPERSET ALONGSIDE the
|
|
249
|
+
* `naps`/`sandbox` fields (TERM-05 back-compat). The 0.13 shim has NO
|
|
235
250
|
* special `perm:` logic — `supports('perm:popups')` is an ordinary bare-domain
|
|
236
251
|
* membership check, so kehto's `perm:`-prefixed sandbox entries are folded into
|
|
237
252
|
* `domains` (empty by default, preserving the default-empty sandbox behavior).
|
|
@@ -262,38 +277,25 @@ interface ShellCapabilities {
|
|
|
262
277
|
protocols: Record<string, string[]>;
|
|
263
278
|
/**
|
|
264
279
|
* NAP-vocabulary domain entries the shell handles (PRIMARY — consumed by
|
|
265
|
-
* `@napplet/shim >=0.9.0`). Bare domain `inc` (the NAP rename of `
|
|
280
|
+
* `@napplet/shim >=0.9.0`). Bare domain `inc` (the NAP rename of `inc`)
|
|
266
281
|
* plus protocol IDs `inc:NAP-01..inc:NAP-06`. Conditional entries:
|
|
267
282
|
* `relay`, `outbox` prepended when a relay pool is wired; `upload` appended
|
|
268
283
|
* when an upload backend is wired; `intent` appended when an intent
|
|
269
284
|
* dispatcher is available.
|
|
270
285
|
*
|
|
271
|
-
* Contains NO `
|
|
286
|
+
* Contains NO `NAP-NN` protocol strings (those live in `protocols`).
|
|
272
287
|
*/
|
|
273
288
|
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
289
|
/**
|
|
288
290
|
* Sandbox permissions under the `perm:<permission>` namespace. Each entry
|
|
289
291
|
* MUST begin with the literal prefix `'perm:'` — e.g. `'perm:popups'`,
|
|
290
292
|
* `'perm:modals'`, `'perm:downloads'`. Napplets call
|
|
291
293
|
* `shell.supports('perm:<permission>')` to check sandbox entitlements.
|
|
292
294
|
*
|
|
293
|
-
* The `perm:` prefix is what separates sandbox permissions from
|
|
295
|
+
* The `perm:` prefix is what separates sandbox permissions from NAP
|
|
294
296
|
* capabilities; bare-name entries here violate the NIP-5D contract and will
|
|
295
|
-
* be unreachable through `supports()` (see
|
|
296
|
-
*
|
|
297
|
+
* be unreachable through `supports()` (see the living NIP-5D at
|
|
298
|
+
* https://github.com/nostr-protocol/nips/pull/2303/). NAP-capability lookups (on `naps`) retain the bare-name
|
|
297
299
|
* convention and do NOT use the `perm:` prefix.
|
|
298
300
|
*/
|
|
299
301
|
sandbox: string[];
|
|
@@ -339,22 +341,24 @@ interface ShellAdapter {
|
|
|
339
341
|
intent?: IntentHooks;
|
|
340
342
|
/** Called on every ACL enforcement check. Both allows and denials are reported. */
|
|
341
343
|
onAclCheck?: (event: AclCheckEvent) => void;
|
|
344
|
+
/**
|
|
345
|
+
* Called when `ShellBridge.handleMessage` drops an incoming postMessage because
|
|
346
|
+
* it cannot be routed to a registered napplet window (no source window, or the
|
|
347
|
+
* source `Window` is not in `originRegistry`). Observe-only — the message is
|
|
348
|
+
* still dropped; this hook exists so otherwise-silent drops are diagnosable
|
|
349
|
+
* (the FEED-02 / hyprgate#21 class of "a napplet's messages vanish" bug).
|
|
350
|
+
*/
|
|
351
|
+
onUnroutedMessage?: (info: UnroutedMessageInfo) => void;
|
|
342
352
|
/** Called when aggregate hash verification fails (computed != declared). */
|
|
343
353
|
onHashMismatch?: (dTag: string, claimed: string, computed: string) => void;
|
|
344
354
|
/**
|
|
345
355
|
* 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.
|
|
356
|
+
* Returns identity metadata for originRegistry.register(). Returning null
|
|
357
|
+
* means "not NIP-5D / skip registration".
|
|
353
358
|
*/
|
|
354
359
|
onNip5dIframeCreate?: (windowId: string) => {
|
|
355
360
|
dTag: string;
|
|
356
361
|
aggregateHash: string;
|
|
357
|
-
class: NappletClass;
|
|
358
362
|
} | null;
|
|
359
363
|
/**
|
|
360
364
|
* Optional service extensions. Each key is a service name (e.g., 'audio',
|
|
@@ -381,146 +385,6 @@ interface ShellAdapter {
|
|
|
381
385
|
getConfigOverrides?(): RuntimeConfigOverrides;
|
|
382
386
|
}
|
|
383
387
|
|
|
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
388
|
/**
|
|
525
389
|
* Shell-side message bridge that handles NIP-5D communication with napplet iframes.
|
|
526
390
|
*
|
|
@@ -548,7 +412,7 @@ interface ShellBridge {
|
|
|
548
412
|
*
|
|
549
413
|
* shell.ready messages are handled locally: the bridge responds with shell.init
|
|
550
414
|
* containing the capability set and registered service list. All other envelopes
|
|
551
|
-
* are delegated to the runtime's
|
|
415
|
+
* are delegated to the runtime's NAP domain dispatch.
|
|
552
416
|
*
|
|
553
417
|
* @param event - The raw MessageEvent from window.addEventListener('message', ...)
|
|
554
418
|
* @example
|
|
@@ -559,7 +423,7 @@ interface ShellBridge {
|
|
|
559
423
|
handleMessage(event: MessageEvent): void;
|
|
560
424
|
/**
|
|
561
425
|
* Inject a shell-originated event into subscription delivery. Under NIP-5D,
|
|
562
|
-
* shell-originated events are forwarded to napplets as
|
|
426
|
+
* shell-originated events are forwarded to napplets as inc.event envelope
|
|
563
427
|
* messages. The runtime's injectEvent() handles the per-session routing.
|
|
564
428
|
*
|
|
565
429
|
* v1.10 hard-removed the v1.8 soft-rename compatibility branch for the
|
|
@@ -640,45 +504,7 @@ interface ShellBridge {
|
|
|
640
504
|
* and manifestCache.
|
|
641
505
|
*/
|
|
642
506
|
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
507
|
}
|
|
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
508
|
declare function createShellBridge(hooks: ShellAdapter): ShellBridge;
|
|
683
509
|
|
|
684
510
|
/**
|
|
@@ -1221,27 +1047,23 @@ declare function adaptHooks(shellHooks: ShellAdapter, deps: BrowserDeps): Runtim
|
|
|
1221
1047
|
/**
|
|
1222
1048
|
* Build the shell's static capability set from adapter configuration.
|
|
1223
1049
|
*
|
|
1224
|
-
* Returns
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1227
|
-
*
|
|
1050
|
+
* Returns the conformant NAP-SHELL `domains`/`protocols` shape (consumed by
|
|
1051
|
+
* `@napplet/shim >=0.13` via `@napplet/nap@0.12`'s `createShellEnvironment` +
|
|
1052
|
+
* `makeSupports`) alongside the flat `naps` array (consumed by
|
|
1053
|
+
* `@napplet/shim >=0.9.0`) and the `sandbox` array.
|
|
1228
1054
|
*
|
|
1229
1055
|
* ### naps array (NAP vocabulary)
|
|
1230
|
-
* Bare domain `inc`
|
|
1056
|
+
* Bare domain `inc` + `inc:NAP-01..inc:NAP-06`.
|
|
1231
1057
|
* Conditional: `relay`+`outbox` prepended when hooks.relayPool;
|
|
1232
1058
|
* `upload` appended when hooks.upload;
|
|
1233
1059
|
* `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
1060
|
*
|
|
1240
1061
|
* Sandbox permissions are left empty by default — host apps may extend after
|
|
1241
1062
|
* construction. Sandbox entries (and any host-app extensions) MUST use the
|
|
1242
1063
|
* canonical `perm:<permission>` form — e.g. `'perm:popups'`, `'perm:modals'`,
|
|
1243
1064
|
* `'perm:downloads'`. Napplets rely on the `perm:` prefix to distinguish
|
|
1244
|
-
* sandbox permissions from
|
|
1065
|
+
* sandbox permissions from NAP-capability lookups; see the living NIP-5D at
|
|
1066
|
+
* https://github.com/nostr-protocol/nips/pull/2303/
|
|
1245
1067
|
*
|
|
1246
1068
|
* ### domains array + protocols map (conformant NAP-SHELL — @napplet/core@0.12)
|
|
1247
1069
|
* The structured shape the released `@napplet/shim@0.13` actually reads via
|
|
@@ -1255,26 +1077,23 @@ declare function adaptHooks(shellHooks: ShellAdapter, deps: BrowserDeps): Runtim
|
|
|
1255
1077
|
* - `protocols` — `{ inc: ['NAP-01'..'NAP-06'] }`, derived from
|
|
1256
1078
|
* `NAP_INC_PROTOCOLS` by stripping the `inc:` prefix.
|
|
1257
1079
|
*
|
|
1258
|
-
* Emitted as a SUPERSET alongside `naps`/`
|
|
1080
|
+
* Emitted as a SUPERSET alongside `naps`/`sandbox` (TERM-05 back-compat).
|
|
1259
1081
|
*
|
|
1260
1082
|
* @param hooks - The ShellAdapter provided by the host app
|
|
1261
1083
|
* @returns ShellCapabilities with domains/protocols (conformant 0.13 shape) plus
|
|
1262
|
-
* naps (NAP vocab)
|
|
1084
|
+
* naps (NAP vocab) and sandbox (perm:-prefixed) arrays
|
|
1263
1085
|
* @example
|
|
1264
1086
|
* ```ts
|
|
1265
1087
|
* const caps = buildShellCapabilities(hooks);
|
|
1266
|
-
* // caps.domains => ['relay','outbox','identity','storage','inc','theme','keys','media','notify','config','resource','
|
|
1088
|
+
* // caps.domains => ['relay','outbox','identity','storage','inc','theme','keys','media','notify','config','resource','cvm']
|
|
1267
1089
|
* // (relay + outbox present when hooks.relayPool is provided; 'upload'/'intent'
|
|
1268
1090
|
* // appended under their hooks; perm:<x> sandbox entries appended when extended)
|
|
1269
1091
|
* // 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','
|
|
1092
|
+
* // caps.naps => ['relay','outbox','identity','storage','inc','theme','keys','media','notify','config','resource','cvm',
|
|
1271
1093
|
* // 'inc:NAP-01','inc:NAP-02','inc:NAP-03','inc:NAP-04','inc:NAP-05','inc:NAP-06']
|
|
1272
1094
|
* // (relay + outbox present when hooks.relayPool is provided; 'upload'
|
|
1273
1095
|
* // 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)
|
|
1096
|
+
* // hooks.intent.isAvailable() is true)
|
|
1278
1097
|
* // caps.sandbox => [] // host app may extend with 'perm:popups', etc.
|
|
1279
1098
|
* ```
|
|
1280
1099
|
*/
|
|
@@ -1738,15 +1557,15 @@ declare function createNotifyProxy(deps: NotifyProxyDeps): NotifyProxy;
|
|
|
1738
1557
|
|
|
1739
1558
|
/**
|
|
1740
1559
|
* keys-forwarder.ts — Shell-side host keydown listener that forwards events
|
|
1741
|
-
* to registered napplets as `keys.forward` envelopes (Plan 12-11,
|
|
1560
|
+
* to registered napplets as `keys.forward` envelopes (Plan 12-11, NAP-05
|
|
1742
1561
|
* shell-side half).
|
|
1743
1562
|
*
|
|
1744
1563
|
* Per `@napplet/nap/keys`, `keys.forward` is fire-and-forget (no result
|
|
1745
|
-
* envelope, no correlation id). Field names follow the
|
|
1564
|
+
* envelope, no correlation id). Field names follow the nap convention:
|
|
1746
1565
|
* `{ ctrl, alt, shift, meta }` — NOT the DOM-style `ctrlKey`/etc.
|
|
1747
1566
|
*
|
|
1748
1567
|
* Capability gate: only forwards to napplets whose ACL grants the
|
|
1749
|
-
* `keys:forward` capability (per Plan 12-10 `
|
|
1568
|
+
* `keys:forward` capability (per Plan 12-10 `resolveCapabilitiesNap` 'keys'
|
|
1750
1569
|
* case). The caller wires the cap-lookup via the `hasKeysForwardCap` dep so
|
|
1751
1570
|
* this module stays free of any direct ACL-store dependency.
|
|
1752
1571
|
*
|
|
@@ -1831,63 +1650,6 @@ interface KeysForwarder {
|
|
|
1831
1650
|
*/
|
|
1832
1651
|
declare function createKeysForwarder(deps: KeysForwarderDeps): KeysForwarder;
|
|
1833
1652
|
|
|
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
1653
|
/**
|
|
1892
1654
|
* @file internal-resource.ts
|
|
1893
1655
|
*
|
|
@@ -1897,8 +1659,8 @@ interface ConnectConsentRequest {
|
|
|
1897
1659
|
* field names (kehto's `requestId` vs upstream `id`; kehto's `bodyBase64` vs
|
|
1898
1660
|
* upstream `blob` + `mime`), different message-type names
|
|
1899
1661
|
* (`ResourceBytesRequest` vs `ResourceBytesMessage`), and disjoint error
|
|
1900
|
-
* vocabularies (kehto:
|
|
1901
|
-
*
|
|
1662
|
+
* vocabularies (kehto: 4 codes `{denied, canceled, network-error, invalid-url}`;
|
|
1663
|
+
* upstream: 8 codes `{not-found, blocked-by-policy,
|
|
1902
1664
|
* timeout, too-large, unsupported-scheme, decode-failed, network-error,
|
|
1903
1665
|
* quota-exceeded}`).
|
|
1904
1666
|
*
|
|
@@ -1954,7 +1716,7 @@ interface ResourceBytesResult {
|
|
|
1954
1716
|
* Canonical typed-error codes for RESOURCE-03 cancel correlation + H-03
|
|
1955
1717
|
* ungranted-origin refusal.
|
|
1956
1718
|
*/
|
|
1957
|
-
type ResourceErrorCode = 'denied' | 'canceled' | 'network-error' | 'invalid-url'
|
|
1719
|
+
type ResourceErrorCode = 'denied' | 'canceled' | 'network-error' | 'invalid-url';
|
|
1958
1720
|
/**
|
|
1959
1721
|
* Outbound: error result — used for both grant-refusal (RESOURCE-01) and
|
|
1960
1722
|
* cancel-correlation (RESOURCE-03) cases.
|
|
@@ -1974,4 +1736,4 @@ type ResourceInbound = ResourceBytesRequest | ResourceCancelRequest;
|
|
|
1974
1736
|
*/
|
|
1975
1737
|
type ResourceOutbound = ResourceBytesResult | ResourceBytesError;
|
|
1976
1738
|
|
|
1977
|
-
export { type AclCheckEvent, type AclEntry, type AudioSource, type AuthHooks, type BrowserDeps, type ConfigHooks, type
|
|
1739
|
+
export { type AclCheckEvent, type AclEntry, type AudioSource, type AuthHooks, type BrowserDeps, 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 };
|