@dexterai/x402 1.9.1 → 1.9.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/README.md CHANGED
@@ -77,10 +77,22 @@ The simplest way to make x402 payments from scripts:
77
77
  ```typescript
78
78
  import { wrapFetch } from '@dexterai/x402/client';
79
79
 
80
+ // Solana
80
81
  const x402Fetch = wrapFetch(fetch, {
81
82
  walletPrivateKey: process.env.SOLANA_PRIVATE_KEY,
82
83
  });
83
84
 
85
+ // EVM (Base, Polygon, Arbitrum, Optimism, Avalanche, SKALE)
86
+ const x402Fetch = wrapFetch(fetch, {
87
+ evmPrivateKey: process.env.EVM_PRIVATE_KEY, // requires: npm install viem
88
+ });
89
+
90
+ // Both — SDK picks the chain with balance
91
+ const x402Fetch = wrapFetch(fetch, {
92
+ walletPrivateKey: process.env.SOLANA_PRIVATE_KEY,
93
+ evmPrivateKey: process.env.EVM_PRIVATE_KEY,
94
+ });
95
+
84
96
  // That's it. 402 responses are handled automatically.
85
97
  const response = await x402Fetch('https://api.example.com/protected');
86
98
  ```
@@ -431,9 +431,104 @@ function createX402Server(config) {
431
431
  };
432
432
  }
433
433
 
434
+ // src/server/stripe-payto.ts
435
+ var stripeProviderNetworks = /* @__PURE__ */ new WeakMap();
436
+ function getStripeProviderNetwork(provider) {
437
+ return stripeProviderNetworks.get(provider);
438
+ }
439
+ var STRIPE_NETWORK_KEYS = {
440
+ "base": "base",
441
+ "base-sepolia": "base_sepolia"
442
+ };
443
+ var CAIP2_NETWORKS = {
444
+ "base": "eip155:8453",
445
+ "base-sepolia": "eip155:84532"
446
+ };
447
+ var USDC_DECIMALS = 6;
448
+ function stripePayTo(secretKeyOrConfig) {
449
+ const config = typeof secretKeyOrConfig === "string" ? { secretKey: secretKeyOrConfig } : secretKeyOrConfig;
450
+ const networkName = config.network ?? "base";
451
+ const stripeNetworkKey = STRIPE_NETWORK_KEYS[networkName] ?? "base";
452
+ const caip2Network = CAIP2_NETWORKS[networkName] ?? "eip155:8453";
453
+ const apiVersion = config.apiVersion ?? "2026-01-28.clover";
454
+ let stripeClient = null;
455
+ async function getStripe() {
456
+ if (stripeClient) return stripeClient;
457
+ try {
458
+ const { default: Stripe } = await import("stripe");
459
+ stripeClient = new Stripe(config.secretKey, {
460
+ apiVersion,
461
+ appInfo: {
462
+ name: "@dexterai/x402",
463
+ url: "https://dexter.cash/sdk"
464
+ }
465
+ });
466
+ return stripeClient;
467
+ } catch {
468
+ throw new Error(
469
+ 'The "stripe" package is required for stripePayTo(). Install it with: npm install stripe'
470
+ );
471
+ }
472
+ }
473
+ const provider = async (context) => {
474
+ if (context.paymentHeader) {
475
+ try {
476
+ const decoded = JSON.parse(
477
+ Buffer.from(context.paymentHeader, "base64").toString()
478
+ );
479
+ const toAddress = decoded.payload?.authorization?.to;
480
+ if (toAddress && typeof toAddress === "string") {
481
+ return toAddress;
482
+ }
483
+ const acceptedPayTo = decoded.accepted?.payTo;
484
+ if (acceptedPayTo && typeof acceptedPayTo === "string") {
485
+ return acceptedPayTo;
486
+ }
487
+ } catch {
488
+ }
489
+ throw new Error(
490
+ "Could not extract deposit address from payment header. Ensure the client is sending a valid x402 PAYMENT-SIGNATURE."
491
+ );
492
+ }
493
+ const stripe = await getStripe();
494
+ const amountAtomic = context.amountAtomic ? parseInt(context.amountAtomic, 10) : 1e4;
495
+ const amountInCents = Math.max(1, Math.round(amountAtomic / Math.pow(10, USDC_DECIMALS - 2)));
496
+ const paymentIntent = await stripe.paymentIntents.create({
497
+ amount: amountInCents,
498
+ currency: "usd",
499
+ payment_method_types: ["crypto"],
500
+ payment_method_data: { type: "crypto" },
501
+ payment_method_options: {
502
+ crypto: { mode: "custom" }
503
+ },
504
+ confirm: true
505
+ });
506
+ const nextAction = paymentIntent.next_action;
507
+ if (!nextAction?.crypto_collect_deposit_details) {
508
+ throw new Error(
509
+ "Stripe PaymentIntent did not return crypto deposit details. Ensure your Stripe account has crypto payins enabled: https://support.stripe.com/questions/get-started-with-pay-with-crypto"
510
+ );
511
+ }
512
+ const depositDetails = nextAction.crypto_collect_deposit_details;
513
+ const payToAddress = depositDetails.deposit_addresses?.[stripeNetworkKey]?.address;
514
+ if (!payToAddress) {
515
+ throw new Error(
516
+ `No deposit address found for network "${stripeNetworkKey}". Available networks: ${Object.keys(depositDetails.deposit_addresses || {}).join(", ")}`
517
+ );
518
+ }
519
+ return payToAddress;
520
+ };
521
+ provider._x402Defaults = {
522
+ network: caip2Network,
523
+ facilitatorUrl: "https://x402.dexter.cash"
524
+ };
525
+ stripeProviderNetworks.set(provider, caip2Network);
526
+ return provider;
527
+ }
528
+
434
529
  // src/server/middleware.ts
435
530
  var DEFAULT_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
436
- var USDC_DECIMALS = 6;
531
+ var USDC_DECIMALS2 = 6;
437
532
  function resolvePayToForNetwork(payTo, network) {
438
533
  if (typeof payTo === "string" || typeof payTo === "function") return payTo;
439
534
  if (network in payTo) return payTo[network];
@@ -471,9 +566,9 @@ function x402Middleware(config) {
471
566
  const servers = /* @__PURE__ */ new Map();
472
567
  for (const net of configuredNetworks) {
473
568
  const netPayTo = resolvePayToForNetwork(payTo, net);
474
- if (typeof netPayTo === "function" && netPayTo._stripeNetwork) {
475
- const stripeNet = netPayTo._stripeNetwork;
476
- if (net !== stripeNet) {
569
+ if (typeof netPayTo === "function") {
570
+ const stripeNet = getStripeProviderNetwork(netPayTo);
571
+ if (stripeNet && net !== stripeNet) {
477
572
  throw new Error(
478
573
  `stripePayTo is configured for "${stripeNet}" but middleware includes network "${net}". Stripe only supports Base deposit addresses. Use a static payTo for other chains.`
479
574
  );
@@ -496,7 +591,7 @@ function x402Middleware(config) {
496
591
  const resourceUrl = getResourceUrl?.(req) ?? staticResourceUrl ?? `${req.protocol}://${req.get("host")}${req.originalUrl}`;
497
592
  const requestAmount = getAmount?.(req) ?? amount;
498
593
  const requestDescription = getDescription?.(req) ?? description;
499
- const decimals = asset?.decimals ?? USDC_DECIMALS;
594
+ const decimals = asset?.decimals ?? USDC_DECIMALS2;
500
595
  const amountAtomic = toAtomicUnits(parseFloat(requestAmount), decimals);
501
596
  const requirementsOptions = {
502
597
  amountAtomic,
@@ -1017,7 +1112,7 @@ function verifyJwt(token, secret) {
1017
1112
  }
1018
1113
  }
1019
1114
  var DEFAULT_NETWORK2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
1020
- var USDC_DECIMALS2 = 6;
1115
+ var USDC_DECIMALS3 = 6;
1021
1116
  function x402AccessPass(config) {
1022
1117
  const {
1023
1118
  payTo,
@@ -1040,7 +1135,7 @@ function x402AccessPass(config) {
1040
1135
  }
1041
1136
  const log = verbose ? console.log.bind(console, "[x402:access-pass]") : () => {
1042
1137
  };
1043
- const decimals = asset?.decimals ?? USDC_DECIMALS2;
1138
+ const decimals = asset?.decimals ?? USDC_DECIMALS3;
1044
1139
  const builtTiers = [];
1045
1140
  if (tierPrices) {
1046
1141
  for (const [id, price] of Object.entries(tierPrices)) {
@@ -1304,7 +1399,6 @@ function formatPricing(config) {
1304
1399
 
1305
1400
  // src/server/token-pricing.ts
1306
1401
  var import_crypto3 = require("crypto");
1307
- var import_tiktoken = require("tiktoken");
1308
1402
 
1309
1403
  // src/server/model-registry.ts
1310
1404
  var STANDARD_PARAMS = {
@@ -1881,17 +1975,30 @@ var MODEL_PRICING_MAP = Object.fromEntries(
1881
1975
  );
1882
1976
 
1883
1977
  // src/server/token-pricing.ts
1978
+ var _tiktoken = null;
1979
+ async function loadTiktoken() {
1980
+ if (_tiktoken) return _tiktoken;
1981
+ try {
1982
+ _tiktoken = await import("tiktoken");
1983
+ return _tiktoken;
1984
+ } catch {
1985
+ throw new Error(
1986
+ 'Token pricing requires the "tiktoken" package. Install with: npm install tiktoken'
1987
+ );
1988
+ }
1989
+ }
1884
1990
  var MODEL_PRICING = MODEL_PRICING_MAP;
1885
1991
  var DEFAULT_MODEL = "gpt-4o-mini";
1886
- function getEncodingForModel(model) {
1992
+ async function getEncodingForModel(model) {
1993
+ const tiktoken = await loadTiktoken();
1887
1994
  try {
1888
- return (0, import_tiktoken.encoding_for_model)(model);
1995
+ return tiktoken.encoding_for_model(model);
1889
1996
  } catch {
1890
- return (0, import_tiktoken.get_encoding)("cl100k_base");
1997
+ return tiktoken.get_encoding("cl100k_base");
1891
1998
  }
1892
1999
  }
1893
- function countTokens(text, model = DEFAULT_MODEL) {
1894
- const encoding = getEncodingForModel(model);
2000
+ async function countTokens(text, model = DEFAULT_MODEL) {
2001
+ const encoding = await getEncodingForModel(model);
1895
2002
  try {
1896
2003
  const tokens = encoding.encode(text);
1897
2004
  return tokens.length;
@@ -1925,17 +2032,17 @@ function createTokenPricing(config = {}) {
1925
2032
  decimals: config.decimals ?? 6
1926
2033
  };
1927
2034
  const { minUsd, maxUsd, decimals } = fullConfig;
1928
- function countTokensInternal(input) {
2035
+ async function countTokensInternal(input) {
1929
2036
  if (customTokenizer) {
1930
2037
  return customTokenizer(input);
1931
2038
  }
1932
2039
  return countTokens(input, model);
1933
2040
  }
1934
- function calculate(input, systemPrompt) {
2041
+ async function calculate(input, systemPrompt) {
1935
2042
  const fullInput = systemPrompt ? `${systemPrompt}
1936
2043
 
1937
2044
  ${input}` : input;
1938
- const inputTokens = countTokensInternal(fullInput);
2045
+ const inputTokens = await countTokensInternal(fullInput);
1939
2046
  let usdAmount = inputTokens / 1e6 * modelInfo.input;
1940
2047
  usdAmount = Math.max(usdAmount, minUsd);
1941
2048
  usdAmount = Math.min(usdAmount, maxUsd);
@@ -1954,9 +2061,9 @@ ${input}` : input;
1954
2061
  quoteHash
1955
2062
  };
1956
2063
  }
1957
- function validateQuote(input, quoteHash) {
2064
+ async function validateQuote(input, quoteHash) {
1958
2065
  if (!quoteHash) return false;
1959
- const inputTokens = countTokensInternal(input);
2066
+ const inputTokens = await countTokensInternal(input);
1960
2067
  const expectedHash = generateQuoteHash(input, model, modelInfo.input, inputTokens);
1961
2068
  return expectedHash === quoteHash;
1962
2069
  }
@@ -1991,97 +2098,6 @@ function formatTokenPricing(model = DEFAULT_MODEL) {
1991
2098
  return `$${pricing.input.toFixed(2)} per 1M tokens (${actualModel})`;
1992
2099
  }
1993
2100
 
1994
- // src/server/stripe-payto.ts
1995
- var STRIPE_NETWORK_KEYS = {
1996
- "base": "base",
1997
- "base-sepolia": "base_sepolia"
1998
- };
1999
- var CAIP2_NETWORKS = {
2000
- "base": "eip155:8453",
2001
- "base-sepolia": "eip155:84532"
2002
- };
2003
- var USDC_DECIMALS3 = 6;
2004
- function stripePayTo(secretKeyOrConfig) {
2005
- const config = typeof secretKeyOrConfig === "string" ? { secretKey: secretKeyOrConfig } : secretKeyOrConfig;
2006
- const networkName = config.network ?? "base";
2007
- const stripeNetworkKey = STRIPE_NETWORK_KEYS[networkName] ?? "base";
2008
- const caip2Network = CAIP2_NETWORKS[networkName] ?? "eip155:8453";
2009
- const apiVersion = config.apiVersion ?? "2026-01-28.clover";
2010
- let stripeClient = null;
2011
- async function getStripe() {
2012
- if (stripeClient) return stripeClient;
2013
- try {
2014
- const { default: Stripe } = await import("stripe");
2015
- stripeClient = new Stripe(config.secretKey, {
2016
- apiVersion,
2017
- appInfo: {
2018
- name: "@dexterai/x402",
2019
- url: "https://dexter.cash/sdk"
2020
- }
2021
- });
2022
- return stripeClient;
2023
- } catch {
2024
- throw new Error(
2025
- 'The "stripe" package is required for stripePayTo(). Install it with: npm install stripe'
2026
- );
2027
- }
2028
- }
2029
- const provider = async (context) => {
2030
- if (context.paymentHeader) {
2031
- try {
2032
- const decoded = JSON.parse(
2033
- Buffer.from(context.paymentHeader, "base64").toString()
2034
- );
2035
- const toAddress = decoded.payload?.authorization?.to;
2036
- if (toAddress && typeof toAddress === "string") {
2037
- return toAddress;
2038
- }
2039
- const acceptedPayTo = decoded.accepted?.payTo;
2040
- if (acceptedPayTo && typeof acceptedPayTo === "string") {
2041
- return acceptedPayTo;
2042
- }
2043
- } catch {
2044
- }
2045
- throw new Error(
2046
- "Could not extract deposit address from payment header. Ensure the client is sending a valid x402 PAYMENT-SIGNATURE."
2047
- );
2048
- }
2049
- const stripe = await getStripe();
2050
- const amountAtomic = context.amountAtomic ? parseInt(context.amountAtomic, 10) : 1e4;
2051
- const amountInCents = Math.max(1, Math.round(amountAtomic / Math.pow(10, USDC_DECIMALS3 - 2)));
2052
- const paymentIntent = await stripe.paymentIntents.create({
2053
- amount: amountInCents,
2054
- currency: "usd",
2055
- payment_method_types: ["crypto"],
2056
- payment_method_data: { type: "crypto" },
2057
- payment_method_options: {
2058
- crypto: { mode: "custom" }
2059
- },
2060
- confirm: true
2061
- });
2062
- const nextAction = paymentIntent.next_action;
2063
- if (!nextAction?.crypto_collect_deposit_details) {
2064
- throw new Error(
2065
- "Stripe PaymentIntent did not return crypto deposit details. Ensure your Stripe account has crypto payins enabled: https://support.stripe.com/questions/get-started-with-pay-with-crypto"
2066
- );
2067
- }
2068
- const depositDetails = nextAction.crypto_collect_deposit_details;
2069
- const payToAddress = depositDetails.deposit_addresses?.[stripeNetworkKey]?.address;
2070
- if (!payToAddress) {
2071
- throw new Error(
2072
- `No deposit address found for network "${stripeNetworkKey}". Available networks: ${Object.keys(depositDetails.deposit_addresses || {}).join(", ")}`
2073
- );
2074
- }
2075
- return payToAddress;
2076
- };
2077
- provider._x402Defaults = {
2078
- network: caip2Network,
2079
- facilitatorUrl: "https://x402.dexter.cash"
2080
- };
2081
- provider._stripeNetwork = caip2Network;
2082
- return provider;
2083
- }
2084
-
2085
2101
  // src/server/index.ts
2086
2102
  var import_x402_ads_types = require("@dexterai/x402-ads-types");
2087
2103
  // Annotate the CommonJS export names for ESM import in node: