@zeroxyz/sdk 0.13.0 → 0.14.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.
@@ -6,7 +6,6 @@ import { x402Client } from '@x402/core/client';
6
6
  import { x402HTTPClient, decodePaymentResponseHeader, encodePaymentRequiredHeader } from '@x402/core/http';
7
7
  import { registerExactEvmScheme } from '@x402/evm/exact/client';
8
8
  import { createSIWxClientHook } from '@x402/extensions/sign-in-with-x';
9
- import { wrapFetchWithPayment } from '@x402/fetch';
10
9
  import { Receipt, Challenge } from 'mppx';
11
10
  import { Mppx, tempo } from 'mppx/client';
12
11
  import { createHash } from 'crypto';
@@ -698,6 +697,9 @@ var Payments = class {
698
697
  input.walletAddress
699
698
  );
700
699
  let capturedAmount = null;
700
+ let pendingAmountUnits = 0n;
701
+ let identityChallengeHandled = false;
702
+ let paidChallengeHandled = false;
701
703
  let capturedNetwork;
702
704
  let preflightError = null;
703
705
  const x402 = registerExactEvmScheme(new x402Client(), { signer: account });
@@ -726,11 +728,25 @@ var Payments = class {
726
728
  };
727
729
  }
728
730
  const rawAmountUnits = BigInt(rawAmount);
729
- capturedAmount = formatUnits(rawAmountUnits, 6);
731
+ pendingAmountUnits = rawAmountUnits;
732
+ const challengeAmount = formatUnits(rawAmountUnits, 6);
733
+ if (rawAmountUnits === 0n) {
734
+ if (identityChallengeHandled || paidChallengeHandled) {
735
+ return {
736
+ abort: true,
737
+ reason: "Only one zero-value identity challenge is allowed, and it must precede payment."
738
+ };
739
+ }
740
+ } else if (paidChallengeHandled) {
741
+ return {
742
+ abort: true,
743
+ reason: "A positive-value x402 payment was already attempted for this fetch; refusing a second charge."
744
+ };
745
+ }
730
746
  if (maxPayUnits !== null && rawAmountUnits > maxPayUnits) {
731
747
  return {
732
748
  abort: true,
733
- reason: `Payment of ${capturedAmount} USDC exceeds maxPay ${input.maxPay}`
749
+ reason: `Payment of ${challengeAmount} USDC exceeds maxPay ${input.maxPay}`
734
750
  };
735
751
  }
736
752
  const detected = networkToChain(capturedNetwork);
@@ -750,9 +766,10 @@ var Payments = class {
750
766
  }
751
767
  if (balance !== null && balance < rawAmountUnits) {
752
768
  const have = formatUnits(balance, 6);
769
+ const requiredAmount = formatUnits(rawAmountUnits, 6);
753
770
  preflightError = new ZeroInsufficientFundsError(
754
- `wallet has ${have} USDC on Base, needs ${capturedAmount}.`,
755
- { have, need: capturedAmount }
771
+ `wallet has ${have} USDC on Base, needs ${requiredAmount}.`,
772
+ { have, need: requiredAmount }
756
773
  );
757
774
  return { abort: true, reason: preflightError.message };
758
775
  }
@@ -763,18 +780,64 @@ var Payments = class {
763
780
  const httpClient = new x402HTTPClient(x402).onPaymentRequired(
764
781
  createSIWxClientHook(account)
765
782
  );
766
- const wrappedFetch = wrapFetchWithPayment(
767
- withSynthesizedX402Header(configuredFetch),
768
- httpClient
769
- );
783
+ const paymentFetch = withSynthesizedX402Header(configuredFetch);
770
784
  let response;
771
785
  try {
772
- response = await wrappedFetch(input.url, {
786
+ const request2 = new Request(input.url, {
773
787
  method: input.method ?? "GET",
774
788
  headers: input.headers,
775
789
  body: input.body,
776
790
  signal: input.signal
777
791
  });
792
+ response = await paymentFetch(request2.clone());
793
+ for (let paymentStage = 0; paymentStage < 2; paymentStage++) {
794
+ if (response.status !== 402) break;
795
+ const parseChallenge = async (challengeResponse) => {
796
+ let body;
797
+ try {
798
+ const text = await challengeResponse.clone().text();
799
+ if (text) body = JSON.parse(text);
800
+ } catch {
801
+ }
802
+ return httpClient.getPaymentRequiredResponse(
803
+ (name) => challengeResponse.headers.get(name),
804
+ body
805
+ );
806
+ };
807
+ let paymentRequired = await parseChallenge(response);
808
+ const hookHeaders = await httpClient.handlePaymentRequired(paymentRequired);
809
+ if (hookHeaders) {
810
+ const hookRequest = request2.clone();
811
+ for (const [key, value] of Object.entries(hookHeaders)) {
812
+ hookRequest.headers.set(key, value);
813
+ }
814
+ response = await paymentFetch(hookRequest);
815
+ if (response.status === 402) {
816
+ paymentRequired = await parseChallenge(response);
817
+ } else {
818
+ break;
819
+ }
820
+ }
821
+ pendingAmountUnits = 0n;
822
+ const paymentPayload = await x402.createPaymentPayload(paymentRequired);
823
+ if (pendingAmountUnits === 0n) {
824
+ identityChallengeHandled = true;
825
+ capturedAmount = "0";
826
+ } else {
827
+ paidChallengeHandled = true;
828
+ capturedAmount = formatUnits(pendingAmountUnits, 6);
829
+ }
830
+ const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);
831
+ const paidRequest = request2.clone();
832
+ for (const [key, value] of Object.entries(paymentHeaders)) {
833
+ paidRequest.headers.set(key, value);
834
+ }
835
+ paidRequest.headers.set(
836
+ "Access-Control-Expose-Headers",
837
+ "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE"
838
+ );
839
+ response = await paymentFetch(paidRequest);
840
+ }
778
841
  } catch (err) {
779
842
  if (preflightError) throw preflightError;
780
843
  if (err instanceof ZeroError) throw err;
@@ -1342,8 +1405,17 @@ var cancelBody2 = (response) => {
1342
1405
  } catch {
1343
1406
  }
1344
1407
  };
1345
- var detectPaymentRequirement = async (response) => {
1408
+ var detectPaymentRequirement = async (response, preferredProtocol) => {
1346
1409
  if (response.status !== 402) return null;
1410
+ const wwwAuth = response.headers.get("www-authenticate");
1411
+ const advertisesMpp = wwwAuth ? splitWwwAuthenticateChallenges(wwwAuth).some((challenge) => {
1412
+ const scheme = challenge.trim().split(/\s+/)[0]?.toLowerCase() ?? "";
1413
+ return MPP_SCHEME_TOKENS.has(scheme);
1414
+ }) : false;
1415
+ if (preferredProtocol === "mpp") {
1416
+ cancelBody2(response);
1417
+ return advertisesMpp ? { protocol: "mpp", raw: { "www-authenticate": wwwAuth } } : { protocol: "unknown", raw: { requestedProtocol: "mpp" } };
1418
+ }
1347
1419
  const x402Header = response.headers.get("payment-required") ?? response.headers.get("x-payment-required");
1348
1420
  if (x402Header) {
1349
1421
  cancelBody2(response);
@@ -1373,15 +1445,13 @@ var detectPaymentRequirement = async (response) => {
1373
1445
  } catch {
1374
1446
  }
1375
1447
  }
1376
- const wwwAuth = response.headers.get("www-authenticate");
1377
- if (wwwAuth) {
1378
- const schemes = splitWwwAuthenticateChallenges(wwwAuth).map(
1379
- (challenge) => challenge.trim().split(/\s+/)[0]?.toLowerCase() ?? ""
1380
- );
1381
- if (schemes.some((scheme) => MPP_SCHEME_TOKENS.has(scheme))) {
1382
- cancelBody2(response);
1383
- return { protocol: "mpp", raw: { "www-authenticate": wwwAuth } };
1384
- }
1448
+ if (preferredProtocol === "x402") {
1449
+ cancelBody2(response);
1450
+ return { protocol: "unknown", raw: { requestedProtocol: "x402" } };
1451
+ }
1452
+ if (advertisesMpp) {
1453
+ cancelBody2(response);
1454
+ return { protocol: "mpp", raw: { "www-authenticate": wwwAuth } };
1385
1455
  }
1386
1456
  cancelBody2(response);
1387
1457
  return { protocol: "unknown", raw: {} };
@@ -1707,7 +1777,10 @@ var clientFetch = async (client, url, opts = {}) => {
1707
1777
  return result2;
1708
1778
  }
1709
1779
  if (response.status === 402) {
1710
- const requirement = await detectPaymentRequirement(response);
1780
+ const requirement = await detectPaymentRequirement(
1781
+ response,
1782
+ opts.paymentProtocol
1783
+ );
1711
1784
  if (requirement?.protocol === "x402" || requirement?.protocol === "mpp") {
1712
1785
  const payCall = requirement.protocol === "x402" ? client.payments.pay : client.payments.payMpp;
1713
1786
  try {
@@ -1779,7 +1852,7 @@ var clientFetch = async (client, url, opts = {}) => {
1779
1852
  } else if (requirement?.protocol === "unknown") {
1780
1853
  const result2 = errorFetchResult(
1781
1854
  startedAt,
1782
- "Capability returned 402 with an unrecognized payment protocol. Neither x402 nor MPP markers were detected in the response headers or body.",
1855
+ opts.paymentProtocol ? `Capability did not advertise the requested ${opts.paymentProtocol} payment protocol.` : "Capability returned 402 with an unrecognized payment protocol. Neither x402 nor MPP markers were detected in the response headers or body.",
1783
1856
  "unrecognized_402_protocol",
1784
1857
  capabilityIdRequested,
1785
1858
  "payment_failed",
@@ -1963,7 +2036,7 @@ var clientFetch = async (client, url, opts = {}) => {
1963
2036
 
1964
2037
  // package.json
1965
2038
  var package_default = {
1966
- version: "0.13.0"};
2039
+ version: "0.14.0"};
1967
2040
 
1968
2041
  // src/version.ts
1969
2042
  var SDK_VERSION = package_default.version;
@@ -3914,5 +3987,5 @@ var ZeroClient = class _ZeroClient {
3914
3987
  };
3915
3988
 
3916
3989
  export { Auth, AuthAgent, AuthDevice, BUG_REPORT_CATEGORIES, BugReports, Capabilities, DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT_MS, FETCH_SKIP_REASONS, FETCH_WARNINGS, Payments, Runs, SDK_VERSION, TEMPO_CHAIN_ID2 as TEMPO_CHAIN_ID, TEMPO_TESTNET_CHAIN_ID, USDC_BASE, USDC_DECIMALS, USDC_TEMPO, Wallet, ZeroAgentAuthError, ZeroApiError, ZeroAuthError, ZeroClient, ZeroConfigurationError, ZeroError, ZeroPaymentError, ZeroSessionCloseFailedError, ZeroTimeoutError, ZeroValidationError, ZeroWalletError, asSchemaNode, coerceTempoChainId, createManagedAccount, extractInputEnvelope, isShortToken, normalizeTransportEnvelopeRequest, paymentHasAnchor, tempoChainLabelFromId, unwrapTransportEnvelope };
3917
- //# sourceMappingURL=chunk-CYB4Y3ID.js.map
3918
- //# sourceMappingURL=chunk-CYB4Y3ID.js.map
3990
+ //# sourceMappingURL=chunk-FWHVWIO2.js.map
3991
+ //# sourceMappingURL=chunk-FWHVWIO2.js.map