@toon-protocol/client 0.14.0 → 0.14.2
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 +81 -10
- package/dist/index.js +117 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -404,13 +404,21 @@ interface SignedBalanceProof extends BalanceProofParams {
|
|
|
404
404
|
*
|
|
405
405
|
* ## FULFILL data contract
|
|
406
406
|
*
|
|
407
|
-
*
|
|
408
|
-
* returns the
|
|
409
|
-
*
|
|
410
|
-
*
|
|
407
|
+
* The deployed connector is a payment-proxy (HTTP-in-ILP): a successful blob
|
|
408
|
+
* upload returns the DVM's verbatim **HTTP/1.1 response message** in the ILP
|
|
409
|
+
* FULFILL `data` field. For a single-packet (non-chunked) upload the body is a
|
|
410
|
+
* JSON object:
|
|
411
411
|
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
412
|
+
* HTTP/1.1 200 OK\r\n
|
|
413
|
+
* content-length: 189\r\n
|
|
414
|
+
* \r\n
|
|
415
|
+
* {"accept":true,"txId":"<43-char base64url>","data":"<base64 of txId>",...}
|
|
416
|
+
*
|
|
417
|
+
* We parse the HTTP envelope, fail on a non-2xx status (or `accept:false`), and
|
|
418
|
+
* read the Arweave tx ID from `txId` (falling back to base64-decoding `data`).
|
|
419
|
+
* An Arweave tx ID is a 43-character base64url string (32 raw bytes). A legacy
|
|
420
|
+
* fallback still accepts a bare `base64(utf8(txId))` FULFILL (no HTTP envelope)
|
|
421
|
+
* so non-proxy providers do not regress. See {@link extractArweaveTxId}.
|
|
414
422
|
*
|
|
415
423
|
* See `packages/sdk/src/arweave/arweave-dvm-handler.ts` for the server side and
|
|
416
424
|
* `packages/client/tests/e2e/docker-arweave-dvm-e2e.test.ts` for the reference
|
|
@@ -1059,6 +1067,9 @@ declare class ToonClient {
|
|
|
1059
1067
|
destination?: string;
|
|
1060
1068
|
claim?: SignedBalanceProof;
|
|
1061
1069
|
ilpAmount?: bigint;
|
|
1070
|
+
/** HTTP request-target the payment-proxy replays (default '/write', the
|
|
1071
|
+
* relay; use '/store' for the Arweave store/DVM backend). */
|
|
1072
|
+
proxyPath?: string;
|
|
1062
1073
|
}): Promise<PublishEventResult>;
|
|
1063
1074
|
/**
|
|
1064
1075
|
* Payment-aware HTTP fetch over TOON (issue #50). A `fetch()`-like method that
|
|
@@ -2359,14 +2370,74 @@ declare function withRetry<T>(operation: () => Promise<T>, options: RetryOptions
|
|
|
2359
2370
|
*/
|
|
2360
2371
|
|
|
2361
2372
|
/**
|
|
2362
|
-
* Wrap a signed Nostr event in the
|
|
2363
|
-
*
|
|
2373
|
+
* Wrap a signed Nostr event in the HTTP envelope the deployed payment-proxy
|
|
2374
|
+
* reverse-proxies to its backend. Defaults to the relay's `POST /write`; pass
|
|
2375
|
+
* `requestTarget: '/store'` for the Arweave store/DVM backend.
|
|
2364
2376
|
*
|
|
2365
2377
|
* @param event - A finalized (signed) Nostr event — passed through to the store
|
|
2366
2378
|
* as the JSON `event` field verbatim (the store re-verifies the signature).
|
|
2379
|
+
* @param requestTarget - HTTP request-target the proxy replays (default `/write`).
|
|
2367
2380
|
* @returns The envelope bytes to use as the ILP PREPARE `data`.
|
|
2368
2381
|
*/
|
|
2369
|
-
declare function buildStoreWriteEnvelope(event: NostrEvent): Uint8Array;
|
|
2382
|
+
declare function buildStoreWriteEnvelope(event: NostrEvent, requestTarget?: string): Uint8Array;
|
|
2383
|
+
|
|
2384
|
+
/**
|
|
2385
|
+
* Shared parser for the HTTP-over-ILP response carried in an ILP **FULFILL**
|
|
2386
|
+
* packet's `data` field.
|
|
2387
|
+
*
|
|
2388
|
+
* The deployed connector is a payment-proxy (HTTP-in-ILP): a paid write/upload
|
|
2389
|
+
* is reverse-proxied to the relay/DVM origin and the origin's reply is returned
|
|
2390
|
+
* **verbatim as a full HTTP/1.1 response message** inside the FULFILL `data`:
|
|
2391
|
+
*
|
|
2392
|
+
* HTTP/1.1 200 OK\r\n
|
|
2393
|
+
* content-length: 189\r\n
|
|
2394
|
+
* \r\n
|
|
2395
|
+
* {"accept":true,"txId":"4QcRav...","data":"<base64-txid>",...}
|
|
2396
|
+
*
|
|
2397
|
+
* Callers (`ToonClient.publishEvent`, `requestBlobStorage`) previously treated
|
|
2398
|
+
* this `data` as opaque success bytes — `publishEvent` reported success on ANY
|
|
2399
|
+
* FULFILL even when the embedded HTTP status was `404 Not Found`, and
|
|
2400
|
+
* `requestBlobStorage` base64-decoded the WHOLE response as if it were the bare
|
|
2401
|
+
* Arweave tx id. This module makes the HTTP envelope first-class so both paths
|
|
2402
|
+
* can read the real status and body.
|
|
2403
|
+
*
|
|
2404
|
+
* The full Web-`Response` reconstruction used by the h402 fetch path lives in
|
|
2405
|
+
* `adapters/Http402Client.ts` (`parseHttpResponse`); this is a smaller,
|
|
2406
|
+
* dependency-free helper that returns the status code + raw body string, which
|
|
2407
|
+
* is all the publish/upload paths need.
|
|
2408
|
+
*
|
|
2409
|
+
* DEFENSIVE: not every FULFILL is HTTP-enveloped (e.g. Mill-swap raw-TOON
|
|
2410
|
+
* FULFILLs go through `sendSwapPacket`, not these paths). If the decoded data
|
|
2411
|
+
* does not begin with an `HTTP/<v>` status line, `isHttp` is `false` and the
|
|
2412
|
+
* caller should fall back to its prior (non-HTTP) interpretation rather than
|
|
2413
|
+
* fail. This keeps non-HTTP FULFILLs from regressing.
|
|
2414
|
+
*/
|
|
2415
|
+
/** Result of parsing FULFILL `data` as an HTTP/1.1 response. */
|
|
2416
|
+
interface ParsedFulfillHttp {
|
|
2417
|
+
/** Whether the data looked like an HTTP/1.1 response (status line present). */
|
|
2418
|
+
isHttp: boolean;
|
|
2419
|
+
/** HTTP status code (e.g. 200, 404). Only meaningful when `isHttp` is true. */
|
|
2420
|
+
status: number;
|
|
2421
|
+
/** Reason phrase from the status line (may be empty). */
|
|
2422
|
+
statusText: string;
|
|
2423
|
+
/** Decoded response body as a UTF-8 string (empty when none). */
|
|
2424
|
+
body: string;
|
|
2425
|
+
}
|
|
2426
|
+
/**
|
|
2427
|
+
* Parse FULFILL `data` bytes as an HTTP/1.1 response.
|
|
2428
|
+
*
|
|
2429
|
+
* Returns `{ isHttp: false, ... }` (without throwing) when the payload does not
|
|
2430
|
+
* start with an `HTTP/<v>` status line, so callers can fall back to their
|
|
2431
|
+
* legacy non-HTTP interpretation. When it IS an HTTP response, the status code
|
|
2432
|
+
* and body are extracted; a present-but-malformed status line yields
|
|
2433
|
+
* `isHttp: false` as well (treated as non-HTTP rather than throwing).
|
|
2434
|
+
*/
|
|
2435
|
+
declare function parseFulfillHttpBytes(bytes: Uint8Array): ParsedFulfillHttp;
|
|
2436
|
+
/**
|
|
2437
|
+
* Convenience wrapper: decode a base64 FULFILL `data` string (the shape carried
|
|
2438
|
+
* on `IlpSendResult.data`) and parse it as an HTTP/1.1 response.
|
|
2439
|
+
*/
|
|
2440
|
+
declare function parseFulfillHttp(base64Data: string): ParsedFulfillHttp;
|
|
2370
2441
|
|
|
2371
2442
|
/**
|
|
2372
2443
|
* Settlement info produced by buildSettlementInfo().
|
|
@@ -3270,4 +3341,4 @@ declare function loadKeystore(path: string, password: string): string;
|
|
|
3270
3341
|
*/
|
|
3271
3342
|
declare function writeKeystoreFile(path: string, keystore: EncryptedKeystore): void;
|
|
3272
3343
|
|
|
3273
|
-
export { type BackupPayload, type BalanceProofParams, BtpRuntimeClient, type BtpRuntimeClientConfig, type ChainMetadata, type ChainSigner, ChannelManager, type ClaimMessage, type ClaimResolver, ConnectorError, type DiscoveredIlpPeer, type EVMClaimMessage, type EncryptedKeystore, EvmSigner, type FaucetChain, type FundWalletOptions, type FundWalletResult, type H402FetchOptions, Http402Client, type Http402ClientConfig, HttpConnectorAdmin, type HttpConnectorAdminConfig, HttpIlpClient, type HttpIlpClientConfig, type HttpIlpClientFactory, HttpRuntimeClient, type HttpRuntimeClientConfig, ILP_CLAIM_HEADER, ILP_CLAIM_WRAPPED_HEADER, ILP_PEER_ID_HEADER, type IlpTransportChoice, type InteractionResultContent, KeyManager, type KeyManagerConfig, type MinaClaimMessage, type MinaDepositReader, MinaSigner, type MinaSignerOptions, NetworkError, OnChainChannelClient, type OnChainChannelClientConfig, type ParsedX402Challenge, type PasskeyInfo, type PetDvmProvider, type PetInteractionEventData, type PetInteractionRequestParams, type PetInteractionResultData, type PetListing, type PetListingFilterOptions, type PetListingParams, type PetPurchaseRequestParams, type ProofStatus, type PublishEventResult, type RequestBlobStorageParams, type RequestBlobStorageResult, type RetryOptions, type SelectIlpTransportOptions, type SignedBalanceProof, type SolanaChannelClientOptions, type SolanaClaimMessage, SolanaSigner, type StatValues, type ToonChannelAccept, ToonClient, type ToonClientConfig, ToonClientError, type ToonIdentity, type ToonSigners, type ToonStartResult, type UnsignedNostrEvent, ValidationError, type VaultData, applyDefaults, applyNetworkPresets, buildBackupEvent, buildBackupFilter, buildPetInteractionRequest, buildPetListingEvent, buildPetPurchaseRequest, buildSettlementInfo, buildStoreWriteEnvelope, decryptMnemonic, deriveFromNsec, deriveFullIdentity, deriveNostrKeyFromMnemonic, encryptMnemonic, filterPetDvmProviders, filterPetListings, fundWallet, generateKeystore, generateMnemonic, generateRandomIdentity, getNetworkStatus, httpEndpointToBtpUrl, importKeystore, isPrfSupported, loadKeystore, parseBackupPayload, parseHttpResponse, parsePetInteractionEvent, parsePetInteractionResult, parsePetListing, parseX402Body, parseX402Challenge, proxyIlpEndpoint, readDiscoveredIlpPeer, readMinaDepositTotal, requestBlobStorage, selectIlpTransport, serializeHttpRequest, validateConfig, validateMnemonic, withRetry, writeKeystoreFile };
|
|
3344
|
+
export { type BackupPayload, type BalanceProofParams, BtpRuntimeClient, type BtpRuntimeClientConfig, type ChainMetadata, type ChainSigner, ChannelManager, type ClaimMessage, type ClaimResolver, ConnectorError, type DiscoveredIlpPeer, type EVMClaimMessage, type EncryptedKeystore, EvmSigner, type FaucetChain, type FundWalletOptions, type FundWalletResult, type H402FetchOptions, Http402Client, type Http402ClientConfig, HttpConnectorAdmin, type HttpConnectorAdminConfig, HttpIlpClient, type HttpIlpClientConfig, type HttpIlpClientFactory, HttpRuntimeClient, type HttpRuntimeClientConfig, ILP_CLAIM_HEADER, ILP_CLAIM_WRAPPED_HEADER, ILP_PEER_ID_HEADER, type IlpTransportChoice, type InteractionResultContent, KeyManager, type KeyManagerConfig, type MinaClaimMessage, type MinaDepositReader, MinaSigner, type MinaSignerOptions, NetworkError, OnChainChannelClient, type OnChainChannelClientConfig, type ParsedFulfillHttp, type ParsedX402Challenge, type PasskeyInfo, type PetDvmProvider, type PetInteractionEventData, type PetInteractionRequestParams, type PetInteractionResultData, type PetListing, type PetListingFilterOptions, type PetListingParams, type PetPurchaseRequestParams, type ProofStatus, type PublishEventResult, type RequestBlobStorageParams, type RequestBlobStorageResult, type RetryOptions, type SelectIlpTransportOptions, type SignedBalanceProof, type SolanaChannelClientOptions, type SolanaClaimMessage, SolanaSigner, type StatValues, type ToonChannelAccept, ToonClient, type ToonClientConfig, ToonClientError, type ToonIdentity, type ToonSigners, type ToonStartResult, type UnsignedNostrEvent, ValidationError, type VaultData, applyDefaults, applyNetworkPresets, buildBackupEvent, buildBackupFilter, buildPetInteractionRequest, buildPetListingEvent, buildPetPurchaseRequest, buildSettlementInfo, buildStoreWriteEnvelope, decryptMnemonic, deriveFromNsec, deriveFullIdentity, deriveNostrKeyFromMnemonic, encryptMnemonic, filterPetDvmProviders, filterPetListings, fundWallet, generateKeystore, generateMnemonic, generateRandomIdentity, getNetworkStatus, httpEndpointToBtpUrl, importKeystore, isPrfSupported, loadKeystore, parseBackupPayload, parseFulfillHttp, parseFulfillHttpBytes, parseHttpResponse, parsePetInteractionEvent, parsePetInteractionResult, parsePetListing, parseX402Body, parseX402Challenge, proxyIlpEndpoint, readDiscoveredIlpPeer, readMinaDepositTotal, requestBlobStorage, selectIlpTransport, serializeHttpRequest, validateConfig, validateMnemonic, withRetry, writeKeystoreFile };
|
package/dist/index.js
CHANGED
|
@@ -510,14 +510,52 @@ function isBase64(str) {
|
|
|
510
510
|
}
|
|
511
511
|
|
|
512
512
|
// src/utils/store-envelope.ts
|
|
513
|
-
var
|
|
513
|
+
var DEFAULT_REQUEST_TARGET = "/write";
|
|
514
514
|
var HEADERS = ["Host: relay", "Content-Type: application/json"];
|
|
515
|
-
function buildStoreWriteEnvelope(event) {
|
|
515
|
+
function buildStoreWriteEnvelope(event, requestTarget = DEFAULT_REQUEST_TARGET) {
|
|
516
516
|
const body = JSON.stringify({ event });
|
|
517
|
-
const head = [
|
|
517
|
+
const head = [`POST ${requestTarget} HTTP/1.1`, ...HEADERS].join("\r\n");
|
|
518
518
|
return encodeUtf8(head + "\r\n\r\n" + body);
|
|
519
519
|
}
|
|
520
520
|
|
|
521
|
+
// src/utils/fulfill-http.ts
|
|
522
|
+
var CRLF = "\r\n";
|
|
523
|
+
function findHeaderEnd(bytes) {
|
|
524
|
+
for (let i = 0; i + 3 < bytes.length; i++) {
|
|
525
|
+
if (bytes[i] === 13 && bytes[i + 1] === 10 && bytes[i + 2] === 13 && bytes[i + 3] === 10) {
|
|
526
|
+
return i + 4;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return -1;
|
|
530
|
+
}
|
|
531
|
+
function parseFulfillHttpBytes(bytes) {
|
|
532
|
+
const notHttp = {
|
|
533
|
+
isHttp: false,
|
|
534
|
+
status: 0,
|
|
535
|
+
statusText: "",
|
|
536
|
+
body: ""
|
|
537
|
+
};
|
|
538
|
+
const headerEnd = findHeaderEnd(bytes);
|
|
539
|
+
const headBytes = headerEnd === -1 ? bytes : bytes.subarray(0, headerEnd - 2);
|
|
540
|
+
const bodyBytes = headerEnd === -1 ? new Uint8Array(0) : bytes.subarray(headerEnd);
|
|
541
|
+
const headText = decodeUtf8(headBytes);
|
|
542
|
+
const lines = headText.split(CRLF).filter((l) => l.length > 0);
|
|
543
|
+
const statusLine = lines.shift();
|
|
544
|
+
if (!statusLine) return notHttp;
|
|
545
|
+
if (!statusLine.trimStart().startsWith("HTTP/")) return notHttp;
|
|
546
|
+
const match = /^HTTP\/\d\.\d\s+(\d{3})(?:\s+(.*))?$/.exec(statusLine.trim());
|
|
547
|
+
if (!match) return notHttp;
|
|
548
|
+
return {
|
|
549
|
+
isHttp: true,
|
|
550
|
+
status: parseInt(match[1], 10),
|
|
551
|
+
statusText: match[2] ?? "",
|
|
552
|
+
body: decodeUtf8(bodyBytes)
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function parseFulfillHttp(base64Data) {
|
|
556
|
+
return parseFulfillHttpBytes(fromBase64(base64Data));
|
|
557
|
+
}
|
|
558
|
+
|
|
521
559
|
// src/modes/http.ts
|
|
522
560
|
import { BootstrapService, createDiscoveryTracker } from "@toon-protocol/core";
|
|
523
561
|
|
|
@@ -2313,12 +2351,12 @@ var OnChainChannelClient = class {
|
|
|
2313
2351
|
*/
|
|
2314
2352
|
parseChainId(chain) {
|
|
2315
2353
|
const parts = chain.split(":");
|
|
2316
|
-
if (parts.length <
|
|
2354
|
+
if (parts.length < 2) {
|
|
2317
2355
|
throw new Error(
|
|
2318
|
-
`Invalid chain format: "${chain}". Expected "evm:{network}:{chainId}".`
|
|
2356
|
+
`Invalid chain format: "${chain}". Expected "evm:{network}:{chainId}" or "evm:{chainId}".`
|
|
2319
2357
|
);
|
|
2320
2358
|
}
|
|
2321
|
-
const chainIdStr = parts[2];
|
|
2359
|
+
const chainIdStr = parts.length >= 3 ? parts[2] : parts[1];
|
|
2322
2360
|
if (!chainIdStr) {
|
|
2323
2361
|
throw new Error(
|
|
2324
2362
|
`Invalid chain format: "${chain}". Expected "evm:{network}:{chainId}".`
|
|
@@ -3544,7 +3582,9 @@ async function requestBlobStorage(client, secretKey, params) {
|
|
|
3544
3582
|
const result = await client.publishEvent(event, {
|
|
3545
3583
|
destination: params.destination,
|
|
3546
3584
|
claim: params.claim,
|
|
3547
|
-
ilpAmount: params.ilpAmount
|
|
3585
|
+
ilpAmount: params.ilpAmount,
|
|
3586
|
+
// The store/DVM backend serves POST /store (not the relay's /write).
|
|
3587
|
+
proxyPath: "/store"
|
|
3548
3588
|
});
|
|
3549
3589
|
if (!result.success) {
|
|
3550
3590
|
return {
|
|
@@ -3557,15 +3597,17 @@ async function requestBlobStorage(client, secretKey, params) {
|
|
|
3557
3597
|
return {
|
|
3558
3598
|
success: false,
|
|
3559
3599
|
eventId: event.id,
|
|
3560
|
-
error: "FULFILL contained no data; expected
|
|
3600
|
+
error: "FULFILL contained no data; expected an HTTP response with the Arweave tx ID"
|
|
3561
3601
|
};
|
|
3562
3602
|
}
|
|
3563
|
-
|
|
3564
|
-
|
|
3603
|
+
let txId;
|
|
3604
|
+
try {
|
|
3605
|
+
txId = extractArweaveTxId(result.data);
|
|
3606
|
+
} catch (error) {
|
|
3565
3607
|
return {
|
|
3566
3608
|
success: false,
|
|
3567
3609
|
eventId: event.id,
|
|
3568
|
-
error:
|
|
3610
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3569
3611
|
};
|
|
3570
3612
|
}
|
|
3571
3613
|
return {
|
|
@@ -3574,6 +3616,49 @@ async function requestBlobStorage(client, secretKey, params) {
|
|
|
3574
3616
|
eventId: event.id
|
|
3575
3617
|
};
|
|
3576
3618
|
}
|
|
3619
|
+
function extractArweaveTxId(base64Data) {
|
|
3620
|
+
const http2 = parseFulfillHttp(base64Data);
|
|
3621
|
+
if (!http2.isHttp) {
|
|
3622
|
+
const legacy = decodeUtf8(fromBase64(base64Data));
|
|
3623
|
+
if (!ARWEAVE_TX_ID_REGEX.test(legacy)) {
|
|
3624
|
+
throw new Error(
|
|
3625
|
+
`Decoded FULFILL data is not a valid Arweave tx ID: "${legacy}"`
|
|
3626
|
+
);
|
|
3627
|
+
}
|
|
3628
|
+
return legacy;
|
|
3629
|
+
}
|
|
3630
|
+
if (http2.status < 200 || http2.status >= 300) {
|
|
3631
|
+
const detail = http2.body ? ` - ${http2.body}` : "";
|
|
3632
|
+
throw new Error(
|
|
3633
|
+
`Blob upload failed: DVM returned HTTP ${http2.status} ${http2.statusText}`.trimEnd() + detail
|
|
3634
|
+
);
|
|
3635
|
+
}
|
|
3636
|
+
let parsed;
|
|
3637
|
+
try {
|
|
3638
|
+
parsed = JSON.parse(http2.body);
|
|
3639
|
+
} catch {
|
|
3640
|
+
throw new Error(
|
|
3641
|
+
`Blob upload response body was not valid JSON: "${http2.body}"`
|
|
3642
|
+
);
|
|
3643
|
+
}
|
|
3644
|
+
const body = parsed;
|
|
3645
|
+
if (body.accept === false) {
|
|
3646
|
+
const reason = typeof body.error === "string" ? `: ${body.error}` : "";
|
|
3647
|
+
throw new Error(`Blob upload rejected by DVM (accept:false)${reason}`);
|
|
3648
|
+
}
|
|
3649
|
+
if (typeof body.txId === "string" && ARWEAVE_TX_ID_REGEX.test(body.txId)) {
|
|
3650
|
+
return body.txId;
|
|
3651
|
+
}
|
|
3652
|
+
if (typeof body.data === "string" && body.data.length > 0) {
|
|
3653
|
+
const decoded = decodeUtf8(fromBase64(body.data));
|
|
3654
|
+
if (ARWEAVE_TX_ID_REGEX.test(decoded)) {
|
|
3655
|
+
return decoded;
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
throw new Error(
|
|
3659
|
+
`Blob upload response did not contain a valid Arweave tx ID: "${http2.body}"`
|
|
3660
|
+
);
|
|
3661
|
+
}
|
|
3577
3662
|
|
|
3578
3663
|
// src/adapters/Http402Client.ts
|
|
3579
3664
|
var Http402Client = class {
|
|
@@ -3748,7 +3833,7 @@ function parseX402Body(body) {
|
|
|
3748
3833
|
}
|
|
3749
3834
|
return version !== void 0 ? { x402Version: version } : {};
|
|
3750
3835
|
}
|
|
3751
|
-
var
|
|
3836
|
+
var CRLF2 = "\r\n";
|
|
3752
3837
|
function concatHeadAndBody(head, body) {
|
|
3753
3838
|
const headBytes = encodeUtf8(head);
|
|
3754
3839
|
const out = new Uint8Array(headBytes.length + body.length);
|
|
@@ -3778,10 +3863,10 @@ function serializeHttpRequest(req) {
|
|
|
3778
3863
|
`${req.method.toUpperCase()} ${target} HTTP/1.1`,
|
|
3779
3864
|
...headers.values()
|
|
3780
3865
|
];
|
|
3781
|
-
const head = lines.join(
|
|
3866
|
+
const head = lines.join(CRLF2) + CRLF2 + CRLF2;
|
|
3782
3867
|
return concatHeadAndBody(head, bodyBytes);
|
|
3783
3868
|
}
|
|
3784
|
-
function
|
|
3869
|
+
function findHeaderEnd2(bytes) {
|
|
3785
3870
|
for (let i = 0; i + 3 < bytes.length; i++) {
|
|
3786
3871
|
if (bytes[i] === 13 && bytes[i + 1] === 10 && bytes[i + 2] === 13 && bytes[i + 3] === 10) {
|
|
3787
3872
|
return i + 4;
|
|
@@ -3790,11 +3875,11 @@ function findHeaderEnd(bytes) {
|
|
|
3790
3875
|
return -1;
|
|
3791
3876
|
}
|
|
3792
3877
|
function parseHttpResponse(bytes) {
|
|
3793
|
-
const headerEnd =
|
|
3878
|
+
const headerEnd = findHeaderEnd2(bytes);
|
|
3794
3879
|
const headBytes = headerEnd === -1 ? bytes : bytes.subarray(0, headerEnd - 2);
|
|
3795
3880
|
const body = headerEnd === -1 ? new Uint8Array(0) : bytes.subarray(headerEnd);
|
|
3796
3881
|
const headText = decodeUtf8(headBytes);
|
|
3797
|
-
const lines = headText.split(
|
|
3882
|
+
const lines = headText.split(CRLF2).filter((l) => l.length > 0);
|
|
3798
3883
|
const statusLine = lines.shift();
|
|
3799
3884
|
if (!statusLine) {
|
|
3800
3885
|
throw new ConnectorError(
|
|
@@ -4003,7 +4088,7 @@ var ToonClient = class {
|
|
|
4003
4088
|
if (result.negotiatedChain && result.settlementAddress) {
|
|
4004
4089
|
const chainType = result.negotiatedChain.split(":")[0] ?? "evm";
|
|
4005
4090
|
const parts = result.negotiatedChain.split(":");
|
|
4006
|
-
const chainId = parts.length >= 3 ? parseInt(parts[2] ?? "0", 10) : 0;
|
|
4091
|
+
const chainId = parts.length >= 3 ? parseInt(parts[2] ?? "0", 10) : parts.length >= 2 ? parseInt(parts[1] ?? "0", 10) : 0;
|
|
4007
4092
|
const r = result;
|
|
4008
4093
|
this.peerNegotiations.set(result.registeredPeerId, {
|
|
4009
4094
|
chain: result.negotiatedChain,
|
|
@@ -4021,7 +4106,7 @@ var ToonClient = class {
|
|
|
4021
4106
|
if (matchedChain) {
|
|
4022
4107
|
const peerAddr = peerInfo.settlementAddresses?.[matchedChain];
|
|
4023
4108
|
const parts = matchedChain.split(":");
|
|
4024
|
-
const chainId = parts.length >= 3 ? parseInt(parts[2] ?? "0", 10) : 0;
|
|
4109
|
+
const chainId = parts.length >= 3 ? parseInt(parts[2] ?? "0", 10) : parts.length >= 2 ? parseInt(parts[1] ?? "0", 10) : 0;
|
|
4025
4110
|
if (peerAddr) {
|
|
4026
4111
|
this.peerNegotiations.set(result.registeredPeerId, {
|
|
4027
4112
|
chain: matchedChain,
|
|
@@ -4106,7 +4191,7 @@ var ToonClient = class {
|
|
|
4106
4191
|
const toonData = this.config.toonEncoder(event);
|
|
4107
4192
|
const basePricePerByte = 10n;
|
|
4108
4193
|
const amount = options?.ilpAmount !== void 0 ? String(options.ilpAmount) : String(BigInt(toonData.length) * basePricePerByte);
|
|
4109
|
-
const writeData = buildStoreWriteEnvelope(event);
|
|
4194
|
+
const writeData = buildStoreWriteEnvelope(event, options?.proxyPath);
|
|
4110
4195
|
const destination = options?.destination ?? this.config.destinationAddress;
|
|
4111
4196
|
const transport = this.getClaimTransport();
|
|
4112
4197
|
let claimMessage;
|
|
@@ -4151,6 +4236,16 @@ var ToonClient = class {
|
|
|
4151
4236
|
error: `Event rejected: ${response.code} - ${response.message}`
|
|
4152
4237
|
};
|
|
4153
4238
|
}
|
|
4239
|
+
if (response.data) {
|
|
4240
|
+
const httpResult = parseFulfillHttp(response.data);
|
|
4241
|
+
if (httpResult.isHttp && (httpResult.status < 200 || httpResult.status >= 300)) {
|
|
4242
|
+
const detail = httpResult.body ? ` - ${httpResult.body}` : "";
|
|
4243
|
+
return {
|
|
4244
|
+
success: false,
|
|
4245
|
+
error: `Write failed: relay returned HTTP ${httpResult.status} ${httpResult.statusText}`.trimEnd() + detail
|
|
4246
|
+
};
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
4154
4249
|
return {
|
|
4155
4250
|
success: true,
|
|
4156
4251
|
eventId: event.id,
|
|
@@ -4468,7 +4563,7 @@ var ToonClient = class {
|
|
|
4468
4563
|
getChainContext(negotiatedChain) {
|
|
4469
4564
|
if (!negotiatedChain) return void 0;
|
|
4470
4565
|
const parts = negotiatedChain.split(":");
|
|
4471
|
-
const chainIdPart = parts.length >= 3 ? parts[2] : void 0;
|
|
4566
|
+
const chainIdPart = parts.length >= 3 ? parts[2] : parts.length >= 2 ? parts[1] : void 0;
|
|
4472
4567
|
const numericChainId = chainIdPart !== void 0 ? parseInt(chainIdPart, 10) : NaN;
|
|
4473
4568
|
if (isNaN(numericChainId)) return void 0;
|
|
4474
4569
|
const tokenNetworkAddress = this.config.tokenNetworks?.[negotiatedChain];
|
|
@@ -6483,6 +6578,8 @@ export {
|
|
|
6483
6578
|
isTrustDowngrade,
|
|
6484
6579
|
loadKeystore,
|
|
6485
6580
|
parseBackupPayload,
|
|
6581
|
+
parseFulfillHttp,
|
|
6582
|
+
parseFulfillHttpBytes,
|
|
6486
6583
|
parseHttpResponse,
|
|
6487
6584
|
parsePetInteractionEvent,
|
|
6488
6585
|
parsePetInteractionResult,
|