@toon-protocol/client-mcp 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -38
- package/dist/app/index.html +166 -0
- package/dist/{chunk-5KFXUT5Q.js → chunk-CQ2QIZ6Z.js} +864 -604
- package/dist/chunk-CQ2QIZ6Z.js.map +1 -0
- package/dist/{chunk-FSS45ZX3.js → chunk-DLYE6U2Z.js} +1516 -316
- package/dist/chunk-DLYE6U2Z.js.map +1 -0
- package/dist/{chunk-3NAWISI5.js → chunk-QFHCXJ2V.js} +348 -101
- package/dist/chunk-QFHCXJ2V.js.map +1 -0
- package/dist/chunk-XV52IHVR.js +977 -0
- package/dist/chunk-XV52IHVR.js.map +1 -0
- package/dist/daemon.js +3 -4
- package/dist/daemon.js.map +1 -1
- package/dist/e2e/run-journey.d.ts +1 -0
- package/dist/e2e/run-journey.js +19953 -0
- package/dist/e2e/run-journey.js.map +1 -0
- package/dist/{ed25519-2QVPINLS.js → ed25519-2LFQXLYS.js} +6 -2
- package/dist/index.d.ts +282 -68
- package/dist/index.js +380 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +39 -6
- package/dist/mcp.js.map +1 -1
- package/package.json +11 -7
- package/dist/anon-proxy-W3KMM7GU-FN7ZJY7P.js +0 -25
- package/dist/chunk-3NAWISI5.js.map +0 -1
- package/dist/chunk-5KFXUT5Q.js.map +0 -1
- package/dist/chunk-FSS45ZX3.js.map +0 -1
- package/dist/chunk-SKQTKZIH.js +0 -278
- package/dist/chunk-SKQTKZIH.js.map +0 -1
- package/dist/chunk-ZQKYZJWT.js +0 -359
- package/dist/chunk-ZQKYZJWT.js.map +0 -1
- package/dist/ed25519-2QVPINLS.js.map +0 -1
- package/dist/gateway-QOK47RKS-SEGTXBR3.js +0 -16
- package/dist/gateway-QOK47RKS-SEGTXBR3.js.map +0 -1
- package/dist/socks5-WTJBYGME-6COK4LXW.js +0 -139
- package/dist/socks5-WTJBYGME-6COK4LXW.js.map +0 -1
- /package/dist/{anon-proxy-W3KMM7GU-FN7ZJY7P.js.map → ed25519-2LFQXLYS.js.map} +0 -0
|
@@ -3,11 +3,13 @@ import {
|
|
|
3
3
|
hmac
|
|
4
4
|
} from "./chunk-32QD72IL.js";
|
|
5
5
|
import {
|
|
6
|
-
ed25519
|
|
7
|
-
|
|
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
|
|
1136
|
-
if (
|
|
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
|
|
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 =
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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([
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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 },
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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-
|
|
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);
|
|
@@ -7161,26 +6831,49 @@ function getNetworkStatus(config) {
|
|
|
7161
6831
|
if (!network || network === "custom") return void 0;
|
|
7162
6832
|
return resolveClientNetwork(network).status;
|
|
7163
6833
|
}
|
|
6834
|
+
function proxyIlpEndpoint(proxyUrl) {
|
|
6835
|
+
if (!proxyUrl) return void 0;
|
|
6836
|
+
const trimmed = proxyUrl.replace(/\/+$/, "");
|
|
6837
|
+
return /\/ilp$/i.test(trimmed) ? trimmed : `${trimmed}/ilp`;
|
|
6838
|
+
}
|
|
7164
6839
|
function validateConfig(config) {
|
|
7165
6840
|
if (config.connector !== void 0) {
|
|
7166
6841
|
throw new ValidationError(
|
|
7167
6842
|
"Embedded mode not yet implemented in ToonClient. Use connectorUrl for HTTP mode."
|
|
7168
6843
|
);
|
|
7169
6844
|
}
|
|
7170
|
-
if (!config.connectorUrl) {
|
|
6845
|
+
if (!config.connectorUrl && !config.proxyUrl) {
|
|
7171
6846
|
throw new ValidationError(
|
|
7172
|
-
'connectorUrl is required for HTTP mode. Example: "http://localhost:8080"'
|
|
6847
|
+
'connectorUrl (or proxyUrl) is required for HTTP mode. Example: "http://localhost:8080"'
|
|
7173
6848
|
);
|
|
7174
6849
|
}
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
6850
|
+
if (config.connectorUrl) {
|
|
6851
|
+
try {
|
|
6852
|
+
const url = new URL(config.connectorUrl);
|
|
6853
|
+
if (!url.protocol.startsWith("http")) {
|
|
6854
|
+
throw new Error("Must be HTTP or HTTPS");
|
|
6855
|
+
}
|
|
6856
|
+
} catch (error) {
|
|
6857
|
+
throw new ValidationError(
|
|
6858
|
+
`Invalid connectorUrl: must be a valid HTTP/HTTPS URL (e.g., "http://localhost:8080"). Error: ${error instanceof Error ? error.message : String(error)}`
|
|
6859
|
+
);
|
|
6860
|
+
}
|
|
6861
|
+
}
|
|
6862
|
+
for (const [field, value] of [
|
|
6863
|
+
["proxyUrl", config.proxyUrl],
|
|
6864
|
+
["faucetUrl", config.faucetUrl]
|
|
6865
|
+
]) {
|
|
6866
|
+
if (value === void 0) continue;
|
|
6867
|
+
try {
|
|
6868
|
+
const url = new URL(value);
|
|
6869
|
+
if (!url.protocol.startsWith("http")) {
|
|
6870
|
+
throw new Error("Must be HTTP or HTTPS");
|
|
6871
|
+
}
|
|
6872
|
+
} catch (error) {
|
|
6873
|
+
throw new ValidationError(
|
|
6874
|
+
`Invalid ${field}: must be a valid HTTP/HTTPS URL. Error: ${error instanceof Error ? error.message : String(error)}`
|
|
6875
|
+
);
|
|
7179
6876
|
}
|
|
7180
|
-
} catch (error) {
|
|
7181
|
-
throw new ValidationError(
|
|
7182
|
-
`Invalid connectorUrl: must be a valid HTTP/HTTPS URL (e.g., "http://localhost:8080"). Error: ${error instanceof Error ? error.message : String(error)}`
|
|
7183
|
-
);
|
|
7184
6877
|
}
|
|
7185
6878
|
if (config.secretKey !== void 0) {
|
|
7186
6879
|
if (!config.secretKey || config.secretKey.length !== 32) {
|
|
@@ -7244,25 +6937,6 @@ function validateConfig(config) {
|
|
|
7244
6937
|
);
|
|
7245
6938
|
}
|
|
7246
6939
|
}
|
|
7247
|
-
if (config.transport) {
|
|
7248
|
-
if (config.transport.type === "socks5") {
|
|
7249
|
-
if (!config.transport.socksProxy?.startsWith("socks5h://")) {
|
|
7250
|
-
throw new ValidationError(
|
|
7251
|
-
'transport.socksProxy must use socks5h:// scheme to prevent DNS leaks. The "h" suffix ensures .anyone hostnames are resolved by the proxy, not locally.'
|
|
7252
|
-
);
|
|
7253
|
-
}
|
|
7254
|
-
} else if (config.transport.type === "gateway") {
|
|
7255
|
-
if (!config.transport.gatewayUrl) {
|
|
7256
|
-
throw new ValidationError(
|
|
7257
|
-
"transport.gatewayUrl is required for gateway transport"
|
|
7258
|
-
);
|
|
7259
|
-
}
|
|
7260
|
-
} else if (config.transport.type !== "direct") {
|
|
7261
|
-
throw new ValidationError(
|
|
7262
|
-
`Unknown transport type: "${config.transport.type}"`
|
|
7263
|
-
);
|
|
7264
|
-
}
|
|
7265
|
-
}
|
|
7266
6940
|
if (config.chainRpcUrls && config.supportedChains) {
|
|
7267
6941
|
for (const chain2 of Object.keys(config.chainRpcUrls)) {
|
|
7268
6942
|
if (!config.supportedChains.includes(chain2)) {
|
|
@@ -7279,19 +6953,21 @@ function applyDefaults(rawConfig) {
|
|
|
7279
6953
|
config.mnemonic,
|
|
7280
6954
|
config.mnemonicAccountIndex ?? 0
|
|
7281
6955
|
).secretKey : generateSecretKey2());
|
|
6956
|
+
const connectorHttpEndpoint = config.connectorHttpEndpoint ?? proxyIlpEndpoint(config.proxyUrl);
|
|
6957
|
+
const connectorUrl = config.connectorUrl ?? config.proxyUrl?.replace(/\/+$/, "");
|
|
7282
6958
|
let btpUrl = config.btpUrl;
|
|
7283
|
-
if (!btpUrl &&
|
|
6959
|
+
if (!btpUrl && connectorUrl && !connectorHttpEndpoint) {
|
|
7284
6960
|
try {
|
|
7285
|
-
const url = new URL(
|
|
6961
|
+
const url = new URL(connectorUrl);
|
|
7286
6962
|
const wsProtocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
7287
6963
|
btpUrl = `${wsProtocol}//${url.hostname}:3000`;
|
|
7288
6964
|
} catch {
|
|
7289
6965
|
}
|
|
7290
6966
|
}
|
|
7291
6967
|
let destinationAddress = config.destinationAddress;
|
|
7292
|
-
if (!destinationAddress &&
|
|
6968
|
+
if (!destinationAddress && connectorUrl) {
|
|
7293
6969
|
try {
|
|
7294
|
-
const url = new URL(
|
|
6970
|
+
const url = new URL(connectorUrl);
|
|
7295
6971
|
if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
|
|
7296
6972
|
if (url.port === "8080") {
|
|
7297
6973
|
destinationAddress = "g.toon.genesis";
|
|
@@ -7314,8 +6990,10 @@ function applyDefaults(rawConfig) {
|
|
|
7314
6990
|
...config,
|
|
7315
6991
|
secretKey,
|
|
7316
6992
|
evmPrivateKey,
|
|
7317
|
-
connectorUrl
|
|
7318
|
-
|
|
6993
|
+
// Satisfied by connectorUrl OR proxyUrl (validateConfig enforced one of them).
|
|
6994
|
+
connectorUrl,
|
|
6995
|
+
// Surface the derived `POST /ilp` endpoint so HTTP mode selects HttpIlpClient.
|
|
6996
|
+
...connectorHttpEndpoint ? { connectorHttpEndpoint } : {},
|
|
7319
6997
|
relayUrl: config.relayUrl ?? "ws://localhost:7100",
|
|
7320
6998
|
queryTimeout: config.queryTimeout ?? 3e4,
|
|
7321
6999
|
maxRetries: config.maxRetries ?? 3,
|
|
@@ -7369,9 +7047,19 @@ function toHex2(bytes) {
|
|
|
7369
7047
|
function encodeUtf8(str) {
|
|
7370
7048
|
return new TextEncoder().encode(str);
|
|
7371
7049
|
}
|
|
7050
|
+
function decodeUtf8(bytes) {
|
|
7051
|
+
return new TextDecoder().decode(bytes);
|
|
7052
|
+
}
|
|
7372
7053
|
function isBase64(str) {
|
|
7373
7054
|
return /^[A-Za-z0-9+/]*={0,2}$/.test(str);
|
|
7374
7055
|
}
|
|
7056
|
+
var REQUEST_LINE = "POST /write HTTP/1.1";
|
|
7057
|
+
var HEADERS = ["Host: relay", "Content-Type: application/json"];
|
|
7058
|
+
function buildStoreWriteEnvelope(event) {
|
|
7059
|
+
const body = JSON.stringify({ event });
|
|
7060
|
+
const head = [REQUEST_LINE, ...HEADERS].join("\r\n");
|
|
7061
|
+
return encodeUtf8(head + "\r\n\r\n" + body);
|
|
7062
|
+
}
|
|
7375
7063
|
async function withRetry(operation, options) {
|
|
7376
7064
|
const {
|
|
7377
7065
|
maxRetries,
|
|
@@ -8232,6 +7920,227 @@ var BtpRuntimeClient = class {
|
|
|
8232
7920
|
};
|
|
8233
7921
|
}
|
|
8234
7922
|
};
|
|
7923
|
+
var ILP_CLAIM_HEADER = "ILP-Payment-Channel-Claim";
|
|
7924
|
+
var ILP_PEER_ID_HEADER = "ILP-Peer-Id";
|
|
7925
|
+
var HttpIlpClient = class {
|
|
7926
|
+
httpEndpoint;
|
|
7927
|
+
peerId;
|
|
7928
|
+
authToken;
|
|
7929
|
+
timeout;
|
|
7930
|
+
retryConfig;
|
|
7931
|
+
httpClient;
|
|
7932
|
+
createWebSocket;
|
|
7933
|
+
constructor(config) {
|
|
7934
|
+
this.httpEndpoint = config.httpEndpoint;
|
|
7935
|
+
this.peerId = config.peerId;
|
|
7936
|
+
this.authToken = config.authToken;
|
|
7937
|
+
this.timeout = config.timeout ?? 3e4;
|
|
7938
|
+
this.retryConfig = {
|
|
7939
|
+
maxRetries: config.maxRetries ?? 3,
|
|
7940
|
+
retryDelay: config.retryDelay ?? 1e3
|
|
7941
|
+
};
|
|
7942
|
+
this.httpClient = config.httpClient ?? fetch;
|
|
7943
|
+
this.createWebSocket = config.createWebSocket;
|
|
7944
|
+
}
|
|
7945
|
+
/**
|
|
7946
|
+
* Send an ILP PREPARE via `POST /ilp` WITHOUT a claim. The connector accepts
|
|
7947
|
+
* this only on free/zero-amount routes; paid writes must use
|
|
7948
|
+
* {@link sendIlpPacketWithClaim}. Satisfies the IlpClient interface.
|
|
7949
|
+
*/
|
|
7950
|
+
async sendIlpPacket(params) {
|
|
7951
|
+
return withRetry(() => this.postPrepare(params), {
|
|
7952
|
+
maxRetries: this.retryConfig.maxRetries,
|
|
7953
|
+
retryDelay: this.retryConfig.retryDelay,
|
|
7954
|
+
exponentialBackoff: true,
|
|
7955
|
+
shouldRetry: (error) => error instanceof NetworkError
|
|
7956
|
+
});
|
|
7957
|
+
}
|
|
7958
|
+
/**
|
|
7959
|
+
* Send an ILP PREPARE via `POST /ilp` with the payment-channel claim attached
|
|
7960
|
+
* as the `ILP-Payment-Channel-Claim` header. `claim` is the SAME JSON object
|
|
7961
|
+
* the BTP path attaches as the `payment-channel-claim` protocolData entry —
|
|
7962
|
+
* we base64(JSON.stringify(claim)) it, byte-for-byte identical to BTP.
|
|
7963
|
+
*/
|
|
7964
|
+
async sendIlpPacketWithClaim(params, claim) {
|
|
7965
|
+
return withRetry(() => this.postPrepare(params, claim), {
|
|
7966
|
+
maxRetries: this.retryConfig.maxRetries,
|
|
7967
|
+
retryDelay: this.retryConfig.retryDelay,
|
|
7968
|
+
exponentialBackoff: true,
|
|
7969
|
+
shouldRetry: (error) => error instanceof NetworkError
|
|
7970
|
+
});
|
|
7971
|
+
}
|
|
7972
|
+
/**
|
|
7973
|
+
* Upgrade to a duplex BTP session over the SAME endpoint.
|
|
7974
|
+
*
|
|
7975
|
+
* Derives the `ws(s)://` URL from `httpEndpoint`, opens a WebSocket with
|
|
7976
|
+
* `Sec-WebSocket-Protocol: btp` and the same `ILP-Peer-Id` + `Authorization`
|
|
7977
|
+
* headers, and returns a connected {@link BtpRuntimeClient}. When auth headers
|
|
7978
|
+
* are present the connector pre-authenticates the session (no in-band auth
|
|
7979
|
+
* frame); without them the BtpRuntimeClient falls back to the normal BTP
|
|
7980
|
+
* auth-frame flow.
|
|
7981
|
+
*
|
|
7982
|
+
* NOTE: passing per-connection headers + a subprotocol to a WebSocket is
|
|
7983
|
+
* Node-only (the `ws` package). Browsers cannot set arbitrary request headers
|
|
7984
|
+
* on a WebSocket handshake, so a browser consumer must use the gateway
|
|
7985
|
+
* transport or BTP-with-auth-frame instead.
|
|
7986
|
+
*/
|
|
7987
|
+
async upgradeToBtp() {
|
|
7988
|
+
const btpUrl = httpEndpointToBtpUrl(this.httpEndpoint);
|
|
7989
|
+
const createWebSocket = this.createWebSocket ?? await makeBtpWebSocketFactory(this.authHeaders());
|
|
7990
|
+
const client = new BtpRuntimeClient({
|
|
7991
|
+
btpUrl,
|
|
7992
|
+
// BtpRuntimeClient sends an auth frame using these; when the connector
|
|
7993
|
+
// pre-authenticated via Upgrade headers it accepts the (redundant) frame.
|
|
7994
|
+
peerId: this.peerId ?? "client",
|
|
7995
|
+
authToken: this.authToken ?? "",
|
|
7996
|
+
createWebSocket
|
|
7997
|
+
});
|
|
7998
|
+
await client.connect();
|
|
7999
|
+
return client;
|
|
8000
|
+
}
|
|
8001
|
+
// ─── Private ──────────────────────────────────────────────────────────────
|
|
8002
|
+
authHeaders() {
|
|
8003
|
+
const headers = {};
|
|
8004
|
+
if (this.peerId) headers[ILP_PEER_ID_HEADER] = this.peerId;
|
|
8005
|
+
if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
|
|
8006
|
+
return headers;
|
|
8007
|
+
}
|
|
8008
|
+
/**
|
|
8009
|
+
* Single attempt: serialize the PREPARE, POST it, and map the response.
|
|
8010
|
+
* @throws {NetworkError} On connection/timeout failures (retried).
|
|
8011
|
+
* @throws {ConnectorError} On non-retryable transport errors (5xx / unexpected).
|
|
8012
|
+
*/
|
|
8013
|
+
async postPrepare(params, claim) {
|
|
8014
|
+
const requestTimeout = params.timeout ?? this.timeout;
|
|
8015
|
+
const prepare = serializeIlpPrepare({
|
|
8016
|
+
type: ILPPacketType.PREPARE,
|
|
8017
|
+
amount: BigInt(params.amount),
|
|
8018
|
+
destination: params.destination,
|
|
8019
|
+
executionCondition: new Uint8Array(32),
|
|
8020
|
+
expiresAt: new Date(Date.now() + requestTimeout),
|
|
8021
|
+
data: fromBase64(params.data)
|
|
8022
|
+
});
|
|
8023
|
+
const headers = {
|
|
8024
|
+
"Content-Type": "application/octet-stream",
|
|
8025
|
+
...this.authHeaders()
|
|
8026
|
+
};
|
|
8027
|
+
if (claim !== void 0) {
|
|
8028
|
+
headers[ILP_CLAIM_HEADER] = toBase64(
|
|
8029
|
+
encodeUtf8(JSON.stringify(claim))
|
|
8030
|
+
);
|
|
8031
|
+
}
|
|
8032
|
+
const controller = new AbortController();
|
|
8033
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
|
|
8034
|
+
try {
|
|
8035
|
+
const response = await this.httpClient(this.httpEndpoint, {
|
|
8036
|
+
method: "POST",
|
|
8037
|
+
headers,
|
|
8038
|
+
// Copy into a fresh ArrayBuffer so fetch sees a clean body, not a view.
|
|
8039
|
+
body: prepare.slice(),
|
|
8040
|
+
signal: controller.signal
|
|
8041
|
+
});
|
|
8042
|
+
clearTimeout(timeoutId);
|
|
8043
|
+
return await this.mapResponse(response);
|
|
8044
|
+
} catch (error) {
|
|
8045
|
+
clearTimeout(timeoutId);
|
|
8046
|
+
throw this.mapTransportError(error, requestTimeout);
|
|
8047
|
+
}
|
|
8048
|
+
}
|
|
8049
|
+
/**
|
|
8050
|
+
* Map a `200 OK` body (OER FULFILL/REJECT) to an IlpSendResult; map a non-2xx
|
|
8051
|
+
* to a transport error. Per the wire contract, ILP-level rejects arrive as a
|
|
8052
|
+
* 200 + REJECT body — only HTTP non-2xx means a transport-layer failure.
|
|
8053
|
+
*/
|
|
8054
|
+
async mapResponse(response) {
|
|
8055
|
+
if (response.ok) {
|
|
8056
|
+
const buf = new Uint8Array(await response.arrayBuffer());
|
|
8057
|
+
if (buf.length === 0) {
|
|
8058
|
+
throw new ConnectorError("Empty 200 body from /ilp (expected OER ILP response)");
|
|
8059
|
+
}
|
|
8060
|
+
const ilp = deserializeIlpPacket(buf);
|
|
8061
|
+
if (ilp.type === ILPPacketType.FULFILL) {
|
|
8062
|
+
return {
|
|
8063
|
+
accepted: true,
|
|
8064
|
+
data: ilp.data.length > 0 ? toBase64(ilp.data) : void 0
|
|
8065
|
+
};
|
|
8066
|
+
}
|
|
8067
|
+
return {
|
|
8068
|
+
accepted: false,
|
|
8069
|
+
code: ilp.code,
|
|
8070
|
+
message: ilp.message,
|
|
8071
|
+
data: ilp.data.length > 0 ? toBase64(ilp.data) : void 0
|
|
8072
|
+
};
|
|
8073
|
+
}
|
|
8074
|
+
const body = await response.text().catch(() => "");
|
|
8075
|
+
const detail = body ? `: ${body}` : "";
|
|
8076
|
+
if (response.status >= 500) {
|
|
8077
|
+
throw new ConnectorError(
|
|
8078
|
+
`Connector transport error (${response.status} ${response.statusText})${detail}`
|
|
8079
|
+
);
|
|
8080
|
+
}
|
|
8081
|
+
throw new ConnectorError(
|
|
8082
|
+
`ILP-over-HTTP request rejected (${response.status} ${response.statusText})${detail}`
|
|
8083
|
+
);
|
|
8084
|
+
}
|
|
8085
|
+
mapTransportError(error, requestTimeout) {
|
|
8086
|
+
if (error instanceof ConnectorError || error instanceof NetworkError) {
|
|
8087
|
+
return error;
|
|
8088
|
+
}
|
|
8089
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
8090
|
+
return new NetworkError(`Request timeout after ${requestTimeout}ms`, error);
|
|
8091
|
+
}
|
|
8092
|
+
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"))) {
|
|
8093
|
+
return new NetworkError(`Network connection failed: ${error.message}`, error);
|
|
8094
|
+
}
|
|
8095
|
+
return new ConnectorError(
|
|
8096
|
+
`Unexpected error during ILP-over-HTTP request: ${error instanceof Error ? error.message : String(error)}`,
|
|
8097
|
+
error instanceof Error ? error : void 0
|
|
8098
|
+
);
|
|
8099
|
+
}
|
|
8100
|
+
};
|
|
8101
|
+
function httpEndpointToBtpUrl(httpEndpoint) {
|
|
8102
|
+
return httpEndpoint.replace(/^https:\/\//i, "wss://").replace(/^http:\/\//i, "ws://");
|
|
8103
|
+
}
|
|
8104
|
+
async function makeBtpWebSocketFactory(headers) {
|
|
8105
|
+
const { createRequire } = await import("module");
|
|
8106
|
+
const require2 = createRequire(import.meta.url);
|
|
8107
|
+
const WS = require2("ws");
|
|
8108
|
+
const ws = WS;
|
|
8109
|
+
const WSClass = typeof ws === "function" ? ws : typeof ws.default === "function" ? ws.default : typeof ws.WebSocket === "function" ? ws.WebSocket : null;
|
|
8110
|
+
if (WSClass === null) {
|
|
8111
|
+
throw new Error(
|
|
8112
|
+
"makeBtpWebSocketFactory: require('ws') did not yield a constructor on .default, .WebSocket, or the module root."
|
|
8113
|
+
);
|
|
8114
|
+
}
|
|
8115
|
+
return (url) => (
|
|
8116
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8117
|
+
new WSClass(url, "btp", { headers })
|
|
8118
|
+
);
|
|
8119
|
+
}
|
|
8120
|
+
function readDiscoveredIlpPeer(peer) {
|
|
8121
|
+
const p = peer ?? {};
|
|
8122
|
+
return {
|
|
8123
|
+
btpEndpoint: typeof p["btpEndpoint"] === "string" ? p["btpEndpoint"] : void 0,
|
|
8124
|
+
httpEndpoint: typeof p["httpEndpoint"] === "string" ? p["httpEndpoint"] : void 0,
|
|
8125
|
+
supportsUpgrade: typeof p["supportsUpgrade"] === "boolean" ? p["supportsUpgrade"] : void 0
|
|
8126
|
+
};
|
|
8127
|
+
}
|
|
8128
|
+
function selectIlpTransport(peer, options = {}) {
|
|
8129
|
+
const needsDuplex = options.needsDuplex ?? false;
|
|
8130
|
+
const http2 = peer.httpEndpoint?.trim() || void 0;
|
|
8131
|
+
const btp = peer.btpEndpoint?.trim() || void 0;
|
|
8132
|
+
const canUpgrade = peer.supportsUpgrade === true;
|
|
8133
|
+
if (needsDuplex) {
|
|
8134
|
+
if (btp) return { kind: "btp", btpEndpoint: btp };
|
|
8135
|
+
if (http2 && canUpgrade) return { kind: "http-upgradable", httpEndpoint: http2 };
|
|
8136
|
+
throw new Error(
|
|
8137
|
+
"Duplex transport required but peer exposes neither a btpEndpoint nor an upgradable httpEndpoint"
|
|
8138
|
+
);
|
|
8139
|
+
}
|
|
8140
|
+
if (http2) return { kind: "http", httpEndpoint: http2, canUpgrade };
|
|
8141
|
+
if (btp) return { kind: "btp", btpEndpoint: btp };
|
|
8142
|
+
throw new Error("Peer exposes neither an httpEndpoint nor a btpEndpoint");
|
|
8143
|
+
}
|
|
8235
8144
|
var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
8236
8145
|
var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
|
|
8237
8146
|
var RENT_SYSVAR_ID = "SysvarRent111111111111111111111111111111111";
|
|
@@ -8319,7 +8228,7 @@ function findProgramAddress(seeds, programId) {
|
|
|
8319
8228
|
input.set(programId, offset);
|
|
8320
8229
|
offset += programId.length;
|
|
8321
8230
|
input.set(PDA_MARKER, offset);
|
|
8322
|
-
const hash =
|
|
8231
|
+
const hash = sha2562(input);
|
|
8323
8232
|
if (!isOnCurve(hash)) return { pda: hash, bump };
|
|
8324
8233
|
}
|
|
8325
8234
|
throw new Error("Could not find a viable PDA bump seed");
|
|
@@ -9325,96 +9234,41 @@ var EvmSigner = class {
|
|
|
9325
9234
|
};
|
|
9326
9235
|
}
|
|
9327
9236
|
};
|
|
9328
|
-
function isAnyoneHost(url) {
|
|
9329
|
-
if (!url) return false;
|
|
9330
|
-
try {
|
|
9331
|
-
const withScheme = /:\/\//.test(url) ? url : `ws://${url}`;
|
|
9332
|
-
const host = new URL(withScheme).hostname.toLowerCase();
|
|
9333
|
-
return host.endsWith(".anyone");
|
|
9334
|
-
} catch {
|
|
9335
|
-
return false;
|
|
9336
|
-
}
|
|
9337
|
-
}
|
|
9338
|
-
async function resolveTransport(transport, originalBtpUrl, originalConnectorUrl, managedProxyOptions) {
|
|
9339
|
-
const hasExplicitProxy = !!transport && (transport.type === "socks5" || transport.type === "gateway");
|
|
9340
|
-
const envProxy = process.env["ANYONE_PROXY_URLS"];
|
|
9341
|
-
if (!hasExplicitProxy && managedProxyOptions?.managedAnonProxy !== false && !envProxy && isAnyoneHost(originalBtpUrl)) {
|
|
9342
|
-
const { startManagedAnonProxy: startManagedAnonProxy2 } = await import("./anon-proxy-W3KMM7GU-FN7ZJY7P.js");
|
|
9343
|
-
const { createSocks5WebSocketFactory, createSocks5Fetch } = await import("./socks5-WTJBYGME-6COK4LXW.js");
|
|
9344
|
-
const proxy = await startManagedAnonProxy2({
|
|
9345
|
-
...managedProxyOptions?.managedAnonSocksPort !== void 0 ? { socksPort: managedProxyOptions.managedAnonSocksPort } : {}
|
|
9346
|
-
});
|
|
9347
|
-
try {
|
|
9348
|
-
return {
|
|
9349
|
-
createWebSocket: createSocks5WebSocketFactory(proxy.socksProxy),
|
|
9350
|
-
httpClient: createSocks5Fetch(proxy.socksProxy),
|
|
9351
|
-
stopManagedProxy: proxy.stop
|
|
9352
|
-
};
|
|
9353
|
-
} catch (err) {
|
|
9354
|
-
await proxy.stop();
|
|
9355
|
-
throw err;
|
|
9356
|
-
}
|
|
9357
|
-
}
|
|
9358
|
-
if (!transport || transport.type === "direct") {
|
|
9359
|
-
return {};
|
|
9360
|
-
}
|
|
9361
|
-
if (transport.type === "socks5") {
|
|
9362
|
-
const {
|
|
9363
|
-
createSocks5WebSocketFactory,
|
|
9364
|
-
createSocks5Fetch,
|
|
9365
|
-
probeSocks5Proxy
|
|
9366
|
-
} = await import("./socks5-WTJBYGME-6COK4LXW.js");
|
|
9367
|
-
await probeSocks5Proxy(transport.socksProxy);
|
|
9368
|
-
return {
|
|
9369
|
-
createWebSocket: createSocks5WebSocketFactory(transport.socksProxy),
|
|
9370
|
-
httpClient: createSocks5Fetch(transport.socksProxy)
|
|
9371
|
-
};
|
|
9372
|
-
}
|
|
9373
|
-
if (transport.type === "gateway") {
|
|
9374
|
-
const { rewriteUrlsForGateway } = await import("./gateway-QOK47RKS-SEGTXBR3.js");
|
|
9375
|
-
const rewritten = rewriteUrlsForGateway(
|
|
9376
|
-
transport.gatewayUrl,
|
|
9377
|
-
originalBtpUrl,
|
|
9378
|
-
originalConnectorUrl
|
|
9379
|
-
);
|
|
9380
|
-
return {
|
|
9381
|
-
btpUrl: rewritten.btpUrl,
|
|
9382
|
-
connectorUrl: rewritten.connectorUrl
|
|
9383
|
-
};
|
|
9384
|
-
}
|
|
9385
|
-
throw new Error(
|
|
9386
|
-
`Unknown transport type: "${transport.type}"`
|
|
9387
|
-
);
|
|
9388
|
-
}
|
|
9389
9237
|
async function initializeHttpMode(config) {
|
|
9390
|
-
const
|
|
9391
|
-
|
|
9392
|
-
config.btpUrl,
|
|
9393
|
-
config.connectorUrl,
|
|
9394
|
-
{
|
|
9395
|
-
...config.managedAnonProxy !== void 0 ? { managedAnonProxy: config.managedAnonProxy } : {},
|
|
9396
|
-
...config.managedAnonSocksPort !== void 0 ? { managedAnonSocksPort: config.managedAnonSocksPort } : {}
|
|
9397
|
-
}
|
|
9398
|
-
);
|
|
9399
|
-
const effectiveBtpUrl = transport.btpUrl ?? config.btpUrl;
|
|
9400
|
-
const effectiveConnectorUrl = transport.connectorUrl ?? config.connectorUrl;
|
|
9238
|
+
const effectiveBtpUrl = config.btpUrl;
|
|
9239
|
+
const effectiveConnectorUrl = config.connectorUrl;
|
|
9401
9240
|
const settlementInfo = buildSettlementInfo(config);
|
|
9241
|
+
const discoveredPeer = readDiscoveredIlpPeer({
|
|
9242
|
+
btpEndpoint: effectiveBtpUrl,
|
|
9243
|
+
httpEndpoint: config.connectorHttpEndpoint,
|
|
9244
|
+
supportsUpgrade: config.connectorSupportsUpgrade
|
|
9245
|
+
});
|
|
9246
|
+
const transportChoice = discoveredPeer.httpEndpoint || discoveredPeer.btpEndpoint ? selectIlpTransport(discoveredPeer, { needsDuplex: false }) : null;
|
|
9402
9247
|
let btpClient = null;
|
|
9403
9248
|
if (effectiveBtpUrl) {
|
|
9404
9249
|
btpClient = new BtpRuntimeClient({
|
|
9405
9250
|
btpUrl: effectiveBtpUrl,
|
|
9406
9251
|
peerId: config.btpPeerId ?? `client`,
|
|
9407
|
-
authToken: config.btpAuthToken ?? ""
|
|
9408
|
-
createWebSocket: transport.createWebSocket
|
|
9252
|
+
authToken: config.btpAuthToken ?? ""
|
|
9409
9253
|
});
|
|
9410
9254
|
await btpClient.connect();
|
|
9411
9255
|
}
|
|
9412
|
-
|
|
9256
|
+
let httpIlpClient = null;
|
|
9257
|
+
if (transportChoice && (transportChoice.kind === "http" || transportChoice.kind === "http-upgradable")) {
|
|
9258
|
+
httpIlpClient = new HttpIlpClient({
|
|
9259
|
+
httpEndpoint: transportChoice.httpEndpoint,
|
|
9260
|
+
...config.btpPeerId !== void 0 ? { peerId: config.btpPeerId } : {},
|
|
9261
|
+
...config.btpAuthToken !== void 0 ? { authToken: config.btpAuthToken } : {},
|
|
9262
|
+
timeout: config.queryTimeout,
|
|
9263
|
+
maxRetries: config.maxRetries,
|
|
9264
|
+
retryDelay: config.retryDelay
|
|
9265
|
+
});
|
|
9266
|
+
}
|
|
9267
|
+
const runtimeClient = httpIlpClient ?? btpClient ?? new HttpRuntimeClient({
|
|
9413
9268
|
connectorUrl: effectiveConnectorUrl,
|
|
9414
9269
|
timeout: config.queryTimeout,
|
|
9415
9270
|
maxRetries: config.maxRetries,
|
|
9416
|
-
retryDelay: config.retryDelay
|
|
9417
|
-
httpClient: transport.httpClient
|
|
9271
|
+
retryDelay: config.retryDelay
|
|
9418
9272
|
});
|
|
9419
9273
|
let onChainChannelClient = null;
|
|
9420
9274
|
if (config.chainRpcUrls) {
|
|
@@ -9459,10 +9313,7 @@ async function initializeHttpMode(config) {
|
|
|
9459
9313
|
runtimeClient,
|
|
9460
9314
|
adminClient: null,
|
|
9461
9315
|
btpClient,
|
|
9462
|
-
onChainChannelClient
|
|
9463
|
-
// Teardown handle for a managed `anon` proxy this init STARTED (undefined
|
|
9464
|
-
// for explicit-proxy/direct/gateway). ToonClient.stop() invokes it.
|
|
9465
|
-
stopManagedProxy: transport.stopManagedProxy
|
|
9316
|
+
onChainChannelClient
|
|
9466
9317
|
};
|
|
9467
9318
|
}
|
|
9468
9319
|
var SolanaSigner = class {
|
|
@@ -9666,7 +9517,7 @@ var DEFAULT_MINA_TOKEN_ID = "MINA";
|
|
|
9666
9517
|
var MINA_CLAIM_NETWORK = "devnet";
|
|
9667
9518
|
function deriveMinaSalt(zkAppAddress, nonce) {
|
|
9668
9519
|
const digestHex = bytesToHex(
|
|
9669
|
-
|
|
9520
|
+
sha2562(new TextEncoder().encode(`mina-pc-salt:${zkAppAddress}:${nonce}`))
|
|
9670
9521
|
);
|
|
9671
9522
|
const salt = BigInt("0x" + digestHex.slice(0, 60));
|
|
9672
9523
|
return salt === 0n ? 1n : salt;
|
|
@@ -10134,6 +9985,319 @@ var JsonFileChannelStore = class {
|
|
|
10134
9985
|
writeFileSync(this.filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
10135
9986
|
}
|
|
10136
9987
|
};
|
|
9988
|
+
var ARWEAVE_TX_ID_REGEX = /^[A-Za-z0-9_-]{43}$/;
|
|
9989
|
+
async function requestBlobStorage(client, secretKey, params) {
|
|
9990
|
+
const bid = params.bid ?? (params.ilpAmount !== void 0 ? String(params.ilpAmount) : void 0);
|
|
9991
|
+
if (bid === void 0 || bid === "") {
|
|
9992
|
+
return {
|
|
9993
|
+
success: false,
|
|
9994
|
+
error: "requestBlobStorage requires a bid (or ilpAmount to derive it)"
|
|
9995
|
+
};
|
|
9996
|
+
}
|
|
9997
|
+
const blobBuffer = Buffer.from(
|
|
9998
|
+
params.blobData.buffer,
|
|
9999
|
+
params.blobData.byteOffset,
|
|
10000
|
+
params.blobData.byteLength
|
|
10001
|
+
);
|
|
10002
|
+
let event;
|
|
10003
|
+
try {
|
|
10004
|
+
event = buildBlobStorageRequest(
|
|
10005
|
+
{
|
|
10006
|
+
blobData: blobBuffer,
|
|
10007
|
+
contentType: params.contentType,
|
|
10008
|
+
bid
|
|
10009
|
+
},
|
|
10010
|
+
secretKey
|
|
10011
|
+
);
|
|
10012
|
+
} catch (error) {
|
|
10013
|
+
return {
|
|
10014
|
+
success: false,
|
|
10015
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10016
|
+
};
|
|
10017
|
+
}
|
|
10018
|
+
const result = await client.publishEvent(event, {
|
|
10019
|
+
destination: params.destination,
|
|
10020
|
+
claim: params.claim,
|
|
10021
|
+
ilpAmount: params.ilpAmount
|
|
10022
|
+
});
|
|
10023
|
+
if (!result.success) {
|
|
10024
|
+
return {
|
|
10025
|
+
success: false,
|
|
10026
|
+
eventId: result.eventId ?? event.id,
|
|
10027
|
+
error: result.error ?? "Blob storage request rejected"
|
|
10028
|
+
};
|
|
10029
|
+
}
|
|
10030
|
+
if (!result.data) {
|
|
10031
|
+
return {
|
|
10032
|
+
success: false,
|
|
10033
|
+
eventId: event.id,
|
|
10034
|
+
error: "FULFILL contained no data; expected base64-encoded Arweave tx ID"
|
|
10035
|
+
};
|
|
10036
|
+
}
|
|
10037
|
+
const txId = decodeUtf8(fromBase64(result.data));
|
|
10038
|
+
if (!ARWEAVE_TX_ID_REGEX.test(txId)) {
|
|
10039
|
+
return {
|
|
10040
|
+
success: false,
|
|
10041
|
+
eventId: event.id,
|
|
10042
|
+
error: `Decoded FULFILL data is not a valid Arweave tx ID: "${txId}"`
|
|
10043
|
+
};
|
|
10044
|
+
}
|
|
10045
|
+
return {
|
|
10046
|
+
success: true,
|
|
10047
|
+
txId,
|
|
10048
|
+
eventId: event.id
|
|
10049
|
+
};
|
|
10050
|
+
}
|
|
10051
|
+
var Http402Client = class {
|
|
10052
|
+
fetchImpl;
|
|
10053
|
+
resolveClaim;
|
|
10054
|
+
createIlpClient;
|
|
10055
|
+
needsDuplex;
|
|
10056
|
+
constructor(config = {}) {
|
|
10057
|
+
this.fetchImpl = config.fetch ?? fetch;
|
|
10058
|
+
this.resolveClaim = config.resolveClaim;
|
|
10059
|
+
this.createIlpClient = config.createIlpClient ?? ((httpEndpoint) => new HttpIlpClient({ httpEndpoint }));
|
|
10060
|
+
this.needsDuplex = config.needsDuplex ?? false;
|
|
10061
|
+
}
|
|
10062
|
+
/**
|
|
10063
|
+
* `fetch()`-like entry point. Issues the request; on `402` parses the x402
|
|
10064
|
+
* challenge and — when a usable `toon-channel` offer is present and a claim
|
|
10065
|
+
* resolver is configured — pays over TOON and returns the reconstructed
|
|
10066
|
+
* `Response`. Otherwise returns the original 402 unchanged (AC5).
|
|
10067
|
+
*/
|
|
10068
|
+
async fetch(url, opts = {}) {
|
|
10069
|
+
const method = (opts.method ?? "GET").toUpperCase();
|
|
10070
|
+
const probe = await this.fetchImpl(url, {
|
|
10071
|
+
method,
|
|
10072
|
+
...opts.headers ? { headers: opts.headers } : {},
|
|
10073
|
+
...opts.body !== void 0 ? { body: opts.body } : {},
|
|
10074
|
+
...opts.timeout !== void 0 ? { signal: AbortSignal.timeout(opts.timeout) } : {}
|
|
10075
|
+
});
|
|
10076
|
+
if (probe.status !== 402) return probe;
|
|
10077
|
+
const challenge = await parseX402Challenge(probe.clone());
|
|
10078
|
+
const accept = challenge.toonChannel;
|
|
10079
|
+
if (!accept || !this.resolveClaim) return probe;
|
|
10080
|
+
return this.payOverToon(url, method, opts, accept, this.resolveClaim);
|
|
10081
|
+
}
|
|
10082
|
+
/**
|
|
10083
|
+
* Open/reuse a channel (via the injected claim resolver), serialize the HTTP
|
|
10084
|
+
* request into the ILP packet `data`, send it to `POST /ilp` with the claim,
|
|
10085
|
+
* and reconstruct the origin `Response` from the FULFILL `data`.
|
|
10086
|
+
*/
|
|
10087
|
+
async payOverToon(url, method, opts, accept, resolveClaim) {
|
|
10088
|
+
const destination = opts.destination ?? accept.destination;
|
|
10089
|
+
const claim = await resolveClaim(destination, accept.amount);
|
|
10090
|
+
const requestBytes = serializeHttpRequest({
|
|
10091
|
+
method,
|
|
10092
|
+
url,
|
|
10093
|
+
headers: opts.headers,
|
|
10094
|
+
body: opts.body
|
|
10095
|
+
});
|
|
10096
|
+
const peer = {
|
|
10097
|
+
httpEndpoint: accept.httpEndpoint,
|
|
10098
|
+
supportsUpgrade: accept.supportsUpgrade
|
|
10099
|
+
};
|
|
10100
|
+
const choice = selectIlpTransport(peer, {
|
|
10101
|
+
needsDuplex: this.needsDuplex
|
|
10102
|
+
});
|
|
10103
|
+
const ilpClient = this.createIlpClient(accept.httpEndpoint);
|
|
10104
|
+
const result = await this.sendOverChoice(
|
|
10105
|
+
ilpClient,
|
|
10106
|
+
choice,
|
|
10107
|
+
{
|
|
10108
|
+
destination,
|
|
10109
|
+
amount: String(accept.amount),
|
|
10110
|
+
data: toBase64(requestBytes),
|
|
10111
|
+
...opts.timeout !== void 0 ? { timeout: opts.timeout } : {}
|
|
10112
|
+
},
|
|
10113
|
+
claim
|
|
10114
|
+
);
|
|
10115
|
+
if (!result.accepted) {
|
|
10116
|
+
throw new ConnectorError(
|
|
10117
|
+
`h402 payment rejected by connector: ${result.code ?? "F00"} ${result.message ?? ""}`.trim()
|
|
10118
|
+
);
|
|
10119
|
+
}
|
|
10120
|
+
if (!result.data) {
|
|
10121
|
+
throw new ConnectorError(
|
|
10122
|
+
"h402 FULFILL carried no data (expected an HTTP response payload)"
|
|
10123
|
+
);
|
|
10124
|
+
}
|
|
10125
|
+
return parseHttpResponse(fromBase64(result.data));
|
|
10126
|
+
}
|
|
10127
|
+
/**
|
|
10128
|
+
* Send the serialized HTTP-in-ILP PREPARE over the selected transport.
|
|
10129
|
+
*
|
|
10130
|
+
* - `http` / `http-upgradable`: stateless one-shot `POST /ilp` with the claim.
|
|
10131
|
+
* - `http-upgradable` additionally exercises {@link HttpIlpClient.upgradeToBtp}
|
|
10132
|
+
* for the duplex/streaming path (AC4). v1 still drives the actual write over
|
|
10133
|
+
* the one-shot HTTP method even after upgrading — full duplex body streaming
|
|
10134
|
+
* is a documented follow-up — but the upgrade call path is wired here.
|
|
10135
|
+
* - `btp`: not reachable from h402 (the x402 offer only carries an
|
|
10136
|
+
* `httpEndpoint`); guarded for completeness.
|
|
10137
|
+
*/
|
|
10138
|
+
async sendOverChoice(ilpClient, choice, params, claim) {
|
|
10139
|
+
if (choice.kind === "http-upgradable") {
|
|
10140
|
+
const btp = await ilpClient.upgradeToBtp();
|
|
10141
|
+
try {
|
|
10142
|
+
return await btp.sendIlpPacketWithClaim(
|
|
10143
|
+
params,
|
|
10144
|
+
claim
|
|
10145
|
+
);
|
|
10146
|
+
} finally {
|
|
10147
|
+
await btp.disconnect().catch(() => {
|
|
10148
|
+
});
|
|
10149
|
+
}
|
|
10150
|
+
}
|
|
10151
|
+
if (choice.kind === "btp") {
|
|
10152
|
+
throw new ToonClientError(
|
|
10153
|
+
"h402 offer resolved to a BTP-only transport; the x402 toon-channel entry must advertise an httpEndpoint",
|
|
10154
|
+
"INVALID_STATE"
|
|
10155
|
+
);
|
|
10156
|
+
}
|
|
10157
|
+
return ilpClient.sendIlpPacketWithClaim(params, claim);
|
|
10158
|
+
}
|
|
10159
|
+
};
|
|
10160
|
+
function readString(obj, keys) {
|
|
10161
|
+
for (const k of keys) {
|
|
10162
|
+
const v = obj[k];
|
|
10163
|
+
if (typeof v === "string" && v.trim().length > 0) return v.trim();
|
|
10164
|
+
}
|
|
10165
|
+
return void 0;
|
|
10166
|
+
}
|
|
10167
|
+
function readAmount(obj, keys) {
|
|
10168
|
+
for (const k of keys) {
|
|
10169
|
+
const v = obj[k];
|
|
10170
|
+
if (typeof v === "bigint") return v;
|
|
10171
|
+
if (typeof v === "number" && Number.isFinite(v)) return BigInt(Math.trunc(v));
|
|
10172
|
+
if (typeof v === "string" && /^\d+$/.test(v.trim())) return BigInt(v.trim());
|
|
10173
|
+
}
|
|
10174
|
+
return void 0;
|
|
10175
|
+
}
|
|
10176
|
+
async function parseX402Challenge(response) {
|
|
10177
|
+
let body;
|
|
10178
|
+
try {
|
|
10179
|
+
body = await response.json();
|
|
10180
|
+
} catch {
|
|
10181
|
+
return {};
|
|
10182
|
+
}
|
|
10183
|
+
return parseX402Body(body);
|
|
10184
|
+
}
|
|
10185
|
+
function parseX402Body(body) {
|
|
10186
|
+
if (typeof body !== "object" || body === null) return {};
|
|
10187
|
+
const b = body;
|
|
10188
|
+
const version = typeof b["x402Version"] === "number" ? b["x402Version"] : void 0;
|
|
10189
|
+
const accepts = Array.isArray(b["accepts"]) ? b["accepts"] : [];
|
|
10190
|
+
for (const raw of accepts) {
|
|
10191
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
10192
|
+
const entry = raw;
|
|
10193
|
+
const scheme = readString(entry, ["scheme"]);
|
|
10194
|
+
if (scheme !== "toon-channel") continue;
|
|
10195
|
+
const destination = readString(entry, [
|
|
10196
|
+
"destination",
|
|
10197
|
+
"ilpAddress",
|
|
10198
|
+
"payTo"
|
|
10199
|
+
]);
|
|
10200
|
+
const httpEndpoint = readString(entry, [
|
|
10201
|
+
"httpEndpoint",
|
|
10202
|
+
"ilpEndpoint",
|
|
10203
|
+
"endpoint"
|
|
10204
|
+
]);
|
|
10205
|
+
const amount = readAmount(entry, ["amount", "price", "maxAmountRequired"]);
|
|
10206
|
+
if (!destination || !httpEndpoint || amount === void 0) continue;
|
|
10207
|
+
const network = readString(entry, ["network", "chain"]);
|
|
10208
|
+
const supportsUpgrade = entry["supportsUpgrade"] === true || entry["upgradable"] === true;
|
|
10209
|
+
return {
|
|
10210
|
+
...version !== void 0 ? { x402Version: version } : {},
|
|
10211
|
+
toonChannel: {
|
|
10212
|
+
scheme: "toon-channel",
|
|
10213
|
+
...network !== void 0 ? { network } : {},
|
|
10214
|
+
destination,
|
|
10215
|
+
amount,
|
|
10216
|
+
httpEndpoint,
|
|
10217
|
+
supportsUpgrade
|
|
10218
|
+
}
|
|
10219
|
+
};
|
|
10220
|
+
}
|
|
10221
|
+
return version !== void 0 ? { x402Version: version } : {};
|
|
10222
|
+
}
|
|
10223
|
+
var CRLF = "\r\n";
|
|
10224
|
+
function concatHeadAndBody(head, body) {
|
|
10225
|
+
const headBytes = encodeUtf8(head);
|
|
10226
|
+
const out = new Uint8Array(headBytes.length + body.length);
|
|
10227
|
+
out.set(headBytes, 0);
|
|
10228
|
+
out.set(body, headBytes.length);
|
|
10229
|
+
return out;
|
|
10230
|
+
}
|
|
10231
|
+
function bodyToBytes(body) {
|
|
10232
|
+
if (body === void 0) return new Uint8Array(0);
|
|
10233
|
+
return typeof body === "string" ? encodeUtf8(body) : body;
|
|
10234
|
+
}
|
|
10235
|
+
function serializeHttpRequest(req) {
|
|
10236
|
+
const u = new URL(req.url);
|
|
10237
|
+
const target = `${u.pathname}${u.search}` || "/";
|
|
10238
|
+
const bodyBytes = bodyToBytes(req.body);
|
|
10239
|
+
const headers = /* @__PURE__ */ new Map();
|
|
10240
|
+
const put = (name, value) => headers.set(name.toLowerCase(), `${name}: ${value}`);
|
|
10241
|
+
const has = (name) => headers.has(name.toLowerCase());
|
|
10242
|
+
for (const [name, value] of Object.entries(req.headers ?? {})) {
|
|
10243
|
+
put(name, value);
|
|
10244
|
+
}
|
|
10245
|
+
if (!has("host")) put("Host", u.host);
|
|
10246
|
+
if (bodyBytes.length > 0 && !has("content-length")) {
|
|
10247
|
+
put("Content-Length", String(bodyBytes.length));
|
|
10248
|
+
}
|
|
10249
|
+
const lines = [
|
|
10250
|
+
`${req.method.toUpperCase()} ${target} HTTP/1.1`,
|
|
10251
|
+
...headers.values()
|
|
10252
|
+
];
|
|
10253
|
+
const head = lines.join(CRLF) + CRLF + CRLF;
|
|
10254
|
+
return concatHeadAndBody(head, bodyBytes);
|
|
10255
|
+
}
|
|
10256
|
+
function findHeaderEnd(bytes) {
|
|
10257
|
+
for (let i = 0; i + 3 < bytes.length; i++) {
|
|
10258
|
+
if (bytes[i] === 13 && bytes[i + 1] === 10 && bytes[i + 2] === 13 && bytes[i + 3] === 10) {
|
|
10259
|
+
return i + 4;
|
|
10260
|
+
}
|
|
10261
|
+
}
|
|
10262
|
+
return -1;
|
|
10263
|
+
}
|
|
10264
|
+
function parseHttpResponse(bytes) {
|
|
10265
|
+
const headerEnd = findHeaderEnd(bytes);
|
|
10266
|
+
const headBytes = headerEnd === -1 ? bytes : bytes.subarray(0, headerEnd - 2);
|
|
10267
|
+
const body = headerEnd === -1 ? new Uint8Array(0) : bytes.subarray(headerEnd);
|
|
10268
|
+
const headText = decodeUtf8(headBytes);
|
|
10269
|
+
const lines = headText.split(CRLF).filter((l) => l.length > 0);
|
|
10270
|
+
const statusLine = lines.shift();
|
|
10271
|
+
if (!statusLine) {
|
|
10272
|
+
throw new ConnectorError(
|
|
10273
|
+
"h402 response payload had no HTTP status line"
|
|
10274
|
+
);
|
|
10275
|
+
}
|
|
10276
|
+
const match = /^HTTP\/\d\.\d\s+(\d{3})(?:\s+(.*))?$/.exec(statusLine.trim());
|
|
10277
|
+
if (!match) {
|
|
10278
|
+
throw new ConnectorError(
|
|
10279
|
+
`h402 response payload had a malformed status line: "${statusLine}"`
|
|
10280
|
+
);
|
|
10281
|
+
}
|
|
10282
|
+
const status = parseInt(match[1], 10);
|
|
10283
|
+
const statusText = match[2] ?? "";
|
|
10284
|
+
const headers = new Headers();
|
|
10285
|
+
for (const line of lines) {
|
|
10286
|
+
const idx = line.indexOf(":");
|
|
10287
|
+
if (idx === -1) continue;
|
|
10288
|
+
const name = line.slice(0, idx).trim();
|
|
10289
|
+
const value = line.slice(idx + 1).trim();
|
|
10290
|
+
if (name.length === 0) continue;
|
|
10291
|
+
headers.append(name, value);
|
|
10292
|
+
}
|
|
10293
|
+
const nullBodyStatus = status === 101 || status === 204 || status === 205 || status === 304;
|
|
10294
|
+
const init = { status, headers };
|
|
10295
|
+
if (statusText) init.statusText = statusText;
|
|
10296
|
+
return new Response(
|
|
10297
|
+
nullBodyStatus || body.length === 0 ? null : body.slice(),
|
|
10298
|
+
init
|
|
10299
|
+
);
|
|
10300
|
+
}
|
|
10137
10301
|
var ToonClient = class {
|
|
10138
10302
|
config;
|
|
10139
10303
|
state = null;
|
|
@@ -10184,6 +10348,28 @@ var ToonClient = class {
|
|
|
10184
10348
|
getPublicKey() {
|
|
10185
10349
|
return getPublicKey22(this.config.secretKey);
|
|
10186
10350
|
}
|
|
10351
|
+
/**
|
|
10352
|
+
* Sign an unsigned Nostr event template with the client's Nostr secret key,
|
|
10353
|
+
* returning a fully-signed event (id + pubkey + sig).
|
|
10354
|
+
*
|
|
10355
|
+
* This is the key primitive behind the daemon's sign-and-publish path: a UI
|
|
10356
|
+
* or agent supplies only `{ kind, content, tags, created_at }` and never holds
|
|
10357
|
+
* the private key — signing happens here, inside the key owner.
|
|
10358
|
+
*/
|
|
10359
|
+
signEvent(template) {
|
|
10360
|
+
return finalizeEvent11(template, this.config.secretKey);
|
|
10361
|
+
}
|
|
10362
|
+
/**
|
|
10363
|
+
* Upload bytes to Arweave via the kind:5094 blob-storage DVM (single-packet),
|
|
10364
|
+
* signing the request with this client's Nostr key and paying through its
|
|
10365
|
+
* existing channel. Returns the Arweave tx id on success.
|
|
10366
|
+
*
|
|
10367
|
+
* Backs the daemon's `upload-media` path: the key and claim/channel plumbing
|
|
10368
|
+
* stay inside the client; callers pass only the bytes.
|
|
10369
|
+
*/
|
|
10370
|
+
async uploadBlob(params) {
|
|
10371
|
+
return requestBlobStorage(this, this.config.secretKey, params);
|
|
10372
|
+
}
|
|
10187
10373
|
/**
|
|
10188
10374
|
* Per-chain settlement readiness for the configured `network` tier, mirroring
|
|
10189
10375
|
* the townhouse node's status. Returns `undefined` when no named `network` is
|
|
@@ -10266,13 +10452,7 @@ var ToonClient = class {
|
|
|
10266
10452
|
}
|
|
10267
10453
|
}
|
|
10268
10454
|
const initialization = await initializeHttpMode(this.config);
|
|
10269
|
-
const {
|
|
10270
|
-
bootstrapService,
|
|
10271
|
-
discoveryTracker,
|
|
10272
|
-
runtimeClient,
|
|
10273
|
-
btpClient,
|
|
10274
|
-
stopManagedProxy
|
|
10275
|
-
} = initialization;
|
|
10455
|
+
const { bootstrapService, discoveryTracker, runtimeClient, btpClient } = initialization;
|
|
10276
10456
|
if (this.channelManager) {
|
|
10277
10457
|
const cm = this.channelManager;
|
|
10278
10458
|
const nostrPubkey = this.getPublicKey();
|
|
@@ -10360,8 +10540,7 @@ var ToonClient = class {
|
|
|
10360
10540
|
discoveryTracker,
|
|
10361
10541
|
runtimeClient,
|
|
10362
10542
|
peersDiscovered: bootstrapResults.length,
|
|
10363
|
-
btpClient: btpClient ?? void 0
|
|
10364
|
-
...stopManagedProxy ? { stopManagedProxy } : {}
|
|
10543
|
+
btpClient: btpClient ?? void 0
|
|
10365
10544
|
};
|
|
10366
10545
|
return {
|
|
10367
10546
|
peersDiscovered: bootstrapResults.length,
|
|
@@ -10397,13 +10576,9 @@ var ToonClient = class {
|
|
|
10397
10576
|
const toonData = this.config.toonEncoder(event);
|
|
10398
10577
|
const basePricePerByte = 10n;
|
|
10399
10578
|
const amount = options?.ilpAmount !== void 0 ? String(options.ilpAmount) : String(BigInt(toonData.length) * basePricePerByte);
|
|
10579
|
+
const writeData = buildStoreWriteEnvelope(event);
|
|
10400
10580
|
const destination = options?.destination ?? this.config.destinationAddress;
|
|
10401
|
-
|
|
10402
|
-
throw new ToonClientError(
|
|
10403
|
-
"BTP client required for publishing. Configure btpUrl.",
|
|
10404
|
-
"NO_BTP_CLIENT"
|
|
10405
|
-
);
|
|
10406
|
-
}
|
|
10581
|
+
const transport = this.getClaimTransport();
|
|
10407
10582
|
let claimMessage;
|
|
10408
10583
|
if (options?.claim) {
|
|
10409
10584
|
claimMessage = this.buildClaimMessageForProof(options.claim);
|
|
@@ -10432,13 +10607,11 @@ var ToonClient = class {
|
|
|
10432
10607
|
"MISSING_CLAIM"
|
|
10433
10608
|
);
|
|
10434
10609
|
}
|
|
10435
|
-
const response = await
|
|
10610
|
+
const response = await transport.sendIlpPacketWithClaim(
|
|
10436
10611
|
{
|
|
10437
10612
|
destination,
|
|
10438
10613
|
amount,
|
|
10439
|
-
data: toBase64(
|
|
10440
|
-
toonData instanceof Uint8Array ? toonData : new Uint8Array(toonData)
|
|
10441
|
-
)
|
|
10614
|
+
data: toBase64(writeData)
|
|
10442
10615
|
},
|
|
10443
10616
|
claimMessage
|
|
10444
10617
|
);
|
|
@@ -10466,6 +10639,46 @@ var ToonClient = class {
|
|
|
10466
10639
|
);
|
|
10467
10640
|
}
|
|
10468
10641
|
}
|
|
10642
|
+
/**
|
|
10643
|
+
* Payment-aware HTTP fetch over TOON (issue #50). A `fetch()`-like method that
|
|
10644
|
+
* makes paying for an HTTP resource transparent:
|
|
10645
|
+
*
|
|
10646
|
+
* 1. Issues the HTTP request to `url`.
|
|
10647
|
+
* 2. On `402`, parses the x402 `accepts` array and selects the
|
|
10648
|
+
* `toon-channel` entry (see {@link Http402Client} for the wire shape).
|
|
10649
|
+
* 3. Opens/reuses a payment channel for the entry's ILP destination (via
|
|
10650
|
+
* ChannelManager), signs a balance proof for the demanded price, and
|
|
10651
|
+
* re-sends the SAME HTTP request as a transparent HTTP-in-ILP packet to
|
|
10652
|
+
* the connector's `POST /ilp` (via {@link HttpIlpClient}), with the claim
|
|
10653
|
+
* in the `ILP-Payment-Channel-Claim` header.
|
|
10654
|
+
* 4. Reconstructs and returns a standard Web `Response` from the FULFILL
|
|
10655
|
+
* `data`. The caller never sees ILP.
|
|
10656
|
+
*
|
|
10657
|
+
* If the origin offers no `toon-channel` entry, the original `402` Response is
|
|
10658
|
+
* returned unchanged (the caller sees the vanilla x402 challenge).
|
|
10659
|
+
*
|
|
10660
|
+
* The channel/claim plumbing is wired to the live ChannelManager + per-chain
|
|
10661
|
+
* signer via `resolveClaimForDestination` — identical to `publishEvent`. The
|
|
10662
|
+
* `amount` paid comes from the selected x402 entry (the resource's price).
|
|
10663
|
+
*
|
|
10664
|
+
* @throws {ToonClientError} If the client is not started.
|
|
10665
|
+
* @throws {ConnectorError} If the connector rejects the payment or returns no
|
|
10666
|
+
* HTTP payload.
|
|
10667
|
+
*/
|
|
10668
|
+
async h402Fetch(url, opts) {
|
|
10669
|
+
if (!this.state) {
|
|
10670
|
+
throw new ToonClientError(
|
|
10671
|
+
"Client not started. Call start() first.",
|
|
10672
|
+
"INVALID_STATE"
|
|
10673
|
+
);
|
|
10674
|
+
}
|
|
10675
|
+
const client = new Http402Client({
|
|
10676
|
+
...this.channelManager ? {
|
|
10677
|
+
resolveClaim: (destination, amount) => this.resolveClaimForDestination(destination, amount)
|
|
10678
|
+
} : {}
|
|
10679
|
+
});
|
|
10680
|
+
return client.fetch(url, opts);
|
|
10681
|
+
}
|
|
10469
10682
|
/**
|
|
10470
10683
|
* Sends a raw swap ILP packet (Story 12.5) to a Mill peer with an attached
|
|
10471
10684
|
* balance-proof claim. This is a lower-level surface than `publishEvent`:
|
|
@@ -10478,7 +10691,7 @@ var ToonClient = class {
|
|
|
10478
10691
|
* matching `destination`,
|
|
10479
10692
|
* (c) neither -> throw MISSING_CLAIM.
|
|
10480
10693
|
*
|
|
10481
|
-
* @throws {ToonClientError} INVALID_STATE /
|
|
10694
|
+
* @throws {ToonClientError} INVALID_STATE / NO_ILP_TRANSPORT / MISSING_CLAIM
|
|
10482
10695
|
*/
|
|
10483
10696
|
async sendSwapPacket(params) {
|
|
10484
10697
|
if (!this.state) {
|
|
@@ -10487,18 +10700,13 @@ var ToonClient = class {
|
|
|
10487
10700
|
"INVALID_STATE"
|
|
10488
10701
|
);
|
|
10489
10702
|
}
|
|
10490
|
-
|
|
10491
|
-
throw new ToonClientError(
|
|
10492
|
-
"BTP client required for sending swap packets. Configure btpUrl.",
|
|
10493
|
-
"NO_BTP_CLIENT"
|
|
10494
|
-
);
|
|
10495
|
-
}
|
|
10703
|
+
const transport = this.getClaimTransport();
|
|
10496
10704
|
const claimMessage = await this.resolveClaimForDestination(
|
|
10497
10705
|
params.destination,
|
|
10498
10706
|
params.amount,
|
|
10499
10707
|
params.claim
|
|
10500
10708
|
);
|
|
10501
|
-
return
|
|
10709
|
+
return transport.sendIlpPacketWithClaim(
|
|
10502
10710
|
{
|
|
10503
10711
|
destination: params.destination,
|
|
10504
10712
|
amount: String(params.amount),
|
|
@@ -10538,6 +10746,51 @@ var ToonClient = class {
|
|
|
10538
10746
|
}
|
|
10539
10747
|
return EvmSigner.buildClaimMessage(claim, this.getPublicKey());
|
|
10540
10748
|
}
|
|
10749
|
+
/**
|
|
10750
|
+
* Resolve the ILP transport for a paid (claim-bearing) write.
|
|
10751
|
+
*
|
|
10752
|
+
* The connector is a payment-proxy: paid writes carry an ILP PREPARE plus the
|
|
10753
|
+
* signed payment-channel claim. Either transport speaks the SAME claim
|
|
10754
|
+
* contract — the BTP `payment-channel-claim` protocolData entry and the
|
|
10755
|
+
* ILP-over-HTTP `ILP-Payment-Channel-Claim` header serialize the same claim
|
|
10756
|
+
* JSON — so we route through whichever transport is ACTIVE rather than
|
|
10757
|
+
* hard-requiring BTP.
|
|
10758
|
+
*
|
|
10759
|
+
* Selection (mirrors `modes/http.ts` runtime-client precedence):
|
|
10760
|
+
* 1. `runtimeClient` when it implements `sendIlpPacketWithClaim` — this is
|
|
10761
|
+
* the HttpIlpClient (proxy `POST /ilp`) when a `proxyUrl`/
|
|
10762
|
+
* `connectorHttpEndpoint` is configured, else the BtpRuntimeClient.
|
|
10763
|
+
* 2. `btpClient` as an explicit fallback (always present when `btpUrl` is set).
|
|
10764
|
+
*
|
|
10765
|
+
* The level-3 `HttpRuntimeClient` (connector-admin HTTP, no `btpUrl` AND no
|
|
10766
|
+
* proxy) does NOT implement `sendIlpPacketWithClaim`; in that case there is no
|
|
10767
|
+
* paid-write transport and we throw a clear, actionable error.
|
|
10768
|
+
*
|
|
10769
|
+
* @throws {ToonClientError} NO_ILP_TRANSPORT when no active transport can send
|
|
10770
|
+
* a packet+claim.
|
|
10771
|
+
*/
|
|
10772
|
+
getClaimTransport() {
|
|
10773
|
+
const state = this.state;
|
|
10774
|
+
if (!state) {
|
|
10775
|
+
throw new ToonClientError(
|
|
10776
|
+
"Client not started. Call start() first.",
|
|
10777
|
+
"INVALID_STATE"
|
|
10778
|
+
);
|
|
10779
|
+
}
|
|
10780
|
+
const candidates = [
|
|
10781
|
+
state.runtimeClient,
|
|
10782
|
+
state.btpClient
|
|
10783
|
+
];
|
|
10784
|
+
for (const candidate of candidates) {
|
|
10785
|
+
if (candidate && typeof candidate.sendIlpPacketWithClaim === "function") {
|
|
10786
|
+
return candidate;
|
|
10787
|
+
}
|
|
10788
|
+
}
|
|
10789
|
+
throw new ToonClientError(
|
|
10790
|
+
"No ILP transport for paid writes. Configure `proxyUrl`/`connectorHttpEndpoint` (route through the connector proxy over ILP-over-HTTP) or `btpUrl` (BTP socket).",
|
|
10791
|
+
"NO_ILP_TRANSPORT"
|
|
10792
|
+
);
|
|
10793
|
+
}
|
|
10541
10794
|
/**
|
|
10542
10795
|
* Shared claim-resolution logic used by `publishEvent` and `sendSwapPacket`.
|
|
10543
10796
|
* TODO(12.5 followup): also factor `publishEvent`'s inline claim resolution
|
|
@@ -10726,14 +10979,9 @@ var ToonClient = class {
|
|
|
10726
10979
|
"MISSING_CLAIM"
|
|
10727
10980
|
);
|
|
10728
10981
|
}
|
|
10729
|
-
|
|
10730
|
-
throw new ToonClientError(
|
|
10731
|
-
"BTP client required for sending payments. Configure btpUrl.",
|
|
10732
|
-
"NO_BTP_CLIENT"
|
|
10733
|
-
);
|
|
10734
|
-
}
|
|
10982
|
+
const transport = this.getClaimTransport();
|
|
10735
10983
|
const claimMessage = this.buildClaimMessageForProof(params.claim);
|
|
10736
|
-
return
|
|
10984
|
+
return transport.sendIlpPacketWithClaim(
|
|
10737
10985
|
ilpParams,
|
|
10738
10986
|
claimMessage
|
|
10739
10987
|
);
|
|
@@ -10751,14 +10999,10 @@ var ToonClient = class {
|
|
|
10751
10999
|
if (!this.state) {
|
|
10752
11000
|
throw new ToonClientError("Client not started", "INVALID_STATE");
|
|
10753
11001
|
}
|
|
10754
|
-
const stopManagedProxy = this.state.stopManagedProxy;
|
|
10755
11002
|
try {
|
|
10756
11003
|
if (this.state.btpClient) {
|
|
10757
11004
|
await this.state.btpClient.disconnect();
|
|
10758
11005
|
}
|
|
10759
|
-
if (stopManagedProxy) {
|
|
10760
|
-
await stopManagedProxy();
|
|
10761
|
-
}
|
|
10762
11006
|
this.state = null;
|
|
10763
11007
|
} catch (error) {
|
|
10764
11008
|
throw new ToonClientError(
|
|
@@ -10961,71 +11205,40 @@ function resolveMnemonic(file) {
|
|
|
10961
11205
|
}
|
|
10962
11206
|
function resolveConfig(file) {
|
|
10963
11207
|
const mnemonic = resolveMnemonic(file);
|
|
11208
|
+
const proxyUrl = process.env["TOON_CLIENT_PROXY_URL"] ?? file.proxyUrl;
|
|
11209
|
+
const faucetUrl = process.env["TOON_CLIENT_FAUCET_URL"] ?? file.faucetUrl;
|
|
10964
11210
|
const btpUrl = process.env["TOON_CLIENT_BTP_URL"] ?? file.btpUrl;
|
|
10965
|
-
|
|
10966
|
-
throw new Error(
|
|
10967
|
-
"No btpUrl configured. Set TOON_CLIENT_BTP_URL or add `btpUrl` to the config file."
|
|
10968
|
-
);
|
|
10969
|
-
}
|
|
11211
|
+
const hasUplink = Boolean(btpUrl || proxyUrl);
|
|
10970
11212
|
const relayUrl = process.env["TOON_CLIENT_RELAY_URL"] ?? file.relayUrl ?? "ws://localhost:7100";
|
|
10971
|
-
const explicitSocks = process.env["TOON_CLIENT_SOCKS"] ?? file.socksProxy;
|
|
10972
11213
|
const httpPort = Number(
|
|
10973
11214
|
process.env["TOON_CLIENT_HTTP_PORT"] ?? file.httpPort ?? 8787
|
|
10974
11215
|
);
|
|
10975
|
-
const destination = file.destination ?? "g.townhouse.town";
|
|
11216
|
+
const destination = process.env["TOON_CLIENT_DESTINATION"] ?? file.destination ?? "g.townhouse.town";
|
|
10976
11217
|
const feePerEvent = BigInt(file.feePerEvent ?? "1");
|
|
10977
11218
|
const network = process.env["TOON_CLIENT_NETWORK"] ?? file.network;
|
|
10978
11219
|
const chain2 = process.env["TOON_CLIENT_CHAIN"] ?? file.chain ?? "evm";
|
|
10979
|
-
const apex = file.apexChains?.[chain2] ?? file.apex;
|
|
10980
|
-
const managedPort = Number(file.managedAnonSocksPort ?? 9050);
|
|
10981
|
-
const allowManaged = file.managedAnonProxy ?? true;
|
|
10982
|
-
const btpIsAnyone = isAnyoneHost2(btpUrl);
|
|
10983
|
-
const relayIsAnyone = isAnyoneHost2(relayUrl);
|
|
10984
|
-
let transport;
|
|
10985
|
-
let managedAnonProxy;
|
|
10986
|
-
let managedAnonSocksPort;
|
|
10987
|
-
let readsSocksProxy;
|
|
10988
|
-
let manageReadProxy = false;
|
|
10989
|
-
if (explicitSocks) {
|
|
10990
|
-
transport = { type: "socks5", socksProxy: explicitSocks };
|
|
10991
|
-
managedAnonProxy = false;
|
|
10992
|
-
readsSocksProxy = explicitSocks;
|
|
10993
|
-
} else if (allowManaged && btpIsAnyone) {
|
|
10994
|
-
transport = { type: "direct" };
|
|
10995
|
-
managedAnonProxy = true;
|
|
10996
|
-
managedAnonSocksPort = managedPort;
|
|
10997
|
-
readsSocksProxy = `socks5h://127.0.0.1:${managedPort}`;
|
|
10998
|
-
} else if (allowManaged && relayIsAnyone) {
|
|
10999
|
-
transport = { type: "direct" };
|
|
11000
|
-
managedAnonProxy = false;
|
|
11001
|
-
manageReadProxy = true;
|
|
11002
|
-
managedAnonSocksPort = managedPort;
|
|
11003
|
-
readsSocksProxy = `socks5h://127.0.0.1:${managedPort}`;
|
|
11004
|
-
} else {
|
|
11005
|
-
transport = { type: "direct" };
|
|
11006
|
-
managedAnonProxy = false;
|
|
11007
|
-
}
|
|
11220
|
+
const apex = file.apexChains?.[chain2] ?? file.apex ?? buildProxyApexNegotiation(file, chain2, destination);
|
|
11008
11221
|
const channelStorePath = file.channelStorePath ?? join2(configDir(), "channels.json");
|
|
11009
11222
|
const apexChannelStorePath = join2(configDir(), "apex-channels.json");
|
|
11010
11223
|
const toonClientConfig = {
|
|
11011
|
-
//
|
|
11012
|
-
connectorUrl
|
|
11224
|
+
// validateConfig requires connectorUrl OR proxyUrl. When only BTP is set
|
|
11225
|
+
// we pass a dummy connectorUrl (unused at runtime — BTP transport is used);
|
|
11226
|
+
// when a proxy is configured, `proxyUrl` satisfies the requirement and the
|
|
11227
|
+
// client derives the `POST /ilp` endpoint + routes writes over HTTP.
|
|
11228
|
+
...proxyUrl ? { proxyUrl } : { connectorUrl: "http://127.0.0.1:1" },
|
|
11229
|
+
...faucetUrl ? { faucetUrl } : {},
|
|
11013
11230
|
mnemonic,
|
|
11014
11231
|
mnemonicAccountIndex: file.mnemonicAccountIndex ?? 0,
|
|
11015
11232
|
ilpInfo: {
|
|
11016
11233
|
pubkey: "00".repeat(32),
|
|
11017
11234
|
ilpAddress: "g.toon.client",
|
|
11018
|
-
btpEndpoint: btpUrl,
|
|
11235
|
+
btpEndpoint: btpUrl ?? "",
|
|
11019
11236
|
assetCode: "USD",
|
|
11020
11237
|
assetScale: 6
|
|
11021
11238
|
},
|
|
11022
11239
|
toonEncoder: encodeEventToToon,
|
|
11023
11240
|
toonDecoder: decodeEventFromToon,
|
|
11024
|
-
btpUrl,
|
|
11025
|
-
btpAuthToken: "",
|
|
11026
|
-
transport,
|
|
11027
|
-
managedAnonProxy,
|
|
11028
|
-
...managedAnonSocksPort !== void 0 ? { managedAnonSocksPort } : {},
|
|
11241
|
+
...btpUrl ? { btpUrl, btpAuthToken: "" } : {},
|
|
11029
11242
|
destinationAddress: destination,
|
|
11030
11243
|
relayUrl: "",
|
|
11031
11244
|
// reads use our own RelaySubscription, not bootstrap discovery
|
|
@@ -11043,12 +11256,12 @@ function resolveConfig(file) {
|
|
|
11043
11256
|
return {
|
|
11044
11257
|
httpPort,
|
|
11045
11258
|
relayUrl,
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
...
|
|
11259
|
+
hasUplink,
|
|
11260
|
+
...proxyUrl ? { proxyUrl } : {},
|
|
11261
|
+
...faucetUrl ? { faucetUrl } : {},
|
|
11049
11262
|
destination,
|
|
11050
11263
|
feePerEvent,
|
|
11051
|
-
apex,
|
|
11264
|
+
...apex ? { apex } : {},
|
|
11052
11265
|
...file.apexChildPeers ? { apexChildPeers: file.apexChildPeers } : {},
|
|
11053
11266
|
chain: chain2,
|
|
11054
11267
|
apexChannelStorePath,
|
|
@@ -11056,12 +11269,38 @@ function resolveConfig(file) {
|
|
|
11056
11269
|
network
|
|
11057
11270
|
};
|
|
11058
11271
|
}
|
|
11059
|
-
function
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11272
|
+
function defaultChainKey(chain2, chainId) {
|
|
11273
|
+
switch (chain2) {
|
|
11274
|
+
case "evm":
|
|
11275
|
+
return `evm:devnet:${chainId}`;
|
|
11276
|
+
case "solana":
|
|
11277
|
+
return "solana:devnet";
|
|
11278
|
+
case "mina":
|
|
11279
|
+
return "mina:devnet";
|
|
11280
|
+
}
|
|
11281
|
+
}
|
|
11282
|
+
function buildProxyApexNegotiation(file, chain2, destination) {
|
|
11283
|
+
const proxyUrl = process.env["TOON_CLIENT_PROXY_URL"] ?? file.proxyUrl;
|
|
11284
|
+
if (!proxyUrl) return void 0;
|
|
11285
|
+
const settlementAddresses = file.settlementAddresses ?? {};
|
|
11286
|
+
const familyKeys = (rec) => Object.keys(rec).filter((k) => k.split(":")[0] === chain2);
|
|
11287
|
+
const chainKey = familyKeys(settlementAddresses)[0] ?? familyKeys(file.tokenNetworks ?? {})[0] ?? familyKeys(file.preferredTokens ?? {})[0];
|
|
11288
|
+
if (!chainKey) return void 0;
|
|
11289
|
+
const settlementAddress = settlementAddresses[chainKey];
|
|
11290
|
+
if (!settlementAddress) return void 0;
|
|
11291
|
+
const parts = chainKey.split(":");
|
|
11292
|
+
const chainId = chain2 === "evm" && parts.length >= 3 ? Number(parts[2] ?? 0) : 0;
|
|
11293
|
+
const peerId = destination.split(".").at(-1) ?? destination;
|
|
11294
|
+
return {
|
|
11295
|
+
destination,
|
|
11296
|
+
peerId,
|
|
11297
|
+
chain: chain2,
|
|
11298
|
+
chainKey: chainKey || defaultChainKey(chain2, chainId),
|
|
11299
|
+
chainId,
|
|
11300
|
+
settlementAddress,
|
|
11301
|
+
...file.preferredTokens?.[chainKey] ? { tokenAddress: file.preferredTokens[chainKey] } : {},
|
|
11302
|
+
...file.tokenNetworks?.[chainKey] ? { tokenNetwork: file.tokenNetworks[chainKey] } : {}
|
|
11303
|
+
};
|
|
11065
11304
|
}
|
|
11066
11305
|
|
|
11067
11306
|
// src/control-client.ts
|
|
@@ -11073,6 +11312,9 @@ var ControlApiError = class extends Error {
|
|
|
11073
11312
|
this.detail = detail;
|
|
11074
11313
|
this.name = "ControlApiError";
|
|
11075
11314
|
}
|
|
11315
|
+
status;
|
|
11316
|
+
retryable;
|
|
11317
|
+
detail;
|
|
11076
11318
|
};
|
|
11077
11319
|
var DaemonUnreachableError = class extends Error {
|
|
11078
11320
|
constructor(baseUrl, causedBy) {
|
|
@@ -11081,6 +11323,8 @@ var DaemonUnreachableError = class extends Error {
|
|
|
11081
11323
|
this.causedBy = causedBy;
|
|
11082
11324
|
this.name = "DaemonUnreachableError";
|
|
11083
11325
|
}
|
|
11326
|
+
baseUrl;
|
|
11327
|
+
causedBy;
|
|
11084
11328
|
};
|
|
11085
11329
|
var ControlClient = class {
|
|
11086
11330
|
baseUrl;
|
|
@@ -11107,9 +11351,18 @@ var ControlClient = class {
|
|
|
11107
11351
|
publish(body) {
|
|
11108
11352
|
return this.request("POST", "/publish", body);
|
|
11109
11353
|
}
|
|
11354
|
+
publishUnsigned(body) {
|
|
11355
|
+
return this.request("POST", "/publish-unsigned", body);
|
|
11356
|
+
}
|
|
11357
|
+
uploadMedia(body) {
|
|
11358
|
+
return this.request("POST", "/upload-media", body);
|
|
11359
|
+
}
|
|
11110
11360
|
subscribe(body) {
|
|
11111
11361
|
return this.request("POST", "/subscribe", body);
|
|
11112
11362
|
}
|
|
11363
|
+
query(body) {
|
|
11364
|
+
return this.request("POST", "/query", body);
|
|
11365
|
+
}
|
|
11113
11366
|
events(query = {}) {
|
|
11114
11367
|
const qs = new URLSearchParams();
|
|
11115
11368
|
if (query.subId) qs.set("subId", query.subId);
|
|
@@ -11128,6 +11381,13 @@ var ControlClient = class {
|
|
|
11128
11381
|
swap(body) {
|
|
11129
11382
|
return this.request("POST", "/swap", body);
|
|
11130
11383
|
}
|
|
11384
|
+
httpFetchPaid(body) {
|
|
11385
|
+
return this.request(
|
|
11386
|
+
"POST",
|
|
11387
|
+
"/http-fetch-paid",
|
|
11388
|
+
body
|
|
11389
|
+
);
|
|
11390
|
+
}
|
|
11131
11391
|
targets() {
|
|
11132
11392
|
return this.request("GET", "/targets");
|
|
11133
11393
|
}
|
|
@@ -11318,4 +11578,4 @@ export {
|
|
|
11318
11578
|
@scure/bip32/lib/esm/index.js:
|
|
11319
11579
|
(*! scure-bip32 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
|
|
11320
11580
|
*/
|
|
11321
|
-
//# sourceMappingURL=chunk-
|
|
11581
|
+
//# sourceMappingURL=chunk-CQ2QIZ6Z.js.map
|