@x402/fetch
Advanced tools
@@ -42,3 +42,3 @@ import { x402Client, x402HTTPClient, x402ClientConfig } from '@x402/core/client'; | ||
| */ | ||
| declare function wrapFetchWithPayment(fetch: typeof globalThis.fetch, client: x402Client | x402HTTPClient): (input: RequestInfo, init?: RequestInit) => Promise<Response>; | ||
| declare function wrapFetchWithPayment(fetch: typeof globalThis.fetch, client: x402Client | x402HTTPClient): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>; | ||
| /** | ||
@@ -51,4 +51,4 @@ * Creates a payment-enabled fetch function from a configuration object. | ||
| */ | ||
| declare function wrapFetchWithPaymentFromConfig(fetch: typeof globalThis.fetch, config: x402ClientConfig): (input: RequestInfo, init?: RequestInit) => Promise<Response>; | ||
| declare function wrapFetchWithPaymentFromConfig(fetch: typeof globalThis.fetch, config: x402ClientConfig): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>; | ||
| export { wrapFetchWithPayment, wrapFetchWithPaymentFromConfig }; |
+12
-15
@@ -36,3 +36,5 @@ "use strict"; | ||
| return async (input, init) => { | ||
| const response = await fetch(input, init); | ||
| const request = new Request(input, init); | ||
| const clonedRequest = request.clone(); | ||
| const response = await fetch(request); | ||
| if (response.status !== 402) { | ||
@@ -67,18 +69,13 @@ return response; | ||
| const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload); | ||
| if (!init) { | ||
| throw new Error("Missing fetch request configuration"); | ||
| } | ||
| if (init.__is402Retry) { | ||
| if (clonedRequest.headers.has("PAYMENT-SIGNATURE") || clonedRequest.headers.has("X-PAYMENT")) { | ||
| throw new Error("Payment already attempted"); | ||
| } | ||
| const newInit = { | ||
| ...init, | ||
| headers: { | ||
| ...init.headers || {}, | ||
| ...paymentHeaders, | ||
| "Access-Control-Expose-Headers": "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE" | ||
| }, | ||
| __is402Retry: true | ||
| }; | ||
| const secondResponse = await fetch(input, newInit); | ||
| for (const [key, value] of Object.entries(paymentHeaders)) { | ||
| clonedRequest.headers.set(key, value); | ||
| } | ||
| clonedRequest.headers.set( | ||
| "Access-Control-Expose-Headers", | ||
| "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE" | ||
| ); | ||
| const secondResponse = await fetch(clonedRequest); | ||
| return secondResponse; | ||
@@ -85,0 +82,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import { x402Client, x402ClientConfig, x402HTTPClient } from \"@x402/core/client\";\nimport { type PaymentRequired } from \"@x402/core/types\";\n\n/**\n * Enables the payment of APIs using the x402 payment protocol v2.\n *\n * This function wraps the native fetch API to automatically handle 402 Payment Required responses\n * by creating and sending payment headers. It will:\n * 1. Make the initial request\n * 2. If a 402 response is received, 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 fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param client - Configured x402Client or x402HTTPClient instance for handling payments\n * @returns A wrapped fetch function that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import { wrapFetchWithPayment, x402Client } from '@x402/fetch';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { ExactSvmScheme } from '@x402/svm';\n *\n * const client = new x402Client()\n * .register('eip155:8453', new ExactEvmScheme(evmSigner))\n * .register('solana:mainnet', new ExactSvmScheme(svmSigner))\n * .register('eip155:1', new ExactEvmScheme(evmSigner), 1); // v1 protocol\n *\n * const fetchWithPay = wrapFetchWithPayment(fetch, client);\n *\n * // Make a request that may require payment\n * const response = await fetchWithPay('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 wrapFetchWithPayment(\n fetch: typeof globalThis.fetch,\n client: x402Client | x402HTTPClient,\n) {\n const httpClient = client instanceof x402HTTPClient ? client : new x402HTTPClient(client);\n\n return async (input: RequestInfo, init?: RequestInit) => {\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n // Parse payment requirements from response\n let paymentRequired: PaymentRequired;\n try {\n // Create getHeader function for case-insensitive header lookup\n const getHeader = (name: string) => response.headers.get(name);\n\n // Try to get from headers first (v2), then from body (v1)\n let body: PaymentRequired | undefined;\n try {\n const responseText = await response.text();\n if (responseText) {\n body = JSON.parse(responseText) as PaymentRequired;\n }\n } catch {\n // Ignore JSON parse errors - might be header-only response\n }\n\n paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);\n } catch (error) {\n throw new Error(\n `Failed to parse payment requirements: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Create payment payload (copy extensions from PaymentRequired)\n let paymentPayload;\n try {\n paymentPayload = await client.createPaymentPayload(paymentRequired);\n } catch (error) {\n throw new Error(\n `Failed to create payment payload: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Encode payment header\n const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);\n\n // Ensure we have request init\n if (!init) {\n throw new Error(\"Missing fetch request configuration\");\n }\n\n // Check if this is already a retry to prevent infinite loops\n if ((init as { __is402Retry?: boolean }).__is402Retry) {\n throw new Error(\"Payment already attempted\");\n }\n\n // Create new request with payment header\n const newInit = {\n ...init,\n headers: {\n ...(init.headers || {}),\n ...paymentHeaders,\n \"Access-Control-Expose-Headers\": \"PAYMENT-RESPONSE,X-PAYMENT-RESPONSE\",\n },\n __is402Retry: true,\n };\n\n // Retry the request with payment\n const secondResponse = await fetch(input, newInit);\n return secondResponse;\n };\n}\n\n/**\n * Creates a payment-enabled fetch function from a configuration object.\n *\n * @param fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param config - Configuration options including scheme registrations and selectors\n * @returns A wrapped fetch function that handles 402 responses automatically\n */\nexport function wrapFetchWithPaymentFromConfig(\n fetch: typeof globalThis.fetch,\n config: x402ClientConfig,\n) {\n const client = x402Client.fromConfig(config);\n return wrapFetchWithPayment(fetch, 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;AAoI7D,IAAAA,iBAA2C;AAO3C,kBAA4C;AApGrC,SAAS,qBACd,OACA,QACA;AACA,QAAM,aAAa,kBAAkB,+BAAiB,SAAS,IAAI,6BAAe,MAAM;AAExF,SAAO,OAAO,OAAoB,SAAuB;AACvD,UAAM,WAAW,MAAM,MAAM,OAAO,IAAI;AAExC,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AAGA,QAAI;AACJ,QAAI;AAEF,YAAM,YAAY,CAAC,SAAiB,SAAS,QAAQ,IAAI,IAAI;AAG7D,UAAI;AACJ,UAAI;AACF,cAAM,eAAe,MAAM,SAAS,KAAK;AACzC,YAAI,cAAc;AAChB,iBAAO,KAAK,MAAM,YAAY;AAAA,QAChC;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,wBAAkB,WAAW,2BAA2B,WAAW,IAAI;AAAA,IACzE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,yCAAyC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACnG;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,uBAAiB,MAAM,OAAO,qBAAqB,eAAe;AAAA,IACpE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,qCAAqC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC/F;AAAA,IACF;AAGA,UAAM,iBAAiB,WAAW,6BAA6B,cAAc;AAG7E,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAGA,QAAK,KAAoC,cAAc;AACrD,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAGA,UAAM,UAAU;AAAA,MACd,GAAG;AAAA,MACH,SAAS;AAAA,QACP,GAAI,KAAK,WAAW,CAAC;AAAA,QACrB,GAAG;AAAA,QACH,iCAAiC;AAAA,MACnC;AAAA,MACA,cAAc;AAAA,IAChB;AAGA,UAAM,iBAAiB,MAAM,MAAM,OAAO,OAAO;AACjD,WAAO;AAAA,EACT;AACF;AASO,SAAS,+BACd,OACA,QACA;AACA,QAAM,SAAS,yBAAW,WAAW,MAAM;AAC3C,SAAO,qBAAqB,OAAO,MAAM;AAC3C;","names":["import_client"]} | ||
| {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import { x402Client, x402ClientConfig, x402HTTPClient } from \"@x402/core/client\";\nimport { type PaymentRequired } from \"@x402/core/types\";\n\n/**\n * Enables the payment of APIs using the x402 payment protocol v2.\n *\n * This function wraps the native fetch API to automatically handle 402 Payment Required responses\n * by creating and sending payment headers. It will:\n * 1. Make the initial request\n * 2. If a 402 response is received, 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 fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param client - Configured x402Client or x402HTTPClient instance for handling payments\n * @returns A wrapped fetch function that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import { wrapFetchWithPayment, x402Client } from '@x402/fetch';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { ExactSvmScheme } from '@x402/svm';\n *\n * const client = new x402Client()\n * .register('eip155:8453', new ExactEvmScheme(evmSigner))\n * .register('solana:mainnet', new ExactSvmScheme(svmSigner))\n * .register('eip155:1', new ExactEvmScheme(evmSigner), 1); // v1 protocol\n *\n * const fetchWithPay = wrapFetchWithPayment(fetch, client);\n *\n * // Make a request that may require payment\n * const response = await fetchWithPay('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 wrapFetchWithPayment(\n fetch: typeof globalThis.fetch,\n client: x402Client | x402HTTPClient,\n) {\n const httpClient = client instanceof x402HTTPClient ? client : new x402HTTPClient(client);\n\n return async (input: RequestInfo | URL, init?: RequestInit) => {\n const request = new Request(input, init);\n const clonedRequest = request.clone();\n\n const response = await fetch(request);\n\n if (response.status !== 402) {\n return response;\n }\n\n // Parse payment requirements from response\n let paymentRequired: PaymentRequired;\n try {\n // Create getHeader function for case-insensitive header lookup\n const getHeader = (name: string) => response.headers.get(name);\n\n // Try to get from headers first (v2), then from body (v1)\n let body: PaymentRequired | undefined;\n try {\n const responseText = await response.text();\n if (responseText) {\n body = JSON.parse(responseText) as PaymentRequired;\n }\n } catch {\n // Ignore JSON parse errors - might be header-only response\n }\n\n paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);\n } catch (error) {\n throw new Error(\n `Failed to parse payment requirements: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Create payment payload (copy extensions from PaymentRequired)\n let paymentPayload;\n try {\n paymentPayload = await client.createPaymentPayload(paymentRequired);\n } catch (error) {\n throw new Error(\n `Failed to create payment payload: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Encode payment header\n const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);\n\n // Check if this is already a retry to prevent infinite loops\n if (clonedRequest.headers.has(\"PAYMENT-SIGNATURE\") || clonedRequest.headers.has(\"X-PAYMENT\")) {\n throw new Error(\"Payment already attempted\");\n }\n\n // Add payment headers to cloned request\n for (const [key, value] of Object.entries(paymentHeaders)) {\n clonedRequest.headers.set(key, value);\n }\n clonedRequest.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 fetch(clonedRequest);\n return secondResponse;\n };\n}\n\n/**\n * Creates a payment-enabled fetch function from a configuration object.\n *\n * @param fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param config - Configuration options including scheme registrations and selectors\n * @returns A wrapped fetch function that handles 402 responses automatically\n */\nexport function wrapFetchWithPaymentFromConfig(\n fetch: typeof globalThis.fetch,\n config: x402ClientConfig,\n) {\n const client = x402Client.fromConfig(config);\n return wrapFetchWithPayment(fetch, 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;AAgI7D,IAAAA,iBAA2C;AAO3C,kBAA4C;AAhGrC,SAAS,qBACd,OACA,QACA;AACA,QAAM,aAAa,kBAAkB,+BAAiB,SAAS,IAAI,6BAAe,MAAM;AAExF,SAAO,OAAO,OAA0B,SAAuB;AAC7D,UAAM,UAAU,IAAI,QAAQ,OAAO,IAAI;AACvC,UAAM,gBAAgB,QAAQ,MAAM;AAEpC,UAAM,WAAW,MAAM,MAAM,OAAO;AAEpC,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AAGA,QAAI;AACJ,QAAI;AAEF,YAAM,YAAY,CAAC,SAAiB,SAAS,QAAQ,IAAI,IAAI;AAG7D,UAAI;AACJ,UAAI;AACF,cAAM,eAAe,MAAM,SAAS,KAAK;AACzC,YAAI,cAAc;AAChB,iBAAO,KAAK,MAAM,YAAY;AAAA,QAChC;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,wBAAkB,WAAW,2BAA2B,WAAW,IAAI;AAAA,IACzE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,yCAAyC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACnG;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,uBAAiB,MAAM,OAAO,qBAAqB,eAAe;AAAA,IACpE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,qCAAqC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC/F;AAAA,IACF;AAGA,UAAM,iBAAiB,WAAW,6BAA6B,cAAc;AAG7E,QAAI,cAAc,QAAQ,IAAI,mBAAmB,KAAK,cAAc,QAAQ,IAAI,WAAW,GAAG;AAC5F,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAGA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,cAAc,GAAG;AACzD,oBAAc,QAAQ,IAAI,KAAK,KAAK;AAAA,IACtC;AACA,kBAAc,QAAQ;AAAA,MACpB;AAAA,MACA;AAAA,IACF;AAGA,UAAM,iBAAiB,MAAM,MAAM,aAAa;AAChD,WAAO;AAAA,EACT;AACF;AASO,SAAS,+BACd,OACA,QACA;AACA,QAAM,SAAS,yBAAW,WAAW,MAAM;AAC3C,SAAO,qBAAqB,OAAO,MAAM;AAC3C;","names":["import_client"]} |
@@ -42,3 +42,3 @@ import { x402Client, x402HTTPClient, x402ClientConfig } from '@x402/core/client'; | ||
| */ | ||
| declare function wrapFetchWithPayment(fetch: typeof globalThis.fetch, client: x402Client | x402HTTPClient): (input: RequestInfo, init?: RequestInit) => Promise<Response>; | ||
| declare function wrapFetchWithPayment(fetch: typeof globalThis.fetch, client: x402Client | x402HTTPClient): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>; | ||
| /** | ||
@@ -51,4 +51,4 @@ * Creates a payment-enabled fetch function from a configuration object. | ||
| */ | ||
| declare function wrapFetchWithPaymentFromConfig(fetch: typeof globalThis.fetch, config: x402ClientConfig): (input: RequestInfo, init?: RequestInit) => Promise<Response>; | ||
| declare function wrapFetchWithPaymentFromConfig(fetch: typeof globalThis.fetch, config: x402ClientConfig): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>; | ||
| export { wrapFetchWithPayment, wrapFetchWithPaymentFromConfig }; |
+12
-15
@@ -8,3 +8,5 @@ // src/index.ts | ||
| return async (input, init) => { | ||
| const response = await fetch(input, init); | ||
| const request = new Request(input, init); | ||
| const clonedRequest = request.clone(); | ||
| const response = await fetch(request); | ||
| if (response.status !== 402) { | ||
@@ -39,18 +41,13 @@ return response; | ||
| const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload); | ||
| if (!init) { | ||
| throw new Error("Missing fetch request configuration"); | ||
| } | ||
| if (init.__is402Retry) { | ||
| if (clonedRequest.headers.has("PAYMENT-SIGNATURE") || clonedRequest.headers.has("X-PAYMENT")) { | ||
| throw new Error("Payment already attempted"); | ||
| } | ||
| const newInit = { | ||
| ...init, | ||
| headers: { | ||
| ...init.headers || {}, | ||
| ...paymentHeaders, | ||
| "Access-Control-Expose-Headers": "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE" | ||
| }, | ||
| __is402Retry: true | ||
| }; | ||
| const secondResponse = await fetch(input, newInit); | ||
| for (const [key, value] of Object.entries(paymentHeaders)) { | ||
| clonedRequest.headers.set(key, value); | ||
| } | ||
| clonedRequest.headers.set( | ||
| "Access-Control-Expose-Headers", | ||
| "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE" | ||
| ); | ||
| const secondResponse = await fetch(clonedRequest); | ||
| return secondResponse; | ||
@@ -57,0 +54,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import { x402Client, x402ClientConfig, x402HTTPClient } from \"@x402/core/client\";\nimport { type PaymentRequired } from \"@x402/core/types\";\n\n/**\n * Enables the payment of APIs using the x402 payment protocol v2.\n *\n * This function wraps the native fetch API to automatically handle 402 Payment Required responses\n * by creating and sending payment headers. It will:\n * 1. Make the initial request\n * 2. If a 402 response is received, 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 fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param client - Configured x402Client or x402HTTPClient instance for handling payments\n * @returns A wrapped fetch function that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import { wrapFetchWithPayment, x402Client } from '@x402/fetch';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { ExactSvmScheme } from '@x402/svm';\n *\n * const client = new x402Client()\n * .register('eip155:8453', new ExactEvmScheme(evmSigner))\n * .register('solana:mainnet', new ExactSvmScheme(svmSigner))\n * .register('eip155:1', new ExactEvmScheme(evmSigner), 1); // v1 protocol\n *\n * const fetchWithPay = wrapFetchWithPayment(fetch, client);\n *\n * // Make a request that may require payment\n * const response = await fetchWithPay('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 wrapFetchWithPayment(\n fetch: typeof globalThis.fetch,\n client: x402Client | x402HTTPClient,\n) {\n const httpClient = client instanceof x402HTTPClient ? client : new x402HTTPClient(client);\n\n return async (input: RequestInfo, init?: RequestInit) => {\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n // Parse payment requirements from response\n let paymentRequired: PaymentRequired;\n try {\n // Create getHeader function for case-insensitive header lookup\n const getHeader = (name: string) => response.headers.get(name);\n\n // Try to get from headers first (v2), then from body (v1)\n let body: PaymentRequired | undefined;\n try {\n const responseText = await response.text();\n if (responseText) {\n body = JSON.parse(responseText) as PaymentRequired;\n }\n } catch {\n // Ignore JSON parse errors - might be header-only response\n }\n\n paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);\n } catch (error) {\n throw new Error(\n `Failed to parse payment requirements: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Create payment payload (copy extensions from PaymentRequired)\n let paymentPayload;\n try {\n paymentPayload = await client.createPaymentPayload(paymentRequired);\n } catch (error) {\n throw new Error(\n `Failed to create payment payload: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Encode payment header\n const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);\n\n // Ensure we have request init\n if (!init) {\n throw new Error(\"Missing fetch request configuration\");\n }\n\n // Check if this is already a retry to prevent infinite loops\n if ((init as { __is402Retry?: boolean }).__is402Retry) {\n throw new Error(\"Payment already attempted\");\n }\n\n // Create new request with payment header\n const newInit = {\n ...init,\n headers: {\n ...(init.headers || {}),\n ...paymentHeaders,\n \"Access-Control-Expose-Headers\": \"PAYMENT-RESPONSE,X-PAYMENT-RESPONSE\",\n },\n __is402Retry: true,\n };\n\n // Retry the request with payment\n const secondResponse = await fetch(input, newInit);\n return secondResponse;\n };\n}\n\n/**\n * Creates a payment-enabled fetch function from a configuration object.\n *\n * @param fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param config - Configuration options including scheme registrations and selectors\n * @returns A wrapped fetch function that handles 402 responses automatically\n */\nexport function wrapFetchWithPaymentFromConfig(\n fetch: typeof globalThis.fetch,\n config: x402ClientConfig,\n) {\n const client = x402Client.fromConfig(config);\n return wrapFetchWithPayment(fetch, 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;AAoI7D,SAAS,cAAAA,aAAY,kBAAAC,uBAAsB;AAO3C,SAAS,mCAAmC;AApGrC,SAAS,qBACd,OACA,QACA;AACA,QAAM,aAAa,kBAAkB,iBAAiB,SAAS,IAAI,eAAe,MAAM;AAExF,SAAO,OAAO,OAAoB,SAAuB;AACvD,UAAM,WAAW,MAAM,MAAM,OAAO,IAAI;AAExC,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AAGA,QAAI;AACJ,QAAI;AAEF,YAAM,YAAY,CAAC,SAAiB,SAAS,QAAQ,IAAI,IAAI;AAG7D,UAAI;AACJ,UAAI;AACF,cAAM,eAAe,MAAM,SAAS,KAAK;AACzC,YAAI,cAAc;AAChB,iBAAO,KAAK,MAAM,YAAY;AAAA,QAChC;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,wBAAkB,WAAW,2BAA2B,WAAW,IAAI;AAAA,IACzE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,yCAAyC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACnG;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,uBAAiB,MAAM,OAAO,qBAAqB,eAAe;AAAA,IACpE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,qCAAqC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC/F;AAAA,IACF;AAGA,UAAM,iBAAiB,WAAW,6BAA6B,cAAc;AAG7E,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAGA,QAAK,KAAoC,cAAc;AACrD,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAGA,UAAM,UAAU;AAAA,MACd,GAAG;AAAA,MACH,SAAS;AAAA,QACP,GAAI,KAAK,WAAW,CAAC;AAAA,QACrB,GAAG;AAAA,QACH,iCAAiC;AAAA,MACnC;AAAA,MACA,cAAc;AAAA,IAChB;AAGA,UAAM,iBAAiB,MAAM,MAAM,OAAO,OAAO;AACjD,WAAO;AAAA,EACT;AACF;AASO,SAAS,+BACd,OACA,QACA;AACA,QAAM,SAAS,WAAW,WAAW,MAAM;AAC3C,SAAO,qBAAqB,OAAO,MAAM;AAC3C;","names":["x402Client","x402HTTPClient"]} | ||
| {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import { x402Client, x402ClientConfig, x402HTTPClient } from \"@x402/core/client\";\nimport { type PaymentRequired } from \"@x402/core/types\";\n\n/**\n * Enables the payment of APIs using the x402 payment protocol v2.\n *\n * This function wraps the native fetch API to automatically handle 402 Payment Required responses\n * by creating and sending payment headers. It will:\n * 1. Make the initial request\n * 2. If a 402 response is received, 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 fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param client - Configured x402Client or x402HTTPClient instance for handling payments\n * @returns A wrapped fetch function that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * import { wrapFetchWithPayment, x402Client } from '@x402/fetch';\n * import { ExactEvmScheme } from '@x402/evm';\n * import { ExactSvmScheme } from '@x402/svm';\n *\n * const client = new x402Client()\n * .register('eip155:8453', new ExactEvmScheme(evmSigner))\n * .register('solana:mainnet', new ExactSvmScheme(svmSigner))\n * .register('eip155:1', new ExactEvmScheme(evmSigner), 1); // v1 protocol\n *\n * const fetchWithPay = wrapFetchWithPayment(fetch, client);\n *\n * // Make a request that may require payment\n * const response = await fetchWithPay('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 wrapFetchWithPayment(\n fetch: typeof globalThis.fetch,\n client: x402Client | x402HTTPClient,\n) {\n const httpClient = client instanceof x402HTTPClient ? client : new x402HTTPClient(client);\n\n return async (input: RequestInfo | URL, init?: RequestInit) => {\n const request = new Request(input, init);\n const clonedRequest = request.clone();\n\n const response = await fetch(request);\n\n if (response.status !== 402) {\n return response;\n }\n\n // Parse payment requirements from response\n let paymentRequired: PaymentRequired;\n try {\n // Create getHeader function for case-insensitive header lookup\n const getHeader = (name: string) => response.headers.get(name);\n\n // Try to get from headers first (v2), then from body (v1)\n let body: PaymentRequired | undefined;\n try {\n const responseText = await response.text();\n if (responseText) {\n body = JSON.parse(responseText) as PaymentRequired;\n }\n } catch {\n // Ignore JSON parse errors - might be header-only response\n }\n\n paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);\n } catch (error) {\n throw new Error(\n `Failed to parse payment requirements: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Create payment payload (copy extensions from PaymentRequired)\n let paymentPayload;\n try {\n paymentPayload = await client.createPaymentPayload(paymentRequired);\n } catch (error) {\n throw new Error(\n `Failed to create payment payload: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Encode payment header\n const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);\n\n // Check if this is already a retry to prevent infinite loops\n if (clonedRequest.headers.has(\"PAYMENT-SIGNATURE\") || clonedRequest.headers.has(\"X-PAYMENT\")) {\n throw new Error(\"Payment already attempted\");\n }\n\n // Add payment headers to cloned request\n for (const [key, value] of Object.entries(paymentHeaders)) {\n clonedRequest.headers.set(key, value);\n }\n clonedRequest.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 fetch(clonedRequest);\n return secondResponse;\n };\n}\n\n/**\n * Creates a payment-enabled fetch function from a configuration object.\n *\n * @param fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param config - Configuration options including scheme registrations and selectors\n * @returns A wrapped fetch function that handles 402 responses automatically\n */\nexport function wrapFetchWithPaymentFromConfig(\n fetch: typeof globalThis.fetch,\n config: x402ClientConfig,\n) {\n const client = x402Client.fromConfig(config);\n return wrapFetchWithPayment(fetch, 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;AAgI7D,SAAS,cAAAA,aAAY,kBAAAC,uBAAsB;AAO3C,SAAS,mCAAmC;AAhGrC,SAAS,qBACd,OACA,QACA;AACA,QAAM,aAAa,kBAAkB,iBAAiB,SAAS,IAAI,eAAe,MAAM;AAExF,SAAO,OAAO,OAA0B,SAAuB;AAC7D,UAAM,UAAU,IAAI,QAAQ,OAAO,IAAI;AACvC,UAAM,gBAAgB,QAAQ,MAAM;AAEpC,UAAM,WAAW,MAAM,MAAM,OAAO;AAEpC,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AAGA,QAAI;AACJ,QAAI;AAEF,YAAM,YAAY,CAAC,SAAiB,SAAS,QAAQ,IAAI,IAAI;AAG7D,UAAI;AACJ,UAAI;AACF,cAAM,eAAe,MAAM,SAAS,KAAK;AACzC,YAAI,cAAc;AAChB,iBAAO,KAAK,MAAM,YAAY;AAAA,QAChC;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,wBAAkB,WAAW,2BAA2B,WAAW,IAAI;AAAA,IACzE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,yCAAyC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACnG;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,uBAAiB,MAAM,OAAO,qBAAqB,eAAe;AAAA,IACpE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,qCAAqC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC/F;AAAA,IACF;AAGA,UAAM,iBAAiB,WAAW,6BAA6B,cAAc;AAG7E,QAAI,cAAc,QAAQ,IAAI,mBAAmB,KAAK,cAAc,QAAQ,IAAI,WAAW,GAAG;AAC5F,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAGA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,cAAc,GAAG;AACzD,oBAAc,QAAQ,IAAI,KAAK,KAAK;AAAA,IACtC;AACA,kBAAc,QAAQ;AAAA,MACpB;AAAA,MACA;AAAA,IACF;AAGA,UAAM,iBAAiB,MAAM,MAAM,aAAa;AAChD,WAAO;AAAA,EACT;AACF;AASO,SAAS,+BACd,OACA,QACA;AACA,QAAM,SAAS,WAAW,WAAW,MAAM;AAC3C,SAAO,qBAAqB,OAAO,MAAM;AAC3C;","names":["x402Client","x402HTTPClient"]} |
+2
-2
| { | ||
| "name": "@x402/fetch", | ||
| "version": "2.1.0", | ||
| "version": "2.2.0", | ||
| "main": "./dist/cjs/index.js", | ||
@@ -32,3 +32,3 @@ "module": "./dist/esm/index.js", | ||
| "zod": "^3.24.2", | ||
| "@x402/core": "^2.1.0" | ||
| "@x402/core": "^2.2.0" | ||
| }, | ||
@@ -35,0 +35,0 @@ "exports": { |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
32025
0.8%42
-4.55%206
-2.83%Updated