@toon-protocol/client 0.9.2 → 0.10.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/dist/index.d.ts +357 -100
- package/dist/index.js +345 -70
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-WHAEQLIW.js";
|
|
7
7
|
|
|
8
8
|
// src/ToonClient.ts
|
|
9
|
-
import { generateSecretKey as generateSecretKey3, getPublicKey as getPublicKey2 } from "nostr-tools/pure";
|
|
9
|
+
import { generateSecretKey as generateSecretKey3, getPublicKey as getPublicKey2, finalizeEvent } from "nostr-tools/pure";
|
|
10
10
|
|
|
11
11
|
// src/config.ts
|
|
12
12
|
import { generateSecretKey as generateSecretKey2 } from "nostr-tools/pure";
|
|
@@ -21,6 +21,7 @@ var ToonClientError = class extends Error {
|
|
|
21
21
|
this.code = code;
|
|
22
22
|
this.name = "ToonClientError";
|
|
23
23
|
}
|
|
24
|
+
code;
|
|
24
25
|
};
|
|
25
26
|
var NetworkError = class extends ToonClientError {
|
|
26
27
|
constructor(message, cause) {
|
|
@@ -1352,6 +1353,232 @@ var BtpRuntimeClient = class {
|
|
|
1352
1353
|
}
|
|
1353
1354
|
};
|
|
1354
1355
|
|
|
1356
|
+
// src/adapters/HttpIlpClient.ts
|
|
1357
|
+
var ILP_CLAIM_HEADER = "ILP-Payment-Channel-Claim";
|
|
1358
|
+
var ILP_CLAIM_WRAPPED_HEADER = "ILP-Payment-Channel-Claim-Wrapped";
|
|
1359
|
+
var ILP_PEER_ID_HEADER = "ILP-Peer-Id";
|
|
1360
|
+
var HttpIlpClient = class {
|
|
1361
|
+
httpEndpoint;
|
|
1362
|
+
peerId;
|
|
1363
|
+
authToken;
|
|
1364
|
+
timeout;
|
|
1365
|
+
retryConfig;
|
|
1366
|
+
httpClient;
|
|
1367
|
+
createWebSocket;
|
|
1368
|
+
constructor(config) {
|
|
1369
|
+
this.httpEndpoint = config.httpEndpoint;
|
|
1370
|
+
this.peerId = config.peerId;
|
|
1371
|
+
this.authToken = config.authToken;
|
|
1372
|
+
this.timeout = config.timeout ?? 3e4;
|
|
1373
|
+
this.retryConfig = {
|
|
1374
|
+
maxRetries: config.maxRetries ?? 3,
|
|
1375
|
+
retryDelay: config.retryDelay ?? 1e3
|
|
1376
|
+
};
|
|
1377
|
+
this.httpClient = config.httpClient ?? fetch;
|
|
1378
|
+
this.createWebSocket = config.createWebSocket;
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* Send an ILP PREPARE via `POST /ilp` WITHOUT a claim. The connector accepts
|
|
1382
|
+
* this only on free/zero-amount routes; paid writes must use
|
|
1383
|
+
* {@link sendIlpPacketWithClaim}. Satisfies the IlpClient interface.
|
|
1384
|
+
*/
|
|
1385
|
+
async sendIlpPacket(params) {
|
|
1386
|
+
return withRetry(() => this.postPrepare(params), {
|
|
1387
|
+
maxRetries: this.retryConfig.maxRetries,
|
|
1388
|
+
retryDelay: this.retryConfig.retryDelay,
|
|
1389
|
+
exponentialBackoff: true,
|
|
1390
|
+
shouldRetry: (error) => error instanceof NetworkError
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Send an ILP PREPARE via `POST /ilp` with the payment-channel claim attached
|
|
1395
|
+
* as the `ILP-Payment-Channel-Claim` header. `claim` is the SAME JSON object
|
|
1396
|
+
* the BTP path attaches as the `payment-channel-claim` protocolData entry —
|
|
1397
|
+
* we base64(JSON.stringify(claim)) it, byte-for-byte identical to BTP.
|
|
1398
|
+
*/
|
|
1399
|
+
async sendIlpPacketWithClaim(params, claim) {
|
|
1400
|
+
return withRetry(() => this.postPrepare(params, claim), {
|
|
1401
|
+
maxRetries: this.retryConfig.maxRetries,
|
|
1402
|
+
retryDelay: this.retryConfig.retryDelay,
|
|
1403
|
+
exponentialBackoff: true,
|
|
1404
|
+
shouldRetry: (error) => error instanceof NetworkError
|
|
1405
|
+
});
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Upgrade to a duplex BTP session over the SAME endpoint.
|
|
1409
|
+
*
|
|
1410
|
+
* Derives the `ws(s)://` URL from `httpEndpoint`, opens a WebSocket with
|
|
1411
|
+
* `Sec-WebSocket-Protocol: btp` and the same `ILP-Peer-Id` + `Authorization`
|
|
1412
|
+
* headers, and returns a connected {@link BtpRuntimeClient}. When auth headers
|
|
1413
|
+
* are present the connector pre-authenticates the session (no in-band auth
|
|
1414
|
+
* frame); without them the BtpRuntimeClient falls back to the normal BTP
|
|
1415
|
+
* auth-frame flow.
|
|
1416
|
+
*
|
|
1417
|
+
* NOTE: passing per-connection headers + a subprotocol to a WebSocket is
|
|
1418
|
+
* Node-only (the `ws` package). Browsers cannot set arbitrary request headers
|
|
1419
|
+
* on a WebSocket handshake, so a browser consumer must use the gateway
|
|
1420
|
+
* transport or BTP-with-auth-frame instead.
|
|
1421
|
+
*/
|
|
1422
|
+
async upgradeToBtp() {
|
|
1423
|
+
const btpUrl = httpEndpointToBtpUrl(this.httpEndpoint);
|
|
1424
|
+
const createWebSocket = this.createWebSocket ?? await makeBtpWebSocketFactory(this.authHeaders());
|
|
1425
|
+
const client = new BtpRuntimeClient({
|
|
1426
|
+
btpUrl,
|
|
1427
|
+
// BtpRuntimeClient sends an auth frame using these; when the connector
|
|
1428
|
+
// pre-authenticated via Upgrade headers it accepts the (redundant) frame.
|
|
1429
|
+
peerId: this.peerId ?? "client",
|
|
1430
|
+
authToken: this.authToken ?? "",
|
|
1431
|
+
createWebSocket
|
|
1432
|
+
});
|
|
1433
|
+
await client.connect();
|
|
1434
|
+
return client;
|
|
1435
|
+
}
|
|
1436
|
+
// ─── Private ──────────────────────────────────────────────────────────────
|
|
1437
|
+
authHeaders() {
|
|
1438
|
+
const headers = {};
|
|
1439
|
+
if (this.peerId) headers[ILP_PEER_ID_HEADER] = this.peerId;
|
|
1440
|
+
if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
|
|
1441
|
+
return headers;
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Single attempt: serialize the PREPARE, POST it, and map the response.
|
|
1445
|
+
* @throws {NetworkError} On connection/timeout failures (retried).
|
|
1446
|
+
* @throws {ConnectorError} On non-retryable transport errors (5xx / unexpected).
|
|
1447
|
+
*/
|
|
1448
|
+
async postPrepare(params, claim) {
|
|
1449
|
+
const requestTimeout = params.timeout ?? this.timeout;
|
|
1450
|
+
const prepare = serializeIlpPrepare({
|
|
1451
|
+
type: ILPPacketType.PREPARE,
|
|
1452
|
+
amount: BigInt(params.amount),
|
|
1453
|
+
destination: params.destination,
|
|
1454
|
+
executionCondition: new Uint8Array(32),
|
|
1455
|
+
expiresAt: new Date(Date.now() + requestTimeout),
|
|
1456
|
+
data: fromBase64(params.data)
|
|
1457
|
+
});
|
|
1458
|
+
const headers = {
|
|
1459
|
+
"Content-Type": "application/octet-stream",
|
|
1460
|
+
...this.authHeaders()
|
|
1461
|
+
};
|
|
1462
|
+
if (claim !== void 0) {
|
|
1463
|
+
headers[ILP_CLAIM_HEADER] = toBase64(
|
|
1464
|
+
encodeUtf8(JSON.stringify(claim))
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1467
|
+
const controller = new AbortController();
|
|
1468
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
|
|
1469
|
+
try {
|
|
1470
|
+
const response = await this.httpClient(this.httpEndpoint, {
|
|
1471
|
+
method: "POST",
|
|
1472
|
+
headers,
|
|
1473
|
+
// Copy into a fresh ArrayBuffer so fetch sees a clean body, not a view.
|
|
1474
|
+
body: prepare.slice(),
|
|
1475
|
+
signal: controller.signal
|
|
1476
|
+
});
|
|
1477
|
+
clearTimeout(timeoutId);
|
|
1478
|
+
return await this.mapResponse(response);
|
|
1479
|
+
} catch (error) {
|
|
1480
|
+
clearTimeout(timeoutId);
|
|
1481
|
+
throw this.mapTransportError(error, requestTimeout);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Map a `200 OK` body (OER FULFILL/REJECT) to an IlpSendResult; map a non-2xx
|
|
1486
|
+
* to a transport error. Per the wire contract, ILP-level rejects arrive as a
|
|
1487
|
+
* 200 + REJECT body — only HTTP non-2xx means a transport-layer failure.
|
|
1488
|
+
*/
|
|
1489
|
+
async mapResponse(response) {
|
|
1490
|
+
if (response.ok) {
|
|
1491
|
+
const buf = new Uint8Array(await response.arrayBuffer());
|
|
1492
|
+
if (buf.length === 0) {
|
|
1493
|
+
throw new ConnectorError("Empty 200 body from /ilp (expected OER ILP response)");
|
|
1494
|
+
}
|
|
1495
|
+
const ilp = deserializeIlpPacket(buf);
|
|
1496
|
+
if (ilp.type === ILPPacketType.FULFILL) {
|
|
1497
|
+
return {
|
|
1498
|
+
accepted: true,
|
|
1499
|
+
data: ilp.data.length > 0 ? toBase64(ilp.data) : void 0
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
return {
|
|
1503
|
+
accepted: false,
|
|
1504
|
+
code: ilp.code,
|
|
1505
|
+
message: ilp.message,
|
|
1506
|
+
data: ilp.data.length > 0 ? toBase64(ilp.data) : void 0
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
const body = await response.text().catch(() => "");
|
|
1510
|
+
const detail = body ? `: ${body}` : "";
|
|
1511
|
+
if (response.status >= 500) {
|
|
1512
|
+
throw new ConnectorError(
|
|
1513
|
+
`Connector transport error (${response.status} ${response.statusText})${detail}`
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1516
|
+
throw new ConnectorError(
|
|
1517
|
+
`ILP-over-HTTP request rejected (${response.status} ${response.statusText})${detail}`
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
mapTransportError(error, requestTimeout) {
|
|
1521
|
+
if (error instanceof ConnectorError || error instanceof NetworkError) {
|
|
1522
|
+
return error;
|
|
1523
|
+
}
|
|
1524
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1525
|
+
return new NetworkError(`Request timeout after ${requestTimeout}ms`, error);
|
|
1526
|
+
}
|
|
1527
|
+
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"))) {
|
|
1528
|
+
return new NetworkError(`Network connection failed: ${error.message}`, error);
|
|
1529
|
+
}
|
|
1530
|
+
return new ConnectorError(
|
|
1531
|
+
`Unexpected error during ILP-over-HTTP request: ${error instanceof Error ? error.message : String(error)}`,
|
|
1532
|
+
error instanceof Error ? error : void 0
|
|
1533
|
+
);
|
|
1534
|
+
}
|
|
1535
|
+
};
|
|
1536
|
+
function httpEndpointToBtpUrl(httpEndpoint) {
|
|
1537
|
+
return httpEndpoint.replace(/^https:\/\//i, "wss://").replace(/^http:\/\//i, "ws://");
|
|
1538
|
+
}
|
|
1539
|
+
async function makeBtpWebSocketFactory(headers) {
|
|
1540
|
+
const { createRequire } = await import("module");
|
|
1541
|
+
const require2 = createRequire(import.meta.url);
|
|
1542
|
+
const WS = require2("ws");
|
|
1543
|
+
const ws = WS;
|
|
1544
|
+
const WSClass = typeof ws === "function" ? ws : typeof ws.default === "function" ? ws.default : typeof ws.WebSocket === "function" ? ws.WebSocket : null;
|
|
1545
|
+
if (WSClass === null) {
|
|
1546
|
+
throw new Error(
|
|
1547
|
+
"makeBtpWebSocketFactory: require('ws') did not yield a constructor on .default, .WebSocket, or the module root."
|
|
1548
|
+
);
|
|
1549
|
+
}
|
|
1550
|
+
return (url) => (
|
|
1551
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1552
|
+
new WSClass(url, "btp", { headers })
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// src/adapters/selectIlpTransport.ts
|
|
1557
|
+
function readDiscoveredIlpPeer(peer) {
|
|
1558
|
+
const p = peer ?? {};
|
|
1559
|
+
return {
|
|
1560
|
+
btpEndpoint: typeof p["btpEndpoint"] === "string" ? p["btpEndpoint"] : void 0,
|
|
1561
|
+
httpEndpoint: typeof p["httpEndpoint"] === "string" ? p["httpEndpoint"] : void 0,
|
|
1562
|
+
supportsUpgrade: typeof p["supportsUpgrade"] === "boolean" ? p["supportsUpgrade"] : void 0
|
|
1563
|
+
};
|
|
1564
|
+
}
|
|
1565
|
+
function selectIlpTransport(peer, options = {}) {
|
|
1566
|
+
const needsDuplex = options.needsDuplex ?? false;
|
|
1567
|
+
const http2 = peer.httpEndpoint?.trim() || void 0;
|
|
1568
|
+
const btp = peer.btpEndpoint?.trim() || void 0;
|
|
1569
|
+
const canUpgrade = peer.supportsUpgrade === true;
|
|
1570
|
+
if (needsDuplex) {
|
|
1571
|
+
if (btp) return { kind: "btp", btpEndpoint: btp };
|
|
1572
|
+
if (http2 && canUpgrade) return { kind: "http-upgradable", httpEndpoint: http2 };
|
|
1573
|
+
throw new Error(
|
|
1574
|
+
"Duplex transport required but peer exposes neither a btpEndpoint nor an upgradable httpEndpoint"
|
|
1575
|
+
);
|
|
1576
|
+
}
|
|
1577
|
+
if (http2) return { kind: "http", httpEndpoint: http2, canUpgrade };
|
|
1578
|
+
if (btp) return { kind: "btp", btpEndpoint: btp };
|
|
1579
|
+
throw new Error("Peer exposes neither an httpEndpoint nor a btpEndpoint");
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1355
1582
|
// src/channel/OnChainChannelClient.ts
|
|
1356
1583
|
import {
|
|
1357
1584
|
createPublicClient,
|
|
@@ -2548,6 +2775,12 @@ async function initializeHttpMode(config) {
|
|
|
2548
2775
|
const effectiveBtpUrl = transport.btpUrl ?? config.btpUrl;
|
|
2549
2776
|
const effectiveConnectorUrl = transport.connectorUrl ?? config.connectorUrl;
|
|
2550
2777
|
const settlementInfo = buildSettlementInfo(config);
|
|
2778
|
+
const discoveredPeer = readDiscoveredIlpPeer({
|
|
2779
|
+
btpEndpoint: effectiveBtpUrl,
|
|
2780
|
+
httpEndpoint: config.connectorHttpEndpoint,
|
|
2781
|
+
supportsUpgrade: config.connectorSupportsUpgrade
|
|
2782
|
+
});
|
|
2783
|
+
const transportChoice = discoveredPeer.httpEndpoint || discoveredPeer.btpEndpoint ? selectIlpTransport(discoveredPeer, { needsDuplex: false }) : null;
|
|
2551
2784
|
let btpClient = null;
|
|
2552
2785
|
if (effectiveBtpUrl) {
|
|
2553
2786
|
btpClient = new BtpRuntimeClient({
|
|
@@ -2558,7 +2791,20 @@ async function initializeHttpMode(config) {
|
|
|
2558
2791
|
});
|
|
2559
2792
|
await btpClient.connect();
|
|
2560
2793
|
}
|
|
2561
|
-
|
|
2794
|
+
let httpIlpClient = null;
|
|
2795
|
+
if (transportChoice && (transportChoice.kind === "http" || transportChoice.kind === "http-upgradable")) {
|
|
2796
|
+
httpIlpClient = new HttpIlpClient({
|
|
2797
|
+
httpEndpoint: transportChoice.httpEndpoint,
|
|
2798
|
+
...config.btpPeerId !== void 0 ? { peerId: config.btpPeerId } : {},
|
|
2799
|
+
...config.btpAuthToken !== void 0 ? { authToken: config.btpAuthToken } : {},
|
|
2800
|
+
timeout: config.queryTimeout,
|
|
2801
|
+
maxRetries: config.maxRetries,
|
|
2802
|
+
retryDelay: config.retryDelay,
|
|
2803
|
+
...transport.httpClient !== void 0 ? { httpClient: transport.httpClient } : {},
|
|
2804
|
+
...transport.createWebSocket !== void 0 ? { createWebSocket: transport.createWebSocket } : {}
|
|
2805
|
+
});
|
|
2806
|
+
}
|
|
2807
|
+
const runtimeClient = httpIlpClient ?? btpClient ?? new HttpRuntimeClient({
|
|
2562
2808
|
connectorUrl: effectiveConnectorUrl,
|
|
2563
2809
|
timeout: config.queryTimeout,
|
|
2564
2810
|
maxRetries: config.maxRetries,
|
|
@@ -3304,6 +3550,72 @@ var JsonFileChannelStore = class {
|
|
|
3304
3550
|
}
|
|
3305
3551
|
};
|
|
3306
3552
|
|
|
3553
|
+
// src/blob-storage.ts
|
|
3554
|
+
import { buildBlobStorageRequest } from "@toon-protocol/core";
|
|
3555
|
+
var ARWEAVE_TX_ID_REGEX = /^[A-Za-z0-9_-]{43}$/;
|
|
3556
|
+
async function requestBlobStorage(client, secretKey, params) {
|
|
3557
|
+
const bid = params.bid ?? (params.ilpAmount !== void 0 ? String(params.ilpAmount) : void 0);
|
|
3558
|
+
if (bid === void 0 || bid === "") {
|
|
3559
|
+
return {
|
|
3560
|
+
success: false,
|
|
3561
|
+
error: "requestBlobStorage requires a bid (or ilpAmount to derive it)"
|
|
3562
|
+
};
|
|
3563
|
+
}
|
|
3564
|
+
const blobBuffer = Buffer.from(
|
|
3565
|
+
params.blobData.buffer,
|
|
3566
|
+
params.blobData.byteOffset,
|
|
3567
|
+
params.blobData.byteLength
|
|
3568
|
+
);
|
|
3569
|
+
let event;
|
|
3570
|
+
try {
|
|
3571
|
+
event = buildBlobStorageRequest(
|
|
3572
|
+
{
|
|
3573
|
+
blobData: blobBuffer,
|
|
3574
|
+
contentType: params.contentType,
|
|
3575
|
+
bid
|
|
3576
|
+
},
|
|
3577
|
+
secretKey
|
|
3578
|
+
);
|
|
3579
|
+
} catch (error) {
|
|
3580
|
+
return {
|
|
3581
|
+
success: false,
|
|
3582
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3583
|
+
};
|
|
3584
|
+
}
|
|
3585
|
+
const result = await client.publishEvent(event, {
|
|
3586
|
+
destination: params.destination,
|
|
3587
|
+
claim: params.claim,
|
|
3588
|
+
ilpAmount: params.ilpAmount
|
|
3589
|
+
});
|
|
3590
|
+
if (!result.success) {
|
|
3591
|
+
return {
|
|
3592
|
+
success: false,
|
|
3593
|
+
eventId: result.eventId ?? event.id,
|
|
3594
|
+
error: result.error ?? "Blob storage request rejected"
|
|
3595
|
+
};
|
|
3596
|
+
}
|
|
3597
|
+
if (!result.data) {
|
|
3598
|
+
return {
|
|
3599
|
+
success: false,
|
|
3600
|
+
eventId: event.id,
|
|
3601
|
+
error: "FULFILL contained no data; expected base64-encoded Arweave tx ID"
|
|
3602
|
+
};
|
|
3603
|
+
}
|
|
3604
|
+
const txId = decodeUtf8(fromBase64(result.data));
|
|
3605
|
+
if (!ARWEAVE_TX_ID_REGEX.test(txId)) {
|
|
3606
|
+
return {
|
|
3607
|
+
success: false,
|
|
3608
|
+
eventId: event.id,
|
|
3609
|
+
error: `Decoded FULFILL data is not a valid Arweave tx ID: "${txId}"`
|
|
3610
|
+
};
|
|
3611
|
+
}
|
|
3612
|
+
return {
|
|
3613
|
+
success: true,
|
|
3614
|
+
txId,
|
|
3615
|
+
eventId: event.id
|
|
3616
|
+
};
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3307
3619
|
// src/ToonClient.ts
|
|
3308
3620
|
var ToonClient = class {
|
|
3309
3621
|
config;
|
|
@@ -3355,6 +3667,28 @@ var ToonClient = class {
|
|
|
3355
3667
|
getPublicKey() {
|
|
3356
3668
|
return getPublicKey2(this.config.secretKey);
|
|
3357
3669
|
}
|
|
3670
|
+
/**
|
|
3671
|
+
* Sign an unsigned Nostr event template with the client's Nostr secret key,
|
|
3672
|
+
* returning a fully-signed event (id + pubkey + sig).
|
|
3673
|
+
*
|
|
3674
|
+
* This is the key primitive behind the daemon's sign-and-publish path: a UI
|
|
3675
|
+
* or agent supplies only `{ kind, content, tags, created_at }` and never holds
|
|
3676
|
+
* the private key — signing happens here, inside the key owner.
|
|
3677
|
+
*/
|
|
3678
|
+
signEvent(template) {
|
|
3679
|
+
return finalizeEvent(template, this.config.secretKey);
|
|
3680
|
+
}
|
|
3681
|
+
/**
|
|
3682
|
+
* Upload bytes to Arweave via the kind:5094 blob-storage DVM (single-packet),
|
|
3683
|
+
* signing the request with this client's Nostr key and paying through its
|
|
3684
|
+
* existing channel. Returns the Arweave tx id on success.
|
|
3685
|
+
*
|
|
3686
|
+
* Backs the daemon's `upload-media` path: the key and claim/channel plumbing
|
|
3687
|
+
* stay inside the client; callers pass only the bytes.
|
|
3688
|
+
*/
|
|
3689
|
+
async uploadBlob(params) {
|
|
3690
|
+
return requestBlobStorage(this, this.config.secretKey, params);
|
|
3691
|
+
}
|
|
3358
3692
|
/**
|
|
3359
3693
|
* Per-chain settlement readiness for the configured `network` tier, mirroring
|
|
3360
3694
|
* the townhouse node's status. Returns `undefined` when no named `network` is
|
|
@@ -4735,74 +5069,8 @@ function buildPetPurchaseRequest(params) {
|
|
|
4735
5069
|
};
|
|
4736
5070
|
}
|
|
4737
5071
|
|
|
4738
|
-
// src/blob-storage.ts
|
|
4739
|
-
import { buildBlobStorageRequest } from "@toon-protocol/core";
|
|
4740
|
-
var ARWEAVE_TX_ID_REGEX = /^[A-Za-z0-9_-]{43}$/;
|
|
4741
|
-
async function requestBlobStorage(client, secretKey, params) {
|
|
4742
|
-
const bid = params.bid ?? (params.ilpAmount !== void 0 ? String(params.ilpAmount) : void 0);
|
|
4743
|
-
if (bid === void 0 || bid === "") {
|
|
4744
|
-
return {
|
|
4745
|
-
success: false,
|
|
4746
|
-
error: "requestBlobStorage requires a bid (or ilpAmount to derive it)"
|
|
4747
|
-
};
|
|
4748
|
-
}
|
|
4749
|
-
const blobBuffer = Buffer.from(
|
|
4750
|
-
params.blobData.buffer,
|
|
4751
|
-
params.blobData.byteOffset,
|
|
4752
|
-
params.blobData.byteLength
|
|
4753
|
-
);
|
|
4754
|
-
let event;
|
|
4755
|
-
try {
|
|
4756
|
-
event = buildBlobStorageRequest(
|
|
4757
|
-
{
|
|
4758
|
-
blobData: blobBuffer,
|
|
4759
|
-
contentType: params.contentType,
|
|
4760
|
-
bid
|
|
4761
|
-
},
|
|
4762
|
-
secretKey
|
|
4763
|
-
);
|
|
4764
|
-
} catch (error) {
|
|
4765
|
-
return {
|
|
4766
|
-
success: false,
|
|
4767
|
-
error: error instanceof Error ? error.message : String(error)
|
|
4768
|
-
};
|
|
4769
|
-
}
|
|
4770
|
-
const result = await client.publishEvent(event, {
|
|
4771
|
-
destination: params.destination,
|
|
4772
|
-
claim: params.claim,
|
|
4773
|
-
ilpAmount: params.ilpAmount
|
|
4774
|
-
});
|
|
4775
|
-
if (!result.success) {
|
|
4776
|
-
return {
|
|
4777
|
-
success: false,
|
|
4778
|
-
eventId: result.eventId ?? event.id,
|
|
4779
|
-
error: result.error ?? "Blob storage request rejected"
|
|
4780
|
-
};
|
|
4781
|
-
}
|
|
4782
|
-
if (!result.data) {
|
|
4783
|
-
return {
|
|
4784
|
-
success: false,
|
|
4785
|
-
eventId: event.id,
|
|
4786
|
-
error: "FULFILL contained no data; expected base64-encoded Arweave tx ID"
|
|
4787
|
-
};
|
|
4788
|
-
}
|
|
4789
|
-
const txId = decodeUtf8(fromBase64(result.data));
|
|
4790
|
-
if (!ARWEAVE_TX_ID_REGEX.test(txId)) {
|
|
4791
|
-
return {
|
|
4792
|
-
success: false,
|
|
4793
|
-
eventId: event.id,
|
|
4794
|
-
error: `Decoded FULFILL data is not a valid Arweave tx ID: "${txId}"`
|
|
4795
|
-
};
|
|
4796
|
-
}
|
|
4797
|
-
return {
|
|
4798
|
-
success: true,
|
|
4799
|
-
txId,
|
|
4800
|
-
eventId: event.id
|
|
4801
|
-
};
|
|
4802
|
-
}
|
|
4803
|
-
|
|
4804
5072
|
// src/keys/KeyManager.ts
|
|
4805
|
-
import { finalizeEvent } from "nostr-tools/pure";
|
|
5073
|
+
import { finalizeEvent as finalizeEvent2 } from "nostr-tools/pure";
|
|
4806
5074
|
import { nip19 } from "nostr-tools";
|
|
4807
5075
|
|
|
4808
5076
|
// src/keys/PasskeyAuth.ts
|
|
@@ -5588,7 +5856,7 @@ var KeyManager = class {
|
|
|
5588
5856
|
this.vault,
|
|
5589
5857
|
this.identity.nostr.secretKey
|
|
5590
5858
|
);
|
|
5591
|
-
const signedEvent =
|
|
5859
|
+
const signedEvent = finalizeEvent2(
|
|
5592
5860
|
eventTemplate,
|
|
5593
5861
|
this.identity.nostr.secretKey
|
|
5594
5862
|
);
|
|
@@ -5850,7 +6118,11 @@ export {
|
|
|
5850
6118
|
HS_HOSTNAME_MAX_LENGTH,
|
|
5851
6119
|
HS_HOSTNAME_REGEX,
|
|
5852
6120
|
HttpConnectorAdmin,
|
|
6121
|
+
HttpIlpClient,
|
|
5853
6122
|
HttpRuntimeClient,
|
|
6123
|
+
ILP_CLAIM_HEADER,
|
|
6124
|
+
ILP_CLAIM_WRAPPED_HEADER,
|
|
6125
|
+
ILP_PEER_ID_HEADER,
|
|
5854
6126
|
KeyManager,
|
|
5855
6127
|
MinaSigner,
|
|
5856
6128
|
NetworkError,
|
|
@@ -5879,6 +6151,7 @@ export {
|
|
|
5879
6151
|
generateMnemonic,
|
|
5880
6152
|
generateRandomIdentity,
|
|
5881
6153
|
getNetworkStatus,
|
|
6154
|
+
httpEndpointToBtpUrl,
|
|
5882
6155
|
importKeystore,
|
|
5883
6156
|
isPrfSupported,
|
|
5884
6157
|
isRoutableHsHostname,
|
|
@@ -5887,9 +6160,11 @@ export {
|
|
|
5887
6160
|
parsePetInteractionEvent,
|
|
5888
6161
|
parsePetInteractionResult,
|
|
5889
6162
|
parsePetListing,
|
|
6163
|
+
readDiscoveredIlpPeer,
|
|
5890
6164
|
readMinaDepositTotal,
|
|
5891
6165
|
requestBlobStorage,
|
|
5892
6166
|
selectAnonAsset,
|
|
6167
|
+
selectIlpTransport,
|
|
5893
6168
|
startManagedAnonProxy,
|
|
5894
6169
|
validateConfig,
|
|
5895
6170
|
validateMnemonic,
|