@dexterai/x402 1.8.2 → 1.9.1

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.
Files changed (36) hide show
  1. package/README.md +101 -8
  2. package/dist/adapters/index.cjs +15 -3
  3. package/dist/adapters/index.cjs.map +1 -1
  4. package/dist/adapters/index.d.cts +5 -5
  5. package/dist/adapters/index.d.ts +5 -5
  6. package/dist/adapters/index.js +5 -3
  7. package/dist/adapters/index.js.map +1 -1
  8. package/dist/client/index.cjs +50 -9
  9. package/dist/client/index.cjs.map +1 -1
  10. package/dist/client/index.d.cts +7 -6
  11. package/dist/client/index.d.ts +7 -6
  12. package/dist/client/index.js +37 -9
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/react/index.cjs +64 -12
  15. package/dist/react/index.cjs.map +1 -1
  16. package/dist/react/index.d.cts +13 -4
  17. package/dist/react/index.d.ts +13 -4
  18. package/dist/react/index.js +52 -12
  19. package/dist/react/index.js.map +1 -1
  20. package/dist/server/index.cjs +43 -18
  21. package/dist/server/index.cjs.map +1 -1
  22. package/dist/server/index.d.cts +12 -3
  23. package/dist/server/index.d.ts +12 -3
  24. package/dist/server/index.js +40 -16
  25. package/dist/server/index.js.map +1 -1
  26. package/dist/{solana-BeGAqPta.d.cts → solana-CfHuiW2H.d.cts} +2 -2
  27. package/dist/{solana-CQD9yMju.d.ts → solana-kZcwbUK9.d.ts} +2 -2
  28. package/dist/{x402-client-Dk9q2QQF.d.cts → sponsored-access-BCB2CxdG.d.cts} +70 -3
  29. package/dist/{x402-client-D9b3PHai.d.ts → sponsored-access-H1EX6zpi.d.ts} +70 -3
  30. package/dist/{types-DYLi7SuF.d.cts → types-BQvaF8lB.d.cts} +7 -5
  31. package/dist/{types-DYLi7SuF.d.ts → types-BQvaF8lB.d.ts} +7 -5
  32. package/dist/{types-B477nBpg.d.cts → types-DmqH9yD8.d.cts} +1 -1
  33. package/dist/{types-BWnUAPvD.d.ts → types-ENcnkof8.d.ts} +1 -1
  34. package/dist/utils/index.cjs.map +1 -1
  35. package/dist/utils/index.js.map +1 -1
  36. package/package.json +2 -6
@@ -1,7 +1,10 @@
1
- import { a as X402Client } from '../x402-client-Dk9q2QQF.cjs';
2
- import { W as WalletSet, B as BalanceInfo } from '../types-B477nBpg.cjs';
3
- import { a as AccessPassTier } from '../types-DYLi7SuF.cjs';
4
- export { A as AccessPassClientConfig, b as AccessPassInfo, X as X402Error } from '../types-DYLi7SuF.cjs';
1
+ import { a as X402Client } from '../sponsored-access-BCB2CxdG.cjs';
2
+ export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-BCB2CxdG.cjs';
3
+ import { W as WalletSet, B as BalanceInfo } from '../types-DmqH9yD8.cjs';
4
+ import { SponsoredRecommendation } from '@dexterai/x402-ads-types';
5
+ export { SponsoredRecommendation } from '@dexterai/x402-ads-types';
6
+ import { a as AccessPassTier } from '../types-BQvaF8lB.cjs';
7
+ export { A as AccessPassClientConfig, b as AccessPassInfo, X as X402Error } from '../types-BQvaF8lB.cjs';
5
8
 
6
9
  /**
7
10
  * React Hook for x402 v2 Payments
@@ -114,6 +117,12 @@ interface UseX402PaymentReturn {
114
117
  /** Seconds remaining on the pass */
115
118
  remainingSeconds: number | null;
116
119
  } | null;
120
+ /**
121
+ * Sponsored recommendations from the most recent payment.
122
+ * Populated when the facilitator returns sponsored-access extensions
123
+ * in the settlement response. Null if no recommendations were delivered.
124
+ */
125
+ sponsoredRecommendations: SponsoredRecommendation[] | null;
117
126
  }
118
127
  /**
119
128
  * React hook for managing x402 v2 payments across chains
@@ -1,7 +1,10 @@
1
- import { a as X402Client } from '../x402-client-D9b3PHai.js';
2
- import { W as WalletSet, B as BalanceInfo } from '../types-BWnUAPvD.js';
3
- import { a as AccessPassTier } from '../types-DYLi7SuF.js';
4
- export { A as AccessPassClientConfig, b as AccessPassInfo, X as X402Error } from '../types-DYLi7SuF.js';
1
+ import { a as X402Client } from '../sponsored-access-H1EX6zpi.js';
2
+ export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-H1EX6zpi.js';
3
+ import { W as WalletSet, B as BalanceInfo } from '../types-ENcnkof8.js';
4
+ import { SponsoredRecommendation } from '@dexterai/x402-ads-types';
5
+ export { SponsoredRecommendation } from '@dexterai/x402-ads-types';
6
+ import { a as AccessPassTier } from '../types-BQvaF8lB.js';
7
+ export { A as AccessPassClientConfig, b as AccessPassInfo, X as X402Error } from '../types-BQvaF8lB.js';
5
8
 
6
9
  /**
7
10
  * React Hook for x402 v2 Payments
@@ -114,6 +117,12 @@ interface UseX402PaymentReturn {
114
117
  /** Seconds remaining on the pass */
115
118
  remainingSeconds: number | null;
116
119
  } | null;
120
+ /**
121
+ * Sponsored recommendations from the most recent payment.
122
+ * Populated when the facilitator returns sponsored-access extensions
123
+ * in the settlement response. Null if no recommendations were delivered.
124
+ */
125
+ sponsoredRecommendations: SponsoredRecommendation[] | null;
117
126
  }
118
127
  /**
119
128
  * React hook for managing x402 v2 payments across chains
@@ -124,7 +124,7 @@ var SolanaAdapter = class {
124
124
  const connection = new Connection(url, "confirmed");
125
125
  const userPubkey = new PublicKey(wallet.publicKey.toBase58());
126
126
  const { payTo, asset, extra } = accept;
127
- const amount = accept.amount || accept.maxAmountRequired;
127
+ const amount = accept.amount ?? accept.maxAmountRequired;
128
128
  if (!amount) {
129
129
  throw new Error("Missing amount in payment requirements");
130
130
  }
@@ -362,7 +362,7 @@ var EvmAdapter = class {
362
362
  throw new Error("Wallet not connected");
363
363
  }
364
364
  const { payTo, asset, extra } = accept;
365
- const amount = accept.amount || accept.maxAmountRequired;
365
+ const amount = accept.amount ?? accept.maxAmountRequired;
366
366
  if (!amount) {
367
367
  throw new Error("Missing amount in payment requirements");
368
368
  }
@@ -390,7 +390,9 @@ var EvmAdapter = class {
390
390
  { name: "nonce", type: "bytes32" }
391
391
  ]
392
392
  };
393
- const nonce = "0x" + [...Array(32)].map(() => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")).join("");
393
+ const nonceBytes = new Uint8Array(32);
394
+ (globalThis.crypto ?? (await import("crypto")).webcrypto).getRandomValues(nonceBytes);
395
+ const nonce = "0x" + [...nonceBytes].map((b) => b.toString(16).padStart(2, "0")).join("");
394
396
  const now = Math.floor(Date.now() / 1e3);
395
397
  const authorization = {
396
398
  from: wallet.address,
@@ -447,6 +449,9 @@ function isKnownUSDC(asset) {
447
449
 
448
450
  // src/client/x402-client.ts
449
451
  var receiptStore = /* @__PURE__ */ new WeakMap();
452
+ function getPaymentReceipt(response) {
453
+ return receiptStore.get(response);
454
+ }
450
455
  function createX402Client(config) {
451
456
  const {
452
457
  adapters = [createSolanaAdapter({ verbose: config.verbose }), createEvmAdapter({ verbose: config.verbose })],
@@ -482,10 +487,11 @@ function createX402Client(config) {
482
487
  const parts = jwt.split(".");
483
488
  if (parts.length === 3) {
484
489
  const payload = JSON.parse(atob(parts[1].replace(/-/g, "+").replace(/_/g, "/")));
485
- if (payload.exp) {
486
- passCache.set(host, { jwt, expiresAt: payload.exp });
487
- log("Access pass cached for", host, "| expires:", new Date(payload.exp * 1e3).toISOString());
488
- }
490
+ const now = Math.floor(Date.now() / 1e3);
491
+ const maxExp = now + 86400;
492
+ const expiresAt = Math.min(typeof payload.exp === "number" ? payload.exp : now, maxExp);
493
+ passCache.set(host, { jwt, expiresAt });
494
+ log("Access pass cached for", host, "| expires:", new Date(expiresAt * 1e3).toISOString());
489
495
  }
490
496
  } catch {
491
497
  log("Failed to cache access pass");
@@ -566,7 +572,7 @@ function createX402Client(config) {
566
572
  if (adapter.name === "Solana" && !accept.extra?.feePayer) return null;
567
573
  const decimals = accept.extra?.decimals ?? (isKnownUSDC(accept.asset) ? 6 : void 0);
568
574
  if (typeof decimals !== "number") return null;
569
- const paymentAmount = accept.amount || accept.maxAmountRequired;
575
+ const paymentAmount = accept.amount ?? accept.maxAmountRequired;
570
576
  if (!paymentAmount) return null;
571
577
  const rpcUrl = getRpcUrl(accept.network, adapter);
572
578
  const balance = await adapter.getBalance(accept, wallet, rpcUrl);
@@ -710,7 +716,7 @@ function createX402Client(config) {
710
716
  "Payment option missing decimals - provide in extra or use a known stablecoin"
711
717
  );
712
718
  }
713
- const paymentAmount = accept.amount || accept.maxAmountRequired;
719
+ const paymentAmount = accept.amount ?? accept.maxAmountRequired;
714
720
  if (!paymentAmount) {
715
721
  throw new X402Error("missing_amount", "Payment option missing amount");
716
722
  }
@@ -875,6 +881,28 @@ function getExplorerUrl(txSignature, network) {
875
881
  return `https://solscan.io/tx/${txSignature}`;
876
882
  }
877
883
 
884
+ // src/client/sponsored-access.ts
885
+ function getSponsoredAccessInfo(response) {
886
+ const receipt = getPaymentReceipt(response);
887
+ if (!receipt?.extensions?.["sponsored-access"]) return void 0;
888
+ return receipt.extensions["sponsored-access"];
889
+ }
890
+ function getSponsoredRecommendations(response) {
891
+ const info = getSponsoredAccessInfo(response);
892
+ if (!info?.recommendations?.length) return void 0;
893
+ return info.recommendations;
894
+ }
895
+ async function fireImpressionBeacon(response) {
896
+ const info = getSponsoredAccessInfo(response);
897
+ const beaconUrl = info?.tracking?.impressionBeacon;
898
+ if (!beaconUrl) return false;
899
+ try {
900
+ await fetch(beaconUrl, { method: "GET" });
901
+ } catch {
902
+ }
903
+ return true;
904
+ }
905
+
878
906
  // src/react/useX402Payment.ts
879
907
  function useX402Payment(config) {
880
908
  const {
@@ -890,6 +918,7 @@ function useX402Payment(config) {
890
918
  const [transactionId, setTransactionId] = useState(null);
891
919
  const [transactionNetwork, setTransactionNetwork] = useState(null);
892
920
  const [balances, setBalances] = useState([]);
921
+ const [sponsoredRecommendations, setSponsoredRecommendations] = useState(null);
893
922
  const log = useCallback((...args) => {
894
923
  if (verbose) console.log("[useX402Payment]", ...args);
895
924
  }, [verbose]);
@@ -921,7 +950,7 @@ function useX402Payment(config) {
921
950
  const accept = {
922
951
  scheme: "exact",
923
952
  network: SOLANA_MAINNET_NETWORK,
924
- maxAmountRequired: "0",
953
+ amount: "0",
925
954
  asset: USDC_MINT,
926
955
  payTo: "",
927
956
  maxTimeoutSeconds: 60,
@@ -946,7 +975,7 @@ function useX402Payment(config) {
946
975
  const accept = {
947
976
  scheme: "exact",
948
977
  network: BASE_MAINNET_NETWORK,
949
- maxAmountRequired: "0",
978
+ amount: "0",
950
979
  asset: USDC_BASE,
951
980
  payTo: "",
952
981
  maxTimeoutSeconds: 60,
@@ -977,6 +1006,7 @@ function useX402Payment(config) {
977
1006
  setError(null);
978
1007
  setTransactionId(null);
979
1008
  setTransactionNetwork(null);
1009
+ setSponsoredRecommendations(null);
980
1010
  }, []);
981
1011
  const client = useMemo(() => createX402Client({
982
1012
  adapters,
@@ -1014,6 +1044,13 @@ function useX402Payment(config) {
1014
1044
  log("Could not parse PAYMENT-RESPONSE header");
1015
1045
  }
1016
1046
  }
1047
+ const recs = getSponsoredRecommendations(response);
1048
+ setSponsoredRecommendations(recs ?? null);
1049
+ if (recs) {
1050
+ log("Sponsored recommendations received:", recs.length);
1051
+ fireImpressionBeacon(response).catch(() => {
1052
+ });
1053
+ }
1017
1054
  setStatus("success");
1018
1055
  return response;
1019
1056
  } catch (err) {
@@ -1044,8 +1081,9 @@ function useX402Payment(config) {
1044
1081
  isAnyWalletConnected,
1045
1082
  reset,
1046
1083
  refreshBalances,
1047
- accessPass: null
1084
+ accessPass: null,
1048
1085
  // Access pass state managed by useAccessPass hook for granular control
1086
+ sponsoredRecommendations
1049
1087
  };
1050
1088
  }
1051
1089
 
@@ -1243,6 +1281,8 @@ function useAccessPass(config) {
1243
1281
  }
1244
1282
  export {
1245
1283
  X402Error,
1284
+ fireImpressionBeacon,
1285
+ getSponsoredRecommendations,
1246
1286
  useAccessPass,
1247
1287
  useX402Payment
1248
1288
  };