@toon-protocol/core 1.1.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.
@@ -0,0 +1,2853 @@
1
+ import { T as ToonError } from './index-DSgMeweu.js';
2
+ export { I as InvalidEventError, P as PeerDiscoveryError, a as ToonDecodeError, b as ToonEncodeError, c as ToonRoutingMeta, d as decodeEventFromToon, e as encodeEventToToon, f as encodeEventToToonString, s as shallowParseToon } from './index-DSgMeweu.js';
3
+ import { NostrEvent } from 'nostr-tools/pure';
4
+ import { SimplePool } from 'nostr-tools/pool';
5
+ import { TurboAuthenticatedClient } from '@ardrive/turbo-sdk';
6
+
7
+ /**
8
+ * Nostr event kind constants for ILP-related events.
9
+ *
10
+ * These follow the NIP convention for replaceable (10000-19999) event kinds.
11
+ */
12
+ /**
13
+ * ILP Peer Info (kind 10032)
14
+ * Replaceable event containing connector's ILP address, BTP endpoint, and settlement info.
15
+ */
16
+ declare const ILP_PEER_INFO_KIND = 10032;
17
+ /**
18
+ * Service Discovery (kind 10035)
19
+ * Replaceable event advertising a node's capabilities, pricing, and endpoints.
20
+ * Published to the local relay and optionally to peers so that clients and
21
+ * agents can programmatically discover available services.
22
+ * NIP-16 replaceable: relays store only the latest event per pubkey + kind.
23
+ */
24
+ declare const SERVICE_DISCOVERY_KIND = 10035;
25
+ /**
26
+ * Seed Relay List (kind 10036)
27
+ * Replaceable event containing a list of relay nodes that serve as bootstrap
28
+ * entry points for new network participants. Published to public Nostr relays.
29
+ * NIP-16 replaceable: relays store only the latest event per pubkey + kind.
30
+ */
31
+ declare const SEED_RELAY_LIST_KIND = 10036;
32
+ /**
33
+ * TEE Attestation (kind 10033)
34
+ * NIP-16 replaceable event containing TEE attestation data: PCR values,
35
+ * enclave image hash, and attestation documents from the TEE platform.
36
+ * Published by nodes running in a Trusted Execution Environment (e.g.,
37
+ * Marlin Oyster CVM / AWS Nitro Enclaves). Relays store only the latest
38
+ * event per pubkey + kind. No `d` tag needed -- NIP-16 replaces by
39
+ * pubkey + kind alone (unlike NIP-33 parameterized replaceable events).
40
+ */
41
+ declare const TEE_ATTESTATION_KIND = 10033;
42
+ /**
43
+ * Base kind for NIP-90 DVM job requests (kind range 5000-5999).
44
+ * Job requests are regular (non-replaceable) events. Each specific DVM task
45
+ * type is assigned a unique kind within this range (e.g., 5100 for text
46
+ * generation). Providers listen for requests in their supported kind range.
47
+ */
48
+ declare const JOB_REQUEST_KIND_BASE = 5000;
49
+ /**
50
+ * Base kind for NIP-90 DVM job results (kind range 6000-6999).
51
+ * Result kind = request kind + 1000 (e.g., Kind 5100 request -> Kind 6100
52
+ * result). Result events reference the original request via an `e` tag and
53
+ * include the compute cost in an `amount` tag.
54
+ */
55
+ declare const JOB_RESULT_KIND_BASE = 6000;
56
+ /**
57
+ * NIP-90 DVM job feedback (kind 7000).
58
+ * A single kind used for all feedback messages (processing, error, success,
59
+ * partial). Feedback events reference the original request via an `e` tag
60
+ * and carry a `status` tag indicating the current job state.
61
+ */
62
+ declare const JOB_FEEDBACK_KIND = 7000;
63
+ /**
64
+ * Text Generation DVM kind (kind 5100).
65
+ * Reference DVM kind for the TOON protocol. Used for general-purpose
66
+ * text generation tasks (e.g., LLM inference, summarization, Q&A).
67
+ */
68
+ declare const TEXT_GENERATION_KIND = 5100;
69
+ /**
70
+ * Image Generation DVM kind (kind 5200).
71
+ * Used for image generation tasks (e.g., text-to-image, image editing).
72
+ * Optional provider support -- not all nodes are required to handle this kind.
73
+ */
74
+ declare const IMAGE_GENERATION_KIND = 5200;
75
+ /**
76
+ * Text-to-Speech DVM kind (kind 5300).
77
+ * Used for text-to-speech conversion tasks.
78
+ * Optional provider support -- not all nodes are required to handle this kind.
79
+ */
80
+ declare const TEXT_TO_SPEECH_KIND = 5300;
81
+ /**
82
+ * Translation DVM kind (kind 5302).
83
+ * Used for language translation tasks.
84
+ * Optional provider support -- not all nodes are required to handle this kind.
85
+ */
86
+ declare const TRANSLATION_KIND = 5302;
87
+
88
+ /**
89
+ * TypeScript interfaces for ILP-related Nostr events.
90
+ */
91
+ /**
92
+ * ILP Peer Info - Published as kind 10032 event.
93
+ * Contains information needed to establish an ILP peering relationship.
94
+ */
95
+ interface IlpPeerInfo {
96
+ /** Nostr pubkey of the peer (64-char hex) */
97
+ pubkey?: string;
98
+ /** ILP address of the peer's connector (e.g., "g.example.connector") */
99
+ ilpAddress: string;
100
+ /** BTP WebSocket endpoint URL for packet exchange */
101
+ btpEndpoint: string;
102
+ /** Optional BLS HTTP endpoint for direct packet delivery (bootstrap only) */
103
+ blsHttpEndpoint?: string;
104
+ /** @deprecated Use supportedChains instead. Kept for backward compatibility. */
105
+ settlementEngine?: string;
106
+ /** Asset code for the peering relationship (e.g., "USD", "XRP") */
107
+ assetCode: string;
108
+ /** Asset scale - number of decimal places (e.g., 9 for XRP, 6 for USD cents) */
109
+ assetScale: number;
110
+ /** Supported settlement chain identifiers in {blockchain}:{network}:{chainId} format (e.g., ["evm:base:8453", "xrp:mainnet"]) */
111
+ supportedChains?: string[];
112
+ /** Maps chain identifier to the peer's settlement address on that chain */
113
+ settlementAddresses?: Record<string, string>;
114
+ /** Maps chain identifier to preferred token contract address */
115
+ preferredTokens?: Record<string, string>;
116
+ /** Maps chain identifier to TokenNetwork contract address (EVM-specific) */
117
+ tokenNetworks?: Record<string, string>;
118
+ }
119
+ /**
120
+ * Subscription handle for real-time event updates.
121
+ * Returned by subscription methods to allow cleanup.
122
+ */
123
+ interface Subscription {
124
+ /** Stops receiving updates and closes the underlying relay subscription */
125
+ unsubscribe(): void;
126
+ }
127
+ /**
128
+ * Parameters for opening a payment channel via the connector Admin API.
129
+ */
130
+ interface OpenChannelParams {
131
+ /** Connector peer identifier */
132
+ peerId: string;
133
+ /** Settlement chain identifier (e.g., "evm:base:8453") */
134
+ chain: string;
135
+ /** Token contract address on the chain */
136
+ token?: string;
137
+ /** TokenNetwork contract address (EVM-specific) */
138
+ tokenNetwork?: string;
139
+ /** Peer's settlement address on the chain */
140
+ peerAddress: string;
141
+ /** Initial deposit amount */
142
+ initialDeposit?: string;
143
+ /** Challenge period in seconds */
144
+ settlementTimeout?: number;
145
+ }
146
+ /**
147
+ * Result of opening a payment channel.
148
+ */
149
+ interface OpenChannelResult {
150
+ /** Unique channel identifier */
151
+ channelId: string;
152
+ /** Channel status after open request */
153
+ status: string;
154
+ }
155
+ /**
156
+ * State of a payment channel from the connector.
157
+ */
158
+ interface ChannelState {
159
+ /** Unique channel identifier */
160
+ channelId: string;
161
+ /** Current channel status */
162
+ status: 'opening' | 'open' | 'closed' | 'settled';
163
+ /** Settlement chain identifier */
164
+ chain: string;
165
+ }
166
+ /**
167
+ * TEE Attestation content for kind:10033 events (Pattern 14).
168
+ * Contains attestation data from a Trusted Execution Environment.
169
+ */
170
+ interface TeeAttestation {
171
+ /** Enclave type identifier (e.g., 'aws-nitro', 'marlin-oyster'). */
172
+ enclave: string;
173
+ /** Platform Configuration Register 0 (SHA-384 hex, 96 chars). */
174
+ pcr0: string;
175
+ /** Platform Configuration Register 1 (SHA-384 hex, 96 chars). */
176
+ pcr1: string;
177
+ /** Platform Configuration Register 2 (SHA-384 hex, 96 chars). */
178
+ pcr2: string;
179
+ /** Base64-encoded attestation document from the TEE platform. */
180
+ attestationDoc: string;
181
+ /** Attestation format version. */
182
+ version: string;
183
+ }
184
+ /**
185
+ * Interface for interacting with the connector's channel Admin API.
186
+ * Abstracts POST /admin/channels and GET /admin/channels/:channelId.
187
+ */
188
+ interface ConnectorChannelClient {
189
+ /** Opens a new payment channel via POST /admin/channels */
190
+ openChannel(params: OpenChannelParams): Promise<OpenChannelResult>;
191
+ /** Gets channel state via GET /admin/channels/:channelId */
192
+ getChannelState(channelId: string): Promise<ChannelState>;
193
+ }
194
+
195
+ /**
196
+ * Parsers for ILP-related Nostr events.
197
+ */
198
+
199
+ /**
200
+ * Validates a chain identifier string.
201
+ * Valid format: {blockchain}:{network} or {blockchain}:{network}:{chainId}
202
+ * Minimum 2 segments, maximum 3, separated by `:`. All segments must be non-empty.
203
+ *
204
+ * @param chainId - The chain identifier to validate
205
+ * @returns true if the chain identifier is valid
206
+ */
207
+ declare function validateChainId(chainId: string): boolean;
208
+ /**
209
+ * Parses a kind:10032 Nostr event into an IlpPeerInfo object.
210
+ *
211
+ * @param event - The Nostr event to parse
212
+ * @returns The parsed IlpPeerInfo object
213
+ * @throws InvalidEventError if the event is malformed or missing required fields
214
+ */
215
+ declare function parseIlpPeerInfo(event: NostrEvent): IlpPeerInfo;
216
+
217
+ /**
218
+ * Builders for ILP-related Nostr events.
219
+ */
220
+
221
+ /**
222
+ * Builds and signs a kind:10032 Nostr event from IlpPeerInfo data.
223
+ *
224
+ * @param info - The ILP peer info to serialize into the event
225
+ * @param secretKey - The secret key to sign the event with
226
+ * @returns A signed Nostr event
227
+ */
228
+ declare function buildIlpPeerInfoEvent(info: IlpPeerInfo, secretKey: Uint8Array): NostrEvent;
229
+
230
+ /**
231
+ * Event builder and parser for kind:10036 Seed Relay List events.
232
+ *
233
+ * Kind 10036 is a NIP-16 replaceable event (kind 10000-19999) published to
234
+ * public Nostr relays. Relays store only the latest event per `pubkey + kind`.
235
+ * The `d` tag with value `toon-seed-list` is included as a content marker
236
+ * for filtering.
237
+ *
238
+ * Seed relay list events advertise relay nodes that can serve as bootstrap
239
+ * entry points for new network participants.
240
+ */
241
+
242
+ /** Content payload for a kind:10036 Seed Relay List event. */
243
+ interface SeedRelayEntry {
244
+ /** WebSocket URL of the relay (wss:// for production, ws:// for dev). */
245
+ url: string;
246
+ /** Nostr pubkey of the relay operator (64-char lowercase hex). */
247
+ pubkey: string;
248
+ /** Optional metadata. */
249
+ metadata?: {
250
+ region?: string;
251
+ version?: string;
252
+ services?: string[];
253
+ };
254
+ }
255
+ /**
256
+ * Builds a kind:10036 Seed Relay List event (NIP-16 replaceable).
257
+ * Uses 'd' tag with value 'toon-seed-list' for replaceable event pattern.
258
+ *
259
+ * @param secretKey - The secret key to sign the event with.
260
+ * @param entries - The seed relay entries to include.
261
+ * @returns A signed Nostr event.
262
+ */
263
+ declare function buildSeedRelayListEvent(secretKey: Uint8Array, entries: SeedRelayEntry[]): NostrEvent;
264
+ /**
265
+ * Parses a kind:10036 event content into SeedRelayEntry[].
266
+ * Validates URLs (WebSocket scheme prefix) and pubkeys (64-char hex).
267
+ * Malformed entries are silently skipped (graceful degradation).
268
+ *
269
+ * @param event - The Nostr event to parse.
270
+ * @returns An array of valid SeedRelayEntry objects.
271
+ */
272
+ declare function parseSeedRelayList(event: NostrEvent): SeedRelayEntry[];
273
+
274
+ /**
275
+ * Event builder and parser for kind:10035 Service Discovery events.
276
+ *
277
+ * Kind 10035 is a NIP-16 replaceable event (kind 10000-19999) published to
278
+ * the local relay and optionally to peers. Relays store only the latest event
279
+ * per `pubkey + kind`. The `d` tag with value `toon-service-discovery` is
280
+ * included as a content marker for filtering.
281
+ *
282
+ * Service discovery events advertise a node's capabilities, pricing, and
283
+ * endpoints so that clients and AI agents can programmatically discover
284
+ * available services.
285
+ */
286
+
287
+ /**
288
+ * Structured skill descriptor for DVM service discovery.
289
+ *
290
+ * Embedded in kind:10035 events to advertise DVM capabilities.
291
+ * Enables programmatic agent-to-agent service discovery: agents
292
+ * can read `inputSchema` to construct valid Kind 5xxx job requests
293
+ * without prior knowledge of the provider's capabilities.
294
+ *
295
+ * The `attestation` field is a placeholder for Epic 6 TEE integration
296
+ * (Story 6.3: TEE-attested DVM results).
297
+ */
298
+ interface SkillDescriptor {
299
+ /** Service identifier (e.g., 'toon-dvm'). */
300
+ name: string;
301
+ /** Schema version (e.g., '1.0'). */
302
+ version: string;
303
+ /** Supported DVM Kind 5xxx numbers (e.g., [5100, 5200]). */
304
+ kinds: number[];
305
+ /** Capability list (e.g., ['text-generation', 'streaming']). */
306
+ features: string[];
307
+ /** JSON Schema draft-07 object describing job request parameters. */
308
+ inputSchema: Record<string, unknown>;
309
+ /** Kind number (as string) -> USDC micro-units cost (as string). */
310
+ pricing: Record<string, string>;
311
+ /** Available AI models (e.g., ['gpt-4', 'claude-3']). */
312
+ models?: string[];
313
+ /** Placeholder for Epic 6 TEE attestation integration. */
314
+ attestation?: Record<string, unknown>;
315
+ }
316
+ /** Content payload for a kind:10035 Service Discovery event. */
317
+ interface ServiceDiscoveryContent {
318
+ /** Service type identifier (e.g., 'relay', 'rig'). */
319
+ serviceType: string;
320
+ /** ILP address of the node's connector. */
321
+ ilpAddress: string;
322
+ /** Pricing configuration. */
323
+ pricing: {
324
+ /** Base price per byte in smallest token unit. */
325
+ basePricePerByte: number;
326
+ /** Payment token symbol (e.g., 'USDC'). */
327
+ currency: string;
328
+ };
329
+ /**
330
+ * x402 endpoint configuration.
331
+ * Omitted entirely when x402 is disabled (not set to `{ enabled: false }`).
332
+ */
333
+ x402?: {
334
+ /** Whether x402 is enabled. */
335
+ enabled: boolean;
336
+ /** HTTP endpoint path (e.g., '/publish'). */
337
+ endpoint?: string;
338
+ };
339
+ /** Nostr event kinds this node accepts for storage. */
340
+ supportedKinds: number[];
341
+ /** Capabilities advertised by this node (e.g., ['relay', 'x402']). */
342
+ capabilities: string[];
343
+ /** Chain preset name (e.g., 'anvil', 'arbitrum-one'). */
344
+ chain: string;
345
+ /** Node software version. */
346
+ version: string;
347
+ /**
348
+ * Optional DVM skill descriptor.
349
+ * Present when the node has DVM handlers registered; omitted otherwise
350
+ * (backward compatible with pre-DVM kind:10035 events).
351
+ */
352
+ skill?: SkillDescriptor;
353
+ }
354
+ /**
355
+ * Builds a kind:10035 Service Discovery event (NIP-16 replaceable).
356
+ * Kind 10035 is in the 10000-19999 replaceable range (NIP-16).
357
+ * Relays store only the latest event per pubkey + kind.
358
+ * Includes 'd' tag with value 'toon-service-discovery' as a content marker.
359
+ *
360
+ * @param content - The service discovery payload.
361
+ * @param secretKey - The secret key to sign the event with.
362
+ * @returns A signed Nostr event.
363
+ */
364
+ declare function buildServiceDiscoveryEvent(content: ServiceDiscoveryContent, secretKey: Uint8Array): NostrEvent;
365
+ /**
366
+ * Parses a kind:10035 event content into ServiceDiscoveryContent.
367
+ * Validates required fields. Returns null for malformed content.
368
+ *
369
+ * @param event - The Nostr event to parse.
370
+ * @returns The parsed content, or null if invalid.
371
+ */
372
+ declare function parseServiceDiscovery(event: NostrEvent): ServiceDiscoveryContent | null;
373
+
374
+ /**
375
+ * Event builder and parser for kind:10033 TEE Attestation events.
376
+ *
377
+ * Kind 10033 is a NIP-16 replaceable event (kind 10000-19999) published by
378
+ * nodes running in a Trusted Execution Environment (TEE). Relays store only
379
+ * the latest event per `pubkey + kind`. No `d` tag is needed -- NIP-16
380
+ * replaces by pubkey + kind alone (unlike NIP-33 parameterized replaceable
381
+ * events in the 30000-39999 range).
382
+ *
383
+ * TEE attestation events contain PCR measurements, enclave type, and the
384
+ * base64-encoded attestation document from the TEE platform (e.g., AWS Nitro
385
+ * Enclaves via Marlin Oyster CVM).
386
+ *
387
+ * Content format (Pattern 14):
388
+ * ```json
389
+ * {
390
+ * "enclave": "marlin-oyster",
391
+ * "pcr0": "<sha384-hex-96-chars>",
392
+ * "pcr1": "<sha384-hex-96-chars>",
393
+ * "pcr2": "<sha384-hex-96-chars>",
394
+ * "attestationDoc": "<base64-encoded>",
395
+ * "version": "1.0.0"
396
+ * }
397
+ * ```
398
+ *
399
+ * Tags: ['relay', url], ['chain', chainId], ['expiry', unixTimestamp]
400
+ */
401
+
402
+ /** Options for building a kind:10033 attestation event. */
403
+ interface AttestationEventOptions {
404
+ /** WebSocket URL where this relay can be reached. */
405
+ relay: string;
406
+ /** Chain identifier (e.g., '42161' for Arbitrum One). */
407
+ chain: string;
408
+ /** Unix timestamp when this attestation expires. */
409
+ expiry: number;
410
+ }
411
+ /** Parsed result from a kind:10033 attestation event. */
412
+ interface ParsedAttestation {
413
+ /** The attestation content fields. */
414
+ attestation: TeeAttestation;
415
+ /** WebSocket relay URL from the 'relay' tag. */
416
+ relay: string;
417
+ /** Chain identifier from the 'chain' tag. */
418
+ chain: string;
419
+ /** Expiry unix timestamp from the 'expiry' tag. */
420
+ expiry: number;
421
+ }
422
+ /**
423
+ * Builds a kind:10033 TEE Attestation event (NIP-16 replaceable).
424
+ *
425
+ * Content is `JSON.stringify(attestation)` per enforcement guideline 11.
426
+ * Tags include relay, chain, and expiry. No `d` tag is included -- NIP-16
427
+ * replaces by pubkey + kind alone.
428
+ *
429
+ * @param attestation - The TEE attestation content payload.
430
+ * @param secretKey - The secret key to sign the event with.
431
+ * @param options - Event options (relay URL, chain ID, expiry timestamp).
432
+ * @returns A signed Nostr event.
433
+ */
434
+ declare function buildAttestationEvent(attestation: TeeAttestation, secretKey: Uint8Array, options: AttestationEventOptions): NostrEvent;
435
+ /**
436
+ * Parses a kind:10033 event into a ParsedAttestation.
437
+ *
438
+ * Validates required content fields (enclave, pcr0-2, attestationDoc, version)
439
+ * and required tags (relay, chain, expiry). Returns `null` for malformed or
440
+ * missing data.
441
+ *
442
+ * When `options.verify` is `true`, performs strict validation:
443
+ * - PCR values must be 96-char lowercase hex (SHA-384)
444
+ * - attestationDoc must be non-empty valid base64
445
+ * Throws on invalid data when verify=true (adversarial input gate).
446
+ *
447
+ * @param event - The Nostr event to parse.
448
+ * @param options - Optional parse options. `verify: true` enables strict validation.
449
+ * @returns The parsed attestation, or null if invalid.
450
+ */
451
+ declare function parseAttestation(event: NostrEvent, options?: {
452
+ verify?: boolean;
453
+ }): ParsedAttestation | null;
454
+
455
+ /**
456
+ * Event builders and parsers for NIP-90 DVM (Data Vending Machine) events.
457
+ *
458
+ * NIP-90 defines three event categories for the DVM protocol:
459
+ * - Kind 5000-5999: Job requests (each task type has a unique kind)
460
+ * - Kind 6000-6999: Job results (result kind = request kind + 1000)
461
+ * - Kind 7000: Job feedback (single kind for all status updates)
462
+ *
463
+ * TOON adopts NIP-90 kinds for cross-network interoperability with the
464
+ * broader Nostr DVM ecosystem. The `bid` and `amount` tags extend NIP-90
465
+ * with a third element ('usdc') for explicit currency declaration. NIP-90
466
+ * uses satoshis; TOON uses USDC micro-units (6 decimals).
467
+ *
468
+ * DVM events are standard Nostr events with specific kinds. They flow
469
+ * through the same SDK processing pipeline as all other events: shallow
470
+ * parse -> verify -> price -> dispatch. No special-casing required.
471
+ *
472
+ * Tag reference:
473
+ *
474
+ * Kind 5xxx (Job Request):
475
+ * Required: ['i', data, type, relay?, marker?], ['bid', amount, 'usdc'], ['output', mimeType]
476
+ * Optional: ['p', providerPubkey], ['param', key, value], ['relays', url1, ...]
477
+ *
478
+ * Kind 6xxx (Job Result):
479
+ * Required: ['e', requestEventId], ['p', customerPubkey], ['amount', cost, 'usdc']
480
+ * Content: result data
481
+ *
482
+ * Kind 7000 (Job Feedback):
483
+ * Required: ['e', requestEventId], ['p', customerPubkey], ['status', statusValue]
484
+ * Content: optional status details
485
+ */
486
+
487
+ /**
488
+ * DVM job status values per NIP-90.
489
+ * - `'processing'`: Job is currently being processed.
490
+ * - `'error'`: Job failed with an error.
491
+ * - `'success'`: Job completed successfully.
492
+ * - `'partial'`: Job returned partial results (more to come).
493
+ */
494
+ type DvmJobStatus = 'processing' | 'error' | 'success' | 'partial';
495
+ /**
496
+ * Parameters for building a Kind 5xxx DVM job request event.
497
+ *
498
+ * The `kind` field must be in the 5000-5999 range (NIP-90 job request range).
499
+ * The `bid` field is the amount the requester is willing to pay, expressed as
500
+ * a string of USDC micro-units (6 decimals) for bigint compatibility.
501
+ */
502
+ interface JobRequestParams {
503
+ /** Event kind in 5000-5999 range (e.g., 5100 for text generation). */
504
+ kind: number;
505
+ /** Input data with type classification. */
506
+ input: {
507
+ /** The input data (text, URL, event ID, etc.). */
508
+ data: string;
509
+ /** Input type identifier (e.g., 'text', 'url', 'event', 'job'). */
510
+ type: string;
511
+ /** Optional relay URL where the input data can be found. */
512
+ relay?: string;
513
+ /** Optional marker for input disambiguation. */
514
+ marker?: string;
515
+ };
516
+ /** Bid amount in USDC micro-units as string (bigint-compatible). */
517
+ bid: string;
518
+ /** Expected output MIME type (e.g., 'text/plain', 'image/png'). */
519
+ output: string;
520
+ /** Optional body text for the event content field. */
521
+ content?: string;
522
+ /** Optional 64-char hex pubkey of a specific target provider. */
523
+ targetProvider?: string;
524
+ /** Optional key-value parameters for the job (repeatable). */
525
+ params?: {
526
+ key: string;
527
+ value: string;
528
+ }[];
529
+ /** Optional preferred relay URLs for result delivery. */
530
+ relays?: string[];
531
+ }
532
+ /**
533
+ * Parameters for building a Kind 6xxx DVM job result event.
534
+ *
535
+ * The `kind` field must be in the 6000-6999 range. Result kind = request
536
+ * kind + 1000 (e.g., Kind 5100 request -> Kind 6100 result).
537
+ * The `amount` field is the actual compute cost in USDC micro-units.
538
+ */
539
+ interface JobResultParams {
540
+ /** Event kind in 6000-6999 range (= request kind + 1000). */
541
+ kind: number;
542
+ /** 64-char hex event ID of the original Kind 5xxx request. */
543
+ requestEventId: string;
544
+ /** 64-char hex pubkey of the customer who posted the request. */
545
+ customerPubkey: string;
546
+ /** Compute cost in USDC micro-units as string (bigint-compatible). */
547
+ amount: string;
548
+ /** Result data (text, URL, etc.). */
549
+ content: string;
550
+ }
551
+ /**
552
+ * Parameters for building a Kind 7000 DVM job feedback event.
553
+ *
554
+ * Feedback events carry status updates about in-progress jobs. The `status`
555
+ * field must be one of the four NIP-90 status values.
556
+ */
557
+ interface JobFeedbackParams {
558
+ /** 64-char hex event ID of the original Kind 5xxx request. */
559
+ requestEventId: string;
560
+ /** 64-char hex pubkey of the customer who posted the request. */
561
+ customerPubkey: string;
562
+ /** Job status value. */
563
+ status: DvmJobStatus;
564
+ /** Optional status details or error message. */
565
+ content?: string;
566
+ }
567
+ /**
568
+ * Parsed result from a Kind 5xxx DVM job request event.
569
+ */
570
+ interface ParsedJobRequest {
571
+ /** Event kind (5000-5999). */
572
+ kind: number;
573
+ /** Input data with type classification. */
574
+ input: {
575
+ /** The input data. */
576
+ data: string;
577
+ /** Input type identifier. */
578
+ type: string;
579
+ /** Optional relay URL. */
580
+ relay?: string;
581
+ /** Optional marker. */
582
+ marker?: string;
583
+ };
584
+ /** Bid amount in USDC micro-units as string. */
585
+ bid: string;
586
+ /** Expected output MIME type. */
587
+ output: string;
588
+ /** Event content field (may be empty string). */
589
+ content: string;
590
+ /** Target provider pubkey if this is a targeted request. */
591
+ targetProvider?: string;
592
+ /** Key-value parameters (may be empty array). */
593
+ params: {
594
+ key: string;
595
+ value: string;
596
+ }[];
597
+ /** Preferred relay URLs (may be empty array). */
598
+ relays: string[];
599
+ }
600
+ /**
601
+ * Parsed result from a Kind 6xxx DVM job result event.
602
+ */
603
+ interface ParsedJobResult {
604
+ /** Event kind (6000-6999). */
605
+ kind: number;
606
+ /** Event ID of the original request. */
607
+ requestEventId: string;
608
+ /** Pubkey of the customer who posted the request. */
609
+ customerPubkey: string;
610
+ /** Compute cost in USDC micro-units as string. */
611
+ amount: string;
612
+ /** Result data from the content field. */
613
+ content: string;
614
+ }
615
+ /**
616
+ * Parsed result from a Kind 7000 DVM job feedback event.
617
+ */
618
+ interface ParsedJobFeedback {
619
+ /** Event ID of the original request. */
620
+ requestEventId: string;
621
+ /** Pubkey of the customer who posted the request. */
622
+ customerPubkey: string;
623
+ /** Job status value. */
624
+ status: DvmJobStatus;
625
+ /** Status details from the content field (may be empty string). */
626
+ content: string;
627
+ }
628
+ /**
629
+ * Builds a Kind 5xxx DVM job request event (NIP-90).
630
+ *
631
+ * Constructs a signed Nostr event with NIP-90 required tags: `i` (input),
632
+ * `bid` (payment offer), and `output` (expected MIME type). Optional tags
633
+ * include `p` (target provider), `param` (key-value pairs), and `relays`
634
+ * (preferred relay URLs).
635
+ *
636
+ * @param params - The job request parameters.
637
+ * @param secretKey - The secret key to sign the event with.
638
+ * @returns A signed Nostr event.
639
+ * @throws ToonError if required params are missing or kind is out of range.
640
+ */
641
+ declare function buildJobRequestEvent(params: JobRequestParams, secretKey: Uint8Array): NostrEvent;
642
+ /**
643
+ * Builds a Kind 6xxx DVM job result event (NIP-90).
644
+ *
645
+ * Constructs a signed Nostr event with NIP-90 required tags: `e` (request
646
+ * reference), `p` (customer pubkey), and `amount` (compute cost). The
647
+ * content field carries the result data.
648
+ *
649
+ * @param params - The job result parameters.
650
+ * @param secretKey - The secret key to sign the event with.
651
+ * @returns A signed Nostr event.
652
+ * @throws ToonError if required params are missing or kind is out of range.
653
+ */
654
+ declare function buildJobResultEvent(params: JobResultParams, secretKey: Uint8Array): NostrEvent;
655
+ /**
656
+ * Builds a Kind 7000 DVM job feedback event (NIP-90).
657
+ *
658
+ * Constructs a signed Nostr event with NIP-90 required tags: `e` (request
659
+ * reference), `p` (customer pubkey), and `status` (job state). The content
660
+ * field carries optional status details or error messages.
661
+ *
662
+ * @param params - The job feedback parameters.
663
+ * @param secretKey - The secret key to sign the event with.
664
+ * @returns A signed Nostr event.
665
+ * @throws ToonError if required params are missing or status is invalid.
666
+ */
667
+ declare function buildJobFeedbackEvent(params: JobFeedbackParams, secretKey: Uint8Array): NostrEvent;
668
+ /**
669
+ * Parses a Kind 5xxx event into a ParsedJobRequest.
670
+ *
671
+ * Validates the event kind is in the 5000-5999 range and extracts required
672
+ * NIP-90 tags: `i` (input), `bid` (amount + currency), and `output` (MIME
673
+ * type). Also extracts optional tags: `p` (target provider), `param`
674
+ * (key-value pairs), and `relays` (preferred URLs).
675
+ *
676
+ * Returns `null` for malformed events (missing required tags, invalid kind
677
+ * range). Follows the lenient parse pattern established by
678
+ * `parseServiceDiscovery()` and `parseAttestation()`.
679
+ *
680
+ * @param event - The Nostr event to parse.
681
+ * @returns The parsed job request, or null if invalid.
682
+ */
683
+ declare function parseJobRequest(event: NostrEvent): ParsedJobRequest | null;
684
+ /**
685
+ * Parses a Kind 6xxx event into a ParsedJobResult.
686
+ *
687
+ * Validates the event kind is in the 6000-6999 range and extracts required
688
+ * NIP-90 tags: `e` (request event ID), `p` (customer pubkey), and `amount`
689
+ * (compute cost + currency).
690
+ *
691
+ * Returns `null` for malformed events. Follows the lenient parse pattern.
692
+ *
693
+ * @param event - The Nostr event to parse.
694
+ * @returns The parsed job result, or null if invalid.
695
+ */
696
+ declare function parseJobResult(event: NostrEvent): ParsedJobResult | null;
697
+ /**
698
+ * Parses a Kind 7000 event into a ParsedJobFeedback.
699
+ *
700
+ * Validates the event kind is exactly 7000 and extracts required NIP-90
701
+ * tags: `e` (request event ID), `p` (customer pubkey), and `status`
702
+ * (job state). The status value must be one of: `'processing'`, `'error'`,
703
+ * `'success'`, `'partial'`.
704
+ *
705
+ * Returns `null` for malformed events or invalid status values.
706
+ * Follows the lenient parse pattern.
707
+ *
708
+ * @param event - The Nostr event to parse.
709
+ * @returns The parsed job feedback, or null if invalid.
710
+ */
711
+ declare function parseJobFeedback(event: NostrEvent): ParsedJobFeedback | null;
712
+
713
+ /**
714
+ * Peer discovery using Nostr NIP-02 follow lists.
715
+ */
716
+
717
+ /**
718
+ * Discovers ILP peers by querying Nostr relays for NIP-02 follow lists.
719
+ */
720
+ declare class NostrPeerDiscovery {
721
+ private readonly relayUrls;
722
+ private readonly pool;
723
+ /**
724
+ * Creates a new NostrPeerDiscovery instance.
725
+ *
726
+ * @param relayUrls - Array of relay WebSocket URLs to query
727
+ * @param pool - Optional SimplePool instance (creates new one if not provided)
728
+ */
729
+ constructor(relayUrls: string[], pool?: SimplePool);
730
+ /**
731
+ * Retrieves the list of pubkeys that a given pubkey follows.
732
+ *
733
+ * Queries NIP-02 kind:3 events from configured relays and returns
734
+ * the followed pubkeys from the most recent event.
735
+ *
736
+ * @param pubkey - The 64-character hex pubkey to get follows for
737
+ * @returns Array of followed pubkeys (deduplicated)
738
+ * @throws PeerDiscoveryError if pubkey format is invalid
739
+ */
740
+ getFollows(pubkey: string): Promise<string[]>;
741
+ /**
742
+ * Discovers ILP peers by querying follow list and their ILP peer info events.
743
+ *
744
+ * For each followed pubkey, queries kind:10032 events to retrieve ILP connection info.
745
+ * Peers without kind:10032 events or with malformed events are silently excluded.
746
+ *
747
+ * @param pubkey - The 64-character hex pubkey to discover peers for
748
+ * @returns Map of pubkey → IlpPeerInfo for peers with valid ILP info
749
+ * @throws PeerDiscoveryError if pubkey format is invalid
750
+ */
751
+ discoverPeers(pubkey: string): Promise<Map<string, IlpPeerInfo>>;
752
+ /**
753
+ * Subscribes to ILP peer info updates from followed pubkeys.
754
+ *
755
+ * Sets up a real-time subscription for kind:10032 events from all pubkeys
756
+ * that the given pubkey follows. The callback is invoked whenever a new
757
+ * or updated ILP peer info event is received.
758
+ *
759
+ * @param pubkey - The 64-character hex pubkey whose follows to monitor
760
+ * @param callback - Function called with (peerPubkey, parsedInfo) for each update
761
+ * @returns Subscription object with unsubscribe() method
762
+ * @throws PeerDiscoveryError if pubkey format is invalid
763
+ */
764
+ subscribeToPeerUpdates(pubkey: string, callback: (pubkey: string, info: IlpPeerInfo) => void): Promise<Subscription>;
765
+ }
766
+
767
+ /**
768
+ * Genesis peer loader for bootstrapping new nodes into the network.
769
+ *
770
+ * Loads well-known genesis peers from a bundled JSON file and supports
771
+ * merging with runtime-provided additional peers.
772
+ */
773
+ /** A genesis peer entry used for network bootstrapping. */
774
+ interface GenesisPeer {
775
+ pubkey: string;
776
+ relayUrl: string;
777
+ ilpAddress: string;
778
+ btpEndpoint: string;
779
+ }
780
+ /** Load and validate genesis peers from the bundled JSON file. */
781
+ declare function loadGenesisPeers(): GenesisPeer[];
782
+ /** Parse and validate additional peers from a JSON string. */
783
+ declare function loadAdditionalPeers(json: string): GenesisPeer[];
784
+ /** Load genesis peers and optionally merge with additional peers. */
785
+ declare function loadAllPeers(additionalPeersJson?: string): GenesisPeer[];
786
+ declare const GenesisPeerLoader: {
787
+ readonly loadGenesisPeers: typeof loadGenesisPeers;
788
+ readonly loadAdditionalPeers: typeof loadAdditionalPeers;
789
+ readonly loadAllPeers: typeof loadAllPeers;
790
+ };
791
+
792
+ /**
793
+ * ArDrive-based peer registry for permanent, decentralized storage
794
+ * of ILP peer info on Arweave.
795
+ *
796
+ * Read path: queries Arweave GraphQL gateway (free, no wallet needed).
797
+ * Write path: uploads via @ardrive/turbo-sdk (caller provides authenticated client).
798
+ */
799
+
800
+ declare function fetchPeers(gatewayUrl?: string): Promise<Map<string, IlpPeerInfo>>;
801
+ declare function publishPeerInfo(peerInfo: IlpPeerInfo, pubkey: string, turboClient: TurboAuthenticatedClient): Promise<string>;
802
+ declare const ArDrivePeerRegistry: {
803
+ readonly fetchPeers: typeof fetchPeers;
804
+ readonly publishPeerInfo: typeof publishPeerInfo;
805
+ };
806
+
807
+ /**
808
+ * Social graph-based peer discovery (passive).
809
+ *
810
+ * Subscribes to NIP-02 follow list changes and emits events
811
+ * for new follows and unfollows. Does NOT auto-peer — the caller
812
+ * decides when and whether to initiate peering.
813
+ */
814
+
815
+ /**
816
+ * Events emitted by SocialPeerDiscovery.
817
+ */
818
+ type SocialDiscoveryEvent = {
819
+ type: 'social:follow-discovered';
820
+ pubkey: string;
821
+ } | {
822
+ type: 'social:follow-removed';
823
+ pubkey: string;
824
+ };
825
+ /**
826
+ * Listener callback for social discovery events.
827
+ */
828
+ type SocialDiscoveryEventListener = (event: SocialDiscoveryEvent) => void;
829
+ /**
830
+ * Configuration for SocialPeerDiscovery.
831
+ */
832
+ interface SocialPeerDiscoveryConfig {
833
+ /** Relays to subscribe to for kind:3 events */
834
+ relayUrls: string[];
835
+ }
836
+ /**
837
+ * Passive social graph peer discovery.
838
+ *
839
+ * Subscribes to NIP-02 kind:3 follow list events and emits:
840
+ * - `social:follow-discovered` when a new pubkey appears in the follow list
841
+ * - `social:follow-removed` when a pubkey disappears from the follow list
842
+ *
843
+ * The caller decides when to peer via `on()` listener.
844
+ */
845
+ declare class SocialPeerDiscovery {
846
+ private readonly config;
847
+ private readonly pubkey;
848
+ private readonly pool;
849
+ private readonly listeners;
850
+ private previousFollows;
851
+ private started;
852
+ /**
853
+ * Creates a new SocialPeerDiscovery instance.
854
+ *
855
+ * @param config - Discovery configuration
856
+ * @param secretKey - Our Nostr secret key (used to derive pubkey)
857
+ * @param pool - Optional SimplePool instance (creates new one if not provided)
858
+ */
859
+ constructor(config: SocialPeerDiscoveryConfig, secretKey: Uint8Array, pool?: SimplePool);
860
+ /**
861
+ * Register a listener for social discovery events.
862
+ */
863
+ on(listener: SocialDiscoveryEventListener): void;
864
+ /**
865
+ * Remove a previously registered listener.
866
+ */
867
+ off(listener: SocialDiscoveryEventListener): void;
868
+ /**
869
+ * Start subscribing to kind:3 follow list events for the node's pubkey.
870
+ *
871
+ * @returns Subscription with unsubscribe() to stop discovery
872
+ * @throws PeerDiscoveryError if already started
873
+ */
874
+ start(): Subscription;
875
+ /**
876
+ * Process a follow list update by diffing against previous state.
877
+ */
878
+ private processFollowListUpdate;
879
+ /**
880
+ * Emit an event to all registered listeners.
881
+ */
882
+ private emit;
883
+ }
884
+
885
+ /**
886
+ * Seed Relay Discovery -- discovers peers via kind:10036 seed relay list events.
887
+ *
888
+ * Uses raw `ws` WebSocket connections to avoid the `ReferenceError: window is
889
+ * not defined` issue that occurs with nostr-tools pool utilities in Node.js
890
+ * containers.
891
+ *
892
+ * Discovery flow:
893
+ * 1. Connect to public Nostr relays and query for kind:10036 events.
894
+ * 2. Parse seed relay entries from kind:10036 event content.
895
+ * 3. Connect to seed relays sequentially (fallback on failure).
896
+ * 4. Subscribe to kind:10032 on the first connected seed relay.
897
+ * 5. Return discovered peers as IlpPeerInfo[].
898
+ */
899
+
900
+ /** Configuration for seed relay discovery. */
901
+ interface SeedRelayDiscoveryConfig {
902
+ /** Public Nostr relay URLs to query for kind:10036 events. */
903
+ publicRelays: string[];
904
+ /** Timeout for relay connections in ms (default: 10000). */
905
+ connectionTimeout?: number;
906
+ /** Timeout for kind:10036 queries in ms (default: 5000). */
907
+ queryTimeout?: number;
908
+ }
909
+ /** Result of seed relay discovery. */
910
+ interface SeedRelayDiscoveryResult {
911
+ /** Number of seed relays successfully connected to. */
912
+ seedRelaysConnected: number;
913
+ /** Total seed relays attempted. */
914
+ attemptedSeeds: number;
915
+ /** WebSocket URLs of connected seed relays. */
916
+ connectedUrls: string[];
917
+ /** Peers discovered via kind:10032 from seed relays. */
918
+ discoveredPeers: IlpPeerInfo[];
919
+ }
920
+ /** Configuration for publishing a seed relay entry. */
921
+ interface PublishSeedRelayConfig {
922
+ /** Secret key for signing the event. */
923
+ secretKey: Uint8Array;
924
+ /** This node's WebSocket relay URL (e.g., wss://my-relay.example.com). */
925
+ relayUrl: string;
926
+ /** Public Nostr relay URLs to publish to. */
927
+ publicRelays: string[];
928
+ /** Optional metadata. */
929
+ metadata?: SeedRelayEntry['metadata'];
930
+ }
931
+ /**
932
+ * Discovers peers via the seed relay list model.
933
+ *
934
+ * Queries public Nostr relays for kind:10036 events, parses seed relay
935
+ * entries, connects to seed relays, and subscribes to kind:10032 events
936
+ * to discover network peers.
937
+ */
938
+ declare class SeedRelayDiscovery {
939
+ private readonly config;
940
+ private readonly connectionTimeout;
941
+ private readonly queryTimeout;
942
+ private readonly openSockets;
943
+ constructor(config: SeedRelayDiscoveryConfig);
944
+ /**
945
+ * Discover peers via seed relay list.
946
+ *
947
+ * 1. Query publicRelays for kind:10036 events
948
+ * 2. Parse seed relay entries
949
+ * 3. Connect to seed relays sequentially (fallback on failure)
950
+ * 4. Subscribe to kind:10032 on connected seed relay
951
+ * 5. Return discovered peers
952
+ *
953
+ * @throws PeerDiscoveryError if all seed relays are exhausted
954
+ */
955
+ discover(): Promise<SeedRelayDiscoveryResult>;
956
+ /**
957
+ * Stop discovery and close all open WebSocket connections.
958
+ */
959
+ close(): Promise<void>;
960
+ /**
961
+ * Query public relays for kind:10036 events and parse seed relay entries.
962
+ */
963
+ private querySeedRelayLists;
964
+ /**
965
+ * Deduplicate seed relay entries by URL, keeping the first occurrence.
966
+ */
967
+ private deduplicateByUrl;
968
+ }
969
+ /**
970
+ * Publish a kind:10036 event advertising this node as a seed relay.
971
+ * Connects to each publicRelay and publishes the event.
972
+ * Returns the number of relays the event was published to.
973
+ *
974
+ * @param config - Configuration for publishing the seed relay entry.
975
+ * @returns The count of successful publishes and the event ID.
976
+ */
977
+ declare function publishSeedRelayEntry(config: PublishSeedRelayConfig): Promise<{
978
+ publishedTo: number;
979
+ eventId: string;
980
+ }>;
981
+
982
+ /**
983
+ * Pure functions for settlement chain negotiation.
984
+ * No I/O or side effects — used during peer registration to determine
985
+ * the best matching settlement chain and token.
986
+ */
987
+ /**
988
+ * Negotiates the best matching settlement chain between requester and responder.
989
+ *
990
+ * Preference order:
991
+ * 1. Chain in intersection with requester's preferred token
992
+ * 2. Chain in intersection with responder's preferred token
993
+ * 3. First chain in intersection (requester's order preserved)
994
+ *
995
+ * @param requesterChains - Chain identifiers the requester supports
996
+ * @param responderChains - Chain identifiers the responder supports
997
+ * @param requesterPreferredTokens - Requester's preferred tokens by chain
998
+ * @param responderPreferredTokens - Responder's preferred tokens by chain
999
+ * @returns The negotiated chain identifier, or null if no intersection
1000
+ */
1001
+ declare function negotiateSettlementChain(requesterChains: string[], responderChains: string[], requesterPreferredTokens?: Record<string, string>, responderPreferredTokens?: Record<string, string>): string | null;
1002
+ /**
1003
+ * Resolves which token to use for a given chain.
1004
+ *
1005
+ * Priority: requester's preference > responder's preference > undefined
1006
+ *
1007
+ * @param chain - The chain identifier to resolve token for
1008
+ * @param requesterPreferredTokens - Requester's preferred tokens by chain
1009
+ * @param responderPreferredTokens - Responder's preferred tokens by chain
1010
+ * @returns The token address, or undefined if neither party has a preference
1011
+ */
1012
+ declare function resolveTokenForChain(chain: string, requesterPreferredTokens?: Record<string, string>, responderPreferredTokens?: Record<string, string>): string | undefined;
1013
+
1014
+ /**
1015
+ * Bootstrap state machine types, event types, and client interfaces.
1016
+ */
1017
+
1018
+ /**
1019
+ * A peer discovered via kind:10032 relay events but not yet peered with.
1020
+ */
1021
+ interface DiscoveredPeer {
1022
+ /** Nostr pubkey of the discovered peer (64-char hex) */
1023
+ pubkey: string;
1024
+ /** Connector peer ID (e.g., "nostr-aabb11cc22dd33ee") */
1025
+ peerId: string;
1026
+ /** Parsed ILP peer info from the kind:10032 event */
1027
+ peerInfo: IlpPeerInfo;
1028
+ /** Timestamp (seconds since epoch) when the peer was first discovered */
1029
+ discoveredAt: number;
1030
+ }
1031
+ /**
1032
+ * Represents a known peer for bootstrap.
1033
+ */
1034
+ interface KnownPeer {
1035
+ /** Nostr pubkey of the peer (64-char hex) */
1036
+ pubkey: string;
1037
+ /** WebSocket URL of the peer's Nostr relay */
1038
+ relayUrl: string;
1039
+ /** BTP WebSocket endpoint for direct connection during bootstrap */
1040
+ btpEndpoint: string;
1041
+ }
1042
+ /**
1043
+ * Result of a successful peer bootstrap.
1044
+ */
1045
+ interface BootstrapResult {
1046
+ /** The known peer that was bootstrapped with */
1047
+ knownPeer: KnownPeer;
1048
+ /** The peer's ILP info from their kind:10032 event */
1049
+ peerInfo: IlpPeerInfo;
1050
+ /** The ID used when registering with the connector (e.g., "nostr-aabb11cc22dd33ee") */
1051
+ registeredPeerId: string;
1052
+ /** Channel ID from unilateral channel opening */
1053
+ channelId?: string;
1054
+ /** Negotiated chain from local settlement negotiation */
1055
+ negotiatedChain?: string;
1056
+ /** Peer's settlement address */
1057
+ settlementAddress?: string;
1058
+ }
1059
+ /**
1060
+ * Callback interface for connector Admin API operations.
1061
+ * Matches the connector admin API shape: POST /admin/peers
1062
+ */
1063
+ interface ConnectorAdminClient {
1064
+ /**
1065
+ * Add a peer to the connector via the admin API.
1066
+ * @param config - Peer configuration matching the connector admin API shape
1067
+ */
1068
+ addPeer(config: {
1069
+ id: string;
1070
+ url: string;
1071
+ authToken: string;
1072
+ routes?: {
1073
+ prefix: string;
1074
+ priority?: number;
1075
+ }[];
1076
+ settlement?: {
1077
+ preference: string;
1078
+ evmAddress?: string;
1079
+ tokenAddress?: string;
1080
+ tokenNetworkAddress?: string;
1081
+ chainId?: number;
1082
+ channelId?: string;
1083
+ initialDeposit?: string;
1084
+ };
1085
+ }): Promise<void>;
1086
+ /**
1087
+ * Remove a peer from the connector via the admin API.
1088
+ * Optional -- not all callers will implement peer removal.
1089
+ * @param peerId - The peer ID to remove
1090
+ */
1091
+ removePeer?(peerId: string): Promise<void>;
1092
+ }
1093
+ /**
1094
+ * Bootstrap phase states.
1095
+ * Two-phase flow: discovering -> registering -> announcing -> ready | failed
1096
+ */
1097
+ type BootstrapPhase = 'discovering' | 'registering' | 'announcing' | 'ready' | 'failed';
1098
+ /**
1099
+ * Bootstrap events emitted during the bootstrap lifecycle.
1100
+ */
1101
+ type BootstrapEvent = {
1102
+ type: 'bootstrap:phase';
1103
+ phase: BootstrapPhase;
1104
+ previousPhase?: BootstrapPhase;
1105
+ } | {
1106
+ type: 'bootstrap:peer-registered';
1107
+ peerId: string;
1108
+ peerPubkey: string;
1109
+ ilpAddress: string;
1110
+ } | {
1111
+ type: 'bootstrap:channel-opened';
1112
+ peerId: string;
1113
+ channelId: string;
1114
+ negotiatedChain: string;
1115
+ } | {
1116
+ type: 'bootstrap:settlement-failed';
1117
+ peerId: string;
1118
+ reason: string;
1119
+ } | {
1120
+ type: 'bootstrap:announced';
1121
+ peerId: string;
1122
+ eventId: string;
1123
+ amount: string;
1124
+ } | {
1125
+ type: 'bootstrap:announce-failed';
1126
+ peerId: string;
1127
+ reason: string;
1128
+ } | {
1129
+ type: 'bootstrap:ready';
1130
+ peerCount: number;
1131
+ channelCount: number;
1132
+ } | {
1133
+ type: 'bootstrap:peer-discovered';
1134
+ peerPubkey: string;
1135
+ ilpAddress: string;
1136
+ } | {
1137
+ type: 'bootstrap:peer-deregistered';
1138
+ peerId: string;
1139
+ peerPubkey: string;
1140
+ reason: string;
1141
+ };
1142
+ /**
1143
+ * Listener callback for bootstrap events.
1144
+ */
1145
+ type BootstrapEventListener = (event: BootstrapEvent) => void;
1146
+ /**
1147
+ * Result of sending an ILP packet via the connector.
1148
+ * The connector may return either `accepted` or `fulfilled` as the
1149
+ * success indicator. IlpClient normalizes to `accepted`.
1150
+ */
1151
+ interface IlpSendResult {
1152
+ accepted: boolean;
1153
+ fulfillment?: string;
1154
+ data?: string;
1155
+ code?: string;
1156
+ message?: string;
1157
+ }
1158
+ /**
1159
+ * Client interface for sending ILP packets via the connector.
1160
+ */
1161
+ interface IlpClient {
1162
+ sendIlpPacket(params: {
1163
+ destination: string;
1164
+ amount: string;
1165
+ data: string;
1166
+ timeout?: number;
1167
+ }): Promise<IlpSendResult>;
1168
+ /**
1169
+ * Optional: Send ILP packet with signed balance proof claim (BTP only).
1170
+ * Falls back to sendIlpPacket if not implemented.
1171
+ */
1172
+ sendIlpPacketWithClaim?(params: {
1173
+ destination: string;
1174
+ amount: string;
1175
+ data: string;
1176
+ timeout?: number;
1177
+ }, claim: unknown): Promise<IlpSendResult>;
1178
+ }
1179
+ /**
1180
+ * @deprecated Use IlpClient instead
1181
+ */
1182
+ type AgentRuntimeClient = IlpClient;
1183
+ /**
1184
+ * Own settlement configuration for local chain selection during registration.
1185
+ */
1186
+ interface SettlementConfig {
1187
+ /** Chain identifiers this node supports */
1188
+ supportedChains?: string[];
1189
+ /** Maps chain identifier to this node's settlement address */
1190
+ settlementAddresses?: Record<string, string>;
1191
+ /** Maps chain identifier to this node's preferred token contract address */
1192
+ preferredTokens?: Record<string, string>;
1193
+ /** Maps chain identifier to TokenNetwork contract address (EVM only) */
1194
+ tokenNetworks?: Record<string, string>;
1195
+ }
1196
+ /**
1197
+ * Base configuration for the bootstrap service.
1198
+ */
1199
+ interface BootstrapConfig {
1200
+ /** List of known peers to bootstrap with */
1201
+ knownPeers: KnownPeer[];
1202
+ /** Timeout for relay queries in milliseconds (default: 5000) */
1203
+ queryTimeout?: number;
1204
+ /** Enable ArDrive peer lookup (default: true) */
1205
+ ardriveEnabled?: boolean;
1206
+ /** Default relay URL for ArDrive-sourced peers that lack relay URLs */
1207
+ defaultRelayUrl?: string;
1208
+ }
1209
+ /**
1210
+ * Extended configuration for the bootstrap service with ILP-first flow support.
1211
+ */
1212
+ interface BootstrapServiceConfig extends BootstrapConfig {
1213
+ /** Own settlement preferences for settlement during peer registration */
1214
+ settlementInfo?: SettlementConfig;
1215
+ /** This node's ILP address (for building ILP PREPARE destinations) */
1216
+ ownIlpAddress?: string;
1217
+ /** DI callback for TOON encoding (avoids circular dep) */
1218
+ toonEncoder?: (event: NostrEvent) => Uint8Array;
1219
+ /** DI callback for TOON decoding (avoids circular dep) */
1220
+ toonDecoder?: (bytes: Uint8Array) => NostrEvent;
1221
+ /** Static BTP secret for initial peer registration (before settlement) */
1222
+ btpSecret?: string;
1223
+ /** Base price per byte for ILP packet pricing (default: 10n) */
1224
+ basePricePerByte?: bigint;
1225
+ }
1226
+
1227
+ /**
1228
+ * Bootstrap service for peer discovery and network initialization.
1229
+ *
1230
+ * Handles the initial peer discovery and registration process
1231
+ * with known peers to bootstrap into the ILP network.
1232
+ *
1233
+ * Two-phase bootstrap:
1234
+ * 1. Discover & Register: Load peers, query relays for kind:10032,
1235
+ * register with connector, select chain locally, open channel unilaterally
1236
+ * 2. Announce: Publish own kind:10032 as paid ILP PREPARE
1237
+ */
1238
+
1239
+ /**
1240
+ * Error thrown when bootstrap operations fail.
1241
+ */
1242
+ declare class BootstrapError extends ToonError {
1243
+ constructor(message: string, cause?: Error);
1244
+ }
1245
+ /**
1246
+ * Service for bootstrapping into the ILP network via known Nostr peers.
1247
+ *
1248
+ * The bootstrap process:
1249
+ * Phase 1 (Discover & Register): Load peers from config, ArDrive, and env var.
1250
+ * For each peer, query their relay for kind:10032 (ILP Peer Info).
1251
+ * Register peer via connector admin API.
1252
+ * Select chain locally and open channel unilaterally.
1253
+ * Phase 2 (Announce): Publish own kind:10032 as paid ILP PREPARE.
1254
+ */
1255
+ declare class BootstrapService {
1256
+ private readonly config;
1257
+ private readonly secretKey;
1258
+ private readonly pubkey;
1259
+ private readonly ownIlpInfo;
1260
+ private readonly pool;
1261
+ private connectorAdmin?;
1262
+ private channelClient?;
1263
+ private claimSigner?;
1264
+ private readonly ilpClient?;
1265
+ private readonly settlementInfo?;
1266
+ private readonly ownIlpAddress?;
1267
+ private readonly toonEncoder?;
1268
+ private readonly toonDecoder?;
1269
+ private readonly basePricePerByte;
1270
+ private listeners;
1271
+ private phase;
1272
+ /**
1273
+ * Creates a new BootstrapService instance.
1274
+ *
1275
+ * @param config - Bootstrap configuration with known peers and optional ILP-first settings
1276
+ * @param secretKey - Our Nostr secret key for signing events
1277
+ * @param ownIlpInfo - Our ILP peer info to publish
1278
+ * @param pool - Optional SimplePool instance (creates new one if not provided)
1279
+ */
1280
+ constructor(config: BootstrapServiceConfig, secretKey: Uint8Array, ownIlpInfo: IlpPeerInfo, pool?: SimplePool);
1281
+ /**
1282
+ * Set the ILP client for sending packets via the connector.
1283
+ * Kept separate from constructor for backward compatibility with existing code
1284
+ * that creates the client after construction.
1285
+ */
1286
+ setIlpClient(client: IlpClient): void;
1287
+ /**
1288
+ * @deprecated Use setIlpClient instead
1289
+ */
1290
+ setAgentRuntimeClient(client: IlpClient): void;
1291
+ /**
1292
+ * Set the connector admin client for adding peers/routes.
1293
+ */
1294
+ setConnectorAdmin(admin: ConnectorAdminClient): void;
1295
+ /**
1296
+ * Set the channel client for opening payment channels.
1297
+ */
1298
+ setChannelClient(client: ConnectorChannelClient): void;
1299
+ /**
1300
+ * Set the claim signer for creating signed balance proofs.
1301
+ * Used by clients to sign payment channel claims for ILP packets.
1302
+ */
1303
+ setClaimSigner(signer: (channelId: string, amount: bigint) => Promise<unknown>): void;
1304
+ /**
1305
+ * Get the current bootstrap phase.
1306
+ */
1307
+ getPhase(): BootstrapPhase;
1308
+ /**
1309
+ * Register an event listener.
1310
+ */
1311
+ on(listener: BootstrapEventListener): void;
1312
+ /**
1313
+ * Unregister an event listener.
1314
+ */
1315
+ off(listener: BootstrapEventListener): void;
1316
+ /**
1317
+ * Emit a bootstrap event to all listeners.
1318
+ */
1319
+ private emit;
1320
+ /**
1321
+ * Transition to a new phase, emitting phase change event.
1322
+ */
1323
+ private setPhase;
1324
+ /**
1325
+ * Load peers from genesis config, ArDrive, and optional env var JSON.
1326
+ * Merges all sources, deduplicating by pubkey (ArDrive overrides genesis for matching pubkeys).
1327
+ */
1328
+ loadPeers(additionalPeersJson?: string): Promise<GenesisPeer[]>;
1329
+ /**
1330
+ * Bootstrap with all known peers.
1331
+ *
1332
+ * Loads peers from genesis config, ArDrive, and optional env var JSON,
1333
+ * then attempts to bootstrap with each peer in order.
1334
+ * Returns results for successfully bootstrapped peers.
1335
+ * Continues to next peer on failure.
1336
+ *
1337
+ * @param additionalPeersJson - Optional JSON string of additional peers to merge
1338
+ * @returns Array of successful bootstrap results
1339
+ */
1340
+ bootstrap(additionalPeersJson?: string): Promise<BootstrapResult[]>;
1341
+ /**
1342
+ * Bootstrap with a single known peer.
1343
+ *
1344
+ * @param knownPeer - The known peer to bootstrap with
1345
+ * @returns Bootstrap result with peer info and registered peer ID
1346
+ * @throws BootstrapError if pubkey is invalid or peer info query fails
1347
+ */
1348
+ bootstrapWithPeer(knownPeer: KnownPeer): Promise<BootstrapResult>;
1349
+ /**
1350
+ * Announce own kind:10032 as paid ILP PREPARE (Phase 2).
1351
+ */
1352
+ private announceViaIlp;
1353
+ /**
1354
+ * Query a peer's relay for their kind:10032 ILP Peer Info event.
1355
+ * Uses direct WebSocket connection for reliable container-to-container communication.
1356
+ */
1357
+ private queryPeerInfo;
1358
+ /**
1359
+ * Add a peer to the connector via Admin API.
1360
+ */
1361
+ private addPeerToConnector;
1362
+ /**
1363
+ * Publish our own kind:10032 ILP Peer Info to a relay.
1364
+ */
1365
+ private publishOurInfo;
1366
+ /**
1367
+ * Query a peer's relay for other peers' kind:10032 events.
1368
+ *
1369
+ * Used after bootstrapping to discover additional peers
1370
+ * that have also published to the bootstrap node's relay.
1371
+ *
1372
+ * @param relayUrl - The relay URL to query
1373
+ * @param excludePubkeys - Pubkeys to exclude from results (e.g., our own, known peers)
1374
+ * @returns Map of pubkey to IlpPeerInfo for discovered peers
1375
+ */
1376
+ discoverPeersViaRelay(relayUrl: string, excludePubkeys?: string[]): Promise<Map<string, IlpPeerInfo>>;
1377
+ /**
1378
+ * Get our pubkey.
1379
+ */
1380
+ getPubkey(): string;
1381
+ /**
1382
+ * Publish our ILP info to a specific relay.
1383
+ *
1384
+ * @param relayUrl - The relay URL to publish to (defaults to 'ws://localhost:7100')
1385
+ */
1386
+ publishToRelay(relayUrl?: string): Promise<void>;
1387
+ }
1388
+
1389
+ /**
1390
+ * Discovery tracker for processing kind:10032 events and managing peer discovery.
1391
+ *
1392
+ * Unlike RelayMonitor, the tracker does NOT own a subscription — callers feed
1393
+ * events in via processEvent(). This enables use from any event source:
1394
+ * relay subscriptions, ILP handlers, or test harnesses.
1395
+ */
1396
+
1397
+ /**
1398
+ * Configuration for creating a DiscoveryTracker.
1399
+ */
1400
+ interface DiscoveryTrackerConfig {
1401
+ /** Nostr secret key for deriving own pubkey (excluded from discovery) */
1402
+ secretKey: Uint8Array;
1403
+ /** Own settlement preferences for local chain negotiation */
1404
+ settlementInfo?: SettlementConfig;
1405
+ }
1406
+ /**
1407
+ * Discovery tracker interface — processes kind:10032 events and manages
1408
+ * peer discovery state without owning a subscription.
1409
+ */
1410
+ interface DiscoveryTracker {
1411
+ /** Process a kind:10032 event for discovery. Called by relay subscription or ILP handler. */
1412
+ processEvent(event: NostrEvent): void;
1413
+ /** Explicitly peer with a discovered peer (register + open channel). */
1414
+ peerWith(pubkey: string): Promise<void>;
1415
+ /** Get discovered peers not yet peered with. */
1416
+ getDiscoveredPeers(): DiscoveredPeer[];
1417
+ /** Check if a pubkey has been actively peered with. */
1418
+ isPeered(pubkey: string): boolean;
1419
+ /** Count of registered (peered) peers. */
1420
+ getPeerCount(): number;
1421
+ /** Count of all discovered peers (including peered). */
1422
+ getDiscoveredCount(): number;
1423
+ /** Register an event listener. */
1424
+ on(listener: BootstrapEventListener): void;
1425
+ /** Unregister an event listener. */
1426
+ off(listener: BootstrapEventListener): void;
1427
+ /** Set connector admin for peer registration (required before peerWith). */
1428
+ setConnectorAdmin(admin: ConnectorAdminClient): void;
1429
+ /** Set channel client for payment channel opening (optional). */
1430
+ setChannelClient(client: ConnectorChannelClient): void;
1431
+ /** Mark pubkeys as already-peered (e.g., from bootstrap phase). */
1432
+ addExcludedPubkeys(pubkeys: string[]): void;
1433
+ }
1434
+ /**
1435
+ * Create a discovery tracker that processes kind:10032 events.
1436
+ *
1437
+ * The tracker does not own a subscription — callers feed events in via
1438
+ * processEvent(). It handles discovery, stale-event filtering,
1439
+ * deregistration, and explicit peering via peerWith().
1440
+ */
1441
+ declare function createDiscoveryTracker(config: DiscoveryTrackerConfig): DiscoveryTracker;
1442
+
1443
+ /**
1444
+ * HTTP client for sending ILP packets via the connector's POST /ilp/send endpoint.
1445
+ */
1446
+
1447
+ /**
1448
+ * Creates an HTTP-based IlpClient that sends ILP packets via POST /ilp/send.
1449
+ *
1450
+ * @param baseUrl - Base URL of the connector (e.g., "http://localhost:3000")
1451
+ * @returns An IlpClient instance
1452
+ * @throws BootstrapError if baseUrl is not a valid URL
1453
+ */
1454
+ declare function createHttpIlpClient$1(baseUrl: string): IlpClient;
1455
+ /**
1456
+ * @deprecated Use createHttpIlpClient instead
1457
+ */
1458
+ declare const createHttpRuntimeClient: typeof createHttpIlpClient$1;
1459
+ /**
1460
+ * @deprecated Use createHttpIlpClient instead
1461
+ */
1462
+ declare const createAgentRuntimeClient: typeof createHttpIlpClient$1;
1463
+
1464
+ /**
1465
+ * Direct (in-process) client for sending ILP packets via a ConnectorNode.
1466
+ *
1467
+ * Unlike the HTTP-based createHttpIlpClient(), this factory wraps a
1468
+ * ConnectorNode's sendPacket() method as an IlpClient, enabling
1469
+ * zero-latency embedded mode without network overhead.
1470
+ */
1471
+
1472
+ /**
1473
+ * Parameters accepted by ConnectorNode.sendPacket().
1474
+ */
1475
+ interface SendPacketParams {
1476
+ /** ILP destination address */
1477
+ destination: string;
1478
+ /** Amount as BigInt (not string) */
1479
+ amount: bigint;
1480
+ /** Binary data (not base64 string) */
1481
+ data: Uint8Array;
1482
+ /** 32-byte SHA-256 execution condition */
1483
+ executionCondition?: Uint8Array;
1484
+ /**
1485
+ * Packet expiration. Included for structural compatibility with ConnectorNode
1486
+ * but is not set by the direct client — callers or the connector provide it
1487
+ * if needed.
1488
+ */
1489
+ expiresAt?: Date;
1490
+ }
1491
+ /**
1492
+ * Result returned by ConnectorNode.sendPacket().
1493
+ *
1494
+ * Accepts both string discriminants ('fulfill'/'reject') for backward
1495
+ * compatibility with test mocks, and numeric PacketType enum values
1496
+ * (13 = FULFILL, 14 = REJECT) used by @toon-protocol/connector@1.6.0+.
1497
+ */
1498
+ type SendPacketResult = {
1499
+ type: 'fulfill';
1500
+ fulfillment: Uint8Array | Buffer;
1501
+ data?: Uint8Array | Buffer;
1502
+ } | {
1503
+ type: 13;
1504
+ fulfillment: Uint8Array | Buffer;
1505
+ data?: Uint8Array | Buffer;
1506
+ } | {
1507
+ type: 'reject';
1508
+ code: string;
1509
+ message: string;
1510
+ data?: Uint8Array | Buffer;
1511
+ } | {
1512
+ type: 14;
1513
+ code: string;
1514
+ message: string;
1515
+ data?: Uint8Array | Buffer;
1516
+ };
1517
+ /**
1518
+ * Structural interface matching ConnectorNode's sendPacket() method.
1519
+ *
1520
+ * Consumers pass a `@toon-protocol/connector` ConnectorNode instance without
1521
+ * needing to import `@toon-protocol/connector` as a dependency.
1522
+ * TypeScript's structural type system handles compatibility automatically.
1523
+ */
1524
+ interface ConnectorNodeLike {
1525
+ sendPacket(params: SendPacketParams): Promise<SendPacketResult>;
1526
+ }
1527
+ /**
1528
+ * Configuration options for the direct runtime client.
1529
+ */
1530
+ interface DirectRuntimeClientConfig {
1531
+ /**
1532
+ * Optional callback for extracting the Nostr event ID from TOON-encoded data.
1533
+ *
1534
+ * When provided, the client computes
1535
+ * `executionCondition = SHA256(SHA256(event.id))` and passes it to
1536
+ * `sendPacket()`.
1537
+ *
1538
+ * When omitted, no executionCondition is set (connector uses its default).
1539
+ *
1540
+ * Note: this is intentionally a narrower type than
1541
+ * `BootstrapServiceConfig.toonDecoder` (which returns a full `NostrEvent`).
1542
+ * Only the `id` field is needed for condition computation, so the interface
1543
+ * is minimal.
1544
+ */
1545
+ toonDecoder?: (bytes: Uint8Array) => {
1546
+ id: string;
1547
+ };
1548
+ }
1549
+ /**
1550
+ * Creates an IlpClient that sends ILP packets by calling
1551
+ * `connector.sendPacket()` directly (no HTTP).
1552
+ *
1553
+ * @param connector - A ConnectorNode-like object with a sendPacket() method
1554
+ * @param config - Optional configuration (e.g., toonDecoder for condition computation)
1555
+ * @returns An IlpClient instance
1556
+ */
1557
+ declare function createDirectIlpClient(connector: ConnectorNodeLike, config?: DirectRuntimeClientConfig): IlpClient;
1558
+ /**
1559
+ * @deprecated Use createDirectIlpClient instead
1560
+ */
1561
+ declare const createDirectRuntimeClient: typeof createDirectIlpClient;
1562
+
1563
+ /**
1564
+ * Parameters for registering a peer on the connector.
1565
+ * Maps to ConnectorNode.registerPeer() params in @toon-protocol/connector.
1566
+ */
1567
+ interface RegisterPeerParams {
1568
+ id: string;
1569
+ url: string;
1570
+ authToken?: string;
1571
+ routes?: {
1572
+ prefix: string;
1573
+ priority?: number;
1574
+ }[];
1575
+ settlement?: Record<string, unknown>;
1576
+ }
1577
+ /**
1578
+ * Structural interface for ConnectorNode admin methods.
1579
+ *
1580
+ * This is a structural interface — consumers pass an `@toon-protocol/connector`
1581
+ * ConnectorNode instance without importing it as a dependency. The ConnectorNode's
1582
+ * `registerPeer()` and `removePeer()` methods match this shape, allowing
1583
+ * zero-dependency coupling for embedded mode.
1584
+ */
1585
+ interface ConnectorAdminLike {
1586
+ registerPeer(params: RegisterPeerParams): Promise<void>;
1587
+ removePeer(peerId: string): Promise<void>;
1588
+ }
1589
+ /**
1590
+ * Creates a ConnectorAdminClient that calls ConnectorNode methods directly
1591
+ * instead of making HTTP requests.
1592
+ *
1593
+ * Used for embedded mode where the ConnectorNode runs in-process.
1594
+ * The returned client conforms to the ConnectorAdminClient interface,
1595
+ * making it a drop-in replacement for the HTTP-based admin client.
1596
+ *
1597
+ * @param connector - A ConnectorNode instance (or any object matching ConnectorAdminLike)
1598
+ * @returns A ConnectorAdminClient that manages peers via direct function calls
1599
+ *
1600
+ * @example
1601
+ * ```typescript
1602
+ * import { ConnectorNode } from '@toon-protocol/connector';
1603
+ * import { createDirectConnectorAdmin } from '@toon-protocol/core/bootstrap';
1604
+ *
1605
+ * const connector = new ConnectorNode({ ... });
1606
+ * const adminClient = createDirectConnectorAdmin(connector);
1607
+ *
1608
+ * await adminClient.addPeer({
1609
+ * id: 'peer1',
1610
+ * url: 'btp+ws://peer1.example.com',
1611
+ * authToken: 'secret',
1612
+ * routes: [{ prefix: 'g.alice', priority: 1 }],
1613
+ * });
1614
+ * ```
1615
+ */
1616
+ declare function createDirectConnectorAdmin(connector: ConnectorAdminLike): ConnectorAdminClient;
1617
+
1618
+ /**
1619
+ * Direct (in-process) client for payment channel operations via a ConnectorNode.
1620
+ *
1621
+ * Unlike HTTP-based channel clients, this factory wraps a ConnectorNode's
1622
+ * openChannel() and getChannelState() methods as a ConnectorChannelClient,
1623
+ * enabling zero-latency embedded mode without network overhead.
1624
+ *
1625
+ * Requires @toon-protocol/connector >=1.2.0 which exposes these methods
1626
+ * as public API on ConnectorNode.
1627
+ */
1628
+
1629
+ /**
1630
+ * Structural interface matching ConnectorNode's channel methods.
1631
+ *
1632
+ * Consumers pass an `@toon-protocol/connector` ConnectorNode instance without
1633
+ * toon needing to import `@toon-protocol/connector` as a dependency.
1634
+ * TypeScript's structural type system handles compatibility automatically.
1635
+ */
1636
+ interface ConnectorChannelLike {
1637
+ openChannel(params: {
1638
+ peerId: string;
1639
+ chain: string;
1640
+ token?: string;
1641
+ tokenNetwork?: string;
1642
+ peerAddress: string;
1643
+ initialDeposit?: string;
1644
+ settlementTimeout?: number;
1645
+ }): Promise<{
1646
+ channelId: string;
1647
+ status: string;
1648
+ }>;
1649
+ getChannelState(channelId: string): Promise<{
1650
+ channelId: string;
1651
+ status: 'opening' | 'open' | 'closed' | 'settled';
1652
+ chain: string;
1653
+ }>;
1654
+ }
1655
+ /**
1656
+ * Creates a ConnectorChannelClient that calls ConnectorNode methods directly
1657
+ * instead of making HTTP requests.
1658
+ *
1659
+ * Used for embedded mode where the ConnectorNode runs in-process.
1660
+ * The returned client conforms to the ConnectorChannelClient interface,
1661
+ * making it a drop-in replacement for the HTTP-based channel client.
1662
+ *
1663
+ * @param connector - A ConnectorNode instance (or any object matching ConnectorChannelLike)
1664
+ * @returns A ConnectorChannelClient that manages channels via direct function calls
1665
+ *
1666
+ * @example
1667
+ * ```typescript
1668
+ * import { ConnectorNode } from '@toon-protocol/connector';
1669
+ * import { createDirectChannelClient } from '@toon-protocol/core/bootstrap';
1670
+ *
1671
+ * const connector = new ConnectorNode({ ... });
1672
+ * const channelClient = createDirectChannelClient(connector);
1673
+ *
1674
+ * const result = await channelClient.openChannel({
1675
+ * peerId: 'nostr-54dad746e52dab00',
1676
+ * chain: 'evm:base:84532',
1677
+ * peerAddress: '0x6AFbC4...',
1678
+ * });
1679
+ * ```
1680
+ */
1681
+ declare function createDirectChannelClient(connector: ConnectorChannelLike): ConnectorChannelClient;
1682
+
1683
+ /**
1684
+ * HTTP-based client for connector admin operations.
1685
+ *
1686
+ * Calls the connector's Admin API over HTTP to register/remove peers.
1687
+ */
1688
+
1689
+ /**
1690
+ * Creates a ConnectorAdminClient that calls the Connector Admin API via HTTP.
1691
+ *
1692
+ * @param adminUrl - Base URL of the connector admin API (e.g., "http://connector:8081")
1693
+ * @param btpSecret - Shared secret for BTP authentication
1694
+ * @returns A ConnectorAdminClient that manages peers via HTTP
1695
+ *
1696
+ * @example
1697
+ * ```typescript
1698
+ * const adminClient = createHttpConnectorAdmin('http://localhost:8091', 'secret');
1699
+ *
1700
+ * await adminClient.addPeer({
1701
+ * id: 'peer2',
1702
+ * url: 'ws://connector-peer2:3000',
1703
+ * authToken: JSON.stringify({ peerId: 'peer2', secret: 'secret' }),
1704
+ * routes: [{ prefix: 'g.toon.peer2', priority: 0 }],
1705
+ * settlement: {
1706
+ * preference: 'evm',
1707
+ * evmAddress: '0x...',
1708
+ * chainId: 31337,
1709
+ * },
1710
+ * });
1711
+ * ```
1712
+ */
1713
+ declare function createHttpConnectorAdmin(adminUrl: string, btpSecret: string): ConnectorAdminClient;
1714
+
1715
+ /**
1716
+ * HTTP-based client for sending ILP packets via the connector API.
1717
+ *
1718
+ * Calls the connector's packet handling endpoint over HTTP.
1719
+ */
1720
+
1721
+ /**
1722
+ * Creates an IlpClient that sends ILP packets via HTTP.
1723
+ *
1724
+ * @param connectorUrl - Base URL of the connector (e.g., "http://connector:8080")
1725
+ * @returns An IlpClient instance
1726
+ *
1727
+ * @example
1728
+ * ```typescript
1729
+ * const ilpClient = createHttpIlpClient('http://localhost:8081');
1730
+ *
1731
+ * const result = await ilpClient.sendIlpPacket({
1732
+ * destination: 'g.toon.peer2',
1733
+ * amount: '1000',
1734
+ * data: base64EncodedToon,
1735
+ * });
1736
+ * ```
1737
+ */
1738
+ declare function createHttpIlpClient(connectorUrl: string): IlpClient;
1739
+
1740
+ /**
1741
+ * HTTP-based client for payment channel operations.
1742
+ *
1743
+ * Calls the connector's Admin API to open channels and query channel state.
1744
+ */
1745
+
1746
+ /**
1747
+ * Creates a ConnectorChannelClient that calls the Connector Admin API via HTTP.
1748
+ *
1749
+ * @param adminUrl - Base URL of the connector admin API (e.g., "http://connector:8081")
1750
+ * @returns A ConnectorChannelClient that manages channels via HTTP
1751
+ *
1752
+ * @example
1753
+ * ```typescript
1754
+ * const channelClient = createHttpChannelClient('http://localhost:8091');
1755
+ *
1756
+ * const result = await channelClient.openChannel({
1757
+ * peerId: 'peer2',
1758
+ * chain: 'evm:base:31337',
1759
+ * peerAddress: '0x90F79bf6EB2c4f870365E785982E1f101E93b906',
1760
+ * initialDeposit: '100000',
1761
+ * });
1762
+ * ```
1763
+ */
1764
+ declare function createHttpChannelClient(adminUrl: string): ConnectorChannelClient;
1765
+
1766
+ /**
1767
+ * AttestationVerifier -- TEE attestation verification, state lifecycle,
1768
+ * and attestation-aware peer ranking for Story 4.3.
1769
+ *
1770
+ * This is a pure logic class with no transport layer. It receives parsed
1771
+ * attestation data and returns verification results. The transport layer
1772
+ * (subscribing to kind:10033 events on relays) is a Story 4.6 concern.
1773
+ *
1774
+ * The AttestationVerifier is the single source of truth for attestation
1775
+ * state (R-E4-008). Both the kind:10033 Nostr event path and the /health
1776
+ * HTTP endpoint derive their TEE state from the same verifier instance.
1777
+ *
1778
+ * Attestation State Machine (Decision 12):
1779
+ * VALID (within validitySeconds)
1780
+ * -> STALE (within graceSeconds after validity expires)
1781
+ * -> UNATTESTED (after grace period expires)
1782
+ *
1783
+ * Trust degrades; money doesn't -- attestation state changes never
1784
+ * trigger payment channel closure.
1785
+ */
1786
+
1787
+ /**
1788
+ * Attestation lifecycle state.
1789
+ *
1790
+ * Transitions: VALID -> STALE -> UNATTESTED.
1791
+ * A peer that was never attested starts as UNATTESTED.
1792
+ */
1793
+ declare enum AttestationState {
1794
+ /** Attestation is within validity period. */
1795
+ VALID = "valid",
1796
+ /** Attestation has expired but is within the grace period. */
1797
+ STALE = "stale",
1798
+ /** Attestation has expired past the grace period or was never attested. */
1799
+ UNATTESTED = "unattested"
1800
+ }
1801
+ /** Result of PCR verification against a known-good registry. */
1802
+ interface VerificationResult {
1803
+ valid: boolean;
1804
+ reason?: string;
1805
+ }
1806
+ /**
1807
+ * Descriptor for a peer in the attestation-aware ranking system.
1808
+ * Used by `rankPeers()` to order peers by attestation status.
1809
+ */
1810
+ interface PeerDescriptor {
1811
+ pubkey: string;
1812
+ relayUrl: string;
1813
+ attested: boolean;
1814
+ attestationTimestamp?: number;
1815
+ }
1816
+ /**
1817
+ * Configuration for the AttestationVerifier.
1818
+ */
1819
+ interface AttestationVerifierConfig {
1820
+ /** Map of known-good PCR values. Key is PCR hash, value is trust status. */
1821
+ knownGoodPcrs: Map<string, boolean>;
1822
+ /** Attestation validity period in seconds (default: 300). */
1823
+ validitySeconds?: number;
1824
+ /** Grace period in seconds after validity expires before marking as unattested (default: 30). */
1825
+ graceSeconds?: number;
1826
+ }
1827
+ /**
1828
+ * Verifies TEE attestations, computes attestation lifecycle state,
1829
+ * and ranks peers by attestation status.
1830
+ *
1831
+ * Single source of truth for attestation state (R-E4-008).
1832
+ */
1833
+ declare class AttestationVerifier {
1834
+ private readonly knownGoodPcrs;
1835
+ private readonly validitySeconds;
1836
+ private readonly graceSeconds;
1837
+ constructor(config: AttestationVerifierConfig);
1838
+ /**
1839
+ * Verifies a TEE attestation's PCR values against the known-good registry.
1840
+ *
1841
+ * All three PCR values (pcr0, pcr1, pcr2) must be present and truthy in
1842
+ * the registry for verification to pass.
1843
+ *
1844
+ * @param attestation - The TEE attestation to verify.
1845
+ * @returns Verification result with `valid: true` or `valid: false` with reason.
1846
+ */
1847
+ verify(attestation: TeeAttestation): VerificationResult;
1848
+ /**
1849
+ * Computes the attestation lifecycle state based on timing.
1850
+ *
1851
+ * Boundary behavior:
1852
+ * - At exactly `attestedAt + validitySeconds`: VALID (inclusive <=)
1853
+ * - At exactly `attestedAt + validitySeconds + graceSeconds`: STALE (inclusive <=)
1854
+ * - After grace expires: UNATTESTED
1855
+ *
1856
+ * @param _attestation - The TEE attestation (unused, reserved for future per-attestation logic).
1857
+ * @param attestedAt - Unix timestamp when the attestation was created.
1858
+ * @param now - Optional current unix timestamp (defaults to real clock).
1859
+ * @returns The current attestation state.
1860
+ */
1861
+ getAttestationState(_attestation: TeeAttestation, attestedAt: number, now?: number): AttestationState;
1862
+ /**
1863
+ * Ranks peers by attestation status: attested peers first, then non-attested.
1864
+ *
1865
+ * Preserves relative order within each group (stable sort via filter).
1866
+ * Does NOT mutate the input array -- returns a new sorted array.
1867
+ *
1868
+ * Attestation is a preference, not a requirement. Non-attested peers
1869
+ * remain in the result and are connectable.
1870
+ *
1871
+ * @param peers - Array of peer descriptors to rank.
1872
+ * @returns New array with attested peers first, preserving relative order.
1873
+ */
1874
+ rankPeers(peers: PeerDescriptor[]): PeerDescriptor[];
1875
+ }
1876
+
1877
+ /**
1878
+ * AttestationBootstrap -- attestation-first seed relay bootstrap for Story 4.6.
1879
+ *
1880
+ * Implements FR-TEE-6: the bootstrap trust flow that verifies kind:10033 TEE
1881
+ * attestation on each seed relay BEFORE trusting its kind:10032 peer list.
1882
+ * This prevents seed relay list poisoning (R-E4-004).
1883
+ *
1884
+ * Trust flow:
1885
+ * 1. Read seed relay list from kind:10036 (Story 3.4)
1886
+ * 2. Connect to seed relay
1887
+ * 3. Query kind:10033 attestation
1888
+ * 4. Verify PCR measurement (Story 4.3)
1889
+ * 5. If valid -> subscribe to kind:10032 -> discover peers
1890
+ * 6. If invalid -> fall back to next seed relay
1891
+ *
1892
+ * This is a pure orchestration class with no transport logic. The
1893
+ * `queryAttestation` and `subscribePeers` callbacks are injected via DI,
1894
+ * keeping the class fully testable without WebSocket mocks.
1895
+ *
1896
+ * Decision 12 invariant: "Trust degrades; money doesn't." This class
1897
+ * never touches payment channel state.
1898
+ */
1899
+
1900
+ /**
1901
+ * Configuration for the attestation-first bootstrap flow.
1902
+ */
1903
+ interface AttestationBootstrapConfig {
1904
+ /** Seed relay WebSocket URLs from kind:10036 */
1905
+ seedRelays: string[];
1906
+ /**
1907
+ * Nostr secret key for signing (reserved for future use).
1908
+ * @remarks Stored in config but not accessed by bootstrap(). Maintained for
1909
+ * API consistency with BootstrapService and future subscription signing.
1910
+ */
1911
+ secretKey: Uint8Array;
1912
+ /**
1913
+ * Verifier instance (or mock) with verify method.
1914
+ *
1915
+ * The DI interface accepts NostrEvent (the raw attestation event) and
1916
+ * returns boolean | Promise<boolean> | VerificationResult to support
1917
+ * both the real verifier (after caller extracts TeeAttestation) and
1918
+ * test mocks (which return Promise<boolean> via mockResolvedValue).
1919
+ *
1920
+ * The implementation normalizes via: await Promise.resolve(verifier.verify(event))
1921
+ */
1922
+ verifier: {
1923
+ verify: (attestation: NostrEvent) => boolean | VerificationResult | Promise<boolean | VerificationResult>;
1924
+ getState?: (...args: unknown[]) => unknown;
1925
+ };
1926
+ /** DI callback: query a relay for its kind:10033 attestation event */
1927
+ queryAttestation: (relayUrl: string) => Promise<NostrEvent | null>;
1928
+ /** DI callback: subscribe to a relay's kind:10032 peer info events */
1929
+ subscribePeers: (relayUrl: string) => Promise<NostrEvent[]>;
1930
+ }
1931
+ /**
1932
+ * Result of the attestation-first bootstrap flow.
1933
+ */
1934
+ interface AttestationBootstrapResult {
1935
+ /** 'attested' if at least one seed relay passed verification, 'degraded' otherwise */
1936
+ mode: 'attested' | 'degraded';
1937
+ /** URL of the first seed relay that passed attestation (undefined in degraded mode) */
1938
+ attestedSeedRelay?: string;
1939
+ /** Peer info events discovered from attested seed relays */
1940
+ discoveredPeers: NostrEvent[];
1941
+ }
1942
+ /**
1943
+ * Lifecycle events emitted during attestation-first bootstrap.
1944
+ */
1945
+ type AttestationBootstrapEvent = {
1946
+ type: 'attestation:seed-connected';
1947
+ relayUrl: string;
1948
+ } | {
1949
+ type: 'attestation:verified';
1950
+ relayUrl: string;
1951
+ pubkey: string;
1952
+ } | {
1953
+ type: 'attestation:verification-failed';
1954
+ relayUrl: string;
1955
+ reason: string;
1956
+ } | {
1957
+ type: 'attestation:peers-discovered';
1958
+ relayUrl: string;
1959
+ peerCount: number;
1960
+ } | {
1961
+ type: 'attestation:degraded';
1962
+ triedCount: number;
1963
+ };
1964
+ /** Listener callback for attestation bootstrap events. */
1965
+ type AttestationBootstrapEventListener = (event: AttestationBootstrapEvent) => void;
1966
+ /**
1967
+ * Orchestrates attestation-first seed relay bootstrap.
1968
+ *
1969
+ * Iterates seed relays sequentially, verifying kind:10033 attestation
1970
+ * before subscribing to kind:10032 peer info events. Falls back to
1971
+ * degraded mode when all seed relays fail attestation verification.
1972
+ */
1973
+ declare class AttestationBootstrap {
1974
+ private readonly config;
1975
+ private listeners;
1976
+ constructor(config: AttestationBootstrapConfig);
1977
+ /**
1978
+ * Register an event listener.
1979
+ */
1980
+ on(listener: AttestationBootstrapEventListener): void;
1981
+ /**
1982
+ * Unregister an event listener.
1983
+ */
1984
+ off(listener: AttestationBootstrapEventListener): void;
1985
+ /**
1986
+ * Emit an attestation bootstrap event to all listeners.
1987
+ */
1988
+ private emit;
1989
+ /**
1990
+ * Execute the attestation-first bootstrap flow.
1991
+ *
1992
+ * Iterates seed relays in order:
1993
+ * 1. Emit seed-connected, query attestation
1994
+ * 2. If null or verify fails or error: emit verification-failed, try next
1995
+ * 3. If valid: emit verified, subscribe peers, emit peers-discovered
1996
+ * 4. Return attested result with discovered peers
1997
+ * 5. If ALL fail: log warning, emit degraded, return degraded result
1998
+ */
1999
+ bootstrap(): Promise<AttestationBootstrapResult>;
2000
+ }
2001
+
2002
+ /**
2003
+ * TOON Node composition API.
2004
+ *
2005
+ * Provides createToonNode() — a single composition function that wires
2006
+ * ConnectorNode ↔ BLS ↔ BootstrapService ↔ DiscoveryTracker into one object
2007
+ * with start() / stop() lifecycle, enabling zero-latency embedded mode without
2008
+ * manually wiring each component.
2009
+ */
2010
+
2011
+ /**
2012
+ * Structural type for incoming ILP packet handler request.
2013
+ *
2014
+ * Matches the shape of BLS HandlePacketRequest without creating a cross-package
2015
+ * dependency from @toon-protocol/core → @toon-protocol/bls.
2016
+ */
2017
+ interface HandlePacketRequest {
2018
+ /** Payment amount as string (parsed to bigint) */
2019
+ amount: string;
2020
+ /** ILP destination address */
2021
+ destination: string;
2022
+ /** Base64-encoded TOON Nostr event */
2023
+ data: string;
2024
+ /** Source ILP address */
2025
+ sourceAccount?: string;
2026
+ }
2027
+ /**
2028
+ * Structural type for ILP packet handler accept response.
2029
+ */
2030
+ interface HandlePacketAcceptResponse {
2031
+ accept: true;
2032
+ /** Base64-encoded fulfillment (SHA-256 of event.id) */
2033
+ fulfillment: string;
2034
+ /** Base64-encoded response data (e.g., TOON-encoded response for relay back in ILP FULFILL) */
2035
+ data?: string;
2036
+ metadata?: Record<string, unknown>;
2037
+ }
2038
+ /**
2039
+ * Structural type for ILP packet handler reject response.
2040
+ */
2041
+ interface HandlePacketRejectResponse {
2042
+ accept: false;
2043
+ /** ILP error code (F00, F06, T00) */
2044
+ code: string;
2045
+ /** Human-readable error message */
2046
+ message: string;
2047
+ metadata?: Record<string, unknown>;
2048
+ }
2049
+ /**
2050
+ * Union type for ILP packet handler response.
2051
+ */
2052
+ type HandlePacketResponse = HandlePacketAcceptResponse | HandlePacketRejectResponse;
2053
+ /**
2054
+ * Callback invoked by the connector for incoming ILP packets.
2055
+ *
2056
+ * **NOTE:** This is a **function** (not a BusinessLogicServer instance) because
2057
+ * packet handling logic lives in the caller's entrypoint code, not in
2058
+ * BusinessLogicServer. The caller provides the full handler that knows how to
2059
+ * process incoming events.
2060
+ */
2061
+ type PacketHandler = (request: HandlePacketRequest) => HandlePacketResponse | Promise<HandlePacketResponse>;
2062
+ /**
2063
+ * Structural interface for the full embedded connector API.
2064
+ *
2065
+ * Combines:
2066
+ * 1. ConnectorNodeLike (sendPacket) — for outbound ILP packets
2067
+ * 2. ConnectorAdminLike (registerPeer, removePeer) — for peer management
2068
+ * 3. setPacketHandler(handler) — for registering the incoming packet callback
2069
+ *
2070
+ * This structural interface allows @toon-protocol/connector's ConnectorNode to
2071
+ * be passed directly without importing it as a dependency.
2072
+ */
2073
+ interface EmbeddableConnectorLike {
2074
+ /** Send an outbound ILP packet */
2075
+ sendPacket(params: SendPacketParams): Promise<SendPacketResult>;
2076
+ /** Register a peer with the connector */
2077
+ registerPeer(params: RegisterPeerParams): Promise<void>;
2078
+ /** Remove a peer from the connector */
2079
+ removePeer(peerId: string): Promise<void>;
2080
+ /**
2081
+ * Register the incoming packet handler callback.
2082
+ * The connector invokes this handler for each incoming ILP packet.
2083
+ * Optional in HTTP mode where packets are delivered via local delivery HTTP endpoint.
2084
+ */
2085
+ setPacketHandler?(handler: (request: HandlePacketRequest) => HandlePacketResponse | Promise<HandlePacketResponse>): void;
2086
+ /**
2087
+ * Open a payment channel via the connector's settlement layer.
2088
+ * Optional — only available on ConnectorNode >=1.2.0.
2089
+ */
2090
+ openChannel?(params: {
2091
+ peerId: string;
2092
+ chain: string;
2093
+ token?: string;
2094
+ tokenNetwork?: string;
2095
+ peerAddress: string;
2096
+ initialDeposit?: string;
2097
+ settlementTimeout?: number;
2098
+ }): Promise<{
2099
+ channelId: string;
2100
+ status: string;
2101
+ }>;
2102
+ /**
2103
+ * Get the state of a payment channel.
2104
+ * Optional — only available on ConnectorNode >=1.2.0.
2105
+ */
2106
+ getChannelState?(channelId: string): Promise<{
2107
+ channelId: string;
2108
+ status: 'opening' | 'open' | 'closed' | 'settled';
2109
+ chain: string;
2110
+ }>;
2111
+ }
2112
+ /**
2113
+ * Configuration for creating an TOON Node.
2114
+ */
2115
+ interface ToonNodeConfig {
2116
+ /** The ConnectorNode instance (embeddable connector) */
2117
+ connector: EmbeddableConnectorLike;
2118
+ /**
2119
+ * Callback for incoming ILP packets.
2120
+ *
2121
+ * **NOTE:** Provided as a **function** (not a BLS instance) because packet
2122
+ * handling logic lives in the caller's entrypoint code.
2123
+ */
2124
+ handlePacket: PacketHandler;
2125
+ /** Nostr secret key (32 bytes) */
2126
+ secretKey: Uint8Array;
2127
+ /** Own ILP peer info (ilpAddress, btpEndpoint, assetCode, assetScale) */
2128
+ ilpInfo: IlpPeerInfo;
2129
+ /**
2130
+ * TOON encoder — **required** for encoding Nostr events to binary.
2131
+ * Used by BootstrapService.
2132
+ */
2133
+ toonEncoder: (event: NostrEvent) => Uint8Array;
2134
+ /**
2135
+ * TOON decoder — **required** for decoding binary to Nostr events.
2136
+ * Used by BootstrapService and DirectRuntimeClient.
2137
+ */
2138
+ toonDecoder: (bytes: Uint8Array) => NostrEvent;
2139
+ /** Relay WebSocket URL for monitoring (default: 'ws://localhost:7100') */
2140
+ relayUrl?: string;
2141
+ /** Initial bootstrap peers (default: []) */
2142
+ knownPeers?: KnownPeer[];
2143
+ /** Optional settlement preferences for peer registration */
2144
+ settlementInfo?: SettlementConfig;
2145
+ /** Base price per byte for ILP packet pricing (default: 10n) */
2146
+ basePricePerByte?: bigint;
2147
+ /** Enable ArDrive peer lookup (default: true) */
2148
+ ardriveEnabled?: boolean;
2149
+ /** Default relay URL for ArDrive-sourced peers that lack relay URLs (default: '') */
2150
+ defaultRelayUrl?: string;
2151
+ /** Timeout for relay queries in milliseconds (default: 5000) */
2152
+ queryTimeout?: number;
2153
+ /** Optional extra peers JSON for bootstrap */
2154
+ additionalPeersJson?: string;
2155
+ }
2156
+ /**
2157
+ * Result returned by ToonNode.start().
2158
+ */
2159
+ interface ToonNodeStartResult {
2160
+ /** Results from the bootstrap phase */
2161
+ bootstrapResults: BootstrapResult[];
2162
+ /** Number of peers successfully bootstrapped */
2163
+ peerCount: number;
2164
+ /** Number of payment channels opened */
2165
+ channelCount: number;
2166
+ }
2167
+ /**
2168
+ * TOON Node instance with lifecycle methods.
2169
+ */
2170
+ interface ToonNode {
2171
+ /**
2172
+ * Wire components and run bootstrap.
2173
+ * Throws BootstrapError if already started or on bootstrap failure.
2174
+ */
2175
+ start(): Promise<ToonNodeStartResult>;
2176
+ /**
2177
+ * Tear down and clean up.
2178
+ * Safe to call when not started (no-op).
2179
+ */
2180
+ stop(): Promise<void>;
2181
+ /**
2182
+ * Read-only access to the bootstrap service.
2183
+ * Allows attaching event listeners before calling start().
2184
+ */
2185
+ readonly bootstrapService: BootstrapService;
2186
+ /**
2187
+ * Read-only access to the discovery tracker.
2188
+ * Allows attaching event listeners before calling start().
2189
+ */
2190
+ readonly discoveryTracker: DiscoveryTracker;
2191
+ /**
2192
+ * Channel client for payment channel operations.
2193
+ * Null if the connector does not expose openChannel()/getChannelState().
2194
+ * Available when using @toon-protocol/connector >=1.2.0.
2195
+ */
2196
+ readonly channelClient: ConnectorChannelClient | null;
2197
+ /**
2198
+ * Read-only access to the ILP client for sending packets.
2199
+ * Used by ServiceNode.publishEvent() to send outbound events.
2200
+ */
2201
+ readonly ilpClient: IlpClient;
2202
+ /**
2203
+ * Initiate peering with a discovered peer.
2204
+ * The peer must have been discovered by the discovery tracker first.
2205
+ * Registers the peer with the connector and attempts settlement.
2206
+ */
2207
+ peerWith(pubkey: string): Promise<void>;
2208
+ }
2209
+ /**
2210
+ * Create a TOON Node with integrated bootstrap and discovery tracking.
2211
+ *
2212
+ * This composition function wires ConnectorNode ↔ DirectRuntimeClient ↔
2213
+ * DirectConnectorAdmin ↔ BootstrapService ↔ DiscoveryTracker into a single
2214
+ * object with start() / stop() lifecycle, enabling zero-latency embedded mode
2215
+ * without manually wiring each component.
2216
+ *
2217
+ * @param config - Configuration for the node
2218
+ * @returns ToonNode instance with start() / stop() methods
2219
+ *
2220
+ * @example
2221
+ * ```typescript
2222
+ * import { ConnectorNode } from '@toon-protocol/connector';
2223
+ * import { createToonNode } from '@toon-protocol/core/compose';
2224
+ * import { encodeEvent, decodeEvent } from '@toon-protocol/relay';
2225
+ *
2226
+ * const connector = new ConnectorNode({ ... });
2227
+ *
2228
+ * const node = createToonNode({
2229
+ * connector,
2230
+ * handlePacket: async (req) => { ... },
2231
+ * secretKey: new Uint8Array(32),
2232
+ * ilpInfo: { ilpAddress: 'g.example', ... },
2233
+ * toonEncoder: encodeEvent,
2234
+ * toonDecoder: decodeEvent,
2235
+ * });
2236
+ *
2237
+ * // Attach event listeners before start
2238
+ * node.bootstrapService.on((event) => console.log('bootstrap:', event));
2239
+ * node.discoveryTracker.on((event) => console.log('discovery:', event));
2240
+ *
2241
+ * // Start the node
2242
+ * const result = await node.start();
2243
+ * console.log(`Bootstrapped ${result.peerCount} peers`);
2244
+ *
2245
+ * // Clean up
2246
+ * await node.stop();
2247
+ * ```
2248
+ */
2249
+ declare function createToonNode(config: ToonNodeConfig): ToonNode;
2250
+
2251
+ /**
2252
+ * Mock USDC token configuration for local development (Anvil).
2253
+ *
2254
+ * In production, USDC is the native Circle USD Coin on Arbitrum One:
2255
+ * 0xaf88d065e77c8cC2239327C5EDb3A432268e5831
2256
+ *
2257
+ * For local development on Anvil, a mock ERC-20 is deployed at a
2258
+ * deterministic address by the DeployLocal.s.sol script in the connector
2259
+ * repo. This contract serves as the mock USDC for payment channel testing.
2260
+ *
2261
+ * **On-chain decimal discrepancy (Anvil only):**
2262
+ * The legacy on-chain mock contract on Anvil uses 18 decimals (inherited
2263
+ * from the original ERC-20 deploy script in the connector repo). The
2264
+ * constants below reflect production USDC semantics (6 decimals). When
2265
+ * interacting with the Anvil mock contract directly (e.g., fund-peer-wallet.sh,
2266
+ * faucet), use 18 decimals for on-chain amounts. The pricing pipeline
2267
+ * (basePricePerByte * toonLength) is denomination-agnostic (bigint math)
2268
+ * and works correctly regardless of on-chain decimals.
2269
+ *
2270
+ * **FiatTokenV2_2-compatible mock (Epic 5 prep):**
2271
+ * For DVM compute settlement and x402 testing with proper 6-decimal
2272
+ * semantics and EIP-3009 `transferWithAuthorization` support, deploy
2273
+ * the FiatTokenV2_2-compatible mock:
2274
+ * `./scripts/deploy-mock-usdc.sh`
2275
+ * This deploys a contract with 6 decimals, EIP-3009, and EIP-712
2276
+ * domain matching production USDC ("USD Coin", version "2").
2277
+ *
2278
+ * USDC uses 6 decimals (not 18 like most ERC-20 tokens):
2279
+ * 1 USDC = 1,000,000 micro-USDC (10^6)
2280
+ *
2281
+ * @module
2282
+ */
2283
+ /**
2284
+ * Mock USDC contract address on Anvil (deterministic from deployment).
2285
+ *
2286
+ * This is the first contract deployed by DeployLocal.s.sol using
2287
+ * Anvil Account #0 at nonce 0, giving it a deterministic address.
2288
+ */
2289
+ declare const MOCK_USDC_ADDRESS: "0x5FbDB2315678afecb367f032d93F642f64180aa3";
2290
+ /**
2291
+ * USDC uses 6 decimals (1 USDC = 1,000,000 micro-units).
2292
+ *
2293
+ * This differs from most ERC-20 tokens which use 18 decimals.
2294
+ * All pricing amounts in the TOON protocol are denominated
2295
+ * in USDC micro-units when using USDC as the settlement token.
2296
+ */
2297
+ declare const USDC_DECIMALS: 6;
2298
+ /** USDC token symbol. */
2299
+ declare const USDC_SYMBOL: "USDC";
2300
+ /** USDC token name. */
2301
+ declare const USDC_NAME: "USD Coin";
2302
+ /**
2303
+ * Configuration for the mock USDC contract deployment.
2304
+ */
2305
+ interface MockUsdcConfig {
2306
+ /** Contract address on the target chain */
2307
+ address: string;
2308
+ /** Number of decimal places (6 for USDC) */
2309
+ decimals: number;
2310
+ /** Token symbol */
2311
+ symbol: string;
2312
+ /** Token name */
2313
+ name: string;
2314
+ }
2315
+ /**
2316
+ * Default mock USDC configuration for Anvil local development.
2317
+ */
2318
+ declare const MOCK_USDC_CONFIG: MockUsdcConfig;
2319
+
2320
+ /**
2321
+ * Multi-environment chain configuration for TOON relay nodes.
2322
+ *
2323
+ * Provides chain presets for three deployment environments:
2324
+ * - **anvil** (local dev): Deterministic Anvil addresses, localhost RPC
2325
+ * - **arbitrum-sepolia** (staging): Circle testnet USDC on Arbitrum Sepolia
2326
+ * - **arbitrum-one** (production): Native USDC on Arbitrum One
2327
+ *
2328
+ * Environment variable overrides:
2329
+ * - `TOON_CHAIN` overrides the config-level chain parameter
2330
+ * - `TOON_RPC_URL` overrides the preset RPC endpoint
2331
+ * - `TOON_TOKEN_NETWORK` overrides the preset TokenNetwork address
2332
+ *
2333
+ * @module
2334
+ */
2335
+ /**
2336
+ * Supported chain preset names.
2337
+ */
2338
+ type ChainName = 'anvil' | 'arbitrum-sepolia' | 'arbitrum-one';
2339
+ /**
2340
+ * Resolved chain configuration with all fields populated.
2341
+ */
2342
+ interface ChainPreset {
2343
+ /** Preset identifier ('anvil' | 'arbitrum-sepolia' | 'arbitrum-one'). */
2344
+ name: string;
2345
+ /** EVM chain ID. */
2346
+ chainId: number;
2347
+ /** Default RPC endpoint URL. */
2348
+ rpcUrl: string;
2349
+ /** USDC token contract address on this chain. */
2350
+ usdcAddress: string;
2351
+ /** TokenNetwork contract address for USDC on this chain. */
2352
+ tokenNetworkAddress: string;
2353
+ }
2354
+ /**
2355
+ * Built-in chain presets for supported deployment environments.
2356
+ *
2357
+ * Each preset provides the chainId, RPC URL, USDC address, and
2358
+ * TokenNetwork address for its environment. Fields can be overridden
2359
+ * at runtime via environment variables.
2360
+ */
2361
+ declare const CHAIN_PRESETS: Record<ChainName, ChainPreset>;
2362
+ /**
2363
+ * Resolve chain configuration from a chain name, with environment
2364
+ * variable overrides applied.
2365
+ *
2366
+ * Resolution order:
2367
+ * 1. `TOON_CHAIN` env var overrides the `chain` parameter
2368
+ * 2. Defaults to `'anvil'` if neither is provided
2369
+ * 3. Looks up the chain name in `CHAIN_PRESETS`
2370
+ * 4. `TOON_RPC_URL` env var overrides the preset's `rpcUrl`
2371
+ * 5. `TOON_TOKEN_NETWORK` env var overrides the preset's `tokenNetworkAddress`
2372
+ *
2373
+ * Returns a defensive copy -- callers can mutate the result without
2374
+ * affecting the shared preset objects.
2375
+ *
2376
+ * @param chain - Chain name to resolve (default: 'anvil')
2377
+ * @returns Resolved chain preset with env var overrides applied
2378
+ * @throws ToonError if the chain name is not recognized
2379
+ */
2380
+ declare function resolveChainConfig(chain?: ChainName | string): ChainPreset;
2381
+ /**
2382
+ * Build an EIP-712 domain separator from a resolved chain configuration.
2383
+ *
2384
+ * The returned domain matches the structure used by
2385
+ * `getBalanceProofDomain()` in `packages/client/src/signing/evm-signer.ts`:
2386
+ *
2387
+ * ```typescript
2388
+ * { name: 'TokenNetwork', version: '1', chainId, verifyingContract }
2389
+ * ```
2390
+ *
2391
+ * Since `@toon-protocol/core` does not depend on viem, the `verifyingContract`
2392
+ * field is typed as `string` (not viem's `Hex`). Consumers in the client
2393
+ * package can cast to `Hex` if needed.
2394
+ *
2395
+ * @param config - Resolved chain preset
2396
+ * @returns EIP-712 domain separator object
2397
+ */
2398
+ declare function buildEip712Domain(config: ChainPreset): {
2399
+ name: string;
2400
+ version: string;
2401
+ chainId: number;
2402
+ verifyingContract: string;
2403
+ };
2404
+
2405
+ /**
2406
+ * Shared ILP PREPARE packet construction for the TOON protocol.
2407
+ *
2408
+ * This function is the **single point of truth** for constructing ILP PREPARE
2409
+ * packet parameters. Both the x402 `/publish` handler and the existing
2410
+ * `publishEvent()` in the SDK must use it (or produce equivalent output).
2411
+ *
2412
+ * This ensures packet equivalence: the destination relay cannot distinguish
2413
+ * between packets sent via the x402 HTTP on-ramp and the ILP-native rail.
2414
+ *
2415
+ * @module
2416
+ */
2417
+ /**
2418
+ * Parameters for constructing an ILP PREPARE packet.
2419
+ */
2420
+ interface BuildIlpPrepareParams {
2421
+ /** ILP destination address (e.g., "g.toon.target-relay"). */
2422
+ destination: string;
2423
+ /** Payment amount in ILP units (bigint). */
2424
+ amount: bigint;
2425
+ /** TOON-encoded event as raw bytes. */
2426
+ data: Uint8Array;
2427
+ /** Packet expiry. Default: 30 seconds from now. */
2428
+ expiresAt?: Date;
2429
+ }
2430
+ /**
2431
+ * Result of building an ILP PREPARE packet.
2432
+ *
2433
+ * This matches the shape expected by `IlpClient.sendIlpPacket()`:
2434
+ * `{ destination, amount, data }` where amount is a string and data
2435
+ * is base64-encoded.
2436
+ */
2437
+ interface IlpPreparePacket {
2438
+ /** ILP destination address. */
2439
+ destination: string;
2440
+ /** Payment amount as a string (BigInt.toString()). */
2441
+ amount: string;
2442
+ /** TOON-encoded event as base64 string. */
2443
+ data: string;
2444
+ }
2445
+ /**
2446
+ * Build an ILP PREPARE packet from the given parameters.
2447
+ *
2448
+ * Converts the bigint amount to a string, encodes the TOON data to base64,
2449
+ * and passes through the destination. This is deliberately simple -- the
2450
+ * value is in having ONE function both the x402 and ILP paths call, not
2451
+ * in complex logic.
2452
+ *
2453
+ * @param params - Packet construction parameters.
2454
+ * @returns ILP PREPARE packet fields ready for `sendIlpPacket()`.
2455
+ */
2456
+ declare function buildIlpPrepare(params: BuildIlpPrepareParams): IlpPreparePacket;
2457
+
2458
+ /**
2459
+ * KMS identity derivation for TEE enclave-bound keypairs.
2460
+ *
2461
+ * Derives a Nostr-compatible secp256k1 keypair from a raw 32-byte Nautilus
2462
+ * KMS seed using the NIP-06 derivation path (m/44'/1237'/0'/0/{index}).
2463
+ *
2464
+ * The KMS seed is only accessible when the enclave's attestation is valid
2465
+ * (correct PCR values). If the relay code changes, PCR values change,
2466
+ * attestation fails, KMS seed becomes inaccessible, and the relay loses its
2467
+ * identity -- creating a cryptographic binding: identity proves code integrity.
2468
+ *
2469
+ * This module lives in @toon-protocol/core (not SDK) because Docker entrypoints
2470
+ * import from core. It does NOT include EVM address derivation (SDK concern).
2471
+ */
2472
+
2473
+ /**
2474
+ * Error thrown when KMS identity derivation fails.
2475
+ * Signals that the enclave cannot derive its identity -- this is a
2476
+ * security-critical condition that must NEVER fall back to random keys.
2477
+ */
2478
+ declare class KmsIdentityError extends ToonError {
2479
+ constructor(message: string, cause?: Error);
2480
+ }
2481
+ /** A Nostr keypair derived from a KMS seed. */
2482
+ interface KmsKeypair {
2483
+ /** The 32-byte secp256k1 secret key derived from the KMS seed. */
2484
+ secretKey: Uint8Array;
2485
+ /** The x-only Schnorr public key (32 bytes, 64 lowercase hex characters). */
2486
+ pubkey: string;
2487
+ }
2488
+ /** Options for `deriveFromKmsSeed()`. */
2489
+ interface DeriveFromKmsSeedOptions {
2490
+ /** BIP-39 mnemonic -- when provided, takes precedence over raw seed for derivation. */
2491
+ mnemonic?: string;
2492
+ /** Key index in the NIP-06 derivation path. Defaults to 0. */
2493
+ accountIndex?: number;
2494
+ }
2495
+ /**
2496
+ * Derives a Nostr keypair from a raw 32-byte KMS seed or BIP-39 mnemonic
2497
+ * using the NIP-06 derivation path.
2498
+ *
2499
+ * When `options.mnemonic` is provided it takes precedence over the raw seed.
2500
+ * The raw seed is still validated even when a mnemonic is supplied (caller
2501
+ * must always provide a valid seed to prove KMS reachability).
2502
+ *
2503
+ * @param seed - A 32-byte Uint8Array from Nautilus KMS.
2504
+ * @param options - Optional derivation overrides (mnemonic, accountIndex).
2505
+ * @returns A `KmsKeypair` with `secretKey` and `pubkey`.
2506
+ * @throws {KmsIdentityError} If the seed is invalid or derivation fails.
2507
+ */
2508
+ declare function deriveFromKmsSeed(seed: Uint8Array, options?: DeriveFromKmsSeedOptions): KmsKeypair;
2509
+
2510
+ /**
2511
+ * Nix Build Orchestration for Reproducible Docker Images
2512
+ *
2513
+ * The NixBuilder class wraps the `nix build` CLI invocation to produce
2514
+ * deterministic Docker images for TEE (Trusted Execution Environment)
2515
+ * deployment. Each build returns a NixBuildResult containing the image
2516
+ * hash, PCR (Platform Configuration Register) values, and Nix store path.
2517
+ *
2518
+ * PCR values are SHA-384 hashes measured by the TEE hardware from the
2519
+ * loaded image. If the Docker image is deterministic (identical content
2520
+ * hash across builds), then PCR values will also be identical -- enabling
2521
+ * remote attestation verification (Story 4.3 AttestationVerifier).
2522
+ *
2523
+ * IMPORTANT: The NixBuilder shells out to `nix build` -- it requires
2524
+ * the Nix package manager to be installed on the build machine. Tests
2525
+ * that exercise actual Nix builds should be conditionally skipped when
2526
+ * Nix is not available. Unit tests use mocked child_process.
2527
+ *
2528
+ * @module
2529
+ */
2530
+ /**
2531
+ * Result of a Nix build invocation.
2532
+ * Contains the Docker image content hash, PCR values derived from the image,
2533
+ * the Nix store path, and the build timestamp.
2534
+ */
2535
+ interface NixBuildResult {
2536
+ /** Docker image content hash (sha256:... -- 64 lowercase hex chars after prefix) */
2537
+ imageHash: string;
2538
+ /** PCR0 -- SHA-384 hash of the enclave image (96 lowercase hex chars) */
2539
+ pcr0: string;
2540
+ /** PCR1 -- SHA-384 hash of the kernel (96 lowercase hex chars) */
2541
+ pcr1: string;
2542
+ /** PCR2 -- SHA-384 hash of the application (96 lowercase hex chars) */
2543
+ pcr2: string;
2544
+ /** Path to the image in the Nix store (/nix/store/...) */
2545
+ imagePath: string;
2546
+ /** Unix timestamp (seconds since epoch) of the build */
2547
+ buildTimestamp: number;
2548
+ }
2549
+ /**
2550
+ * Configuration for the NixBuilder.
2551
+ */
2552
+ interface NixBuilderConfig {
2553
+ /** Root directory of the project (containing flake.nix) */
2554
+ projectRoot: string;
2555
+ /** Path to Dockerfile.nix relative to projectRoot */
2556
+ dockerfilePath: string;
2557
+ /**
2558
+ * Optional source overrides for testing. Keys are relative paths from
2559
+ * projectRoot, values are the file content to write. When set, NixBuilder
2560
+ * creates a temporary copy of the source tree with the overrides applied
2561
+ * before running the build. This allows testing that source changes
2562
+ * produce different PCR values.
2563
+ */
2564
+ sourceOverride?: Record<string, string>;
2565
+ }
2566
+ /**
2567
+ * Orchestrates Nix-based Docker image builds for reproducible TEE deployment.
2568
+ *
2569
+ * The build() method shells out to `nix build .#docker-image` and parses the
2570
+ * output to extract the image hash, Nix store path, and PCR values. PCR values
2571
+ * are computed from the image content using SHA-384 to simulate the measurement
2572
+ * that would be performed by the TEE hardware (AWS Nitro hypervisor).
2573
+ *
2574
+ * @example
2575
+ * ```typescript
2576
+ * const builder = new NixBuilder({
2577
+ * projectRoot: '/path/to/toon',
2578
+ * dockerfilePath: 'docker/Dockerfile.nix',
2579
+ * });
2580
+ * const result = await builder.build();
2581
+ * console.log(result.imageHash); // sha256:abc123...
2582
+ * console.log(result.pcr0); // 96-char hex string
2583
+ * ```
2584
+ */
2585
+ declare class NixBuilder {
2586
+ private readonly config;
2587
+ constructor(config: NixBuilderConfig);
2588
+ /**
2589
+ * Execute a Nix build and return the result.
2590
+ *
2591
+ * Shells out to `nix build .#docker-image` in the project root directory.
2592
+ * If sourceOverride is configured, creates a temporary modified source tree.
2593
+ *
2594
+ * @throws Error if Nix is not installed or the build fails
2595
+ */
2596
+ build(): Promise<NixBuildResult>;
2597
+ }
2598
+
2599
+ /**
2600
+ * PCR Validation and Dockerfile Determinism Analysis
2601
+ *
2602
+ * Provides utilities for verifying PCR (Platform Configuration Register)
2603
+ * reproducibility across independent Nix builds, and for statically
2604
+ * analyzing Dockerfile.nix expressions for non-deterministic patterns.
2605
+ *
2606
+ * PCR values are SHA-384 hashes (96 lowercase hex characters) measured
2607
+ * by the TEE hardware. If two builds of the same source tree produce
2608
+ * different PCR values, the attestation verification model collapses
2609
+ * (R-E4-002, Score 6) because the AttestationVerifier cannot compare
2610
+ * observed PCR values against a known-good registry.
2611
+ *
2612
+ * @module
2613
+ */
2614
+
2615
+ /**
2616
+ * A forbidden pattern that must not appear in a deterministic Dockerfile/Nix
2617
+ * expression. Each entry includes a regex, a human-readable name, and an
2618
+ * explanation of why the pattern breaks reproducibility.
2619
+ */
2620
+ interface ForbiddenPattern {
2621
+ /** Regex to match against each line of the Dockerfile */
2622
+ pattern: RegExp;
2623
+ /** Human-readable name of the pattern (e.g., 'apt-get update') */
2624
+ name: string;
2625
+ /** Explanation of why this pattern breaks reproducibility */
2626
+ reason: string;
2627
+ }
2628
+ /**
2629
+ * A single violation found during determinism analysis. Includes the line
2630
+ * number (1-indexed), the name of the matched pattern, and the text that
2631
+ * triggered the match.
2632
+ */
2633
+ interface Violation {
2634
+ /** Line number (1-indexed) where the violation was found */
2635
+ line: number;
2636
+ /** Name of the forbidden pattern that matched */
2637
+ patternName: string;
2638
+ /** The text from the line that triggered the match */
2639
+ matchedText: string;
2640
+ }
2641
+ /**
2642
+ * Result of analyzing a Dockerfile for non-deterministic patterns.
2643
+ */
2644
+ interface DeterminismReport {
2645
+ /** True if no forbidden patterns were found */
2646
+ deterministic: boolean;
2647
+ /** List of violations found (empty if deterministic) */
2648
+ violations: Violation[];
2649
+ /** Number of lines scanned */
2650
+ scannedLines: number;
2651
+ }
2652
+ /**
2653
+ * Result of comparing two NixBuildResults for PCR reproducibility.
2654
+ */
2655
+ interface PcrReproducibilityResult {
2656
+ /** True if all PCR values and image hash match */
2657
+ reproducible: boolean;
2658
+ /** Whether PCR0 values match */
2659
+ pcr0Match: boolean;
2660
+ /** Whether PCR1 values match */
2661
+ pcr1Match: boolean;
2662
+ /** Whether PCR2 values match */
2663
+ pcr2Match: boolean;
2664
+ /** Whether Docker image content hashes match */
2665
+ imageHashMatch: boolean;
2666
+ /** The actual PCR and hash values from both builds for debugging */
2667
+ details: {
2668
+ buildA: {
2669
+ pcr0: string;
2670
+ pcr1: string;
2671
+ pcr2: string;
2672
+ imageHash: string;
2673
+ };
2674
+ buildB: {
2675
+ pcr0: string;
2676
+ pcr1: string;
2677
+ pcr2: string;
2678
+ imageHash: string;
2679
+ };
2680
+ };
2681
+ /** Human-readable summary suitable for CI log output */
2682
+ summary: string;
2683
+ }
2684
+ /**
2685
+ * Options for verifyPcrReproducibility().
2686
+ */
2687
+ interface VerifyOptions {
2688
+ /** If true, throws PcrReproducibilityError when builds diverge */
2689
+ throwOnMismatch?: boolean;
2690
+ }
2691
+ /**
2692
+ * Error thrown when PCR reproducibility verification fails (builds diverge).
2693
+ * Contains both build results in the error message for CI debugging.
2694
+ */
2695
+ declare class PcrReproducibilityError extends ToonError {
2696
+ constructor(buildA: NixBuildResult, buildB: NixBuildResult);
2697
+ }
2698
+ /**
2699
+ * Reads the content of a Dockerfile.nix file from disk.
2700
+ *
2701
+ * This is a thin I/O wrapper separated from the analysis function to keep
2702
+ * `analyzeDockerfileForNonDeterminism()` a pure function (no side effects).
2703
+ *
2704
+ * @param filePath - Absolute path to the Dockerfile.nix file
2705
+ * @returns The file content as a UTF-8 string
2706
+ */
2707
+ declare function readDockerfileNix(filePath: string): Promise<string>;
2708
+ /**
2709
+ * Analyzes a Dockerfile/Nix expression for non-deterministic patterns.
2710
+ *
2711
+ * This is a pure function -- it takes the file content as a string and an
2712
+ * array of forbidden patterns, and returns a structured report. No I/O is
2713
+ * performed; file reading is handled by `readDockerfileNix()`.
2714
+ *
2715
+ * Each line of the content is tested against every forbidden pattern. Lines
2716
+ * that start with '#' (comments) are skipped since they don't affect the
2717
+ * build output.
2718
+ *
2719
+ * @param content - The Dockerfile/Nix expression content as a string
2720
+ * @param forbiddenPatterns - Array of patterns that indicate non-determinism
2721
+ * @returns A DeterminismReport with violations and line numbers
2722
+ *
2723
+ * @example
2724
+ * ```typescript
2725
+ * const report = analyzeDockerfileForNonDeterminism(content, [
2726
+ * { pattern: /apt-get\s+update/, name: 'apt-get update', reason: '...' },
2727
+ * ]);
2728
+ * if (!report.deterministic) {
2729
+ * console.error('Violations:', report.violations);
2730
+ * }
2731
+ * ```
2732
+ */
2733
+ declare function analyzeDockerfileForNonDeterminism(content: string, forbiddenPatterns: ForbiddenPattern[]): DeterminismReport;
2734
+ /**
2735
+ * Verifies that two NixBuildResults are reproducible -- i.e., they produce
2736
+ * identical PCR values and Docker image content hashes.
2737
+ *
2738
+ * This function is intended for CI pipelines: build the Docker image twice
2739
+ * from the same source tree, then call this function to verify the outputs
2740
+ * match. If they don't, the build is non-deterministic and PCR-based
2741
+ * attestation verification will fail.
2742
+ *
2743
+ * PCR values are normalized to lowercase before comparison to avoid
2744
+ * case-sensitivity issues.
2745
+ *
2746
+ * @param buildA - Result from the first build
2747
+ * @param buildB - Result from the second build
2748
+ * @param options - Optional: throwOnMismatch to throw PcrReproducibilityError
2749
+ * @returns A structured PcrReproducibilityResult with match details and summary
2750
+ *
2751
+ * Note: This function is async by API contract (Story 4.5 AC #4) to allow
2752
+ * future implementations to perform I/O (e.g., fetching PCR values from a
2753
+ * remote registry). The current implementation is synchronous.
2754
+ *
2755
+ * @example
2756
+ * ```typescript
2757
+ * const buildA = await builder.build();
2758
+ * const buildB = await builder.build();
2759
+ * const result = await verifyPcrReproducibility(buildA, buildB, {
2760
+ * throwOnMismatch: true,
2761
+ * });
2762
+ * console.log(result.summary); // "PCR reproducibility: PASS ..."
2763
+ * ```
2764
+ */
2765
+ declare function verifyPcrReproducibility(buildA: NixBuildResult, buildB: NixBuildResult, options?: VerifyOptions): Promise<PcrReproducibilityResult>;
2766
+
2767
+ /**
2768
+ * Structured logging for the TOON protocol.
2769
+ *
2770
+ * Provides JSON-formatted log output with contextual fields for:
2771
+ * - TEE enclave observability (component, enclaveType)
2772
+ * - DVM job log correlation (correlationId)
2773
+ * - Multi-node debugging (nodeId, pubkey)
2774
+ *
2775
+ * Zero runtime dependencies. Uses console.log/console.error as the
2776
+ * transport layer. Output is structured JSON when `json: true` (default
2777
+ * in production), or human-readable when `json: false` (development).
2778
+ *
2779
+ * @module
2780
+ */
2781
+ /**
2782
+ * Log levels ordered by severity.
2783
+ */
2784
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
2785
+ /**
2786
+ * Configuration for creating a Logger instance.
2787
+ */
2788
+ interface LoggerConfig {
2789
+ /** Component name (e.g., 'bootstrap', 'x402', 'attestation') */
2790
+ component: string;
2791
+ /** Minimum log level to emit. Default: 'info' */
2792
+ level?: LogLevel;
2793
+ /** Output as JSON. Default: true */
2794
+ json?: boolean;
2795
+ /** Static context fields merged into every log entry */
2796
+ context?: Record<string, unknown>;
2797
+ }
2798
+ /**
2799
+ * A structured log entry.
2800
+ */
2801
+ interface LogEntry {
2802
+ /** ISO 8601 timestamp */
2803
+ timestamp: string;
2804
+ /** Log level */
2805
+ level: LogLevel;
2806
+ /** Component that produced the log */
2807
+ component: string;
2808
+ /** Log message */
2809
+ msg: string;
2810
+ /** Additional structured fields */
2811
+ [key: string]: unknown;
2812
+ }
2813
+ /**
2814
+ * Structured logger with contextual fields.
2815
+ *
2816
+ * Usage:
2817
+ * ```typescript
2818
+ * const log = createLogger({ component: 'bootstrap' });
2819
+ * log.info('Peer registered', { peerId: 'abc', ilpAddress: 'g.toon.peer' });
2820
+ * log.error('Bootstrap failed', { error: err.message });
2821
+ *
2822
+ * // Child logger with additional context
2823
+ * const jobLog = log.child({ correlationId: 'job-123' });
2824
+ * jobLog.info('DVM job started');
2825
+ * ```
2826
+ */
2827
+ interface Logger {
2828
+ debug(msg: string, fields?: Record<string, unknown>): void;
2829
+ info(msg: string, fields?: Record<string, unknown>): void;
2830
+ warn(msg: string, fields?: Record<string, unknown>): void;
2831
+ error(msg: string, fields?: Record<string, unknown>): void;
2832
+ /**
2833
+ * Create a child logger with additional context fields.
2834
+ * The child inherits all parent context and adds its own.
2835
+ */
2836
+ child(context: Record<string, unknown>): Logger;
2837
+ }
2838
+ /**
2839
+ * Create a structured logger.
2840
+ *
2841
+ * @param config - Logger configuration
2842
+ * @returns A Logger instance
2843
+ */
2844
+ declare function createLogger(config: LoggerConfig): Logger;
2845
+
2846
+ /**
2847
+ * @toon-protocol/core
2848
+ *
2849
+ * Core library for Nostr-based ILP peer discovery.
2850
+ */
2851
+ declare const VERSION = "0.1.0";
2852
+
2853
+ export { type AgentRuntimeClient, ArDrivePeerRegistry, AttestationBootstrap, type AttestationBootstrapConfig, type AttestationBootstrapEvent, type AttestationBootstrapEventListener, type AttestationBootstrapResult, type AttestationEventOptions, AttestationState, AttestationVerifier, type AttestationVerifierConfig, type BootstrapConfig, BootstrapError, type BootstrapEvent, type BootstrapEventListener, type BootstrapPhase, type BootstrapResult, BootstrapService, type BootstrapServiceConfig, type BuildIlpPrepareParams, CHAIN_PRESETS, type ChainName, type ChainPreset, type ChannelState, type ConnectorAdminClient, type ConnectorAdminLike, type ConnectorChannelClient, type ConnectorChannelLike, type ConnectorNodeLike, type DeriveFromKmsSeedOptions, type DeterminismReport, type DirectRuntimeClientConfig, type DiscoveredPeer, type DiscoveryTracker, type DiscoveryTrackerConfig, type DvmJobStatus, type EmbeddableConnectorLike, type ForbiddenPattern, type GenesisPeer, GenesisPeerLoader, type HandlePacketAcceptResponse, type HandlePacketRejectResponse, type HandlePacketRequest, type HandlePacketResponse, ILP_PEER_INFO_KIND, IMAGE_GENERATION_KIND, type IlpClient, type IlpPeerInfo, type IlpPreparePacket, type IlpSendResult, JOB_FEEDBACK_KIND, JOB_REQUEST_KIND_BASE, JOB_RESULT_KIND_BASE, type JobFeedbackParams, type JobRequestParams, type JobResultParams, KmsIdentityError, type KmsKeypair, type KnownPeer, type LogEntry, type LogLevel, type Logger, type LoggerConfig, MOCK_USDC_ADDRESS, MOCK_USDC_CONFIG, type MockUsdcConfig, type NixBuildResult, NixBuilder, type NixBuilderConfig, NostrPeerDiscovery, type OpenChannelParams, type OpenChannelResult, type PacketHandler, type ParsedAttestation, type ParsedJobFeedback, type ParsedJobRequest, type ParsedJobResult, PcrReproducibilityError, type PcrReproducibilityResult, type PeerDescriptor, type PublishSeedRelayConfig, type RegisterPeerParams, SEED_RELAY_LIST_KIND, SERVICE_DISCOVERY_KIND, SeedRelayDiscovery, type SeedRelayDiscoveryConfig, type SeedRelayDiscoveryResult, type SeedRelayEntry, type SendPacketParams, type SendPacketResult, type ServiceDiscoveryContent, type SettlementConfig, type SkillDescriptor, type SocialDiscoveryEvent, type SocialDiscoveryEventListener, SocialPeerDiscovery, type SocialPeerDiscoveryConfig, type Subscription, TEE_ATTESTATION_KIND, TEXT_GENERATION_KIND, TEXT_TO_SPEECH_KIND, TRANSLATION_KIND, type TeeAttestation, ToonError, type ToonNode, type ToonNodeConfig, type ToonNodeStartResult, USDC_DECIMALS, USDC_NAME, USDC_SYMBOL, VERSION, type VerificationResult, type VerifyOptions, type Violation, analyzeDockerfileForNonDeterminism, buildAttestationEvent, buildEip712Domain, buildIlpPeerInfoEvent, buildIlpPrepare, buildJobFeedbackEvent, buildJobRequestEvent, buildJobResultEvent, buildSeedRelayListEvent, buildServiceDiscoveryEvent, createAgentRuntimeClient, createDirectChannelClient, createDirectConnectorAdmin, createDirectIlpClient, createDirectRuntimeClient, createDiscoveryTracker, createHttpChannelClient, createHttpConnectorAdmin, createHttpIlpClient$1 as createHttpIlpClient, createHttpRuntimeClient, createHttpIlpClient as createHttpRuntimeClientV2, createLogger, createToonNode, deriveFromKmsSeed, negotiateSettlementChain, parseAttestation, parseIlpPeerInfo, parseJobFeedback, parseJobRequest, parseJobResult, parseSeedRelayList, parseServiceDiscovery, publishSeedRelayEntry, readDockerfileNix, resolveChainConfig, resolveTokenForChain, validateChainId, verifyPcrReproducibility };