@kehto/shell 0.19.2 → 0.20.1

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,9 +15,11 @@ 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/nap 0.31.0 contracts are from source
19
- `7b675622e13870628ce174833d7b2a33cf32a0ab` and release
20
- `03ad65b66413e5798536ef48695ffc4c2508f2c3`.
18
+ `>=0.31.0 <0.32.0`. The installed core 0.31.1 / nap 0.31.2 contracts follow
19
+ NAP-INTENT authority `5ac0490461ca6fec2f0d2e45b4835cf9bc08de24`, napplet/web#199
20
+ source `3037200c932488f14f7f369b8583c39c9c16510a` / merge
21
+ `b3f0007867eac109fa4917fac9c285d3b7cc6155`, and Version Packages #198 release
22
+ source `dc1d24153c759152b6ba31a6ec9bea967798f2df`.
21
23
 
22
24
  ## Overview
23
25
 
@@ -28,11 +30,15 @@ The primary entry point is `createShellBridge()` — it owns the postMessage lis
28
30
  Current draft behaviors this package enforces:
29
31
 
30
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).
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.31.0 and shim 0.29.0 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.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.
32
38
  - `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
39
  - 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
40
  - `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.
41
+ - `buildShellCapabilities()` advertises only live domains. Registered `dm` and `fs` services are injected only when their handlers exist; disabled domains are absent from the delivered `domains` and named services snapshots.
36
42
 
37
43
  ### NAP-INC binding and channel contract
38
44
 
@@ -54,7 +60,7 @@ dispatch, and does not infer payload kinds. Runtime delivery supplies the
54
60
  **runtime-attested dTag**; no caller sender is accepted, topic source exclusion
55
61
  is runtime-owned, and IDs and payloads are opaque.
56
62
 
57
- Merged NAP-INC and released `@napplet/nap@0.31.0` both deliver one `IncEvent`
63
+ Merged NAP-INC and released `@napplet/nap@0.31.2` both deliver one `IncEvent`
58
64
  to `on(topic, callback)`.
59
65
 
60
66
  For channels, runtime ACL checks are open-only rather than per-message. The
package/dist/index.d.ts CHANGED
@@ -132,8 +132,15 @@ interface WindowManagerHooks {
132
132
  interface AuthHooks {
133
133
  /** Get the current user's pubkey, or null if not logged in. */
134
134
  getUserPubkey(): string | null;
135
- /** Get the NIP-07 compatible signer, or null if unavailable. */
136
- getSigner(): any | null;
135
+ /**
136
+ * Get the NIP-07 compatible signer, or null if unavailable.
137
+ *
138
+ * The optional window ID lets a shell bind its own signer policy to the
139
+ * requesting napplet without imposing that policy in Kehto.
140
+ *
141
+ * @param windowId - Originating napplet window, when available
142
+ */
143
+ getSigner(windowId?: string): any | null;
137
144
  }
138
145
  /** Hook for config. */
139
146
  interface ConfigHooks {
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
  }
@@ -999,7 +999,8 @@ var SERVICE_ONLY_DOMAINS = [
999
999
  "ble",
1000
1000
  "webrtc",
1001
1001
  "dm",
1002
- "count"
1002
+ "count",
1003
+ "fs"
1003
1004
  ];
1004
1005
  function buildShellCapabilities(hooks) {
1005
1006
  const disabled = new Set(hooks.capabilities?.disabledDomains ?? []);
@@ -1046,8 +1047,6 @@ function isServiceDomainLive(hooks, domain) {
1046
1047
  return hooks.ble?.isAvailable() === true;
1047
1048
  case "webrtc":
1048
1049
  return hooks.webrtc?.isAvailable() === true;
1049
- case "dm":
1050
- return hooks.dm !== void 0;
1051
1050
  default:
1052
1051
  return true;
1053
1052
  }
@@ -2433,6 +2432,30 @@ function nappletNamespacePrelude(domains) {
2433
2432
  }
2434
2433
  };
2435
2434
  }
2435
+ function makeFs() {
2436
+ const withOptions = (payload, options) => {
2437
+ if (options !== void 0) payload.options = options;
2438
+ return payload;
2439
+ };
2440
+ const req = (action, payload, map) => request({ type: `fs.${action}`, ...payload }, `fs.${action}.result`, map);
2441
+ return {
2442
+ info: () => req("info", {}, (msg) => fieldOrThrow(msg, "info", "fs.info.result missing info")),
2443
+ pickFile: (options) => req("pickFile", withOptions({}, options), (msg) => fieldOrThrow(msg, "result", "fs.pickFile.result missing result")),
2444
+ pickFiles: (options) => req("pickFiles", withOptions({}, options), (msg) => fieldOrThrow(msg, "result", "fs.pickFiles.result missing result")),
2445
+ pickDirectory: (options) => req("pickDirectory", withOptions({}, options), (msg) => fieldOrThrow(msg, "result", "fs.pickDirectory.result missing result")),
2446
+ pickSaveFile: (options) => req("pickSaveFile", withOptions({}, options), (msg) => fieldOrThrow(msg, "result", "fs.pickSaveFile.result missing result")),
2447
+ stat: (path) => req("stat", { path }, (msg) => fieldOrThrow(msg, "metadata", "fs.stat.result missing metadata")),
2448
+ list: (path) => req("list", { path }, (msg) => fieldOrThrow(msg, "entries", "fs.list.result missing entries")),
2449
+ read: (path, options) => req("read", withOptions({ path }, options), (msg) => fieldOrThrow(msg, "result", "fs.read.result missing result")),
2450
+ write: (path, data, options) => req("write", withOptions({ path, data }, options), (msg) => fieldOrThrow(msg, "result", "fs.write.result missing result")),
2451
+ mkdir: (path, options) => req("mkdir", withOptions({ path }, options), (msg) => voidResult(msg, "fs mkdir failed")),
2452
+ remove: (path, recursive) => req("remove", { path, ...recursive === void 0 ? {} : { recursive } }, (msg) => voidResult(msg, "fs remove failed")),
2453
+ move: (fromPath, toPath) => req("move", { fromPath, toPath }, (msg) => voidResult(msg, "fs move failed")),
2454
+ watch: (path, options) => req("watch", withOptions({ path }, options), (msg) => fieldOrThrow(msg, "watchId", "fs.watch.result missing watchId")),
2455
+ unwatch: (watchId) => req("unwatch", { watchId }, (msg) => voidResult(msg, "fs unwatch failed")),
2456
+ onChanged: (callback) => domainEventHandle("fs.changed", callback, (msg) => msg.change)
2457
+ };
2458
+ }
2436
2459
  const shell = makeShell();
2437
2460
  let inc;
2438
2461
  let identity;
@@ -2502,6 +2525,8 @@ function nappletNamespacePrelude(domains) {
2502
2525
  return makeSerial();
2503
2526
  case "dm":
2504
2527
  return makeDm();
2528
+ case "fs":
2529
+ return makeFs();
2505
2530
  default:
2506
2531
  return {};
2507
2532
  }