@toon-protocol/client-mcp 0.1.0 → 0.3.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.
Files changed (36) hide show
  1. package/README.md +19 -38
  2. package/dist/app/index.html +166 -0
  3. package/dist/{chunk-5KFXUT5Q.js → chunk-CQ2QIZ6Z.js} +864 -604
  4. package/dist/chunk-CQ2QIZ6Z.js.map +1 -0
  5. package/dist/{chunk-FSS45ZX3.js → chunk-DLYE6U2Z.js} +1516 -316
  6. package/dist/chunk-DLYE6U2Z.js.map +1 -0
  7. package/dist/{chunk-3NAWISI5.js → chunk-QFHCXJ2V.js} +348 -101
  8. package/dist/chunk-QFHCXJ2V.js.map +1 -0
  9. package/dist/chunk-XV52IHVR.js +977 -0
  10. package/dist/chunk-XV52IHVR.js.map +1 -0
  11. package/dist/daemon.js +3 -4
  12. package/dist/daemon.js.map +1 -1
  13. package/dist/e2e/run-journey.d.ts +1 -0
  14. package/dist/e2e/run-journey.js +19953 -0
  15. package/dist/e2e/run-journey.js.map +1 -0
  16. package/dist/{ed25519-2QVPINLS.js → ed25519-2LFQXLYS.js} +6 -2
  17. package/dist/index.d.ts +282 -68
  18. package/dist/index.js +380 -5
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp.js +39 -6
  21. package/dist/mcp.js.map +1 -1
  22. package/package.json +11 -7
  23. package/dist/anon-proxy-W3KMM7GU-FN7ZJY7P.js +0 -25
  24. package/dist/chunk-3NAWISI5.js.map +0 -1
  25. package/dist/chunk-5KFXUT5Q.js.map +0 -1
  26. package/dist/chunk-FSS45ZX3.js.map +0 -1
  27. package/dist/chunk-SKQTKZIH.js +0 -278
  28. package/dist/chunk-SKQTKZIH.js.map +0 -1
  29. package/dist/chunk-ZQKYZJWT.js +0 -359
  30. package/dist/chunk-ZQKYZJWT.js.map +0 -1
  31. package/dist/ed25519-2QVPINLS.js.map +0 -1
  32. package/dist/gateway-QOK47RKS-SEGTXBR3.js +0 -16
  33. package/dist/gateway-QOK47RKS-SEGTXBR3.js.map +0 -1
  34. package/dist/socks5-WTJBYGME-6COK4LXW.js +0 -139
  35. package/dist/socks5-WTJBYGME-6COK4LXW.js.map +0 -1
  36. /package/dist/{anon-proxy-W3KMM7GU-FN7ZJY7P.js.map → ed25519-2LFQXLYS.js.map} +0 -0
@@ -3,25 +3,29 @@ import {
3
3
  ED25519_TORSION_SUBGROUP,
4
4
  _map_to_curve_elligator2_curve25519,
5
5
  ed25519,
6
+ ed25519_FROST,
6
7
  ed25519_hasher,
7
8
  ed25519ctx,
8
9
  ed25519ph,
9
10
  ristretto255,
11
+ ristretto255_FROST,
10
12
  ristretto255_hasher,
11
13
  ristretto255_oprf,
12
14
  x25519
13
- } from "./chunk-FSS45ZX3.js";
15
+ } from "./chunk-DLYE6U2Z.js";
14
16
  import "./chunk-F22GNSF6.js";
15
17
  export {
16
18
  ED25519_TORSION_SUBGROUP,
17
19
  _map_to_curve_elligator2_curve25519,
18
20
  ed25519,
21
+ ed25519_FROST,
19
22
  ed25519_hasher,
20
23
  ed25519ctx,
21
24
  ed25519ph,
22
25
  ristretto255,
26
+ ristretto255_FROST,
23
27
  ristretto255_hasher,
24
28
  ristretto255_oprf,
25
29
  x25519
26
30
  };
27
- //# sourceMappingURL=ed25519-2QVPINLS.js.map
31
+ //# sourceMappingURL=ed25519-2LFQXLYS.js.map
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { NostrEvent } from 'nostr-tools/pure';
1
+ import { NostrEvent, EventTemplate } from 'nostr-tools/pure';
2
2
  import { SwapPair } from '@toon-protocol/core';
3
3
  import { ToonClientConfig } from '@toon-protocol/client';
4
4
  import { FastifyInstance } from 'fastify';
5
+ import { ViewSpec } from '@toon-protocol/views';
5
6
 
6
7
  /**
7
8
  * Shared request/response contract for the `toon-clientd` localhost control
@@ -27,8 +28,8 @@ interface StatusResponse {
27
28
  /** Daemon process uptime, ms. */
28
29
  uptimeMs: number;
29
30
  /**
30
- * True while the managed anon proxy / BTP session / channel are still coming
31
- * up. Tools should surface "bootstrapping — retry" rather than blocking.
31
+ * True while the BTP session / channel are still coming up. Tools should
32
+ * surface "bootstrapping — retry" rather than blocking.
32
33
  */
33
34
  bootstrapping: boolean;
34
35
  /** True once the client has started and a channel is open (ready to publish). */
@@ -42,8 +43,7 @@ interface StatusResponse {
42
43
  minaAddress?: string;
43
44
  };
44
45
  transport: {
45
- type: 'direct' | 'socks5' | 'gateway';
46
- socksProxy?: string;
46
+ type: 'direct';
47
47
  btpUrl?: string;
48
48
  };
49
49
  relay: {
@@ -53,13 +53,6 @@ interface StatusResponse {
53
53
  buffered: number;
54
54
  /** Active subscription ids. */
55
55
  subscriptions: string[];
56
- /**
57
- * Error from the daemon-managed read proxy, if any. Set only in the
58
- * btp-direct + relay-`.anyone` case where the daemon starts its own `anon`
59
- * proxy for reads; a failure here means hidden-service reads are down while
60
- * direct paid writes are unaffected.
61
- */
62
- proxyError?: string;
63
56
  };
64
57
  /** Per-chain settlement status when a named `network` tier is configured. */
65
58
  network?: ChainStatus[];
@@ -90,6 +83,58 @@ interface PublishResponse {
90
83
  /** Channel nonce after this publish (advances by one per paid write). */
91
84
  nonce: number;
92
85
  }
86
+ /**
87
+ * `POST /publish-unsigned` — build, SIGN (with the daemon-held key), and
88
+ * pay-to-write a Nostr event. The caller (a UI/agent) supplies only the event
89
+ * shell — it never holds the private key. For replaceable kinds (0 profile,
90
+ * 3 follow list) the daemon merges the latest known event's tags before signing.
91
+ */
92
+ interface PublishUnsignedRequest {
93
+ /** Event kind to publish (integer, 0–65535). */
94
+ kind: number;
95
+ /** Event content (default ''). */
96
+ content?: string;
97
+ /** Event tags (array of string arrays). */
98
+ tags?: string[][];
99
+ /** ILP destination override (default: the configured apex/town address). */
100
+ destination?: string;
101
+ /** Fee override in base units. Defaults to the daemon's configured fee. */
102
+ fee?: string;
103
+ /** Which apex (BTP write target) to publish through (default: config-seeded). */
104
+ btpUrl?: string;
105
+ }
106
+ /**
107
+ * `POST /upload-media` — two-step spendy write: upload bytes to Arweave via the
108
+ * kind:5094 blob-storage DVM, then sign+publish a media event referencing the
109
+ * resulting Arweave URL. Single-packet only (large media is out of scope; see
110
+ * `requestBlobStorage`).
111
+ */
112
+ interface UploadMediaRequest {
113
+ /** Base64-encoded media bytes. */
114
+ dataBase64: string;
115
+ /** MIME type (default 'application/octet-stream'). */
116
+ mime?: string;
117
+ /**
118
+ * Kind of the media event to publish referencing the upload. Default 1063
119
+ * (NIP-94 file metadata). 20 = NIP-68 picture, 21/22 = NIP-71 video, 1 = note
120
+ * with a NIP-92 `imeta` attachment.
121
+ */
122
+ kind?: number;
123
+ /** Caption / content for the published media event. */
124
+ caption?: string;
125
+ /** Extra tags merged into the published media event. */
126
+ tags?: string[][];
127
+ /** Fee override in base units (applies to the upload + the publish). */
128
+ fee?: string;
129
+ /** Which apex to publish through (default: config-seeded). */
130
+ btpUrl?: string;
131
+ }
132
+ interface UploadMediaResponse extends PublishResponse {
133
+ /** Arweave URL the media event references. */
134
+ url: string;
135
+ /** Arweave transaction id of the uploaded blob. */
136
+ txId: string;
137
+ }
93
138
  /** `POST /subscribe` — register a persistent free-read subscription. */
94
139
  interface SubscribeRequest {
95
140
  /** NIP-01 filter(s). A single object or an array of OR-ed filters. */
@@ -108,6 +153,18 @@ interface SubscribeResponse {
108
153
  /** The relays the subscription was registered on. */
109
154
  relays: string[];
110
155
  }
156
+ /**
157
+ * `POST /query` — one-shot free read: subscribe the filter(s), wait briefly, and
158
+ * return every buffered event matching them. Used by the apps `toon_query` tool.
159
+ */
160
+ interface QueryRequest {
161
+ filters: NostrFilter | NostrFilter[];
162
+ /** Bounded wait for relay delivery, ms (default 1200). */
163
+ timeoutMs?: number;
164
+ }
165
+ interface QueryResponse {
166
+ events: NostrEvent[];
167
+ }
111
168
  /** `GET /events` — drain buffered events for a subscription (free read). */
112
169
  interface EventsQuery {
113
170
  /** Restrict to a single subscription id. */
@@ -211,9 +268,39 @@ interface SwapResponse {
211
268
  /** First rejection message, if any. */
212
269
  message?: string;
213
270
  }
271
+ /**
272
+ * `POST /http-fetch-paid` — payment-aware HTTP GET/POST. The daemon issues the
273
+ * request via `ToonClient.h402Fetch`; if the origin answers `402 Payment
274
+ * Required` the client transparently pays over TOON and retries, returning the
275
+ * settled resource. The caller never holds chain keys — settlement happens
276
+ * inside the daemon against the open apex channel.
277
+ */
278
+ interface HttpFetchPaidRequest {
279
+ /** Absolute URL of the resource to fetch (the origin may gate it behind 402). */
280
+ url: string;
281
+ /** HTTP method (default GET). */
282
+ method?: string;
283
+ /** Request headers as a flat string→string map. */
284
+ headers?: Record<string, string>;
285
+ /** Request body (string; sent verbatim). Typically used with POST. */
286
+ body?: string;
287
+ /** Per-request timeout, ms (passed through to the client). */
288
+ timeout?: number;
289
+ }
290
+ interface HttpFetchPaidResponse {
291
+ /** Final HTTP status after any 402-pay-and-retry round trip. */
292
+ status: number;
293
+ /** Response headers as a flat string→string map. */
294
+ headers: Record<string, string>;
295
+ /**
296
+ * Response body decoded as text. Binary bodies are returned as their decoded
297
+ * text for v1 (acceptable; a base64 path can be added later if needed).
298
+ */
299
+ body: string;
300
+ }
214
301
  /** `POST /relays` — add a relay READ target (fans into all fan-out reads). */
215
302
  interface AddRelayRequest {
216
- /** Relay WS URL, e.g. `ws://host:7100` or a `.anyone` hidden service. */
303
+ /** Relay WS URL, e.g. `ws://host:7100`. */
217
304
  relayUrl: string;
218
305
  }
219
306
  /** `DELETE /relays` — remove a relay read target. */
@@ -337,13 +424,17 @@ declare class ControlClient {
337
424
  ping(): Promise<boolean>;
338
425
  status(): Promise<StatusResponse>;
339
426
  publish(body: PublishRequest): Promise<PublishResponse>;
427
+ publishUnsigned(body: PublishUnsignedRequest): Promise<PublishResponse>;
428
+ uploadMedia(body: UploadMediaRequest): Promise<UploadMediaResponse>;
340
429
  subscribe(body: SubscribeRequest): Promise<SubscribeResponse>;
430
+ query(body: QueryRequest): Promise<QueryResponse>;
341
431
  events(query?: EventsQuery): Promise<EventsResponse>;
342
432
  openChannel(body?: OpenChannelRequest): Promise<{
343
433
  channelId: string;
344
434
  }>;
345
435
  channels(): Promise<ChannelsResponse>;
346
436
  swap(body: SwapRequest): Promise<SwapResponse>;
437
+ httpFetchPaid(body: HttpFetchPaidRequest): Promise<HttpFetchPaidResponse>;
347
438
  targets(): Promise<TargetsResponse>;
348
439
  addRelay(body: AddRelayRequest): Promise<TargetsResponse>;
349
440
  removeRelay(body: RemoveRelayRequest): Promise<TargetsResponse>;
@@ -363,9 +454,7 @@ declare class ControlClient {
363
454
  * with exponential backoff and re-issues every active REQ on reconnect.
364
455
  *
365
456
  * The WebSocket is injectable (`wsFactory`) so unit tests can drive the wire
366
- * protocol without a real relay; the default factory uses the `ws` package and,
367
- * when a `socks5h://` proxy is configured, routes through it so `.anyone`
368
- * hidden-service relays are reachable.
457
+ * protocol without a real relay; the default factory uses the `ws` package.
369
458
  */
370
459
 
371
460
  /** Minimal WebSocket surface this module depends on (subset of `ws`). */
@@ -378,10 +467,8 @@ interface MinimalWebSocket {
378
467
  }
379
468
  type WebSocketFactory = (url: string) => MinimalWebSocket;
380
469
  interface RelaySubscriptionOptions {
381
- /** Town relay WS URL, e.g. `wss://<host>.anyone/` or `ws://localhost:7100`. */
470
+ /** Town relay WS URL, e.g. `ws://localhost:7100`. */
382
471
  relayUrl: string;
383
- /** Optional `socks5h://host:port` proxy for `.anyone` relays. */
384
- socksProxy?: string;
385
472
  /** Max events retained in the ring buffer (oldest evicted). Default 5000. */
386
473
  bufferSize?: number;
387
474
  /** Base reconnect delay, ms. Default 1000. */
@@ -416,7 +503,6 @@ interface DrainResult {
416
503
  }
417
504
  declare class RelaySubscription {
418
505
  private readonly relayUrl;
419
- private readonly socksProxy?;
420
506
  private readonly bufferSize;
421
507
  private readonly reconnectBaseMs;
422
508
  private readonly reconnectMaxMs;
@@ -527,12 +613,19 @@ interface DaemonConfigFile {
527
613
  _help?: Record<string, string>;
528
614
  /** BTP WebSocket URL of the apex/connector. */
529
615
  btpUrl?: string;
530
- /** Transport: `direct` or a `socks5h://` proxy for `.anyone` hosts. */
531
- socksProxy?: string;
532
- /** Auto-manage the anon proxy for `.anyone` BTP hosts. Default true for HS. */
533
- managedAnonProxy?: boolean;
534
- /** Loopback SOCKS port the managed anon proxy binds (also used for reads). Default 9050. */
535
- managedAnonSocksPort?: number;
616
+ /**
617
+ * Connector-PROXY base URL (devnet payment-proxy, e.g.
618
+ * `https://proxy.devnet.toonprotocol.dev`). When set, the daemon routes paid
619
+ * writes through the proxy's `POST /ilp` (ILP-over-HTTP) WITHOUT a BTP socket;
620
+ * `btpUrl` then becomes optional. Env override: `TOON_CLIENT_PROXY_URL`.
621
+ */
622
+ proxyUrl?: string;
623
+ /**
624
+ * Devnet faucet base URL (e.g. `https://faucet.devnet.toonprotocol.dev`),
625
+ * carried through to the ToonClient config for tooling/e2e funding. Env
626
+ * override: `TOON_CLIENT_FAUCET_URL`.
627
+ */
628
+ faucetUrl?: string;
536
629
  /** Town relay WS URL for FREE reads. */
537
630
  relayUrl?: string;
538
631
  /** Default ILP publish destination. Default `g.townhouse.town`. */
@@ -580,16 +673,17 @@ interface DaemonConfigFile {
580
673
  interface ResolvedDaemonConfig {
581
674
  httpPort: number;
582
675
  relayUrl: string;
583
- socksProxy?: string;
584
676
  /**
585
- * When true the daemon must start its OWN managed `anon` proxy for free reads
586
- * the btp-direct + relay-`.anyone` case the ToonClient does not cover (it
587
- * only auto-starts a proxy for a `.anyone` btpUrl). `readProxySocksPort` is the
588
- * loopback port to bind; `socksProxy` already points the relay at it.
677
+ * Whether a write uplink (proxy or BTP) is configured. FREE reads work
678
+ * without one; a write attempt with `hasUplink === false` is rejected at the
679
+ * control plane with a clear "configure an uplink" error (issue #69). Reads
680
+ * (`subscribe`/`query`/`getEvents`) never consult this.
589
681
  */
590
- manageReadProxy: boolean;
591
- /** Loopback SOCKS port for the daemon-managed read proxy (when `manageReadProxy`). */
592
- readProxySocksPort?: number;
682
+ hasUplink: boolean;
683
+ /** Connector-proxy base URL (devnet payment-proxy), when configured. */
684
+ proxyUrl?: string;
685
+ /** Devnet faucet base URL, when configured. */
686
+ faucetUrl?: string;
593
687
  destination: string;
594
688
  feePerEvent: bigint;
595
689
  apex?: ApexNegotiationConfig;
@@ -622,8 +716,9 @@ declare function resolveMnemonic(file: DaemonConfigFile): string;
622
716
  /**
623
717
  * Build the full resolved daemon config (file overlaid with env, mnemonic
624
718
  * resolved, ToonClientConfig assembled). Env overrides supported:
625
- * TOON_CLIENT_BTP_URL, TOON_CLIENT_RELAY_URL, TOON_CLIENT_SOCKS,
626
- * TOON_CLIENT_HTTP_PORT, TOON_CLIENT_NETWORK.
719
+ * TOON_CLIENT_BTP_URL, TOON_CLIENT_PROXY_URL, TOON_CLIENT_FAUCET_URL,
720
+ * TOON_CLIENT_RELAY_URL, TOON_CLIENT_HTTP_PORT, TOON_CLIENT_NETWORK,
721
+ * TOON_CLIENT_DESTINATION.
627
722
  */
628
723
  declare function resolveConfig(file: DaemonConfigFile): ResolvedDaemonConfig;
629
724
 
@@ -643,8 +738,8 @@ declare function resolveConfig(file: DaemonConfigFile): ResolvedDaemonConfig;
643
738
  * relay + apex are the permanent DEFAULT targets and cannot be removed.
644
739
  *
645
740
  * Each apex bootstraps asynchronously and non-blocking: the connection comes up
646
- * in the background (the managed anon proxy alone can take 30–90s). Until ready,
647
- * writes against it report `bootstrapping` so tools surface "retry".
741
+ * in the background. Until ready, writes against it report `bootstrapping` so
742
+ * tools surface "retry".
648
743
  */
649
744
 
650
745
  /** The subset of `ToonClient` the runner depends on. */
@@ -674,6 +769,28 @@ interface ToonClientLike {
674
769
  error?: string;
675
770
  }>;
676
771
  signBalanceProof(channelId: string, amount: bigint): Promise<unknown>;
772
+ /**
773
+ * Sign an unsigned event template with the daemon-held Nostr key (the key
774
+ * never leaves the daemon). Backs the `publish-unsigned` / `upload-media`
775
+ * paths so a UI/agent supplies only the event shell.
776
+ */
777
+ signEvent(template: EventTemplate): NostrEvent | Promise<NostrEvent>;
778
+ /**
779
+ * Upload bytes to Arweave via the kind:5094 blob-storage DVM (single-packet),
780
+ * returning the Arweave tx id. Reuses the client's claim/channel plumbing.
781
+ */
782
+ uploadBlob(params: {
783
+ blobData: Uint8Array;
784
+ contentType?: string;
785
+ bid?: string;
786
+ destination?: string;
787
+ ilpAmount?: bigint;
788
+ }): Promise<{
789
+ success: boolean;
790
+ txId?: string;
791
+ eventId?: string;
792
+ error?: string;
793
+ }>;
677
794
  openChannel(destination?: string): Promise<string>;
678
795
  getTrackedChannels(): string[];
679
796
  getChannelNonce(channelId: string): number;
@@ -689,22 +806,25 @@ interface ToonClientLike {
689
806
  code?: string;
690
807
  message?: string;
691
808
  }>;
809
+ /**
810
+ * Payment-aware HTTP fetch: issue the request and, on a `402 Payment
811
+ * Required`, transparently pay over TOON and retry, returning the settled Web
812
+ * `Response`. Pinned to the `ToonClient.h402Fetch` shape (issue #50).
813
+ */
814
+ h402Fetch(url: string, opts?: {
815
+ method?: string;
816
+ headers?: Record<string, string>;
817
+ body?: string | Uint8Array;
818
+ timeout?: number;
819
+ destination?: string;
820
+ }): Promise<Response>;
692
821
  }
693
822
  /** A started managed proxy: just the teardown handle the runner needs. */
694
- interface ManagedProxyHandle {
695
- stop(): Promise<void>;
696
- }
697
- /** Starts a managed `anon` read proxy on a loopback SOCKS port. */
698
- type StartReadProxy = (opts: {
699
- socksPort: number;
700
- log?: (msg: string) => void;
701
- }) => Promise<ManagedProxyHandle>;
702
823
  /** Builds a `ToonClient` (or a fake) for a given resolved client config. */
703
824
  type CreateClient = (config: ToonClientConfig) => ToonClientLike;
704
- /** Builds a `RelaySubscription` for a given relay URL + optional read proxy. */
825
+ /** Builds a `RelaySubscription` for a given relay URL. */
705
826
  type CreateRelay = (opts: {
706
827
  relayUrl: string;
707
- socksProxy?: string;
708
828
  onEvent: (subId: string, event: NostrEvent) => void;
709
829
  logger?: (msg: string) => void;
710
830
  }) => RelaySubscription;
@@ -714,11 +834,6 @@ interface ClientRunnerDeps {
714
834
  createClient: CreateClient;
715
835
  /** Factory producing a relay subscription (defaults to the real one). */
716
836
  createRelay?: CreateRelay;
717
- /**
718
- * Starts the daemon-managed read proxy (defaults to the real
719
- * `startManagedAnonProxy`). Injected so tests avoid the anon download/spawn.
720
- */
721
- startReadProxy?: StartReadProxy;
722
837
  logger?: (msg: string) => void;
723
838
  /** Path to the dynamic-targets store (tests override). */
724
839
  targetsPath?: string;
@@ -727,7 +842,6 @@ declare class ClientRunner {
727
842
  private readonly config;
728
843
  private readonly createClient;
729
844
  private readonly createRelay;
730
- private readonly startReadProxy;
731
845
  private readonly log;
732
846
  private readonly targetsPath?;
733
847
  private readonly startedAt;
@@ -747,9 +861,6 @@ declare class ClientRunner {
747
861
  private subIdCounter;
748
862
  private readonly defaultBtpUrl;
749
863
  private readonly defaultRelayUrl;
750
- /** Teardown for the daemon-managed read proxy (btp-direct + relay-`.anyone`). */
751
- private stopReadProxy;
752
- private readProxyError;
753
864
  private stopped;
754
865
  private started;
755
866
  constructor(deps: ClientRunnerDeps);
@@ -768,8 +879,7 @@ declare class ClientRunner {
768
879
  */
769
880
  private registerRelay;
770
881
  /**
771
- * Add a relay read target at runtime. `.anyone` relays reuse the managed read
772
- * proxy (started here if needed). Persisted unless `persist` is false.
882
+ * Add a relay read target at runtime. Persisted unless `persist` is false.
773
883
  */
774
884
  addRelay(relayUrl: string, persist?: boolean): Promise<void>;
775
885
  /** Remove a relay read target. The config-seeded default cannot be removed. */
@@ -781,6 +891,16 @@ declare class ClientRunner {
781
891
  * every relay (and onto relays added later); with one it targets that relay.
782
892
  */
783
893
  subscribe(req: SubscribeRequest): SubscribeResponse;
894
+ /**
895
+ * One-shot free read: subscribe the given filter(s) across all relays, wait a
896
+ * bounded window for the relay(s) to deliver, then return every buffered event
897
+ * matching the filter (matched by content, not subId — so events already
898
+ * buffered by other subscriptions are included despite the global dedup).
899
+ *
900
+ * Backs the apps `toon_query` tool the generative-UI runtime calls to resolve
901
+ * a ViewSpec node's data bind.
902
+ */
903
+ query(filters: NostrFilter | NostrFilter[], timeoutMs?: number): Promise<NostrEvent[]>;
784
904
  /** Drain merged events newer than the cursor (free read), optionally scoped. */
785
905
  getEvents(query: EventsQuery): EventsResponse;
786
906
  private makeApex;
@@ -804,10 +924,27 @@ declare class ClientRunner {
804
924
  private deriveApexClientConfig;
805
925
  private apexChannelStorePathFor;
806
926
  private replayPersistedTargets;
807
- private ensureReadProxy;
808
- private bringUpReadProxy;
809
- /** Open the apex channel — or, on a restart, RESUME the existing one. */
927
+ /**
928
+ * Open the apex channel — or, on a restart, RESUME the existing one.
929
+ *
930
+ * With `resumeOnly`, only a persisted channel is resumed (no on-chain open);
931
+ * returns undefined when none exists so the caller can defer the open to the
932
+ * first write (funded-after-start demo flow, #69).
933
+ */
810
934
  private openOrResumeApexChannel;
935
+ /**
936
+ * Persist a (lazily- or eagerly-) opened apex channel so a restart RESUMES it
937
+ * (tracked, no re-deposit) rather than opening a second on-chain channel.
938
+ * No-op when the apex carries no negotiation (nothing to key the store on).
939
+ */
940
+ private persistApexChannel;
941
+ /**
942
+ * Discover the apex's settlement negotiation from its kind:10032 on the
943
+ * default relay and attach it to the apex (proxy-mode fallback when no config
944
+ * negotiation was supplied, #69). Throws ApexDiscoveryError on timeout/missing
945
+ * settlement params so the apex's `lastError` reports exactly what is missing.
946
+ */
947
+ private discoverApexNegotiation;
811
948
  /** Inject the apex settlement negotiation directly into its ToonClient. */
812
949
  private injectApexNegotiation;
813
950
  /** Route apex CHILD peers (dvm/mill) through the SAME apex payment channel. */
@@ -821,6 +958,26 @@ declare class ClientRunner {
821
958
  getTargets(): TargetsResponse;
822
959
  /** Pay-to-write a single event through the selected (or default) apex. */
823
960
  publish(req: PublishRequest): Promise<PublishResponse>;
961
+ /**
962
+ * Build, sign (with the daemon-held key), and pay-to-write an event. The
963
+ * caller supplies only the event shell; the private key never leaves the
964
+ * daemon. Payloads are MODEL-AUTHORED → validated server-side here (the model
965
+ * is not a security boundary). Replaceable kinds (0/3) merge the latest known
966
+ * event's tags before signing.
967
+ */
968
+ publishUnsigned(req: PublishUnsignedRequest): Promise<PublishResponse>;
969
+ /**
970
+ * Upload media to Arweave (kind:5094 blob DVM, single-packet) then sign+publish
971
+ * a media event referencing the resulting URL. One spendy operation, two steps,
972
+ * entirely server-side.
973
+ */
974
+ uploadMedia(req: UploadMediaRequest): Promise<UploadMediaResponse>;
975
+ /** Validate + assemble a signable event template (with replaceable merge). */
976
+ private buildTemplate;
977
+ /** Latest self-authored event of `kind` currently in the merged read buffer. */
978
+ private latestSelfReplaceable;
979
+ /** Tags for a published media event referencing an Arweave URL. */
980
+ private buildMediaTags;
824
981
  /** Open (or return) a payment channel on the selected (or default) apex. */
825
982
  openChannel(destination?: string, btpUrl?: string): Promise<{
826
983
  channelId: string;
@@ -829,7 +986,13 @@ declare class ClientRunner {
829
986
  getChannels(): ChannelsResponse;
830
987
  /** Swap source→target asset against a mill peer via the selected apex. */
831
988
  swap(req: SwapRequest): Promise<SwapResponse>;
832
- /** Graceful teardown: close every relay + stop every apex client + read proxy. */
989
+ /**
990
+ * Payment-aware HTTP fetch through an apex's client. The client issues the
991
+ * request and, on `402 Payment Required`, pays over TOON and retries; we
992
+ * translate the resulting Web `Response` into the wire envelope.
993
+ */
994
+ httpFetchPaid(req: HttpFetchPaidRequest): Promise<HttpFetchPaidResponse>;
995
+ /** Graceful teardown: close every relay + stop every apex client. */
833
996
  stop(): Promise<void>;
834
997
  private selectApex;
835
998
  private assertApexReady;
@@ -859,9 +1022,8 @@ declare class PublishRejectedError extends Error {
859
1022
  * a default password so the identity survives restarts with no env var.
860
1023
  * The mnemonic + derived addresses are printed ONCE for backup.
861
1024
  * 2. **Transport scaffolding** — ensure `config.json` carries the transport
862
- * knobs (`btpUrl`/`relayUrl`/`managedAnonProxy`) plus a `_help` block
863
- * documenting direct-vs-`.anyone` selection, so the user can see what to
864
- * point at.
1025
+ * knobs (`btpUrl`/`relayUrl`) plus a `_help` block documenting them, so the
1026
+ * user can see what to point at.
865
1027
  *
866
1028
  * This is all idempotent: on later runs an identity already exists, so nothing
867
1029
  * is regenerated and the config is left untouched.
@@ -928,7 +1090,8 @@ declare function spawnDaemonDetached(opts?: SpawnDaemonOptions): number;
928
1090
  /**
929
1091
  * Poll the control plane until the daemon answers `GET /status`, up to
930
1092
  * `timeoutMs`. Resolves true once reachable (NOT necessarily done
931
- * bootstrapping — anon can take 30–90s; callers surface `bootstrapping`).
1093
+ * bootstrapping — the BTP session can take a moment; callers surface
1094
+ * `bootstrapping`).
932
1095
  */
933
1096
  declare function waitForReady(baseUrl: string, timeoutMs?: number, intervalMs?: number): Promise<boolean>;
934
1097
 
@@ -944,6 +1107,8 @@ interface ToolDefinition {
944
1107
  name: string;
945
1108
  description: string;
946
1109
  inputSchema: Record<string, unknown>;
1110
+ /** MCP-apps metadata, e.g. `{ ui: { resourceUri } }` linking a UI resource. */
1111
+ _meta?: Record<string, unknown>;
947
1112
  }
948
1113
  /** MCP tool-call result shape (subset of the SDK's CallToolResult). */
949
1114
  interface ToolResult {
@@ -951,6 +1116,8 @@ interface ToolResult {
951
1116
  type: 'text';
952
1117
  text: string;
953
1118
  }[];
1119
+ /** Machine-readable payload the MCP-app iframe reads (events, ViewSpec, …). */
1120
+ structuredContent?: Record<string, unknown>;
954
1121
  isError?: boolean;
955
1122
  }
956
1123
  declare const TOOL_DEFINITIONS: ToolDefinition[];
@@ -962,4 +1129,51 @@ declare const TOOL_DEFINITIONS: ToolDefinition[];
962
1129
  */
963
1130
  declare function dispatchTool(client: ControlClient, name: string, args: Record<string, unknown>): Promise<ToolResult>;
964
1131
 
965
- export { type AddApexRequest, type AddApexResponse, type AddRelayRequest, type ApexNegotiationConfig, type ApexTargetStatus, type ChainStatus, type ChannelInfo, type ChannelsResponse, ClientRunner, type ClientRunnerDeps, ControlApiError, ControlClient, type ControlClientOptions, DEFAULT_KEYSTORE_PASSWORD, type DaemonConfigFile, DaemonUnreachableError, type DrainResult, type ErrorResponse, type EventsQuery, type EventsResponse, type MinimalWebSocket, type NostrFilter, NotReadyError, type OpenChannelRequest, PublishRejectedError, type PublishRequest, type PublishResponse, RelaySubscription, type RelaySubscriptionOptions, type RelayTargetStatus, type RemoveApexRequest, type RemoveRelayRequest, type ResolvedDaemonConfig, type SettlementChain, type StatusResponse, type SubscribeRequest, type SubscribeResponse, type SwapClaim, type SwapRequest, type SwapResponse, TOOL_DEFINITIONS, type TargetsResponse, type ToolDefinition, type ToolResult, type ToonClientLike, type WebSocketFactory, acquireLock, configDir, defaultConfigPath, defaultKeystorePath, dispatchTool, hasConfiguredIdentity, isDaemonRunning, isProcessAlive, readConfigFile, readPid, registerRoutes, releaseLock, resolveConfig, resolveMnemonic, scaffoldFirstRun, spawnDaemonDetached, waitForReady };
1132
+ /** Accumulated per-step results keyed by step id. */
1133
+ type JourneyState = Record<string, unknown>;
1134
+ /** One step in a journey: a tool call with a ViewSpec renderer. */
1135
+ interface JourneyStep {
1136
+ /** Unique identifier for this step within the plan. */
1137
+ id: string;
1138
+ /** MCP tool name to call (e.g. `toon_status`, `toon_publish_unsigned`). */
1139
+ toolName: string;
1140
+ /** Build the tool input from accumulated prior-step state. */
1141
+ buildInput: (state: JourneyState) => Record<string, unknown>;
1142
+ /** Render the step's result data as a ViewSpec panel. */
1143
+ renderPanel: (data: unknown, state: JourneyState) => ViewSpec;
1144
+ }
1145
+ /** Ordered sequence of steps with plan metadata. */
1146
+ interface JourneyPlan {
1147
+ id: string;
1148
+ title: string;
1149
+ steps: JourneyStep[];
1150
+ }
1151
+ /** Result for one executed step. */
1152
+ interface JourneyStepResult {
1153
+ stepId: string;
1154
+ /** Raw ToolResult from the tool call. */
1155
+ toolResult: ToolResult;
1156
+ /** ToolResult carrying the step's ViewSpec panel as structuredContent. */
1157
+ panel: ToolResult;
1158
+ }
1159
+ /** Final result of a runJourney call. */
1160
+ interface JourneyResult {
1161
+ /** True when all steps completed without error. */
1162
+ completed: boolean;
1163
+ /** Results for every step that ran (may be partial on error). */
1164
+ steps: JourneyStepResult[];
1165
+ /** Present when the run halted due to a tool error. */
1166
+ error?: {
1167
+ stepId: string;
1168
+ message: string;
1169
+ };
1170
+ }
1171
+
1172
+ /**
1173
+ * Run all steps in the plan sequentially against the given ControlClient.
1174
+ * Each step's result is threaded forward into the next step's buildInput via
1175
+ * JourneyState. Halts on the first tool error and returns a partial result.
1176
+ */
1177
+ declare function runJourney(plan: JourneyPlan, client: ControlClient): Promise<JourneyResult>;
1178
+
1179
+ export { type AddApexRequest, type AddApexResponse, type AddRelayRequest, type ApexNegotiationConfig, type ApexTargetStatus, type ChainStatus, type ChannelInfo, type ChannelsResponse, ClientRunner, type ClientRunnerDeps, ControlApiError, ControlClient, type ControlClientOptions, DEFAULT_KEYSTORE_PASSWORD, type DaemonConfigFile, DaemonUnreachableError, type DrainResult, type ErrorResponse, type EventsQuery, type EventsResponse, type HttpFetchPaidRequest, type HttpFetchPaidResponse, type JourneyPlan, type JourneyResult, type JourneyState, type JourneyStep, type JourneyStepResult, type MinimalWebSocket, type NostrFilter, NotReadyError, type OpenChannelRequest, PublishRejectedError, type PublishRequest, type PublishResponse, type PublishUnsignedRequest, type QueryRequest, type QueryResponse, RelaySubscription, type RelaySubscriptionOptions, type RelayTargetStatus, type RemoveApexRequest, type RemoveRelayRequest, type ResolvedDaemonConfig, type SettlementChain, type StatusResponse, type SubscribeRequest, type SubscribeResponse, type SwapClaim, type SwapRequest, type SwapResponse, TOOL_DEFINITIONS, type TargetsResponse, type ToolDefinition, type ToolResult, type ToonClientLike, type UploadMediaRequest, type UploadMediaResponse, type WebSocketFactory, acquireLock, configDir, defaultConfigPath, defaultKeystorePath, dispatchTool, hasConfiguredIdentity, isDaemonRunning, isProcessAlive, readConfigFile, readPid, registerRoutes, releaseLock, resolveConfig, resolveMnemonic, runJourney, scaffoldFirstRun, spawnDaemonDetached, waitForReady };