@toon-protocol/client-mcp 0.5.2 → 0.6.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.
@@ -6956,13 +6956,49 @@ function decodeUtf8(bytes) {
6956
6956
  function isBase64(str) {
6957
6957
  return /^[A-Za-z0-9+/]*={0,2}$/.test(str);
6958
6958
  }
6959
- var REQUEST_LINE = "POST /write HTTP/1.1";
6959
+ var DEFAULT_REQUEST_TARGET = "/write";
6960
6960
  var HEADERS = ["Host: relay", "Content-Type: application/json"];
6961
- function buildStoreWriteEnvelope(event) {
6961
+ function buildStoreWriteEnvelope(event, requestTarget = DEFAULT_REQUEST_TARGET) {
6962
6962
  const body = JSON.stringify({ event });
6963
- const head = [REQUEST_LINE, ...HEADERS].join("\r\n");
6963
+ const head = [`POST ${requestTarget} HTTP/1.1`, ...HEADERS].join("\r\n");
6964
6964
  return encodeUtf8(head + "\r\n\r\n" + body);
6965
6965
  }
6966
+ var CRLF = "\r\n";
6967
+ function findHeaderEnd(bytes) {
6968
+ for (let i = 0; i + 3 < bytes.length; i++) {
6969
+ if (bytes[i] === 13 && bytes[i + 1] === 10 && bytes[i + 2] === 13 && bytes[i + 3] === 10) {
6970
+ return i + 4;
6971
+ }
6972
+ }
6973
+ return -1;
6974
+ }
6975
+ function parseFulfillHttpBytes(bytes) {
6976
+ const notHttp = {
6977
+ isHttp: false,
6978
+ status: 0,
6979
+ statusText: "",
6980
+ body: ""
6981
+ };
6982
+ const headerEnd = findHeaderEnd(bytes);
6983
+ const headBytes = headerEnd === -1 ? bytes : bytes.subarray(0, headerEnd - 2);
6984
+ const bodyBytes = headerEnd === -1 ? new Uint8Array(0) : bytes.subarray(headerEnd);
6985
+ const headText = decodeUtf8(headBytes);
6986
+ const lines = headText.split(CRLF).filter((l) => l.length > 0);
6987
+ const statusLine = lines.shift();
6988
+ if (!statusLine) return notHttp;
6989
+ if (!statusLine.trimStart().startsWith("HTTP/")) return notHttp;
6990
+ const match = /^HTTP\/\d\.\d\s+(\d{3})(?:\s+(.*))?$/.exec(statusLine.trim());
6991
+ if (!match) return notHttp;
6992
+ return {
6993
+ isHttp: true,
6994
+ status: parseInt(match[1], 10),
6995
+ statusText: match[2] ?? "",
6996
+ body: decodeUtf8(bodyBytes)
6997
+ };
6998
+ }
6999
+ function parseFulfillHttp(base64Data) {
7000
+ return parseFulfillHttpBytes(fromBase64(base64Data));
7001
+ }
6966
7002
  async function withRetry(operation, options) {
6967
7003
  const {
6968
7004
  maxRetries,
@@ -8719,12 +8755,12 @@ var OnChainChannelClient = class {
8719
8755
  */
8720
8756
  parseChainId(chain2) {
8721
8757
  const parts = chain2.split(":");
8722
- if (parts.length < 3) {
8758
+ if (parts.length < 2) {
8723
8759
  throw new Error(
8724
- `Invalid chain format: "${chain2}". Expected "evm:{network}:{chainId}".`
8760
+ `Invalid chain format: "${chain2}". Expected "evm:{network}:{chainId}" or "evm:{chainId}".`
8725
8761
  );
8726
8762
  }
8727
- const chainIdStr = parts[2];
8763
+ const chainIdStr = parts.length >= 3 ? parts[2] : parts[1];
8728
8764
  if (!chainIdStr) {
8729
8765
  throw new Error(
8730
8766
  `Invalid chain format: "${chain2}". Expected "evm:{network}:{chainId}".`
@@ -9921,7 +9957,9 @@ async function requestBlobStorage(client, secretKey, params) {
9921
9957
  const result = await client.publishEvent(event, {
9922
9958
  destination: params.destination,
9923
9959
  claim: params.claim,
9924
- ilpAmount: params.ilpAmount
9960
+ ilpAmount: params.ilpAmount,
9961
+ // The store/DVM backend serves POST /store (not the relay's /write).
9962
+ proxyPath: "/store"
9925
9963
  });
9926
9964
  if (!result.success) {
9927
9965
  return {
@@ -9934,15 +9972,17 @@ async function requestBlobStorage(client, secretKey, params) {
9934
9972
  return {
9935
9973
  success: false,
9936
9974
  eventId: event.id,
9937
- error: "FULFILL contained no data; expected base64-encoded Arweave tx ID"
9975
+ error: "FULFILL contained no data; expected an HTTP response with the Arweave tx ID"
9938
9976
  };
9939
9977
  }
9940
- const txId = decodeUtf8(fromBase64(result.data));
9941
- if (!ARWEAVE_TX_ID_REGEX.test(txId)) {
9978
+ let txId;
9979
+ try {
9980
+ txId = extractArweaveTxId(result.data);
9981
+ } catch (error) {
9942
9982
  return {
9943
9983
  success: false,
9944
9984
  eventId: event.id,
9945
- error: `Decoded FULFILL data is not a valid Arweave tx ID: "${txId}"`
9985
+ error: error instanceof Error ? error.message : String(error)
9946
9986
  };
9947
9987
  }
9948
9988
  return {
@@ -9951,6 +9991,49 @@ async function requestBlobStorage(client, secretKey, params) {
9951
9991
  eventId: event.id
9952
9992
  };
9953
9993
  }
9994
+ function extractArweaveTxId(base64Data) {
9995
+ const http2 = parseFulfillHttp(base64Data);
9996
+ if (!http2.isHttp) {
9997
+ const legacy = decodeUtf8(fromBase64(base64Data));
9998
+ if (!ARWEAVE_TX_ID_REGEX.test(legacy)) {
9999
+ throw new Error(
10000
+ `Decoded FULFILL data is not a valid Arweave tx ID: "${legacy}"`
10001
+ );
10002
+ }
10003
+ return legacy;
10004
+ }
10005
+ if (http2.status < 200 || http2.status >= 300) {
10006
+ const detail = http2.body ? ` - ${http2.body}` : "";
10007
+ throw new Error(
10008
+ `Blob upload failed: DVM returned HTTP ${http2.status} ${http2.statusText}`.trimEnd() + detail
10009
+ );
10010
+ }
10011
+ let parsed;
10012
+ try {
10013
+ parsed = JSON.parse(http2.body);
10014
+ } catch {
10015
+ throw new Error(
10016
+ `Blob upload response body was not valid JSON: "${http2.body}"`
10017
+ );
10018
+ }
10019
+ const body = parsed;
10020
+ if (body.accept === false) {
10021
+ const reason = typeof body.error === "string" ? `: ${body.error}` : "";
10022
+ throw new Error(`Blob upload rejected by DVM (accept:false)${reason}`);
10023
+ }
10024
+ if (typeof body.txId === "string" && ARWEAVE_TX_ID_REGEX.test(body.txId)) {
10025
+ return body.txId;
10026
+ }
10027
+ if (typeof body.data === "string" && body.data.length > 0) {
10028
+ const decoded = decodeUtf8(fromBase64(body.data));
10029
+ if (ARWEAVE_TX_ID_REGEX.test(decoded)) {
10030
+ return decoded;
10031
+ }
10032
+ }
10033
+ throw new Error(
10034
+ `Blob upload response did not contain a valid Arweave tx ID: "${http2.body}"`
10035
+ );
10036
+ }
9954
10037
  var Http402Client = class {
9955
10038
  fetchImpl;
9956
10039
  resolveClaim;
@@ -10123,7 +10206,7 @@ function parseX402Body(body) {
10123
10206
  }
10124
10207
  return version !== void 0 ? { x402Version: version } : {};
10125
10208
  }
10126
- var CRLF = "\r\n";
10209
+ var CRLF2 = "\r\n";
10127
10210
  function concatHeadAndBody(head, body) {
10128
10211
  const headBytes = encodeUtf8(head);
10129
10212
  const out = new Uint8Array(headBytes.length + body.length);
@@ -10153,10 +10236,10 @@ function serializeHttpRequest(req) {
10153
10236
  `${req.method.toUpperCase()} ${target} HTTP/1.1`,
10154
10237
  ...headers.values()
10155
10238
  ];
10156
- const head = lines.join(CRLF) + CRLF + CRLF;
10239
+ const head = lines.join(CRLF2) + CRLF2 + CRLF2;
10157
10240
  return concatHeadAndBody(head, bodyBytes);
10158
10241
  }
10159
- function findHeaderEnd(bytes) {
10242
+ function findHeaderEnd2(bytes) {
10160
10243
  for (let i = 0; i + 3 < bytes.length; i++) {
10161
10244
  if (bytes[i] === 13 && bytes[i + 1] === 10 && bytes[i + 2] === 13 && bytes[i + 3] === 10) {
10162
10245
  return i + 4;
@@ -10165,11 +10248,11 @@ function findHeaderEnd(bytes) {
10165
10248
  return -1;
10166
10249
  }
10167
10250
  function parseHttpResponse(bytes) {
10168
- const headerEnd = findHeaderEnd(bytes);
10251
+ const headerEnd = findHeaderEnd2(bytes);
10169
10252
  const headBytes = headerEnd === -1 ? bytes : bytes.subarray(0, headerEnd - 2);
10170
10253
  const body = headerEnd === -1 ? new Uint8Array(0) : bytes.subarray(headerEnd);
10171
10254
  const headText = decodeUtf8(headBytes);
10172
- const lines = headText.split(CRLF).filter((l) => l.length > 0);
10255
+ const lines = headText.split(CRLF2).filter((l) => l.length > 0);
10173
10256
  const statusLine = lines.shift();
10174
10257
  if (!statusLine) {
10175
10258
  throw new ConnectorError(
@@ -10376,7 +10459,7 @@ var ToonClient = class {
10376
10459
  if (result.negotiatedChain && result.settlementAddress) {
10377
10460
  const chainType = result.negotiatedChain.split(":")[0] ?? "evm";
10378
10461
  const parts = result.negotiatedChain.split(":");
10379
- const chainId = parts.length >= 3 ? parseInt(parts[2] ?? "0", 10) : 0;
10462
+ const chainId = parts.length >= 3 ? parseInt(parts[2] ?? "0", 10) : parts.length >= 2 ? parseInt(parts[1] ?? "0", 10) : 0;
10380
10463
  const r = result;
10381
10464
  this.peerNegotiations.set(result.registeredPeerId, {
10382
10465
  chain: result.negotiatedChain,
@@ -10394,7 +10477,7 @@ var ToonClient = class {
10394
10477
  if (matchedChain) {
10395
10478
  const peerAddr = peerInfo.settlementAddresses?.[matchedChain];
10396
10479
  const parts = matchedChain.split(":");
10397
- const chainId = parts.length >= 3 ? parseInt(parts[2] ?? "0", 10) : 0;
10480
+ const chainId = parts.length >= 3 ? parseInt(parts[2] ?? "0", 10) : parts.length >= 2 ? parseInt(parts[1] ?? "0", 10) : 0;
10398
10481
  if (peerAddr) {
10399
10482
  this.peerNegotiations.set(result.registeredPeerId, {
10400
10483
  chain: matchedChain,
@@ -10479,7 +10562,7 @@ var ToonClient = class {
10479
10562
  const toonData = this.config.toonEncoder(event);
10480
10563
  const basePricePerByte = 10n;
10481
10564
  const amount = options?.ilpAmount !== void 0 ? String(options.ilpAmount) : String(BigInt(toonData.length) * basePricePerByte);
10482
- const writeData = buildStoreWriteEnvelope(event);
10565
+ const writeData = buildStoreWriteEnvelope(event, options?.proxyPath);
10483
10566
  const destination = options?.destination ?? this.config.destinationAddress;
10484
10567
  const transport = this.getClaimTransport();
10485
10568
  let claimMessage;
@@ -10524,6 +10607,16 @@ var ToonClient = class {
10524
10607
  error: `Event rejected: ${response.code} - ${response.message}`
10525
10608
  };
10526
10609
  }
10610
+ if (response.data) {
10611
+ const httpResult = parseFulfillHttp(response.data);
10612
+ if (httpResult.isHttp && (httpResult.status < 200 || httpResult.status >= 300)) {
10613
+ const detail = httpResult.body ? ` - ${httpResult.body}` : "";
10614
+ return {
10615
+ success: false,
10616
+ error: `Write failed: relay returned HTTP ${httpResult.status} ${httpResult.statusText}`.trimEnd() + detail
10617
+ };
10618
+ }
10619
+ }
10527
10620
  return {
10528
10621
  success: true,
10529
10622
  eventId: event.id,
@@ -10841,7 +10934,7 @@ var ToonClient = class {
10841
10934
  getChainContext(negotiatedChain) {
10842
10935
  if (!negotiatedChain) return void 0;
10843
10936
  const parts = negotiatedChain.split(":");
10844
- const chainIdPart = parts.length >= 3 ? parts[2] : void 0;
10937
+ const chainIdPart = parts.length >= 3 ? parts[2] : parts.length >= 2 ? parts[1] : void 0;
10845
10938
  const numericChainId = chainIdPart !== void 0 ? parseInt(chainIdPart, 10) : NaN;
10846
10939
  if (isNaN(numericChainId)) return void 0;
10847
10940
  const tokenNetworkAddress = this.config.tokenNetworks?.[negotiatedChain];
@@ -11611,6 +11704,18 @@ function buildIlpPrepare(params) {
11611
11704
  };
11612
11705
  }
11613
11706
 
11707
+ // ../arweave/dist/gateways.js
11708
+ var ARWEAVE_GATEWAYS = [
11709
+ "https://ar-io.dev",
11710
+ "https://arweave.net",
11711
+ "https://permagate.io"
11712
+ ];
11713
+ function arweaveUrls(txId, gateways = ARWEAVE_GATEWAYS) {
11714
+ const all = (gateways.length ? gateways : ARWEAVE_GATEWAYS).map((g) => `${g}/${txId}`);
11715
+ const [url, ...fallbacks] = all;
11716
+ return { url: url ?? `${ARWEAVE_GATEWAYS[0]}/${txId}`, fallbacks };
11717
+ }
11718
+
11614
11719
  // src/daemon/config.ts
11615
11720
  var DEFAULT_KEYSTORE_PASSWORD = "toon-client-default";
11616
11721
  function configDir() {
@@ -11646,6 +11751,11 @@ function resolveMnemonic(file) {
11646
11751
  "No mnemonic configured. Set TOON_CLIENT_MNEMONIC, configure a keystorePath (+ TOON_CLIENT_KEYSTORE_PASSWORD), or add `mnemonic` to the config file."
11647
11752
  );
11648
11753
  }
11754
+ function parseCsvEnv(value) {
11755
+ if (!value) return void 0;
11756
+ const items = value.split(",").map((s) => s.trim()).filter(Boolean);
11757
+ return items.length ? items : void 0;
11758
+ }
11649
11759
  function resolveConfig(file) {
11650
11760
  const mnemonic = resolveMnemonic(file);
11651
11761
  const proxyUrl = process.env["TOON_CLIENT_PROXY_URL"] ?? file.proxyUrl;
@@ -11657,7 +11767,10 @@ function resolveConfig(file) {
11657
11767
  process.env["TOON_CLIENT_HTTP_PORT"] ?? file.httpPort ?? 8787
11658
11768
  );
11659
11769
  const destination = process.env["TOON_CLIENT_DESTINATION"] ?? file.destination ?? "g.townhouse.town";
11770
+ const publishDestination = process.env["TOON_CLIENT_PUBLISH_DESTINATION"] ?? file.publishDestination ?? destination;
11771
+ const storeDestination = process.env["TOON_CLIENT_STORE_DESTINATION"] ?? file.storeDestination ?? destination;
11660
11772
  const feePerEvent = BigInt(file.feePerEvent ?? "1");
11773
+ const arweaveGateways = parseCsvEnv(process.env["TOON_CLIENT_ARWEAVE_GATEWAYS"]) ?? file.arweaveGateways ?? [...ARWEAVE_GATEWAYS];
11661
11774
  const network = process.env["TOON_CLIENT_NETWORK"] ?? file.network;
11662
11775
  const chain2 = process.env["TOON_CLIENT_CHAIN"] ?? file.chain ?? "evm";
11663
11776
  const apex = file.apexChains?.[chain2] ?? file.apex ?? buildProxyApexNegotiation(file, chain2, destination);
@@ -11703,13 +11816,16 @@ function resolveConfig(file) {
11703
11816
  ...proxyUrl ? { proxyUrl } : {},
11704
11817
  ...faucetUrl ? { faucetUrl } : {},
11705
11818
  destination,
11819
+ publishDestination,
11820
+ storeDestination,
11706
11821
  feePerEvent,
11707
11822
  ...apex ? { apex } : {},
11708
11823
  ...file.apexChildPeers ? { apexChildPeers: file.apexChildPeers } : {},
11709
11824
  chain: chain2,
11710
11825
  apexChannelStorePath,
11711
11826
  toonClientConfig,
11712
- network
11827
+ network,
11828
+ arweaveGateways
11713
11829
  };
11714
11830
  }
11715
11831
  function defaultChainKey(chain2, chainId) {
@@ -11732,7 +11848,7 @@ function buildProxyApexNegotiation(file, chain2, destination) {
11732
11848
  const settlementAddress = settlementAddresses[chainKey];
11733
11849
  if (!settlementAddress) return void 0;
11734
11850
  const parts = chainKey.split(":");
11735
- const chainId = chain2 === "evm" && parts.length >= 3 ? Number(parts[2] ?? 0) : 0;
11851
+ const chainId = chain2 === "evm" && parts.length >= 2 ? Number(parts[2] ?? parts[1] ?? 0) : 0;
11736
11852
  const peerId = destination.split(".").at(-1) ?? destination;
11737
11853
  return {
11738
11854
  destination,
@@ -11989,6 +12105,7 @@ export {
11989
12105
  parseIlpPeerInfo2 as parseIlpPeerInfo,
11990
12106
  isEventExpired,
11991
12107
  buildIlpPrepare,
12108
+ arweaveUrls,
11992
12109
  DEFAULT_KEYSTORE_PASSWORD,
11993
12110
  configDir,
11994
12111
  defaultConfigPath,
@@ -12025,4 +12142,4 @@ export {
12025
12142
  @scure/bip32/lib/esm/index.js:
12026
12143
  (*! scure-bip32 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
12027
12144
  */
12028
- //# sourceMappingURL=chunk-R75M6TK6.js.map
12145
+ //# sourceMappingURL=chunk-TDXKG3EI.js.map