@kehto/shell 0.20.0 → 0.21.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Browser adapter over @kehto/runtime — ShellBridge and domain proxies.
4
4
 
5
- > **Alpha status:** Kehto is an early runtime implementation for a draft NIP-5D
5
+ > **Alpha status:** Kehto is an early runtime toolkit for a draft NIP-5D
6
6
  > protocol. NAP contracts and injected-domain behavior are still draft; treat
7
7
  > this package as current implementation guidance.
8
8
 
@@ -15,7 +15,7 @@ pnpm add @kehto/shell
15
15
  ## Published Napplet Compatibility
16
16
 
17
17
  `@kehto/shell` publishes against `@napplet/core` and `@napplet/nap`
18
- `>=0.31.0 <0.32.0`. The installed core 0.31.1 / nap 0.31.2 contracts follow
18
+ `>=0.32.0 <0.33.0`. The installed core 0.32.0 / nap 0.32.0 contracts follow
19
19
  NAP-INTENT authority `5ac0490461ca6fec2f0d2e45b4835cf9bc08de24`, napplet/web#199
20
20
  source `3037200c932488f14f7f369b8583c39c9c16510a` / merge
21
21
  `b3f0007867eac109fa4917fac9c285d3b7cc6155`, and Version Packages #198 release
@@ -30,7 +30,12 @@ The primary entry point is `createShellBridge()` — it owns the postMessage lis
30
30
  Current draft behaviors this package enforces:
31
31
 
32
32
  - 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).
33
- - `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.31.1 and shim 0.29.2 omit generic mandatory shell, so Kehto retains this host-owned prelude under NAP-SHELL `5ac0490461ca6fec2f0d2e45b4835cf9bc08de24` until an upstream correction is reviewed.
33
+ - `AuthHooks.getSigner(windowId?)` receives the originating iframe window ID
34
+ when the runtime can identify it. The shell forwards this optional context
35
+ without imposing a consent policy; host runtimes may ignore it or use it to
36
+ resolve their own identity-scoped signer decisions.
37
+ - `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.32.0 and shim 0.30.0 omit generic mandatory shell, so Kehto retains this host-owned prelude under NAP-SHELL `5ac0490461ca6fec2f0d2e45b4835cf9bc08de24` until an upstream correction is reviewed.
38
+ - The injected resource projection follows draft NAP-RESOURCE `9511232f69313aa7953d110e35d32cc28d506f66`: `bytes(url, { servers? })` carries advisory Blossom locations and `bytesMany(requests)` keeps each `{ url, servers? }` entry intact.
34
39
  - `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.
35
40
  - 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.
36
41
  - `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`.
@@ -56,7 +61,7 @@ dispatch, and does not infer payload kinds. Runtime delivery supplies the
56
61
  **runtime-attested dTag**; no caller sender is accepted, topic source exclusion
57
62
  is runtime-owned, and IDs and payloads are opaque.
58
63
 
59
- Merged NAP-INC and released `@napplet/nap@0.31.2` both deliver one `IncEvent`
64
+ Merged NAP-INC and released `@napplet/nap@0.32.0` both deliver one `IncEvent`
60
65
  to `on(topic, callback)`.
61
66
 
62
67
  For channels, runtime ACL checks are open-only rather than per-message. The
package/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@ export { ALL_CAPABILITIES, AclChecker, Capability, ConsentRequest, EnforceConfig
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';
6
+ import { ResourceBytesItem, ResourceBytesRequest as ResourceBytesRequest$1, ResourceInfo } from '@napplet/nap/resource/types';
7
+ export { ResourceInfo } from '@napplet/nap/resource/types';
6
8
 
7
9
  /** NIP-5D identity metadata associated with a registered iframe window. */
8
10
  interface OriginIdentity {
@@ -132,8 +134,15 @@ interface WindowManagerHooks {
132
134
  interface AuthHooks {
133
135
  /** Get the current user's pubkey, or null if not logged in. */
134
136
  getUserPubkey(): string | null;
135
- /** Get the NIP-07 compatible signer, or null if unavailable. */
136
- getSigner(): any | null;
137
+ /**
138
+ * Get the NIP-07 compatible signer, or null if unavailable.
139
+ *
140
+ * The optional window ID lets a shell bind its own signer policy to the
141
+ * requesting napplet without imposing that policy in Kehto.
142
+ *
143
+ * @param windowId - Originating napplet window, when available
144
+ */
145
+ getSigner(windowId?: string): any | null;
137
146
  }
138
147
  /** Hook for config. */
139
148
  interface ConfigHooks {
@@ -1296,15 +1305,11 @@ declare function createNotifyProxy(deps: NotifyProxyDeps): NotifyProxy;
1296
1305
  * @file internal-resource.ts
1297
1306
  *
1298
1307
  * Kehto-internal shell-side resource wire types. Per PROJECT.md Decision #31,
1299
- * this is NOT a staging-ground duplicate of upstream `@napplet/nap/resource`:
1300
- * Phase 44 audit confirmed the two surfaces diverge substantively — different
1301
- * field names (kehto's legacy `requestId` vs upstream `id`; kehto's legacy
1302
- * `bodyBase64` vs upstream `blob` + `mime`), different message-type names
1303
- * (`ResourceBytesRequest` vs `ResourceBytesMessage`), and disjoint error
1304
- * vocabularies (kehto: 4 codes `{denied, canceled, network-error, invalid-url}`;
1305
- * upstream: 8 codes `{not-found, blocked-by-policy,
1306
- * timeout, too-large, unsupported-scheme, decode-failed, network-error,
1307
- * quota-exceeded}`).
1308
+ * this is NOT a staging-ground duplicate of upstream `@napplet/nap/resource`.
1309
+ * Canonical resource info, per-resource request, and result-item shapes are
1310
+ * imported from the published package. The remaining local envelopes retain
1311
+ * Kehto's legacy compatibility fields (`requestId`, `bodyBase64`, status, and
1312
+ * headers) alongside the current `id`, `blob`, and `mime` fields.
1308
1313
  *
1309
1314
  * `resource-service.ts` now emits both legacy single-fetch compatibility
1310
1315
  * fields and the current upstream-compatible fields.
@@ -1315,20 +1320,12 @@ declare function createNotifyProxy(deps: NotifyProxyDeps): NotifyProxy;
1315
1320
  * resource.bytes.result, resource.bytes.error,
1316
1321
  * resource.bytesMany.result, resource.bytesMany.error
1317
1322
  */
1323
+
1318
1324
  /**
1319
1325
  * Unique id for correlating a `resource.bytes` request to its later result /
1320
1326
  * error / cancel envelope.
1321
1327
  */
1322
1328
  type ResourceRequestId = string;
1323
- /** Advisory resource capability and policy limits disclosed by the runtime. */
1324
- interface ResourceInfo {
1325
- schemes: readonly {
1326
- scheme: string;
1327
- enabled: boolean;
1328
- }[];
1329
- maxBytes?: number;
1330
- maxUrls?: number;
1331
- }
1332
1329
  /** Inbound: napplet asks for advisory resource policy and scheme support. */
1333
1330
  interface ResourceInfoRequest {
1334
1331
  type: 'resource.info';
@@ -1346,6 +1343,8 @@ interface ResourceBytesRequest {
1346
1343
  /** Legacy Kehto correlation ID. */
1347
1344
  requestId?: ResourceRequestId;
1348
1345
  url: string;
1346
+ /** Advisory Blossom server locations. Ignored for other schemes. */
1347
+ servers?: readonly string[];
1349
1348
  /** Optional subset of fetch init (method, headers). Body bytes are shell-proxy-internal. */
1350
1349
  init?: {
1351
1350
  method?: string;
@@ -1370,7 +1369,7 @@ interface ResourceCancelRequest {
1370
1369
  interface ResourceBytesManyRequest {
1371
1370
  type: 'resource.bytesMany';
1372
1371
  id: ResourceRequestId;
1373
- urls: readonly string[];
1372
+ requests: readonly ResourceBytesRequest$1[];
1374
1373
  }
1375
1374
  /**
1376
1375
  * Outbound: successful fetch result.
@@ -1413,17 +1412,7 @@ interface ResourceBytesError {
1413
1412
  /**
1414
1413
  * Current NAP-RESOURCE bulk result item.
1415
1414
  */
1416
- type ResourceBytesManyItem = {
1417
- url: string;
1418
- ok: true;
1419
- blob: Blob;
1420
- mime: string;
1421
- } | {
1422
- url: string;
1423
- ok: false;
1424
- error: string;
1425
- message?: string;
1426
- };
1415
+ type ResourceBytesManyItem = ResourceBytesItem;
1427
1416
  /**
1428
1417
  * Outbound: ordered bulk fetch result.
1429
1418
  */
@@ -1463,4 +1452,4 @@ type ResourceInbound = ResourceInfoRequest | ResourceBytesRequest | ResourceByte
1463
1452
  */
1464
1453
  type ResourceOutbound = ResourceInfoResult | ResourceInfoError | ResourceBytesResult | ResourceBytesError | ResourceBytesManyResult | ResourceBytesManyError;
1465
1454
 
1466
- 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 ManifestCache, type ManifestCacheEntry, type MediaProxy, type MediaProxyDeps, type NappletNamespacePreludeOptions, 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 ResourceInfo, type ResourceInfoError, type ResourceInfoRequest, type ResourceInfoResult, type ResourceOutbound, type ResourceRequestId, type SerialHooks, type SessionRegistry, type ShellAdapter, type ShellBridge, type ShellCapabilities, type ShellEnvironment, type ThemeProxy, type ThemeProxyDeps, type UnroutedMessageInfo, type UploadBackendLike, type UploadHooks, type WebrtcHooks, type WindowManagerHooks, type WorkerRelayHooks, type WorkerRelayLike, adaptHooks, audioManager, buildShellCapabilities, createIdentityProxy, createKeysProxy, createMediaProxy, createNotifyProxy, createShellBridge, createThemeProxy, injectNappletNamespacePrelude, manifestCache, nappKeyRegistry, originRegistry, renderNappletNamespacePrelude, resolveShellEnvironment, sessionRegistry };
1455
+ 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 ManifestCache, type ManifestCacheEntry, type MediaProxy, type MediaProxyDeps, type NappletNamespacePreludeOptions, 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 ShellEnvironment, type ThemeProxy, type ThemeProxyDeps, type UnroutedMessageInfo, type UploadBackendLike, type UploadHooks, type WebrtcHooks, type WindowManagerHooks, type WorkerRelayHooks, type WorkerRelayLike, adaptHooks, audioManager, buildShellCapabilities, createIdentityProxy, createKeysProxy, createMediaProxy, createNotifyProxy, createShellBridge, createThemeProxy, injectNappletNamespacePrelude, manifestCache, nappKeyRegistry, originRegistry, renderNappletNamespacePrelude, resolveShellEnvironment, sessionRegistry };
package/dist/index.js CHANGED
@@ -88,8 +88,8 @@ function createAuthAdapter(shellHooks) {
88
88
  getUserPubkey() {
89
89
  return shellHooks.auth.getUserPubkey();
90
90
  },
91
- getSigner() {
92
- return shellHooks.auth.getSigner();
91
+ getSigner(windowId) {
92
+ return shellHooks.auth.getSigner(windowId);
93
93
  }
94
94
  };
95
95
  }
@@ -2071,11 +2071,21 @@ function nappletNamespacePrelude(domains) {
2071
2071
  }
2072
2072
  function makeResource() {
2073
2073
  const objectUrls = /* @__PURE__ */ new Set();
2074
- const bytes = (url) => request({ type: "resource.bytes", url }, "resource.bytes.result", (msg) => msg.blob);
2074
+ const bytes = (url, options) => request({
2075
+ type: "resource.bytes",
2076
+ url,
2077
+ ...Array.isArray(options?.servers) ? { servers: Array.from(options.servers) } : {}
2078
+ }, "resource.bytes.result", (msg) => msg.blob);
2075
2079
  return {
2076
2080
  info: () => request({ type: "resource.info" }, "resource.info.result", (msg) => msg.info),
2077
2081
  bytes,
2078
- bytesMany: (urls) => request({ type: "resource.bytesMany", urls }, "resource.bytesMany.result", (msg) => Array.isArray(msg.items) ? msg.items : []),
2082
+ bytesMany: (requests) => request({
2083
+ type: "resource.bytesMany",
2084
+ requests: Array.from(requests || [], (entry) => ({
2085
+ url: entry.url,
2086
+ ...Array.isArray(entry.servers) ? { servers: Array.from(entry.servers) } : {}
2087
+ }))
2088
+ }, "resource.bytesMany.result", (msg) => Array.isArray(msg.items) ? msg.items : []),
2079
2089
  bytesAsObjectURL(url) {
2080
2090
  let objectUrl = "";
2081
2091
  const handle = {