@x402/axios 2.1.0 → 2.3.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.
@@ -1,4 +1,4 @@
1
- import { x402Client, x402ClientConfig } from '@x402/core/client';
1
+ import { x402Client, x402HTTPClient, x402ClientConfig } from '@x402/core/client';
2
2
  export { PaymentPolicy, SchemeRegistration, SelectPaymentRequirements, x402Client, x402ClientConfig, x402HTTPClient } from '@x402/core/client';
3
3
  import { AxiosInstance } from 'axios';
4
4
  export { decodePaymentResponseHeader } from '@x402/core/http';
@@ -40,7 +40,7 @@ export { Network, PaymentPayload, PaymentRequired, PaymentRequirements, SchemeNe
40
40
  * @throws {Error} If a payment has already been attempted for this request
41
41
  * @throws {Error} If there's an error creating the payment header
42
42
  */
43
- declare function wrapAxiosWithPayment(axiosInstance: AxiosInstance, client: x402Client): AxiosInstance;
43
+ declare function wrapAxiosWithPayment(axiosInstance: AxiosInstance, client: x402Client | x402HTTPClient): AxiosInstance;
44
44
  /**
45
45
  * Wraps an Axios instance with x402 payment handling using a configuration object.
46
46
  *
package/dist/cjs/index.js CHANGED
@@ -31,7 +31,7 @@ var import_client = require("@x402/core/client");
31
31
  var import_client2 = require("@x402/core/client");
32
32
  var import_http = require("@x402/core/http");
33
33
  function wrapAxiosWithPayment(axiosInstance, client) {
34
- const httpClient = new import_client.x402HTTPClient(client);
34
+ const httpClient = client instanceof import_client.x402HTTPClient ? client : new import_client.x402HTTPClient(client);
35
35
  axiosInstance.interceptors.response.use(
36
36
  (response) => response,
37
37
  async (error) => {
@@ -62,6 +62,18 @@ function wrapAxiosWithPayment(axiosInstance, client) {
62
62
  )
63
63
  );
64
64
  }
65
+ const hookHeaders = await httpClient.handlePaymentRequired(paymentRequired);
66
+ if (hookHeaders) {
67
+ const hookConfig = { ...originalConfig };
68
+ hookConfig.headers = { ...originalConfig.headers };
69
+ Object.entries(hookHeaders).forEach(([key, value]) => {
70
+ hookConfig.headers.set(key, value);
71
+ });
72
+ const hookResponse = await axiosInstance.request(hookConfig);
73
+ if (hookResponse.status !== 402) {
74
+ return hookResponse;
75
+ }
76
+ }
65
77
  let paymentPayload;
66
78
  try {
67
79
  paymentPayload = await client.createPaymentPayload(paymentRequired);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import { x402Client, x402ClientConfig, x402HTTPClient } from \"@x402/core/client\";\nimport { type PaymentRequired } from \"@x402/core/types\";\nimport type { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from \"axios\";\n\n/**\n * Wraps an Axios instance with x402 payment handling.\n *\n * This function adds an interceptor to automatically handle 402 Payment Required responses\n * by creating and sending payment headers. It will:\n * 1. Intercept 402 responses\n * 2. Parse the payment requirements\n * 3. Create a payment header using the configured x402HTTPClient\n * 4. Retry the request with the payment header\n *\n * @param axiosInstance - The Axios instance to wrap\n * @param client - Configured x402Client instance for handling payments\n * @returns The wrapped Axios instance that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import axios from 'axios';\n * import { wrapAxiosWithPayment, x402Client } from '@x402/axios';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { privateKeyToAccount } from 'viem/accounts';\n *\n * const account = privateKeyToAccount('0x...');\n * const client = new x402Client()\n * .register('eip155:*', new ExactEvmScheme(account));\n *\n * const api = wrapAxiosWithPayment(axios.create(), client);\n *\n * // Make a request that may require payment\n * const response = await api.get('https://api.example.com/paid-endpoint');\n * ```\n *\n * @throws {Error} If no schemes are provided\n * @throws {Error} If the request configuration is missing\n * @throws {Error} If a payment has already been attempted for this request\n * @throws {Error} If there's an error creating the payment header\n */\nexport function wrapAxiosWithPayment(\n axiosInstance: AxiosInstance,\n client: x402Client,\n): AxiosInstance {\n const httpClient = new x402HTTPClient(client);\n\n axiosInstance.interceptors.response.use(\n response => response,\n async (error: AxiosError) => {\n if (!error.response || error.response.status !== 402) {\n return Promise.reject(error);\n }\n\n const originalConfig = error.config;\n if (!originalConfig || !originalConfig.headers) {\n return Promise.reject(new Error(\"Missing axios request configuration\"));\n }\n\n // Check if this is already a retry to prevent infinite loops\n if (\n (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry\n ) {\n return Promise.reject(error);\n }\n\n try {\n // Parse payment requirements from response\n let paymentRequired: PaymentRequired;\n try {\n const response = error.response!; // Already validated above\n\n // Create getHeader function for case-insensitive header lookup\n const getHeader = (name: string) => {\n const value = response.headers[name] ?? response.headers[name.toLowerCase()];\n return typeof value === \"string\" ? value : undefined;\n };\n\n // Try to get from headers first (v2), then from body (v1)\n const body = response.data as PaymentRequired | undefined;\n\n paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);\n } catch (parseError) {\n return Promise.reject(\n new Error(\n `Failed to parse payment requirements: ${parseError instanceof Error ? parseError.message : \"Unknown error\"}`,\n ),\n );\n }\n\n // Create payment payload\n let paymentPayload;\n try {\n paymentPayload = await client.createPaymentPayload(paymentRequired);\n } catch (paymentError) {\n return Promise.reject(\n new Error(\n `Failed to create payment payload: ${paymentError instanceof Error ? paymentError.message : \"Unknown error\"}`,\n ),\n );\n }\n\n // Encode payment header\n const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);\n\n // Mark this as a retry\n (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry =\n true;\n\n // Add payment headers to the request\n Object.entries(paymentHeaders).forEach(([key, value]) => {\n originalConfig.headers.set(key, value);\n });\n\n // Add CORS header to expose payment response\n originalConfig.headers.set(\n \"Access-Control-Expose-Headers\",\n \"PAYMENT-RESPONSE,X-PAYMENT-RESPONSE\",\n );\n\n // Retry the request with payment\n const secondResponse = await axiosInstance.request(originalConfig);\n return secondResponse;\n } catch (retryError) {\n return Promise.reject(retryError);\n }\n },\n );\n\n return axiosInstance;\n}\n\n/**\n * Wraps an Axios instance with x402 payment handling using a configuration object.\n *\n * @param axiosInstance - The Axios instance to wrap\n * @param config - Configuration options including scheme registrations and selectors\n * @returns The wrapped Axios instance that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import axios from 'axios';\n * import { wrapAxiosWithPaymentFromConfig } from '@x402/axios';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { privateKeyToAccount } from 'viem/accounts';\n *\n * const account = privateKeyToAccount('0x...');\n *\n * const api = wrapAxiosWithPaymentFromConfig(axios.create(), {\n * schemes: [\n * { network: 'eip155:*', client: new ExactEvmScheme(account) }\n * ]\n * });\n *\n * const response = await api.get('https://api.example.com/paid-endpoint');\n * ```\n */\nexport function wrapAxiosWithPaymentFromConfig(\n axiosInstance: AxiosInstance,\n config: x402ClientConfig,\n): AxiosInstance {\n const client = x402Client.fromConfig(config);\n return wrapAxiosWithPayment(axiosInstance, client);\n}\n\n// Re-export types and utilities for convenience\nexport { x402Client, x402HTTPClient } from \"@x402/core/client\";\nexport type {\n PaymentPolicy,\n SchemeRegistration,\n SelectPaymentRequirements,\n x402ClientConfig,\n} from \"@x402/core/client\";\nexport { decodePaymentResponseHeader } from \"@x402/core/http\";\nexport type {\n Network,\n PaymentPayload,\n PaymentRequired,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA6D;AAqK7D,IAAAA,iBAA2C;AAO3C,kBAA4C;AApIrC,SAAS,qBACd,eACA,QACe;AACf,QAAM,aAAa,IAAI,6BAAe,MAAM;AAE5C,gBAAc,aAAa,SAAS;AAAA,IAClC,cAAY;AAAA,IACZ,OAAO,UAAsB;AAC3B,UAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,KAAK;AACpD,eAAO,QAAQ,OAAO,KAAK;AAAA,MAC7B;AAEA,YAAM,iBAAiB,MAAM;AAC7B,UAAI,CAAC,kBAAkB,CAAC,eAAe,SAAS;AAC9C,eAAO,QAAQ,OAAO,IAAI,MAAM,qCAAqC,CAAC;AAAA,MACxE;AAGA,UACG,eAA2E,cAC5E;AACA,eAAO,QAAQ,OAAO,KAAK;AAAA,MAC7B;AAEA,UAAI;AAEF,YAAI;AACJ,YAAI;AACF,gBAAM,WAAW,MAAM;AAGvB,gBAAM,YAAY,CAAC,SAAiB;AAClC,kBAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK,SAAS,QAAQ,KAAK,YAAY,CAAC;AAC3E,mBAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,UAC7C;AAGA,gBAAM,OAAO,SAAS;AAEtB,4BAAkB,WAAW,2BAA2B,WAAW,IAAI;AAAA,QACzE,SAAS,YAAY;AACnB,iBAAO,QAAQ;AAAA,YACb,IAAI;AAAA,cACF,yCAAyC,sBAAsB,QAAQ,WAAW,UAAU,eAAe;AAAA,YAC7G;AAAA,UACF;AAAA,QACF;AAGA,YAAI;AACJ,YAAI;AACF,2BAAiB,MAAM,OAAO,qBAAqB,eAAe;AAAA,QACpE,SAAS,cAAc;AACrB,iBAAO,QAAQ;AAAA,YACb,IAAI;AAAA,cACF,qCAAqC,wBAAwB,QAAQ,aAAa,UAAU,eAAe;AAAA,YAC7G;AAAA,UACF;AAAA,QACF;AAGA,cAAM,iBAAiB,WAAW,6BAA6B,cAAc;AAG7E,QAAC,eAA2E,eAC1E;AAGF,eAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACvD,yBAAe,QAAQ,IAAI,KAAK,KAAK;AAAA,QACvC,CAAC;AAGD,uBAAe,QAAQ;AAAA,UACrB;AAAA,UACA;AAAA,QACF;AAGA,cAAM,iBAAiB,MAAM,cAAc,QAAQ,cAAc;AACjE,eAAO;AAAA,MACT,SAAS,YAAY;AACnB,eAAO,QAAQ,OAAO,UAAU;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AA2BO,SAAS,+BACd,eACA,QACe;AACf,QAAM,SAAS,yBAAW,WAAW,MAAM;AAC3C,SAAO,qBAAqB,eAAe,MAAM;AACnD;","names":["import_client"]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import { x402Client, x402ClientConfig, x402HTTPClient } from \"@x402/core/client\";\nimport { type PaymentRequired } from \"@x402/core/types\";\nimport type { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from \"axios\";\n\n/**\n * Wraps an Axios instance with x402 payment handling.\n *\n * This function adds an interceptor to automatically handle 402 Payment Required responses\n * by creating and sending payment headers. It will:\n * 1. Intercept 402 responses\n * 2. Parse the payment requirements\n * 3. Create a payment header using the configured x402HTTPClient\n * 4. Retry the request with the payment header\n *\n * @param axiosInstance - The Axios instance to wrap\n * @param client - Configured x402Client instance for handling payments\n * @returns The wrapped Axios instance that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import axios from 'axios';\n * import { wrapAxiosWithPayment, x402Client } from '@x402/axios';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { privateKeyToAccount } from 'viem/accounts';\n *\n * const account = privateKeyToAccount('0x...');\n * const client = new x402Client()\n * .register('eip155:*', new ExactEvmScheme(account));\n *\n * const api = wrapAxiosWithPayment(axios.create(), client);\n *\n * // Make a request that may require payment\n * const response = await api.get('https://api.example.com/paid-endpoint');\n * ```\n *\n * @throws {Error} If no schemes are provided\n * @throws {Error} If the request configuration is missing\n * @throws {Error} If a payment has already been attempted for this request\n * @throws {Error} If there's an error creating the payment header\n */\nexport function wrapAxiosWithPayment(\n axiosInstance: AxiosInstance,\n client: x402Client | x402HTTPClient,\n): AxiosInstance {\n const httpClient = client instanceof x402HTTPClient ? client : new x402HTTPClient(client);\n\n axiosInstance.interceptors.response.use(\n response => response,\n async (error: AxiosError) => {\n if (!error.response || error.response.status !== 402) {\n return Promise.reject(error);\n }\n\n const originalConfig = error.config;\n if (!originalConfig || !originalConfig.headers) {\n return Promise.reject(new Error(\"Missing axios request configuration\"));\n }\n\n // Check if this is already a retry to prevent infinite loops\n if (\n (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry\n ) {\n return Promise.reject(error);\n }\n\n try {\n // Parse payment requirements from response\n let paymentRequired: PaymentRequired;\n try {\n const response = error.response!; // Already validated above\n\n // Create getHeader function for case-insensitive header lookup\n const getHeader = (name: string) => {\n const value = response.headers[name] ?? response.headers[name.toLowerCase()];\n return typeof value === \"string\" ? value : undefined;\n };\n\n // Try to get from headers first (v2), then from body (v1)\n const body = response.data as PaymentRequired | undefined;\n\n paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);\n } catch (parseError) {\n return Promise.reject(\n new Error(\n `Failed to parse payment requirements: ${parseError instanceof Error ? parseError.message : \"Unknown error\"}`,\n ),\n );\n }\n\n // Run payment required hooks\n const hookHeaders = await httpClient.handlePaymentRequired(paymentRequired);\n if (hookHeaders) {\n const hookConfig = { ...originalConfig };\n hookConfig.headers = { ...originalConfig.headers } as typeof originalConfig.headers;\n Object.entries(hookHeaders).forEach(([key, value]) => {\n hookConfig.headers.set(key, value);\n });\n const hookResponse = await axiosInstance.request(hookConfig);\n if (hookResponse.status !== 402) {\n return hookResponse; // Hook succeeded\n }\n // Hook's retry got 402, fall through to payment\n }\n\n // Create payment payload\n let paymentPayload;\n try {\n paymentPayload = await client.createPaymentPayload(paymentRequired);\n } catch (paymentError) {\n return Promise.reject(\n new Error(\n `Failed to create payment payload: ${paymentError instanceof Error ? paymentError.message : \"Unknown error\"}`,\n ),\n );\n }\n\n // Encode payment header\n const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);\n\n // Mark this as a retry\n (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry =\n true;\n\n // Add payment headers to the request\n Object.entries(paymentHeaders).forEach(([key, value]) => {\n originalConfig.headers.set(key, value);\n });\n\n // Add CORS header to expose payment response\n originalConfig.headers.set(\n \"Access-Control-Expose-Headers\",\n \"PAYMENT-RESPONSE,X-PAYMENT-RESPONSE\",\n );\n\n // Retry the request with payment\n const secondResponse = await axiosInstance.request(originalConfig);\n return secondResponse;\n } catch (retryError) {\n return Promise.reject(retryError);\n }\n },\n );\n\n return axiosInstance;\n}\n\n/**\n * Wraps an Axios instance with x402 payment handling using a configuration object.\n *\n * @param axiosInstance - The Axios instance to wrap\n * @param config - Configuration options including scheme registrations and selectors\n * @returns The wrapped Axios instance that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import axios from 'axios';\n * import { wrapAxiosWithPaymentFromConfig } from '@x402/axios';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { privateKeyToAccount } from 'viem/accounts';\n *\n * const account = privateKeyToAccount('0x...');\n *\n * const api = wrapAxiosWithPaymentFromConfig(axios.create(), {\n * schemes: [\n * { network: 'eip155:*', client: new ExactEvmScheme(account) }\n * ]\n * });\n *\n * const response = await api.get('https://api.example.com/paid-endpoint');\n * ```\n */\nexport function wrapAxiosWithPaymentFromConfig(\n axiosInstance: AxiosInstance,\n config: x402ClientConfig,\n): AxiosInstance {\n const client = x402Client.fromConfig(config);\n return wrapAxiosWithPayment(axiosInstance, client);\n}\n\n// Re-export types and utilities for convenience\nexport { x402Client, x402HTTPClient } from \"@x402/core/client\";\nexport type {\n PaymentPolicy,\n SchemeRegistration,\n SelectPaymentRequirements,\n x402ClientConfig,\n} from \"@x402/core/client\";\nexport { decodePaymentResponseHeader } from \"@x402/core/http\";\nexport type {\n Network,\n PaymentPayload,\n PaymentRequired,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA6D;AAoL7D,IAAAA,iBAA2C;AAO3C,kBAA4C;AAnJrC,SAAS,qBACd,eACA,QACe;AACf,QAAM,aAAa,kBAAkB,+BAAiB,SAAS,IAAI,6BAAe,MAAM;AAExF,gBAAc,aAAa,SAAS;AAAA,IAClC,cAAY;AAAA,IACZ,OAAO,UAAsB;AAC3B,UAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,KAAK;AACpD,eAAO,QAAQ,OAAO,KAAK;AAAA,MAC7B;AAEA,YAAM,iBAAiB,MAAM;AAC7B,UAAI,CAAC,kBAAkB,CAAC,eAAe,SAAS;AAC9C,eAAO,QAAQ,OAAO,IAAI,MAAM,qCAAqC,CAAC;AAAA,MACxE;AAGA,UACG,eAA2E,cAC5E;AACA,eAAO,QAAQ,OAAO,KAAK;AAAA,MAC7B;AAEA,UAAI;AAEF,YAAI;AACJ,YAAI;AACF,gBAAM,WAAW,MAAM;AAGvB,gBAAM,YAAY,CAAC,SAAiB;AAClC,kBAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK,SAAS,QAAQ,KAAK,YAAY,CAAC;AAC3E,mBAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,UAC7C;AAGA,gBAAM,OAAO,SAAS;AAEtB,4BAAkB,WAAW,2BAA2B,WAAW,IAAI;AAAA,QACzE,SAAS,YAAY;AACnB,iBAAO,QAAQ;AAAA,YACb,IAAI;AAAA,cACF,yCAAyC,sBAAsB,QAAQ,WAAW,UAAU,eAAe;AAAA,YAC7G;AAAA,UACF;AAAA,QACF;AAGA,cAAM,cAAc,MAAM,WAAW,sBAAsB,eAAe;AAC1E,YAAI,aAAa;AACf,gBAAM,aAAa,EAAE,GAAG,eAAe;AACvC,qBAAW,UAAU,EAAE,GAAG,eAAe,QAAQ;AACjD,iBAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,uBAAW,QAAQ,IAAI,KAAK,KAAK;AAAA,UACnC,CAAC;AACD,gBAAM,eAAe,MAAM,cAAc,QAAQ,UAAU;AAC3D,cAAI,aAAa,WAAW,KAAK;AAC/B,mBAAO;AAAA,UACT;AAAA,QAEF;AAGA,YAAI;AACJ,YAAI;AACF,2BAAiB,MAAM,OAAO,qBAAqB,eAAe;AAAA,QACpE,SAAS,cAAc;AACrB,iBAAO,QAAQ;AAAA,YACb,IAAI;AAAA,cACF,qCAAqC,wBAAwB,QAAQ,aAAa,UAAU,eAAe;AAAA,YAC7G;AAAA,UACF;AAAA,QACF;AAGA,cAAM,iBAAiB,WAAW,6BAA6B,cAAc;AAG7E,QAAC,eAA2E,eAC1E;AAGF,eAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACvD,yBAAe,QAAQ,IAAI,KAAK,KAAK;AAAA,QACvC,CAAC;AAGD,uBAAe,QAAQ;AAAA,UACrB;AAAA,UACA;AAAA,QACF;AAGA,cAAM,iBAAiB,MAAM,cAAc,QAAQ,cAAc;AACjE,eAAO;AAAA,MACT,SAAS,YAAY;AACnB,eAAO,QAAQ,OAAO,UAAU;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AA2BO,SAAS,+BACd,eACA,QACe;AACf,QAAM,SAAS,yBAAW,WAAW,MAAM;AAC3C,SAAO,qBAAqB,eAAe,MAAM;AACnD;","names":["import_client"]}
@@ -1,4 +1,4 @@
1
- import { x402Client, x402ClientConfig } from '@x402/core/client';
1
+ import { x402Client, x402HTTPClient, x402ClientConfig } from '@x402/core/client';
2
2
  export { PaymentPolicy, SchemeRegistration, SelectPaymentRequirements, x402Client, x402ClientConfig, x402HTTPClient } from '@x402/core/client';
3
3
  import { AxiosInstance } from 'axios';
4
4
  export { decodePaymentResponseHeader } from '@x402/core/http';
@@ -40,7 +40,7 @@ export { Network, PaymentPayload, PaymentRequired, PaymentRequirements, SchemeNe
40
40
  * @throws {Error} If a payment has already been attempted for this request
41
41
  * @throws {Error} If there's an error creating the payment header
42
42
  */
43
- declare function wrapAxiosWithPayment(axiosInstance: AxiosInstance, client: x402Client): AxiosInstance;
43
+ declare function wrapAxiosWithPayment(axiosInstance: AxiosInstance, client: x402Client | x402HTTPClient): AxiosInstance;
44
44
  /**
45
45
  * Wraps an Axios instance with x402 payment handling using a configuration object.
46
46
  *
@@ -3,7 +3,7 @@ import { x402Client, x402HTTPClient } from "@x402/core/client";
3
3
  import { x402Client as x402Client2, x402HTTPClient as x402HTTPClient2 } from "@x402/core/client";
4
4
  import { decodePaymentResponseHeader } from "@x402/core/http";
5
5
  function wrapAxiosWithPayment(axiosInstance, client) {
6
- const httpClient = new x402HTTPClient(client);
6
+ const httpClient = client instanceof x402HTTPClient ? client : new x402HTTPClient(client);
7
7
  axiosInstance.interceptors.response.use(
8
8
  (response) => response,
9
9
  async (error) => {
@@ -34,6 +34,18 @@ function wrapAxiosWithPayment(axiosInstance, client) {
34
34
  )
35
35
  );
36
36
  }
37
+ const hookHeaders = await httpClient.handlePaymentRequired(paymentRequired);
38
+ if (hookHeaders) {
39
+ const hookConfig = { ...originalConfig };
40
+ hookConfig.headers = { ...originalConfig.headers };
41
+ Object.entries(hookHeaders).forEach(([key, value]) => {
42
+ hookConfig.headers.set(key, value);
43
+ });
44
+ const hookResponse = await axiosInstance.request(hookConfig);
45
+ if (hookResponse.status !== 402) {
46
+ return hookResponse;
47
+ }
48
+ }
37
49
  let paymentPayload;
38
50
  try {
39
51
  paymentPayload = await client.createPaymentPayload(paymentRequired);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import { x402Client, x402ClientConfig, x402HTTPClient } from \"@x402/core/client\";\nimport { type PaymentRequired } from \"@x402/core/types\";\nimport type { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from \"axios\";\n\n/**\n * Wraps an Axios instance with x402 payment handling.\n *\n * This function adds an interceptor to automatically handle 402 Payment Required responses\n * by creating and sending payment headers. It will:\n * 1. Intercept 402 responses\n * 2. Parse the payment requirements\n * 3. Create a payment header using the configured x402HTTPClient\n * 4. Retry the request with the payment header\n *\n * @param axiosInstance - The Axios instance to wrap\n * @param client - Configured x402Client instance for handling payments\n * @returns The wrapped Axios instance that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import axios from 'axios';\n * import { wrapAxiosWithPayment, x402Client } from '@x402/axios';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { privateKeyToAccount } from 'viem/accounts';\n *\n * const account = privateKeyToAccount('0x...');\n * const client = new x402Client()\n * .register('eip155:*', new ExactEvmScheme(account));\n *\n * const api = wrapAxiosWithPayment(axios.create(), client);\n *\n * // Make a request that may require payment\n * const response = await api.get('https://api.example.com/paid-endpoint');\n * ```\n *\n * @throws {Error} If no schemes are provided\n * @throws {Error} If the request configuration is missing\n * @throws {Error} If a payment has already been attempted for this request\n * @throws {Error} If there's an error creating the payment header\n */\nexport function wrapAxiosWithPayment(\n axiosInstance: AxiosInstance,\n client: x402Client,\n): AxiosInstance {\n const httpClient = new x402HTTPClient(client);\n\n axiosInstance.interceptors.response.use(\n response => response,\n async (error: AxiosError) => {\n if (!error.response || error.response.status !== 402) {\n return Promise.reject(error);\n }\n\n const originalConfig = error.config;\n if (!originalConfig || !originalConfig.headers) {\n return Promise.reject(new Error(\"Missing axios request configuration\"));\n }\n\n // Check if this is already a retry to prevent infinite loops\n if (\n (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry\n ) {\n return Promise.reject(error);\n }\n\n try {\n // Parse payment requirements from response\n let paymentRequired: PaymentRequired;\n try {\n const response = error.response!; // Already validated above\n\n // Create getHeader function for case-insensitive header lookup\n const getHeader = (name: string) => {\n const value = response.headers[name] ?? response.headers[name.toLowerCase()];\n return typeof value === \"string\" ? value : undefined;\n };\n\n // Try to get from headers first (v2), then from body (v1)\n const body = response.data as PaymentRequired | undefined;\n\n paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);\n } catch (parseError) {\n return Promise.reject(\n new Error(\n `Failed to parse payment requirements: ${parseError instanceof Error ? parseError.message : \"Unknown error\"}`,\n ),\n );\n }\n\n // Create payment payload\n let paymentPayload;\n try {\n paymentPayload = await client.createPaymentPayload(paymentRequired);\n } catch (paymentError) {\n return Promise.reject(\n new Error(\n `Failed to create payment payload: ${paymentError instanceof Error ? paymentError.message : \"Unknown error\"}`,\n ),\n );\n }\n\n // Encode payment header\n const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);\n\n // Mark this as a retry\n (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry =\n true;\n\n // Add payment headers to the request\n Object.entries(paymentHeaders).forEach(([key, value]) => {\n originalConfig.headers.set(key, value);\n });\n\n // Add CORS header to expose payment response\n originalConfig.headers.set(\n \"Access-Control-Expose-Headers\",\n \"PAYMENT-RESPONSE,X-PAYMENT-RESPONSE\",\n );\n\n // Retry the request with payment\n const secondResponse = await axiosInstance.request(originalConfig);\n return secondResponse;\n } catch (retryError) {\n return Promise.reject(retryError);\n }\n },\n );\n\n return axiosInstance;\n}\n\n/**\n * Wraps an Axios instance with x402 payment handling using a configuration object.\n *\n * @param axiosInstance - The Axios instance to wrap\n * @param config - Configuration options including scheme registrations and selectors\n * @returns The wrapped Axios instance that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import axios from 'axios';\n * import { wrapAxiosWithPaymentFromConfig } from '@x402/axios';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { privateKeyToAccount } from 'viem/accounts';\n *\n * const account = privateKeyToAccount('0x...');\n *\n * const api = wrapAxiosWithPaymentFromConfig(axios.create(), {\n * schemes: [\n * { network: 'eip155:*', client: new ExactEvmScheme(account) }\n * ]\n * });\n *\n * const response = await api.get('https://api.example.com/paid-endpoint');\n * ```\n */\nexport function wrapAxiosWithPaymentFromConfig(\n axiosInstance: AxiosInstance,\n config: x402ClientConfig,\n): AxiosInstance {\n const client = x402Client.fromConfig(config);\n return wrapAxiosWithPayment(axiosInstance, client);\n}\n\n// Re-export types and utilities for convenience\nexport { x402Client, x402HTTPClient } from \"@x402/core/client\";\nexport type {\n PaymentPolicy,\n SchemeRegistration,\n SelectPaymentRequirements,\n x402ClientConfig,\n} from \"@x402/core/client\";\nexport { decodePaymentResponseHeader } from \"@x402/core/http\";\nexport type {\n Network,\n PaymentPayload,\n PaymentRequired,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\n"],"mappings":";AAAA,SAAS,YAA8B,sBAAsB;AAqK7D,SAAS,cAAAA,aAAY,kBAAAC,uBAAsB;AAO3C,SAAS,mCAAmC;AApIrC,SAAS,qBACd,eACA,QACe;AACf,QAAM,aAAa,IAAI,eAAe,MAAM;AAE5C,gBAAc,aAAa,SAAS;AAAA,IAClC,cAAY;AAAA,IACZ,OAAO,UAAsB;AAC3B,UAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,KAAK;AACpD,eAAO,QAAQ,OAAO,KAAK;AAAA,MAC7B;AAEA,YAAM,iBAAiB,MAAM;AAC7B,UAAI,CAAC,kBAAkB,CAAC,eAAe,SAAS;AAC9C,eAAO,QAAQ,OAAO,IAAI,MAAM,qCAAqC,CAAC;AAAA,MACxE;AAGA,UACG,eAA2E,cAC5E;AACA,eAAO,QAAQ,OAAO,KAAK;AAAA,MAC7B;AAEA,UAAI;AAEF,YAAI;AACJ,YAAI;AACF,gBAAM,WAAW,MAAM;AAGvB,gBAAM,YAAY,CAAC,SAAiB;AAClC,kBAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK,SAAS,QAAQ,KAAK,YAAY,CAAC;AAC3E,mBAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,UAC7C;AAGA,gBAAM,OAAO,SAAS;AAEtB,4BAAkB,WAAW,2BAA2B,WAAW,IAAI;AAAA,QACzE,SAAS,YAAY;AACnB,iBAAO,QAAQ;AAAA,YACb,IAAI;AAAA,cACF,yCAAyC,sBAAsB,QAAQ,WAAW,UAAU,eAAe;AAAA,YAC7G;AAAA,UACF;AAAA,QACF;AAGA,YAAI;AACJ,YAAI;AACF,2BAAiB,MAAM,OAAO,qBAAqB,eAAe;AAAA,QACpE,SAAS,cAAc;AACrB,iBAAO,QAAQ;AAAA,YACb,IAAI;AAAA,cACF,qCAAqC,wBAAwB,QAAQ,aAAa,UAAU,eAAe;AAAA,YAC7G;AAAA,UACF;AAAA,QACF;AAGA,cAAM,iBAAiB,WAAW,6BAA6B,cAAc;AAG7E,QAAC,eAA2E,eAC1E;AAGF,eAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACvD,yBAAe,QAAQ,IAAI,KAAK,KAAK;AAAA,QACvC,CAAC;AAGD,uBAAe,QAAQ;AAAA,UACrB;AAAA,UACA;AAAA,QACF;AAGA,cAAM,iBAAiB,MAAM,cAAc,QAAQ,cAAc;AACjE,eAAO;AAAA,MACT,SAAS,YAAY;AACnB,eAAO,QAAQ,OAAO,UAAU;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AA2BO,SAAS,+BACd,eACA,QACe;AACf,QAAM,SAAS,WAAW,WAAW,MAAM;AAC3C,SAAO,qBAAqB,eAAe,MAAM;AACnD;","names":["x402Client","x402HTTPClient"]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import { x402Client, x402ClientConfig, x402HTTPClient } from \"@x402/core/client\";\nimport { type PaymentRequired } from \"@x402/core/types\";\nimport type { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from \"axios\";\n\n/**\n * Wraps an Axios instance with x402 payment handling.\n *\n * This function adds an interceptor to automatically handle 402 Payment Required responses\n * by creating and sending payment headers. It will:\n * 1. Intercept 402 responses\n * 2. Parse the payment requirements\n * 3. Create a payment header using the configured x402HTTPClient\n * 4. Retry the request with the payment header\n *\n * @param axiosInstance - The Axios instance to wrap\n * @param client - Configured x402Client instance for handling payments\n * @returns The wrapped Axios instance that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import axios from 'axios';\n * import { wrapAxiosWithPayment, x402Client } from '@x402/axios';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { privateKeyToAccount } from 'viem/accounts';\n *\n * const account = privateKeyToAccount('0x...');\n * const client = new x402Client()\n * .register('eip155:*', new ExactEvmScheme(account));\n *\n * const api = wrapAxiosWithPayment(axios.create(), client);\n *\n * // Make a request that may require payment\n * const response = await api.get('https://api.example.com/paid-endpoint');\n * ```\n *\n * @throws {Error} If no schemes are provided\n * @throws {Error} If the request configuration is missing\n * @throws {Error} If a payment has already been attempted for this request\n * @throws {Error} If there's an error creating the payment header\n */\nexport function wrapAxiosWithPayment(\n axiosInstance: AxiosInstance,\n client: x402Client | x402HTTPClient,\n): AxiosInstance {\n const httpClient = client instanceof x402HTTPClient ? client : new x402HTTPClient(client);\n\n axiosInstance.interceptors.response.use(\n response => response,\n async (error: AxiosError) => {\n if (!error.response || error.response.status !== 402) {\n return Promise.reject(error);\n }\n\n const originalConfig = error.config;\n if (!originalConfig || !originalConfig.headers) {\n return Promise.reject(new Error(\"Missing axios request configuration\"));\n }\n\n // Check if this is already a retry to prevent infinite loops\n if (\n (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry\n ) {\n return Promise.reject(error);\n }\n\n try {\n // Parse payment requirements from response\n let paymentRequired: PaymentRequired;\n try {\n const response = error.response!; // Already validated above\n\n // Create getHeader function for case-insensitive header lookup\n const getHeader = (name: string) => {\n const value = response.headers[name] ?? response.headers[name.toLowerCase()];\n return typeof value === \"string\" ? value : undefined;\n };\n\n // Try to get from headers first (v2), then from body (v1)\n const body = response.data as PaymentRequired | undefined;\n\n paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);\n } catch (parseError) {\n return Promise.reject(\n new Error(\n `Failed to parse payment requirements: ${parseError instanceof Error ? parseError.message : \"Unknown error\"}`,\n ),\n );\n }\n\n // Run payment required hooks\n const hookHeaders = await httpClient.handlePaymentRequired(paymentRequired);\n if (hookHeaders) {\n const hookConfig = { ...originalConfig };\n hookConfig.headers = { ...originalConfig.headers } as typeof originalConfig.headers;\n Object.entries(hookHeaders).forEach(([key, value]) => {\n hookConfig.headers.set(key, value);\n });\n const hookResponse = await axiosInstance.request(hookConfig);\n if (hookResponse.status !== 402) {\n return hookResponse; // Hook succeeded\n }\n // Hook's retry got 402, fall through to payment\n }\n\n // Create payment payload\n let paymentPayload;\n try {\n paymentPayload = await client.createPaymentPayload(paymentRequired);\n } catch (paymentError) {\n return Promise.reject(\n new Error(\n `Failed to create payment payload: ${paymentError instanceof Error ? paymentError.message : \"Unknown error\"}`,\n ),\n );\n }\n\n // Encode payment header\n const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);\n\n // Mark this as a retry\n (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry =\n true;\n\n // Add payment headers to the request\n Object.entries(paymentHeaders).forEach(([key, value]) => {\n originalConfig.headers.set(key, value);\n });\n\n // Add CORS header to expose payment response\n originalConfig.headers.set(\n \"Access-Control-Expose-Headers\",\n \"PAYMENT-RESPONSE,X-PAYMENT-RESPONSE\",\n );\n\n // Retry the request with payment\n const secondResponse = await axiosInstance.request(originalConfig);\n return secondResponse;\n } catch (retryError) {\n return Promise.reject(retryError);\n }\n },\n );\n\n return axiosInstance;\n}\n\n/**\n * Wraps an Axios instance with x402 payment handling using a configuration object.\n *\n * @param axiosInstance - The Axios instance to wrap\n * @param config - Configuration options including scheme registrations and selectors\n * @returns The wrapped Axios instance that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import axios from 'axios';\n * import { wrapAxiosWithPaymentFromConfig } from '@x402/axios';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { privateKeyToAccount } from 'viem/accounts';\n *\n * const account = privateKeyToAccount('0x...');\n *\n * const api = wrapAxiosWithPaymentFromConfig(axios.create(), {\n * schemes: [\n * { network: 'eip155:*', client: new ExactEvmScheme(account) }\n * ]\n * });\n *\n * const response = await api.get('https://api.example.com/paid-endpoint');\n * ```\n */\nexport function wrapAxiosWithPaymentFromConfig(\n axiosInstance: AxiosInstance,\n config: x402ClientConfig,\n): AxiosInstance {\n const client = x402Client.fromConfig(config);\n return wrapAxiosWithPayment(axiosInstance, client);\n}\n\n// Re-export types and utilities for convenience\nexport { x402Client, x402HTTPClient } from \"@x402/core/client\";\nexport type {\n PaymentPolicy,\n SchemeRegistration,\n SelectPaymentRequirements,\n x402ClientConfig,\n} from \"@x402/core/client\";\nexport { decodePaymentResponseHeader } from \"@x402/core/http\";\nexport type {\n Network,\n PaymentPayload,\n PaymentRequired,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\n"],"mappings":";AAAA,SAAS,YAA8B,sBAAsB;AAoL7D,SAAS,cAAAA,aAAY,kBAAAC,uBAAsB;AAO3C,SAAS,mCAAmC;AAnJrC,SAAS,qBACd,eACA,QACe;AACf,QAAM,aAAa,kBAAkB,iBAAiB,SAAS,IAAI,eAAe,MAAM;AAExF,gBAAc,aAAa,SAAS;AAAA,IAClC,cAAY;AAAA,IACZ,OAAO,UAAsB;AAC3B,UAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,KAAK;AACpD,eAAO,QAAQ,OAAO,KAAK;AAAA,MAC7B;AAEA,YAAM,iBAAiB,MAAM;AAC7B,UAAI,CAAC,kBAAkB,CAAC,eAAe,SAAS;AAC9C,eAAO,QAAQ,OAAO,IAAI,MAAM,qCAAqC,CAAC;AAAA,MACxE;AAGA,UACG,eAA2E,cAC5E;AACA,eAAO,QAAQ,OAAO,KAAK;AAAA,MAC7B;AAEA,UAAI;AAEF,YAAI;AACJ,YAAI;AACF,gBAAM,WAAW,MAAM;AAGvB,gBAAM,YAAY,CAAC,SAAiB;AAClC,kBAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK,SAAS,QAAQ,KAAK,YAAY,CAAC;AAC3E,mBAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,UAC7C;AAGA,gBAAM,OAAO,SAAS;AAEtB,4BAAkB,WAAW,2BAA2B,WAAW,IAAI;AAAA,QACzE,SAAS,YAAY;AACnB,iBAAO,QAAQ;AAAA,YACb,IAAI;AAAA,cACF,yCAAyC,sBAAsB,QAAQ,WAAW,UAAU,eAAe;AAAA,YAC7G;AAAA,UACF;AAAA,QACF;AAGA,cAAM,cAAc,MAAM,WAAW,sBAAsB,eAAe;AAC1E,YAAI,aAAa;AACf,gBAAM,aAAa,EAAE,GAAG,eAAe;AACvC,qBAAW,UAAU,EAAE,GAAG,eAAe,QAAQ;AACjD,iBAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,uBAAW,QAAQ,IAAI,KAAK,KAAK;AAAA,UACnC,CAAC;AACD,gBAAM,eAAe,MAAM,cAAc,QAAQ,UAAU;AAC3D,cAAI,aAAa,WAAW,KAAK;AAC/B,mBAAO;AAAA,UACT;AAAA,QAEF;AAGA,YAAI;AACJ,YAAI;AACF,2BAAiB,MAAM,OAAO,qBAAqB,eAAe;AAAA,QACpE,SAAS,cAAc;AACrB,iBAAO,QAAQ;AAAA,YACb,IAAI;AAAA,cACF,qCAAqC,wBAAwB,QAAQ,aAAa,UAAU,eAAe;AAAA,YAC7G;AAAA,UACF;AAAA,QACF;AAGA,cAAM,iBAAiB,WAAW,6BAA6B,cAAc;AAG7E,QAAC,eAA2E,eAC1E;AAGF,eAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACvD,yBAAe,QAAQ,IAAI,KAAK,KAAK;AAAA,QACvC,CAAC;AAGD,uBAAe,QAAQ;AAAA,UACrB;AAAA,UACA;AAAA,QACF;AAGA,cAAM,iBAAiB,MAAM,cAAc,QAAQ,cAAc;AACjE,eAAO;AAAA,MACT,SAAS,YAAY;AACnB,eAAO,QAAQ,OAAO,UAAU;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AA2BO,SAAS,+BACd,eACA,QACe;AACf,QAAM,SAAS,WAAW,WAAW,MAAM;AAC3C,SAAO,qBAAqB,eAAe,MAAM;AACnD;","names":["x402Client","x402HTTPClient"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x402/axios",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "main": "./dist/cjs/index.js",
5
5
  "module": "./dist/esm/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  "dependencies": {
30
30
  "axios": "^1.7.9",
31
31
  "zod": "^3.24.2",
32
- "@x402/core": "^2.1.0"
32
+ "@x402/core": "~2.3.0"
33
33
  },
34
34
  "exports": {
35
35
  ".": {