@toon-protocol/client-mcp 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,11 +3,13 @@ import {
3
3
  hmac
4
4
  } from "./chunk-32QD72IL.js";
5
5
  import {
6
- ed25519
7
- } from "./chunk-FSS45ZX3.js";
6
+ ed25519,
7
+ hexToBytes,
8
+ sha256
9
+ } from "./chunk-DLYE6U2Z.js";
8
10
  import {
9
11
  HashMD,
10
- sha256,
12
+ sha256 as sha2562,
11
13
  sha512
12
14
  } from "./chunk-LR7W2ISE.js";
13
15
  import {
@@ -20,7 +22,7 @@ import {
20
22
  concatBytes,
21
23
  createHasher,
22
24
  createView,
23
- hexToBytes,
25
+ hexToBytes as hexToBytes2,
24
26
  isBytes,
25
27
  kdfInputToBytes,
26
28
  randomBytes,
@@ -29,7 +31,7 @@ import {
29
31
  } from "./chunk-VA7XC4FD.js";
30
32
 
31
33
  // ../client/dist/index.js
32
- import { generateSecretKey as generateSecretKey3, getPublicKey as getPublicKey22 } from "nostr-tools/pure";
34
+ import { generateSecretKey as generateSecretKey3, getPublicKey as getPublicKey22, finalizeEvent as finalizeEvent11 } from "nostr-tools/pure";
33
35
  import { generateSecretKey as generateSecretKey2 } from "nostr-tools/pure";
34
36
 
35
37
  // ../../node_modules/.pnpm/@toon-protocol+core@1.4.2_@toon-protocol+connector@3.13.0_typescript@5.9.3/node_modules/@toon-protocol/core/dist/chunk-5WT7ISKC.js
@@ -164,380 +166,13 @@ import { SimplePool as SimplePool2 } from "nostr-tools/pool";
164
166
  import { getPublicKey } from "nostr-tools/pure";
165
167
  import WebSocket2 from "ws";
166
168
  import { getPublicKey as getPublicKey2, verifyEvent } from "nostr-tools/pure";
167
-
168
- // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/utils.js
169
- function isBytes2(a) {
170
- return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
171
- }
172
- function abytes2(value, length, title = "") {
173
- const bytes = isBytes2(value);
174
- const len = value?.length;
175
- const needsLen = length !== void 0;
176
- if (!bytes || needsLen && len !== length) {
177
- const prefix = title && `"${title}" `;
178
- const ofLen = needsLen ? ` of length ${length}` : "";
179
- const got = bytes ? `length=${len}` : `type=${typeof value}`;
180
- const message = prefix + "expected Uint8Array" + ofLen + ", got " + got;
181
- if (!bytes)
182
- throw new TypeError(message);
183
- throw new RangeError(message);
184
- }
185
- return value;
186
- }
187
- function aexists(instance, checkFinished = true) {
188
- if (instance.destroyed)
189
- throw new Error("Hash instance has been destroyed");
190
- if (checkFinished && instance.finished)
191
- throw new Error("Hash#digest() has already been called");
192
- }
193
- function aoutput(out, instance) {
194
- abytes2(out, void 0, "digestInto() output");
195
- const min = instance.outputLen;
196
- if (out.length < min) {
197
- throw new RangeError('"digestInto() output" expected to be of length >=' + min);
198
- }
199
- }
200
- function clean2(...arrays) {
201
- for (let i = 0; i < arrays.length; i++) {
202
- arrays[i].fill(0);
203
- }
204
- }
205
- function createView2(arr) {
206
- return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
207
- }
208
- function rotr(word, shift) {
209
- return word << 32 - shift | word >>> shift;
210
- }
211
- var hasHexBuiltin = /* @__PURE__ */ (() => (
212
- // @ts-ignore
213
- typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
214
- ))();
215
- var asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
216
- function asciiToBase16(ch) {
217
- if (ch >= asciis._0 && ch <= asciis._9)
218
- return ch - asciis._0;
219
- if (ch >= asciis.A && ch <= asciis.F)
220
- return ch - (asciis.A - 10);
221
- if (ch >= asciis.a && ch <= asciis.f)
222
- return ch - (asciis.a - 10);
223
- return;
224
- }
225
- function hexToBytes2(hex) {
226
- if (typeof hex !== "string")
227
- throw new TypeError("hex string expected, got " + typeof hex);
228
- if (hasHexBuiltin) {
229
- try {
230
- return Uint8Array.fromHex(hex);
231
- } catch (error) {
232
- if (error instanceof SyntaxError)
233
- throw new RangeError(error.message);
234
- throw error;
235
- }
236
- }
237
- const hl = hex.length;
238
- const al = hl / 2;
239
- if (hl % 2)
240
- throw new RangeError("hex string expected, got unpadded hex of length " + hl);
241
- const array = new Uint8Array(al);
242
- for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
243
- const n1 = asciiToBase16(hex.charCodeAt(hi));
244
- const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
245
- if (n1 === void 0 || n2 === void 0) {
246
- const char = hex[hi] + hex[hi + 1];
247
- throw new RangeError('hex string expected, got non-hex character "' + char + '" at index ' + hi);
248
- }
249
- array[ai] = n1 * 16 + n2;
250
- }
251
- return array;
252
- }
253
- function createHasher2(hashCons, info = {}) {
254
- const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
255
- const tmp = hashCons(void 0);
256
- hashC.outputLen = tmp.outputLen;
257
- hashC.blockLen = tmp.blockLen;
258
- hashC.canXOF = tmp.canXOF;
259
- hashC.create = (opts) => hashCons(opts);
260
- Object.assign(hashC, info);
261
- return Object.freeze(hashC);
262
- }
263
- var oidNist = (suffix) => ({
264
- // Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
265
- // Larger suffix values would need base-128 OID encoding and a different length byte.
266
- oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
267
- });
268
-
269
- // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/_md.js
270
- function Chi(a, b, c) {
271
- return a & b ^ ~a & c;
272
- }
273
- function Maj(a, b, c) {
274
- return a & b ^ a & c ^ b & c;
275
- }
276
- var HashMD2 = class {
277
- blockLen;
278
- outputLen;
279
- canXOF = false;
280
- padOffset;
281
- isLE;
282
- // For partial updates less than block size
283
- buffer;
284
- view;
285
- finished = false;
286
- length = 0;
287
- pos = 0;
288
- destroyed = false;
289
- constructor(blockLen, outputLen, padOffset, isLE) {
290
- this.blockLen = blockLen;
291
- this.outputLen = outputLen;
292
- this.padOffset = padOffset;
293
- this.isLE = isLE;
294
- this.buffer = new Uint8Array(blockLen);
295
- this.view = createView2(this.buffer);
296
- }
297
- update(data) {
298
- aexists(this);
299
- abytes2(data);
300
- const { view, buffer, blockLen } = this;
301
- const len = data.length;
302
- for (let pos = 0; pos < len; ) {
303
- const take = Math.min(blockLen - this.pos, len - pos);
304
- if (take === blockLen) {
305
- const dataView = createView2(data);
306
- for (; blockLen <= len - pos; pos += blockLen)
307
- this.process(dataView, pos);
308
- continue;
309
- }
310
- buffer.set(data.subarray(pos, pos + take), this.pos);
311
- this.pos += take;
312
- pos += take;
313
- if (this.pos === blockLen) {
314
- this.process(view, 0);
315
- this.pos = 0;
316
- }
317
- }
318
- this.length += data.length;
319
- this.roundClean();
320
- return this;
321
- }
322
- digestInto(out) {
323
- aexists(this);
324
- aoutput(out, this);
325
- this.finished = true;
326
- const { buffer, view, blockLen, isLE } = this;
327
- let { pos } = this;
328
- buffer[pos++] = 128;
329
- clean2(this.buffer.subarray(pos));
330
- if (this.padOffset > blockLen - pos) {
331
- this.process(view, 0);
332
- pos = 0;
333
- }
334
- for (let i = pos; i < blockLen; i++)
335
- buffer[i] = 0;
336
- view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
337
- this.process(view, 0);
338
- const oview = createView2(out);
339
- const len = this.outputLen;
340
- if (len % 4)
341
- throw new Error("_sha2: outputLen must be aligned to 32bit");
342
- const outLen = len / 4;
343
- const state = this.get();
344
- if (outLen > state.length)
345
- throw new Error("_sha2: outputLen bigger than state");
346
- for (let i = 0; i < outLen; i++)
347
- oview.setUint32(4 * i, state[i], isLE);
348
- }
349
- digest() {
350
- const { buffer, outputLen } = this;
351
- this.digestInto(buffer);
352
- const res = buffer.slice(0, outputLen);
353
- this.destroy();
354
- return res;
355
- }
356
- _cloneInto(to) {
357
- to ||= new this.constructor();
358
- to.set(...this.get());
359
- const { blockLen, buffer, length, finished, destroyed, pos } = this;
360
- to.destroyed = destroyed;
361
- to.finished = finished;
362
- to.length = length;
363
- to.pos = pos;
364
- if (length % blockLen)
365
- to.buffer.set(buffer);
366
- return to;
367
- }
368
- clone() {
369
- return this._cloneInto();
370
- }
371
- };
372
- var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
373
- 1779033703,
374
- 3144134277,
375
- 1013904242,
376
- 2773480762,
377
- 1359893119,
378
- 2600822924,
379
- 528734635,
380
- 1541459225
381
- ]);
382
-
383
- // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/sha2.js
384
- var SHA256_K = /* @__PURE__ */ Uint32Array.from([
385
- 1116352408,
386
- 1899447441,
387
- 3049323471,
388
- 3921009573,
389
- 961987163,
390
- 1508970993,
391
- 2453635748,
392
- 2870763221,
393
- 3624381080,
394
- 310598401,
395
- 607225278,
396
- 1426881987,
397
- 1925078388,
398
- 2162078206,
399
- 2614888103,
400
- 3248222580,
401
- 3835390401,
402
- 4022224774,
403
- 264347078,
404
- 604807628,
405
- 770255983,
406
- 1249150122,
407
- 1555081692,
408
- 1996064986,
409
- 2554220882,
410
- 2821834349,
411
- 2952996808,
412
- 3210313671,
413
- 3336571891,
414
- 3584528711,
415
- 113926993,
416
- 338241895,
417
- 666307205,
418
- 773529912,
419
- 1294757372,
420
- 1396182291,
421
- 1695183700,
422
- 1986661051,
423
- 2177026350,
424
- 2456956037,
425
- 2730485921,
426
- 2820302411,
427
- 3259730800,
428
- 3345764771,
429
- 3516065817,
430
- 3600352804,
431
- 4094571909,
432
- 275423344,
433
- 430227734,
434
- 506948616,
435
- 659060556,
436
- 883997877,
437
- 958139571,
438
- 1322822218,
439
- 1537002063,
440
- 1747873779,
441
- 1955562222,
442
- 2024104815,
443
- 2227730452,
444
- 2361852424,
445
- 2428436474,
446
- 2756734187,
447
- 3204031479,
448
- 3329325298
449
- ]);
450
- var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
451
- var SHA2_32B = class extends HashMD2 {
452
- constructor(outputLen) {
453
- super(64, outputLen, 8, false);
454
- }
455
- get() {
456
- const { A, B, C, D, E, F, G, H } = this;
457
- return [A, B, C, D, E, F, G, H];
458
- }
459
- // prettier-ignore
460
- set(A, B, C, D, E, F, G, H) {
461
- this.A = A | 0;
462
- this.B = B | 0;
463
- this.C = C | 0;
464
- this.D = D | 0;
465
- this.E = E | 0;
466
- this.F = F | 0;
467
- this.G = G | 0;
468
- this.H = H | 0;
469
- }
470
- process(view, offset) {
471
- for (let i = 0; i < 16; i++, offset += 4)
472
- SHA256_W[i] = view.getUint32(offset, false);
473
- for (let i = 16; i < 64; i++) {
474
- const W15 = SHA256_W[i - 15];
475
- const W2 = SHA256_W[i - 2];
476
- const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
477
- const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
478
- SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
479
- }
480
- let { A, B, C, D, E, F, G, H } = this;
481
- for (let i = 0; i < 64; i++) {
482
- const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
483
- const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
484
- const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
485
- const T2 = sigma0 + Maj(A, B, C) | 0;
486
- H = G;
487
- G = F;
488
- F = E;
489
- E = D + T1 | 0;
490
- D = C;
491
- C = B;
492
- B = A;
493
- A = T1 + T2 | 0;
494
- }
495
- A = A + this.A | 0;
496
- B = B + this.B | 0;
497
- C = C + this.C | 0;
498
- D = D + this.D | 0;
499
- E = E + this.E | 0;
500
- F = F + this.F | 0;
501
- G = G + this.G | 0;
502
- H = H + this.H | 0;
503
- this.set(A, B, C, D, E, F, G, H);
504
- }
505
- roundClean() {
506
- clean2(SHA256_W);
507
- }
508
- destroy() {
509
- this.destroyed = true;
510
- this.set(0, 0, 0, 0, 0, 0, 0, 0);
511
- clean2(this.buffer);
512
- }
513
- };
514
- var _SHA256 = class extends SHA2_32B {
515
- // We cannot use array here since array allows indexing by variable
516
- // which means optimizer/compiler cannot use registers.
517
- A = SHA256_IV[0] | 0;
518
- B = SHA256_IV[1] | 0;
519
- C = SHA256_IV[2] | 0;
520
- D = SHA256_IV[3] | 0;
521
- E = SHA256_IV[4] | 0;
522
- F = SHA256_IV[5] | 0;
523
- G = SHA256_IV[6] | 0;
524
- H = SHA256_IV[7] | 0;
525
- constructor() {
526
- super(32);
527
- }
528
- };
529
- var sha2562 = /* @__PURE__ */ createHasher2(
530
- () => new _SHA256(),
531
- /* @__PURE__ */ oidNist(1)
532
- );
533
-
534
- // ../../node_modules/.pnpm/@toon-protocol+core@1.4.2_@toon-protocol+connector@3.13.0_typescript@5.9.3/node_modules/@toon-protocol/core/dist/index.js
535
169
  import { SimplePool as SimplePool3 } from "nostr-tools/pool";
536
170
  import { getPublicKey as getPublicKey3 } from "nostr-tools/pure";
537
171
  import WebSocket22 from "ws";
538
172
  import { getPublicKey as getPublicKey4 } from "nostr-tools/pure";
539
173
  import { getPublicKey as getPublicKey5 } from "nostr-tools/pure";
540
174
  var ILP_PEER_INFO_KIND = 10032;
175
+ var BLOB_STORAGE_REQUEST_KIND = 5094;
541
176
  var ILP_SEGMENT_PATTERN = /^[a-z0-9-]+$/;
542
177
  var MAX_ILP_ADDRESS_LENGTH = 1023;
543
178
  function isValidIlpAddressStructure(address) {
@@ -920,6 +555,40 @@ function buildIlpPeerInfoEvent(info, secretKey, options = {}) {
920
555
  secretKey
921
556
  );
922
557
  }
558
+ function buildBlobStorageRequest(params, secretKey) {
559
+ if (!params.blobData || params.blobData.length === 0) {
560
+ throw new ToonError(
561
+ "Blob storage request blobData is required and must not be empty",
562
+ "DVM_MISSING_INPUT"
563
+ );
564
+ }
565
+ if (typeof params.bid !== "string" || params.bid === "") {
566
+ throw new ToonError(
567
+ "Blob storage request bid must be a non-empty string (USDC micro-units)",
568
+ "DVM_INVALID_BID"
569
+ );
570
+ }
571
+ const contentType = params.contentType ?? "application/octet-stream";
572
+ const base64Blob = params.blobData.toString("base64");
573
+ const tags = [];
574
+ tags.push(["i", base64Blob, "blob"]);
575
+ tags.push(["bid", params.bid, "usdc"]);
576
+ tags.push(["output", contentType]);
577
+ if (params.params !== void 0) {
578
+ for (const p of params.params) {
579
+ tags.push(["param", p.key, p.value]);
580
+ }
581
+ }
582
+ return finalizeEvent9(
583
+ {
584
+ kind: BLOB_STORAGE_REQUEST_KIND,
585
+ content: "",
586
+ tags,
587
+ created_at: Math.floor(Date.now() / 1e3)
588
+ },
589
+ secretKey
590
+ );
591
+ }
923
592
  var genesis_peers_default = [];
924
593
  var PUBKEY_REGEX3 = /^[0-9a-f]{64}$/;
925
594
  var ILP_ADDRESS_REGEX = /^g\.[a-zA-Z0-9.-]+$/;
@@ -1132,11 +801,11 @@ function resolveTokenForChain(chain2, requesterPreferredTokens, responderPreferr
1132
801
  return void 0;
1133
802
  }
1134
803
  function hexToBytes3(hex) {
1135
- const clean3 = hex.startsWith("0x") ? hex.slice(2) : hex;
1136
- if (clean3.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(clean3)) {
804
+ const clean2 = hex.startsWith("0x") ? hex.slice(2) : hex;
805
+ if (clean2.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(clean2)) {
1137
806
  throw new Error(`Invalid hex string: ${hex}`);
1138
807
  }
1139
- return hexToBytes2(clean3);
808
+ return hexToBytes(clean2);
1140
809
  }
1141
810
  function concatBytes2(...parts) {
1142
811
  let len = 0;
@@ -1197,7 +866,7 @@ function hexToMinaBase58PrivateKey(privateKey) {
1197
866
  Uint8Array.from([MINA_PRIVATE_KEY_VERSION, 1]),
1198
867
  leScalar
1199
868
  );
1200
- const checksum2 = sha2562(sha2562(payload)).slice(0, 4);
869
+ const checksum2 = sha256(sha256(payload)).slice(0, 4);
1201
870
  return base58Encode(concatBytes2(payload, checksum2));
1202
871
  }
1203
872
  var BootstrapError = class extends ToonError {
@@ -2343,7 +2012,7 @@ function pbkdf2(hash, password, salt, opts) {
2343
2012
  }
2344
2013
 
2345
2014
  // ../../node_modules/.pnpm/@scure+base@1.2.6/node_modules/@scure/base/lib/esm/index.js
2346
- function isBytes3(a) {
2015
+ function isBytes2(a) {
2347
2016
  return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
2348
2017
  }
2349
2018
  function isArrayOf(isString, arr) {
@@ -2558,7 +2227,7 @@ function radix(num) {
2558
2227
  const _256 = 2 ** 8;
2559
2228
  return {
2560
2229
  encode: (bytes) => {
2561
- if (!isBytes3(bytes))
2230
+ if (!isBytes2(bytes))
2562
2231
  throw new Error("radix.encode input should be Uint8Array");
2563
2232
  return convertRadix(Array.from(bytes), _256, num);
2564
2233
  },
@@ -2577,7 +2246,7 @@ function radix2(bits, revPadding = false) {
2577
2246
  throw new Error("radix2: carry overflow");
2578
2247
  return {
2579
2248
  encode: (bytes) => {
2580
- if (!isBytes3(bytes))
2249
+ if (!isBytes2(bytes))
2581
2250
  throw new Error("radix2.encode input should be Uint8Array");
2582
2251
  return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
2583
2252
  },
@@ -2592,7 +2261,7 @@ function checksum(len, fn) {
2592
2261
  afn(fn);
2593
2262
  return {
2594
2263
  encode(data) {
2595
- if (!isBytes3(data))
2264
+ if (!isBytes2(data))
2596
2265
  throw new Error("checksum.encode: input should be Uint8Array");
2597
2266
  const sum = fn(data).slice(0, len);
2598
2267
  const res = new Uint8Array(data.length + len);
@@ -2601,7 +2270,7 @@ function checksum(len, fn) {
2601
2270
  return res;
2602
2271
  },
2603
2272
  decode(data) {
2604
- if (!isBytes3(data))
2273
+ if (!isBytes2(data))
2605
2274
  throw new Error("checksum.decode: input should be Uint8Array");
2606
2275
  const payload = data.slice(0, -len);
2607
2276
  const oldChecksum = data.slice(-len);
@@ -2653,7 +2322,7 @@ function generateMnemonic(wordlist2, strength = 128) {
2653
2322
  }
2654
2323
  var calcChecksum = (entropy) => {
2655
2324
  const bitsLeft = 8 - entropy.length / 4;
2656
- return new Uint8Array([sha256(entropy)[0] >> bitsLeft << bitsLeft]);
2325
+ return new Uint8Array([sha2562(entropy)[0] >> bitsLeft << bitsLeft]);
2657
2326
  };
2658
2327
  function getCoder(wordlist2) {
2659
2328
  if (!Array.isArray(wordlist2) || wordlist2.length !== 2048 || typeof wordlist2[0] !== "string")
@@ -4777,7 +4446,7 @@ function bytesToNumberLE(bytes) {
4777
4446
  return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
4778
4447
  }
4779
4448
  function numberToBytesBE(n, len) {
4780
- return hexToBytes(n.toString(16).padStart(len * 2, "0"));
4449
+ return hexToBytes2(n.toString(16).padStart(len * 2, "0"));
4781
4450
  }
4782
4451
  function numberToBytesLE(n, len) {
4783
4452
  return numberToBytesBE(n, len).reverse();
@@ -4786,7 +4455,7 @@ function ensureBytes(title, hex, expectedLength) {
4786
4455
  let res;
4787
4456
  if (typeof hex === "string") {
4788
4457
  try {
4789
- res = hexToBytes(hex);
4458
+ res = hexToBytes2(hex);
4790
4459
  } catch (e) {
4791
4460
  throw new Error(title + " must be hex string or Uint8Array, cause: " + e);
4792
4461
  }
@@ -6266,7 +5935,7 @@ function ecdsa(Point2, hash, ecdsaOpts = {}) {
6266
5935
  return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid);
6267
5936
  }
6268
5937
  static fromHex(hex, format) {
6269
- return this.fromBytes(hexToBytes(hex), format);
5938
+ return this.fromBytes(hexToBytes2(hex), format);
6270
5939
  }
6271
5940
  addRecoveryBit(recovery) {
6272
5941
  return new Signature(this.r, this.s, recovery);
@@ -6301,7 +5970,7 @@ function ecdsa(Point2, hash, ecdsaOpts = {}) {
6301
5970
  toBytes(format = defaultSigOpts_format) {
6302
5971
  validateSigFormat(format);
6303
5972
  if (format === "der")
6304
- return hexToBytes(DER.hexFromSig(this));
5973
+ return hexToBytes2(DER.hexFromSig(this));
6305
5974
  const r = Fn.toBytes(this.r);
6306
5975
  const s = Fn.toBytes(this.s);
6307
5976
  if (format === "recovered") {
@@ -6575,7 +6244,7 @@ function sqrtMod(y) {
6575
6244
  return root;
6576
6245
  }
6577
6246
  var Fpk1 = Field(secp256k1_CURVE.p, { sqrt: sqrtMod });
6578
- var secp256k1 = createCurve({ ...secp256k1_CURVE, Fp: Fpk1, lowS: true, endo: secp256k1_ENDO }, sha256);
6247
+ var secp256k1 = createCurve({ ...secp256k1_CURVE, Fp: Fpk1, lowS: true, endo: secp256k1_ENDO }, sha2562);
6579
6248
 
6580
6249
  // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/legacy.js
6581
6250
  var Rho160 = /* @__PURE__ */ Uint8Array.from([
@@ -6697,7 +6366,7 @@ var ripemd160 = /* @__PURE__ */ createHasher(() => new RIPEMD160());
6697
6366
 
6698
6367
  // ../../node_modules/.pnpm/@scure+bip32@1.7.0/node_modules/@scure/bip32/lib/esm/index.js
6699
6368
  var Point = secp256k1.ProjectivePoint;
6700
- var base58check = createBase58check(sha256);
6369
+ var base58check = createBase58check(sha2562);
6701
6370
  function bytesToNumber(bytes) {
6702
6371
  abytes(bytes);
6703
6372
  const h = bytes.length === 0 ? "0" : bytesToHex(bytes);
@@ -6706,12 +6375,12 @@ function bytesToNumber(bytes) {
6706
6375
  function numberToBytes(num) {
6707
6376
  if (typeof num !== "bigint")
6708
6377
  throw new Error("bigint expected");
6709
- return hexToBytes(num.toString(16).padStart(64, "0"));
6378
+ return hexToBytes2(num.toString(16).padStart(64, "0"));
6710
6379
  }
6711
6380
  var MASTER_SECRET = utf8ToBytes("Bitcoin seed");
6712
6381
  var BITCOIN_VERSIONS = { private: 76066276, public: 76067358 };
6713
6382
  var HARDENED_OFFSET = 2147483648;
6714
- var hash160 = (data) => ripemd160(sha256(data));
6383
+ var hash160 = (data) => ripemd160(sha2562(data));
6715
6384
  var fromU32 = (data) => createView(data).getUint32(0, false);
6716
6385
  var toU32 = (n) => {
6717
6386
  if (!Number.isSafeInteger(n) || n < 0 || n > 2 ** 32 - 1) {
@@ -6952,7 +6621,7 @@ import {
6952
6621
  import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
6953
6622
  import { toHex as toHex3 } from "viem";
6954
6623
  import { readFileSync, writeFileSync, existsSync } from "fs";
6955
- import { finalizeEvent as finalizeEvent11 } from "nostr-tools/pure";
6624
+ import { finalizeEvent as finalizeEvent22 } from "nostr-tools/pure";
6956
6625
  import { nip19 } from "nostr-tools";
6957
6626
  import { getPublicKey as getPublicKey32 } from "nostr-tools/pure";
6958
6627
  import {
@@ -6968,6 +6637,7 @@ var ToonClientError = class extends Error {
6968
6637
  this.code = code;
6969
6638
  this.name = "ToonClientError";
6970
6639
  }
6640
+ code;
6971
6641
  };
6972
6642
  var NetworkError = class extends ToonClientError {
6973
6643
  constructor(message, cause) {
@@ -7021,7 +6691,7 @@ function deriveEvmIdentity(secretKey) {
7021
6691
  async function deriveSolanaKey(seed, accountIndex = 0) {
7022
6692
  const { hmac: hmac2 } = await import("./hmac-26UC6YKX.js");
7023
6693
  const { sha512: sha5122 } = await import("./sha512-WYC446ZM.js");
7024
- const { ed25519: ed255194 } = await import("./ed25519-2QVPINLS.js");
6694
+ const { ed25519: ed255194 } = await import("./ed25519-2LFQXLYS.js");
7025
6695
  const encoder = new TextEncoder();
7026
6696
  let I = hmac2(sha5122, encoder.encode("ed25519 seed"), seed);
7027
6697
  let key = I.slice(0, 32);
@@ -7369,6 +7039,9 @@ function toHex2(bytes) {
7369
7039
  function encodeUtf8(str) {
7370
7040
  return new TextEncoder().encode(str);
7371
7041
  }
7042
+ function decodeUtf8(bytes) {
7043
+ return new TextDecoder().decode(bytes);
7044
+ }
7372
7045
  function isBase64(str) {
7373
7046
  return /^[A-Za-z0-9+/]*={0,2}$/.test(str);
7374
7047
  }
@@ -8232,6 +7905,227 @@ var BtpRuntimeClient = class {
8232
7905
  };
8233
7906
  }
8234
7907
  };
7908
+ var ILP_CLAIM_HEADER = "ILP-Payment-Channel-Claim";
7909
+ var ILP_PEER_ID_HEADER = "ILP-Peer-Id";
7910
+ var HttpIlpClient = class {
7911
+ httpEndpoint;
7912
+ peerId;
7913
+ authToken;
7914
+ timeout;
7915
+ retryConfig;
7916
+ httpClient;
7917
+ createWebSocket;
7918
+ constructor(config) {
7919
+ this.httpEndpoint = config.httpEndpoint;
7920
+ this.peerId = config.peerId;
7921
+ this.authToken = config.authToken;
7922
+ this.timeout = config.timeout ?? 3e4;
7923
+ this.retryConfig = {
7924
+ maxRetries: config.maxRetries ?? 3,
7925
+ retryDelay: config.retryDelay ?? 1e3
7926
+ };
7927
+ this.httpClient = config.httpClient ?? fetch;
7928
+ this.createWebSocket = config.createWebSocket;
7929
+ }
7930
+ /**
7931
+ * Send an ILP PREPARE via `POST /ilp` WITHOUT a claim. The connector accepts
7932
+ * this only on free/zero-amount routes; paid writes must use
7933
+ * {@link sendIlpPacketWithClaim}. Satisfies the IlpClient interface.
7934
+ */
7935
+ async sendIlpPacket(params) {
7936
+ return withRetry(() => this.postPrepare(params), {
7937
+ maxRetries: this.retryConfig.maxRetries,
7938
+ retryDelay: this.retryConfig.retryDelay,
7939
+ exponentialBackoff: true,
7940
+ shouldRetry: (error) => error instanceof NetworkError
7941
+ });
7942
+ }
7943
+ /**
7944
+ * Send an ILP PREPARE via `POST /ilp` with the payment-channel claim attached
7945
+ * as the `ILP-Payment-Channel-Claim` header. `claim` is the SAME JSON object
7946
+ * the BTP path attaches as the `payment-channel-claim` protocolData entry —
7947
+ * we base64(JSON.stringify(claim)) it, byte-for-byte identical to BTP.
7948
+ */
7949
+ async sendIlpPacketWithClaim(params, claim) {
7950
+ return withRetry(() => this.postPrepare(params, claim), {
7951
+ maxRetries: this.retryConfig.maxRetries,
7952
+ retryDelay: this.retryConfig.retryDelay,
7953
+ exponentialBackoff: true,
7954
+ shouldRetry: (error) => error instanceof NetworkError
7955
+ });
7956
+ }
7957
+ /**
7958
+ * Upgrade to a duplex BTP session over the SAME endpoint.
7959
+ *
7960
+ * Derives the `ws(s)://` URL from `httpEndpoint`, opens a WebSocket with
7961
+ * `Sec-WebSocket-Protocol: btp` and the same `ILP-Peer-Id` + `Authorization`
7962
+ * headers, and returns a connected {@link BtpRuntimeClient}. When auth headers
7963
+ * are present the connector pre-authenticates the session (no in-band auth
7964
+ * frame); without them the BtpRuntimeClient falls back to the normal BTP
7965
+ * auth-frame flow.
7966
+ *
7967
+ * NOTE: passing per-connection headers + a subprotocol to a WebSocket is
7968
+ * Node-only (the `ws` package). Browsers cannot set arbitrary request headers
7969
+ * on a WebSocket handshake, so a browser consumer must use the gateway
7970
+ * transport or BTP-with-auth-frame instead.
7971
+ */
7972
+ async upgradeToBtp() {
7973
+ const btpUrl = httpEndpointToBtpUrl(this.httpEndpoint);
7974
+ const createWebSocket = this.createWebSocket ?? await makeBtpWebSocketFactory(this.authHeaders());
7975
+ const client = new BtpRuntimeClient({
7976
+ btpUrl,
7977
+ // BtpRuntimeClient sends an auth frame using these; when the connector
7978
+ // pre-authenticated via Upgrade headers it accepts the (redundant) frame.
7979
+ peerId: this.peerId ?? "client",
7980
+ authToken: this.authToken ?? "",
7981
+ createWebSocket
7982
+ });
7983
+ await client.connect();
7984
+ return client;
7985
+ }
7986
+ // ─── Private ──────────────────────────────────────────────────────────────
7987
+ authHeaders() {
7988
+ const headers = {};
7989
+ if (this.peerId) headers[ILP_PEER_ID_HEADER] = this.peerId;
7990
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
7991
+ return headers;
7992
+ }
7993
+ /**
7994
+ * Single attempt: serialize the PREPARE, POST it, and map the response.
7995
+ * @throws {NetworkError} On connection/timeout failures (retried).
7996
+ * @throws {ConnectorError} On non-retryable transport errors (5xx / unexpected).
7997
+ */
7998
+ async postPrepare(params, claim) {
7999
+ const requestTimeout = params.timeout ?? this.timeout;
8000
+ const prepare = serializeIlpPrepare({
8001
+ type: ILPPacketType.PREPARE,
8002
+ amount: BigInt(params.amount),
8003
+ destination: params.destination,
8004
+ executionCondition: new Uint8Array(32),
8005
+ expiresAt: new Date(Date.now() + requestTimeout),
8006
+ data: fromBase64(params.data)
8007
+ });
8008
+ const headers = {
8009
+ "Content-Type": "application/octet-stream",
8010
+ ...this.authHeaders()
8011
+ };
8012
+ if (claim !== void 0) {
8013
+ headers[ILP_CLAIM_HEADER] = toBase64(
8014
+ encodeUtf8(JSON.stringify(claim))
8015
+ );
8016
+ }
8017
+ const controller = new AbortController();
8018
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
8019
+ try {
8020
+ const response = await this.httpClient(this.httpEndpoint, {
8021
+ method: "POST",
8022
+ headers,
8023
+ // Copy into a fresh ArrayBuffer so fetch sees a clean body, not a view.
8024
+ body: prepare.slice(),
8025
+ signal: controller.signal
8026
+ });
8027
+ clearTimeout(timeoutId);
8028
+ return await this.mapResponse(response);
8029
+ } catch (error) {
8030
+ clearTimeout(timeoutId);
8031
+ throw this.mapTransportError(error, requestTimeout);
8032
+ }
8033
+ }
8034
+ /**
8035
+ * Map a `200 OK` body (OER FULFILL/REJECT) to an IlpSendResult; map a non-2xx
8036
+ * to a transport error. Per the wire contract, ILP-level rejects arrive as a
8037
+ * 200 + REJECT body — only HTTP non-2xx means a transport-layer failure.
8038
+ */
8039
+ async mapResponse(response) {
8040
+ if (response.ok) {
8041
+ const buf = new Uint8Array(await response.arrayBuffer());
8042
+ if (buf.length === 0) {
8043
+ throw new ConnectorError("Empty 200 body from /ilp (expected OER ILP response)");
8044
+ }
8045
+ const ilp = deserializeIlpPacket(buf);
8046
+ if (ilp.type === ILPPacketType.FULFILL) {
8047
+ return {
8048
+ accepted: true,
8049
+ data: ilp.data.length > 0 ? toBase64(ilp.data) : void 0
8050
+ };
8051
+ }
8052
+ return {
8053
+ accepted: false,
8054
+ code: ilp.code,
8055
+ message: ilp.message,
8056
+ data: ilp.data.length > 0 ? toBase64(ilp.data) : void 0
8057
+ };
8058
+ }
8059
+ const body = await response.text().catch(() => "");
8060
+ const detail = body ? `: ${body}` : "";
8061
+ if (response.status >= 500) {
8062
+ throw new ConnectorError(
8063
+ `Connector transport error (${response.status} ${response.statusText})${detail}`
8064
+ );
8065
+ }
8066
+ throw new ConnectorError(
8067
+ `ILP-over-HTTP request rejected (${response.status} ${response.statusText})${detail}`
8068
+ );
8069
+ }
8070
+ mapTransportError(error, requestTimeout) {
8071
+ if (error instanceof ConnectorError || error instanceof NetworkError) {
8072
+ return error;
8073
+ }
8074
+ if (error instanceof Error && error.name === "AbortError") {
8075
+ return new NetworkError(`Request timeout after ${requestTimeout}ms`, error);
8076
+ }
8077
+ if (error instanceof TypeError && (error.message.includes("fetch failed") || error.message.includes("ECONNREFUSED") || error.message.includes("ECONNRESET") || error.message.includes("ETIMEDOUT") || error.message.includes("network"))) {
8078
+ return new NetworkError(`Network connection failed: ${error.message}`, error);
8079
+ }
8080
+ return new ConnectorError(
8081
+ `Unexpected error during ILP-over-HTTP request: ${error instanceof Error ? error.message : String(error)}`,
8082
+ error instanceof Error ? error : void 0
8083
+ );
8084
+ }
8085
+ };
8086
+ function httpEndpointToBtpUrl(httpEndpoint) {
8087
+ return httpEndpoint.replace(/^https:\/\//i, "wss://").replace(/^http:\/\//i, "ws://");
8088
+ }
8089
+ async function makeBtpWebSocketFactory(headers) {
8090
+ const { createRequire } = await import("module");
8091
+ const require2 = createRequire(import.meta.url);
8092
+ const WS = require2("ws");
8093
+ const ws = WS;
8094
+ const WSClass = typeof ws === "function" ? ws : typeof ws.default === "function" ? ws.default : typeof ws.WebSocket === "function" ? ws.WebSocket : null;
8095
+ if (WSClass === null) {
8096
+ throw new Error(
8097
+ "makeBtpWebSocketFactory: require('ws') did not yield a constructor on .default, .WebSocket, or the module root."
8098
+ );
8099
+ }
8100
+ return (url) => (
8101
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8102
+ new WSClass(url, "btp", { headers })
8103
+ );
8104
+ }
8105
+ function readDiscoveredIlpPeer(peer) {
8106
+ const p = peer ?? {};
8107
+ return {
8108
+ btpEndpoint: typeof p["btpEndpoint"] === "string" ? p["btpEndpoint"] : void 0,
8109
+ httpEndpoint: typeof p["httpEndpoint"] === "string" ? p["httpEndpoint"] : void 0,
8110
+ supportsUpgrade: typeof p["supportsUpgrade"] === "boolean" ? p["supportsUpgrade"] : void 0
8111
+ };
8112
+ }
8113
+ function selectIlpTransport(peer, options = {}) {
8114
+ const needsDuplex = options.needsDuplex ?? false;
8115
+ const http2 = peer.httpEndpoint?.trim() || void 0;
8116
+ const btp = peer.btpEndpoint?.trim() || void 0;
8117
+ const canUpgrade = peer.supportsUpgrade === true;
8118
+ if (needsDuplex) {
8119
+ if (btp) return { kind: "btp", btpEndpoint: btp };
8120
+ if (http2 && canUpgrade) return { kind: "http-upgradable", httpEndpoint: http2 };
8121
+ throw new Error(
8122
+ "Duplex transport required but peer exposes neither a btpEndpoint nor an upgradable httpEndpoint"
8123
+ );
8124
+ }
8125
+ if (http2) return { kind: "http", httpEndpoint: http2, canUpgrade };
8126
+ if (btp) return { kind: "btp", btpEndpoint: btp };
8127
+ throw new Error("Peer exposes neither an httpEndpoint nor a btpEndpoint");
8128
+ }
8235
8129
  var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
8236
8130
  var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
8237
8131
  var RENT_SYSVAR_ID = "SysvarRent111111111111111111111111111111111";
@@ -8319,7 +8213,7 @@ function findProgramAddress(seeds, programId) {
8319
8213
  input.set(programId, offset);
8320
8214
  offset += programId.length;
8321
8215
  input.set(PDA_MARKER, offset);
8322
- const hash = sha256(input);
8216
+ const hash = sha2562(input);
8323
8217
  if (!isOnCurve(hash)) return { pda: hash, bump };
8324
8218
  }
8325
8219
  throw new Error("Could not find a viable PDA bump seed");
@@ -9399,6 +9293,12 @@ async function initializeHttpMode(config) {
9399
9293
  const effectiveBtpUrl = transport.btpUrl ?? config.btpUrl;
9400
9294
  const effectiveConnectorUrl = transport.connectorUrl ?? config.connectorUrl;
9401
9295
  const settlementInfo = buildSettlementInfo(config);
9296
+ const discoveredPeer = readDiscoveredIlpPeer({
9297
+ btpEndpoint: effectiveBtpUrl,
9298
+ httpEndpoint: config.connectorHttpEndpoint,
9299
+ supportsUpgrade: config.connectorSupportsUpgrade
9300
+ });
9301
+ const transportChoice = discoveredPeer.httpEndpoint || discoveredPeer.btpEndpoint ? selectIlpTransport(discoveredPeer, { needsDuplex: false }) : null;
9402
9302
  let btpClient = null;
9403
9303
  if (effectiveBtpUrl) {
9404
9304
  btpClient = new BtpRuntimeClient({
@@ -9409,7 +9309,20 @@ async function initializeHttpMode(config) {
9409
9309
  });
9410
9310
  await btpClient.connect();
9411
9311
  }
9412
- const runtimeClient = btpClient ?? new HttpRuntimeClient({
9312
+ let httpIlpClient = null;
9313
+ if (transportChoice && (transportChoice.kind === "http" || transportChoice.kind === "http-upgradable")) {
9314
+ httpIlpClient = new HttpIlpClient({
9315
+ httpEndpoint: transportChoice.httpEndpoint,
9316
+ ...config.btpPeerId !== void 0 ? { peerId: config.btpPeerId } : {},
9317
+ ...config.btpAuthToken !== void 0 ? { authToken: config.btpAuthToken } : {},
9318
+ timeout: config.queryTimeout,
9319
+ maxRetries: config.maxRetries,
9320
+ retryDelay: config.retryDelay,
9321
+ ...transport.httpClient !== void 0 ? { httpClient: transport.httpClient } : {},
9322
+ ...transport.createWebSocket !== void 0 ? { createWebSocket: transport.createWebSocket } : {}
9323
+ });
9324
+ }
9325
+ const runtimeClient = httpIlpClient ?? btpClient ?? new HttpRuntimeClient({
9413
9326
  connectorUrl: effectiveConnectorUrl,
9414
9327
  timeout: config.queryTimeout,
9415
9328
  maxRetries: config.maxRetries,
@@ -9666,7 +9579,7 @@ var DEFAULT_MINA_TOKEN_ID = "MINA";
9666
9579
  var MINA_CLAIM_NETWORK = "devnet";
9667
9580
  function deriveMinaSalt(zkAppAddress, nonce) {
9668
9581
  const digestHex = bytesToHex(
9669
- sha256(new TextEncoder().encode(`mina-pc-salt:${zkAppAddress}:${nonce}`))
9582
+ sha2562(new TextEncoder().encode(`mina-pc-salt:${zkAppAddress}:${nonce}`))
9670
9583
  );
9671
9584
  const salt = BigInt("0x" + digestHex.slice(0, 60));
9672
9585
  return salt === 0n ? 1n : salt;
@@ -10134,6 +10047,319 @@ var JsonFileChannelStore = class {
10134
10047
  writeFileSync(this.filePath, JSON.stringify(data, null, 2), "utf-8");
10135
10048
  }
10136
10049
  };
10050
+ var ARWEAVE_TX_ID_REGEX = /^[A-Za-z0-9_-]{43}$/;
10051
+ async function requestBlobStorage(client, secretKey, params) {
10052
+ const bid = params.bid ?? (params.ilpAmount !== void 0 ? String(params.ilpAmount) : void 0);
10053
+ if (bid === void 0 || bid === "") {
10054
+ return {
10055
+ success: false,
10056
+ error: "requestBlobStorage requires a bid (or ilpAmount to derive it)"
10057
+ };
10058
+ }
10059
+ const blobBuffer = Buffer.from(
10060
+ params.blobData.buffer,
10061
+ params.blobData.byteOffset,
10062
+ params.blobData.byteLength
10063
+ );
10064
+ let event;
10065
+ try {
10066
+ event = buildBlobStorageRequest(
10067
+ {
10068
+ blobData: blobBuffer,
10069
+ contentType: params.contentType,
10070
+ bid
10071
+ },
10072
+ secretKey
10073
+ );
10074
+ } catch (error) {
10075
+ return {
10076
+ success: false,
10077
+ error: error instanceof Error ? error.message : String(error)
10078
+ };
10079
+ }
10080
+ const result = await client.publishEvent(event, {
10081
+ destination: params.destination,
10082
+ claim: params.claim,
10083
+ ilpAmount: params.ilpAmount
10084
+ });
10085
+ if (!result.success) {
10086
+ return {
10087
+ success: false,
10088
+ eventId: result.eventId ?? event.id,
10089
+ error: result.error ?? "Blob storage request rejected"
10090
+ };
10091
+ }
10092
+ if (!result.data) {
10093
+ return {
10094
+ success: false,
10095
+ eventId: event.id,
10096
+ error: "FULFILL contained no data; expected base64-encoded Arweave tx ID"
10097
+ };
10098
+ }
10099
+ const txId = decodeUtf8(fromBase64(result.data));
10100
+ if (!ARWEAVE_TX_ID_REGEX.test(txId)) {
10101
+ return {
10102
+ success: false,
10103
+ eventId: event.id,
10104
+ error: `Decoded FULFILL data is not a valid Arweave tx ID: "${txId}"`
10105
+ };
10106
+ }
10107
+ return {
10108
+ success: true,
10109
+ txId,
10110
+ eventId: event.id
10111
+ };
10112
+ }
10113
+ var Http402Client = class {
10114
+ fetchImpl;
10115
+ resolveClaim;
10116
+ createIlpClient;
10117
+ needsDuplex;
10118
+ constructor(config = {}) {
10119
+ this.fetchImpl = config.fetch ?? fetch;
10120
+ this.resolveClaim = config.resolveClaim;
10121
+ this.createIlpClient = config.createIlpClient ?? ((httpEndpoint) => new HttpIlpClient({ httpEndpoint }));
10122
+ this.needsDuplex = config.needsDuplex ?? false;
10123
+ }
10124
+ /**
10125
+ * `fetch()`-like entry point. Issues the request; on `402` parses the x402
10126
+ * challenge and — when a usable `toon-channel` offer is present and a claim
10127
+ * resolver is configured — pays over TOON and returns the reconstructed
10128
+ * `Response`. Otherwise returns the original 402 unchanged (AC5).
10129
+ */
10130
+ async fetch(url, opts = {}) {
10131
+ const method = (opts.method ?? "GET").toUpperCase();
10132
+ const probe = await this.fetchImpl(url, {
10133
+ method,
10134
+ ...opts.headers ? { headers: opts.headers } : {},
10135
+ ...opts.body !== void 0 ? { body: opts.body } : {},
10136
+ ...opts.timeout !== void 0 ? { signal: AbortSignal.timeout(opts.timeout) } : {}
10137
+ });
10138
+ if (probe.status !== 402) return probe;
10139
+ const challenge = await parseX402Challenge(probe.clone());
10140
+ const accept = challenge.toonChannel;
10141
+ if (!accept || !this.resolveClaim) return probe;
10142
+ return this.payOverToon(url, method, opts, accept, this.resolveClaim);
10143
+ }
10144
+ /**
10145
+ * Open/reuse a channel (via the injected claim resolver), serialize the HTTP
10146
+ * request into the ILP packet `data`, send it to `POST /ilp` with the claim,
10147
+ * and reconstruct the origin `Response` from the FULFILL `data`.
10148
+ */
10149
+ async payOverToon(url, method, opts, accept, resolveClaim) {
10150
+ const destination = opts.destination ?? accept.destination;
10151
+ const claim = await resolveClaim(destination, accept.amount);
10152
+ const requestBytes = serializeHttpRequest({
10153
+ method,
10154
+ url,
10155
+ headers: opts.headers,
10156
+ body: opts.body
10157
+ });
10158
+ const peer = {
10159
+ httpEndpoint: accept.httpEndpoint,
10160
+ supportsUpgrade: accept.supportsUpgrade
10161
+ };
10162
+ const choice = selectIlpTransport(peer, {
10163
+ needsDuplex: this.needsDuplex
10164
+ });
10165
+ const ilpClient = this.createIlpClient(accept.httpEndpoint);
10166
+ const result = await this.sendOverChoice(
10167
+ ilpClient,
10168
+ choice,
10169
+ {
10170
+ destination,
10171
+ amount: String(accept.amount),
10172
+ data: toBase64(requestBytes),
10173
+ ...opts.timeout !== void 0 ? { timeout: opts.timeout } : {}
10174
+ },
10175
+ claim
10176
+ );
10177
+ if (!result.accepted) {
10178
+ throw new ConnectorError(
10179
+ `h402 payment rejected by connector: ${result.code ?? "F00"} ${result.message ?? ""}`.trim()
10180
+ );
10181
+ }
10182
+ if (!result.data) {
10183
+ throw new ConnectorError(
10184
+ "h402 FULFILL carried no data (expected an HTTP response payload)"
10185
+ );
10186
+ }
10187
+ return parseHttpResponse(fromBase64(result.data));
10188
+ }
10189
+ /**
10190
+ * Send the serialized HTTP-in-ILP PREPARE over the selected transport.
10191
+ *
10192
+ * - `http` / `http-upgradable`: stateless one-shot `POST /ilp` with the claim.
10193
+ * - `http-upgradable` additionally exercises {@link HttpIlpClient.upgradeToBtp}
10194
+ * for the duplex/streaming path (AC4). v1 still drives the actual write over
10195
+ * the one-shot HTTP method even after upgrading — full duplex body streaming
10196
+ * is a documented follow-up — but the upgrade call path is wired here.
10197
+ * - `btp`: not reachable from h402 (the x402 offer only carries an
10198
+ * `httpEndpoint`); guarded for completeness.
10199
+ */
10200
+ async sendOverChoice(ilpClient, choice, params, claim) {
10201
+ if (choice.kind === "http-upgradable") {
10202
+ const btp = await ilpClient.upgradeToBtp();
10203
+ try {
10204
+ return await btp.sendIlpPacketWithClaim(
10205
+ params,
10206
+ claim
10207
+ );
10208
+ } finally {
10209
+ await btp.disconnect().catch(() => {
10210
+ });
10211
+ }
10212
+ }
10213
+ if (choice.kind === "btp") {
10214
+ throw new ToonClientError(
10215
+ "h402 offer resolved to a BTP-only transport; the x402 toon-channel entry must advertise an httpEndpoint",
10216
+ "INVALID_STATE"
10217
+ );
10218
+ }
10219
+ return ilpClient.sendIlpPacketWithClaim(params, claim);
10220
+ }
10221
+ };
10222
+ function readString(obj, keys) {
10223
+ for (const k of keys) {
10224
+ const v = obj[k];
10225
+ if (typeof v === "string" && v.trim().length > 0) return v.trim();
10226
+ }
10227
+ return void 0;
10228
+ }
10229
+ function readAmount(obj, keys) {
10230
+ for (const k of keys) {
10231
+ const v = obj[k];
10232
+ if (typeof v === "bigint") return v;
10233
+ if (typeof v === "number" && Number.isFinite(v)) return BigInt(Math.trunc(v));
10234
+ if (typeof v === "string" && /^\d+$/.test(v.trim())) return BigInt(v.trim());
10235
+ }
10236
+ return void 0;
10237
+ }
10238
+ async function parseX402Challenge(response) {
10239
+ let body;
10240
+ try {
10241
+ body = await response.json();
10242
+ } catch {
10243
+ return {};
10244
+ }
10245
+ return parseX402Body(body);
10246
+ }
10247
+ function parseX402Body(body) {
10248
+ if (typeof body !== "object" || body === null) return {};
10249
+ const b = body;
10250
+ const version = typeof b["x402Version"] === "number" ? b["x402Version"] : void 0;
10251
+ const accepts = Array.isArray(b["accepts"]) ? b["accepts"] : [];
10252
+ for (const raw of accepts) {
10253
+ if (typeof raw !== "object" || raw === null) continue;
10254
+ const entry = raw;
10255
+ const scheme = readString(entry, ["scheme"]);
10256
+ if (scheme !== "toon-channel") continue;
10257
+ const destination = readString(entry, [
10258
+ "destination",
10259
+ "ilpAddress",
10260
+ "payTo"
10261
+ ]);
10262
+ const httpEndpoint = readString(entry, [
10263
+ "httpEndpoint",
10264
+ "ilpEndpoint",
10265
+ "endpoint"
10266
+ ]);
10267
+ const amount = readAmount(entry, ["amount", "price", "maxAmountRequired"]);
10268
+ if (!destination || !httpEndpoint || amount === void 0) continue;
10269
+ const network = readString(entry, ["network", "chain"]);
10270
+ const supportsUpgrade = entry["supportsUpgrade"] === true || entry["upgradable"] === true;
10271
+ return {
10272
+ ...version !== void 0 ? { x402Version: version } : {},
10273
+ toonChannel: {
10274
+ scheme: "toon-channel",
10275
+ ...network !== void 0 ? { network } : {},
10276
+ destination,
10277
+ amount,
10278
+ httpEndpoint,
10279
+ supportsUpgrade
10280
+ }
10281
+ };
10282
+ }
10283
+ return version !== void 0 ? { x402Version: version } : {};
10284
+ }
10285
+ var CRLF = "\r\n";
10286
+ function concatHeadAndBody(head, body) {
10287
+ const headBytes = encodeUtf8(head);
10288
+ const out = new Uint8Array(headBytes.length + body.length);
10289
+ out.set(headBytes, 0);
10290
+ out.set(body, headBytes.length);
10291
+ return out;
10292
+ }
10293
+ function bodyToBytes(body) {
10294
+ if (body === void 0) return new Uint8Array(0);
10295
+ return typeof body === "string" ? encodeUtf8(body) : body;
10296
+ }
10297
+ function serializeHttpRequest(req) {
10298
+ const u = new URL(req.url);
10299
+ const target = `${u.pathname}${u.search}` || "/";
10300
+ const bodyBytes = bodyToBytes(req.body);
10301
+ const headers = /* @__PURE__ */ new Map();
10302
+ const put = (name, value) => headers.set(name.toLowerCase(), `${name}: ${value}`);
10303
+ const has = (name) => headers.has(name.toLowerCase());
10304
+ for (const [name, value] of Object.entries(req.headers ?? {})) {
10305
+ put(name, value);
10306
+ }
10307
+ if (!has("host")) put("Host", u.host);
10308
+ if (bodyBytes.length > 0 && !has("content-length")) {
10309
+ put("Content-Length", String(bodyBytes.length));
10310
+ }
10311
+ const lines = [
10312
+ `${req.method.toUpperCase()} ${target} HTTP/1.1`,
10313
+ ...headers.values()
10314
+ ];
10315
+ const head = lines.join(CRLF) + CRLF + CRLF;
10316
+ return concatHeadAndBody(head, bodyBytes);
10317
+ }
10318
+ function findHeaderEnd(bytes) {
10319
+ for (let i = 0; i + 3 < bytes.length; i++) {
10320
+ if (bytes[i] === 13 && bytes[i + 1] === 10 && bytes[i + 2] === 13 && bytes[i + 3] === 10) {
10321
+ return i + 4;
10322
+ }
10323
+ }
10324
+ return -1;
10325
+ }
10326
+ function parseHttpResponse(bytes) {
10327
+ const headerEnd = findHeaderEnd(bytes);
10328
+ const headBytes = headerEnd === -1 ? bytes : bytes.subarray(0, headerEnd - 2);
10329
+ const body = headerEnd === -1 ? new Uint8Array(0) : bytes.subarray(headerEnd);
10330
+ const headText = decodeUtf8(headBytes);
10331
+ const lines = headText.split(CRLF).filter((l) => l.length > 0);
10332
+ const statusLine = lines.shift();
10333
+ if (!statusLine) {
10334
+ throw new ConnectorError(
10335
+ "h402 response payload had no HTTP status line"
10336
+ );
10337
+ }
10338
+ const match = /^HTTP\/\d\.\d\s+(\d{3})(?:\s+(.*))?$/.exec(statusLine.trim());
10339
+ if (!match) {
10340
+ throw new ConnectorError(
10341
+ `h402 response payload had a malformed status line: "${statusLine}"`
10342
+ );
10343
+ }
10344
+ const status = parseInt(match[1], 10);
10345
+ const statusText = match[2] ?? "";
10346
+ const headers = new Headers();
10347
+ for (const line of lines) {
10348
+ const idx = line.indexOf(":");
10349
+ if (idx === -1) continue;
10350
+ const name = line.slice(0, idx).trim();
10351
+ const value = line.slice(idx + 1).trim();
10352
+ if (name.length === 0) continue;
10353
+ headers.append(name, value);
10354
+ }
10355
+ const nullBodyStatus = status === 101 || status === 204 || status === 205 || status === 304;
10356
+ const init = { status, headers };
10357
+ if (statusText) init.statusText = statusText;
10358
+ return new Response(
10359
+ nullBodyStatus || body.length === 0 ? null : body.slice(),
10360
+ init
10361
+ );
10362
+ }
10137
10363
  var ToonClient = class {
10138
10364
  config;
10139
10365
  state = null;
@@ -10184,6 +10410,28 @@ var ToonClient = class {
10184
10410
  getPublicKey() {
10185
10411
  return getPublicKey22(this.config.secretKey);
10186
10412
  }
10413
+ /**
10414
+ * Sign an unsigned Nostr event template with the client's Nostr secret key,
10415
+ * returning a fully-signed event (id + pubkey + sig).
10416
+ *
10417
+ * This is the key primitive behind the daemon's sign-and-publish path: a UI
10418
+ * or agent supplies only `{ kind, content, tags, created_at }` and never holds
10419
+ * the private key — signing happens here, inside the key owner.
10420
+ */
10421
+ signEvent(template) {
10422
+ return finalizeEvent11(template, this.config.secretKey);
10423
+ }
10424
+ /**
10425
+ * Upload bytes to Arweave via the kind:5094 blob-storage DVM (single-packet),
10426
+ * signing the request with this client's Nostr key and paying through its
10427
+ * existing channel. Returns the Arweave tx id on success.
10428
+ *
10429
+ * Backs the daemon's `upload-media` path: the key and claim/channel plumbing
10430
+ * stay inside the client; callers pass only the bytes.
10431
+ */
10432
+ async uploadBlob(params) {
10433
+ return requestBlobStorage(this, this.config.secretKey, params);
10434
+ }
10187
10435
  /**
10188
10436
  * Per-chain settlement readiness for the configured `network` tier, mirroring
10189
10437
  * the townhouse node's status. Returns `undefined` when no named `network` is
@@ -10466,6 +10714,46 @@ var ToonClient = class {
10466
10714
  );
10467
10715
  }
10468
10716
  }
10717
+ /**
10718
+ * Payment-aware HTTP fetch over TOON (issue #50). A `fetch()`-like method that
10719
+ * makes paying for an HTTP resource transparent:
10720
+ *
10721
+ * 1. Issues the HTTP request to `url`.
10722
+ * 2. On `402`, parses the x402 `accepts` array and selects the
10723
+ * `toon-channel` entry (see {@link Http402Client} for the wire shape).
10724
+ * 3. Opens/reuses a payment channel for the entry's ILP destination (via
10725
+ * ChannelManager), signs a balance proof for the demanded price, and
10726
+ * re-sends the SAME HTTP request as a transparent HTTP-in-ILP packet to
10727
+ * the connector's `POST /ilp` (via {@link HttpIlpClient}), with the claim
10728
+ * in the `ILP-Payment-Channel-Claim` header.
10729
+ * 4. Reconstructs and returns a standard Web `Response` from the FULFILL
10730
+ * `data`. The caller never sees ILP.
10731
+ *
10732
+ * If the origin offers no `toon-channel` entry, the original `402` Response is
10733
+ * returned unchanged (the caller sees the vanilla x402 challenge).
10734
+ *
10735
+ * The channel/claim plumbing is wired to the live ChannelManager + per-chain
10736
+ * signer via `resolveClaimForDestination` — identical to `publishEvent`. The
10737
+ * `amount` paid comes from the selected x402 entry (the resource's price).
10738
+ *
10739
+ * @throws {ToonClientError} If the client is not started.
10740
+ * @throws {ConnectorError} If the connector rejects the payment or returns no
10741
+ * HTTP payload.
10742
+ */
10743
+ async h402Fetch(url, opts) {
10744
+ if (!this.state) {
10745
+ throw new ToonClientError(
10746
+ "Client not started. Call start() first.",
10747
+ "INVALID_STATE"
10748
+ );
10749
+ }
10750
+ const client = new Http402Client({
10751
+ ...this.channelManager ? {
10752
+ resolveClaim: (destination, amount) => this.resolveClaimForDestination(destination, amount)
10753
+ } : {}
10754
+ });
10755
+ return client.fetch(url, opts);
10756
+ }
10469
10757
  /**
10470
10758
  * Sends a raw swap ILP packet (Story 12.5) to a Mill peer with an attached
10471
10759
  * balance-proof claim. This is a lower-level surface than `publishEvent`:
@@ -11073,6 +11361,9 @@ var ControlApiError = class extends Error {
11073
11361
  this.detail = detail;
11074
11362
  this.name = "ControlApiError";
11075
11363
  }
11364
+ status;
11365
+ retryable;
11366
+ detail;
11076
11367
  };
11077
11368
  var DaemonUnreachableError = class extends Error {
11078
11369
  constructor(baseUrl, causedBy) {
@@ -11081,6 +11372,8 @@ var DaemonUnreachableError = class extends Error {
11081
11372
  this.causedBy = causedBy;
11082
11373
  this.name = "DaemonUnreachableError";
11083
11374
  }
11375
+ baseUrl;
11376
+ causedBy;
11084
11377
  };
11085
11378
  var ControlClient = class {
11086
11379
  baseUrl;
@@ -11107,9 +11400,18 @@ var ControlClient = class {
11107
11400
  publish(body) {
11108
11401
  return this.request("POST", "/publish", body);
11109
11402
  }
11403
+ publishUnsigned(body) {
11404
+ return this.request("POST", "/publish-unsigned", body);
11405
+ }
11406
+ uploadMedia(body) {
11407
+ return this.request("POST", "/upload-media", body);
11408
+ }
11110
11409
  subscribe(body) {
11111
11410
  return this.request("POST", "/subscribe", body);
11112
11411
  }
11412
+ query(body) {
11413
+ return this.request("POST", "/query", body);
11414
+ }
11113
11415
  events(query = {}) {
11114
11416
  const qs = new URLSearchParams();
11115
11417
  if (query.subId) qs.set("subId", query.subId);
@@ -11128,6 +11430,13 @@ var ControlClient = class {
11128
11430
  swap(body) {
11129
11431
  return this.request("POST", "/swap", body);
11130
11432
  }
11433
+ httpFetchPaid(body) {
11434
+ return this.request(
11435
+ "POST",
11436
+ "/http-fetch-paid",
11437
+ body
11438
+ );
11439
+ }
11131
11440
  targets() {
11132
11441
  return this.request("GET", "/targets");
11133
11442
  }
@@ -11318,4 +11627,4 @@ export {
11318
11627
  @scure/bip32/lib/esm/index.js:
11319
11628
  (*! scure-bip32 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
11320
11629
  */
11321
- //# sourceMappingURL=chunk-5KFXUT5Q.js.map
11630
+ //# sourceMappingURL=chunk-NP35YO5O.js.map