@wtflabs/x402-fetch 0.0.1-beta.10 → 0.0.1-beta.12
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/dist/cjs/index.d.ts +5 -1
- package/dist/cjs/index.js +5 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.mts +5 -1
- package/dist/esm/index.mjs +4 -1
- package/dist/esm/index.mjs.map +1 -1
- package/package.json +15 -15
package/dist/cjs/index.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ export { PaymentRequirementsSelector } from '@wtflabs/x402/client';
|
|
|
5
5
|
export { decodeXPaymentResponse } from '@wtflabs/x402/shared';
|
|
6
6
|
export { Chain, Hex } from 'viem';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Header name for specifying payment type
|
|
10
|
+
*/
|
|
11
|
+
declare const PAYMENT_TYPE_HEADER: "x-payment-type";
|
|
8
12
|
/**
|
|
9
13
|
* Enables the payment of APIs using the x402 payment protocol.
|
|
10
14
|
*
|
|
@@ -45,4 +49,4 @@ export { Chain, Hex } from 'viem';
|
|
|
45
49
|
declare function wrapFetchWithPayment(fetch: typeof globalThis.fetch, walletClient: Signer | MultiNetworkSigner, maxValue?: bigint, // Default to 0.10 USDC
|
|
46
50
|
paymentRequirementsSelector?: PaymentRequirementsSelector, config?: X402Config): (input: RequestInfo, init?: RequestInit) => Promise<Response>;
|
|
47
51
|
|
|
48
|
-
export { wrapFetchWithPayment };
|
|
52
|
+
export { PAYMENT_TYPE_HEADER, wrapFetchWithPayment };
|
package/dist/cjs/index.js
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
+
PAYMENT_TYPE_HEADER: () => PAYMENT_TYPE_HEADER,
|
|
23
24
|
createConnectedClient: () => import_types2.createConnectedClient,
|
|
24
25
|
createSigner: () => import_types2.createSigner,
|
|
25
26
|
decodeXPaymentResponse: () => import_shared.decodeXPaymentResponse,
|
|
@@ -32,6 +33,7 @@ var import_client = require("@wtflabs/x402/client");
|
|
|
32
33
|
var import_schemes = require("@wtflabs/x402/schemes");
|
|
33
34
|
var import_shared = require("@wtflabs/x402/shared");
|
|
34
35
|
var import_types2 = require("@wtflabs/x402/types");
|
|
36
|
+
var PAYMENT_TYPE_HEADER = "x-payment-type";
|
|
35
37
|
function wrapFetchWithPayment(fetch, walletClient, maxValue = BigInt(0.1 * 10 ** 6), paymentRequirementsSelector = import_client.selectPaymentRequirements, config) {
|
|
36
38
|
return async (input, init) => {
|
|
37
39
|
var _a;
|
|
@@ -50,7 +52,8 @@ function wrapFetchWithPayment(fetch, walletClient, maxValue = BigInt(0.1 * 10 **
|
|
|
50
52
|
if (BigInt(selectedPaymentRequirements.maxAmountRequired) > maxValue) {
|
|
51
53
|
throw new Error("Payment amount exceeds maximum allowed");
|
|
52
54
|
}
|
|
53
|
-
const
|
|
55
|
+
const headerPaymentType = response.headers.get(PAYMENT_TYPE_HEADER);
|
|
56
|
+
const paymentType = selectedPaymentRequirements.paymentType || headerPaymentType || await import_schemes.exact.evm.getRecommendedPaymentMethod(
|
|
54
57
|
selectedPaymentRequirements.asset,
|
|
55
58
|
walletClient
|
|
56
59
|
) || "eip3009";
|
|
@@ -105,6 +108,7 @@ function wrapFetchWithPayment(fetch, walletClient, maxValue = BigInt(0.1 * 10 **
|
|
|
105
108
|
}
|
|
106
109
|
// Annotate the CommonJS export names for ESM import in node:
|
|
107
110
|
0 && (module.exports = {
|
|
111
|
+
PAYMENT_TYPE_HEADER,
|
|
108
112
|
createConnectedClient,
|
|
109
113
|
createSigner,
|
|
110
114
|
decodeXPaymentResponse,
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import {\n ChainIdToNetwork,\n PaymentRequirementsSchema,\n Signer,\n evm,\n MultiNetworkSigner,\n isMultiNetworkSigner,\n isSvmSignerWallet,\n Network,\n X402Config,\n} from \"@wtflabs/x402/types\";\nimport {\n createPaymentHeader,\n PaymentRequirementsSelector,\n selectPaymentRequirements,\n} from \"@wtflabs/x402/client\";\nimport { exact } from \"@wtflabs/x402/schemes\";\n\n/**\n * Enables the payment of APIs using the x402 payment protocol.\n *\n * This function wraps the native fetch API to automatically handle 402 Payment Required responses\n * by creating and sending a payment header. It will:\n * 1. Make the initial request\n * 2. If a 402 response is received, parse the payment requirements\n * 3. Verify the payment amount is within the allowed maximum\n * 4. Create a payment header using the provided wallet client\n * 5. Retry the request with the payment header\n *\n * @param fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param walletClient - The wallet client used to sign payment messages\n * @param maxValue - The maximum allowed payment amount in base units (defaults to 0.1 USDC)\n * @param paymentRequirementsSelector - A function that selects the payment requirements from the response\n * @param config - Optional configuration for X402 operations (e.g., custom RPC URLs)\n * @returns A wrapped fetch function that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * const wallet = new SignerWallet(...);\n * const fetchWithPay = wrapFetchWithPayment(fetch, wallet);\n *\n * // With custom RPC configuration\n * const fetchWithPay = wrapFetchWithPayment(fetch, wallet, undefined, undefined, {\n * svmConfig: { rpcUrl: \"http://localhost:8899\" }\n * });\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 the payment amount exceeds the maximum allowed value\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 walletClient: Signer | MultiNetworkSigner,\n maxValue: bigint = BigInt(0.1 * 10 ** 6), // Default to 0.10 USDC\n paymentRequirementsSelector: PaymentRequirementsSelector = selectPaymentRequirements,\n config?: X402Config,\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 const { x402Version, accepts } = (await response.json()) as {\n x402Version: number;\n accepts: unknown[];\n };\n const parsedPaymentRequirements = accepts.map(x => PaymentRequirementsSchema.parse(x));\n\n const network = isMultiNetworkSigner(walletClient)\n ? undefined\n : evm.isSignerWallet(walletClient as typeof evm.EvmSigner)\n ? ChainIdToNetwork[(walletClient as typeof evm.EvmSigner).chain?.id]\n : isSvmSignerWallet(walletClient)\n ? ([\"solana\", \"solana-devnet\"] as Network[])\n : undefined;\n\n const selectedPaymentRequirements = paymentRequirementsSelector(\n parsedPaymentRequirements,\n network,\n \"exact\",\n );\n\n if (BigInt(selectedPaymentRequirements.maxAmountRequired) > maxValue) {\n throw new Error(\"Payment amount exceeds maximum allowed\");\n }\n\n //
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import {\n ChainIdToNetwork,\n PaymentRequirementsSchema,\n Signer,\n evm,\n MultiNetworkSigner,\n isMultiNetworkSigner,\n isSvmSignerWallet,\n Network,\n X402Config,\n} from \"@wtflabs/x402/types\";\nimport {\n createPaymentHeader,\n PaymentRequirementsSelector,\n selectPaymentRequirements,\n} from \"@wtflabs/x402/client\";\nimport { exact } from \"@wtflabs/x402/schemes\";\n\n/**\n * Header name for specifying payment type\n */\nexport const PAYMENT_TYPE_HEADER = \"x-payment-type\" as const;\n\n/**\n * Enables the payment of APIs using the x402 payment protocol.\n *\n * This function wraps the native fetch API to automatically handle 402 Payment Required responses\n * by creating and sending a payment header. It will:\n * 1. Make the initial request\n * 2. If a 402 response is received, parse the payment requirements\n * 3. Verify the payment amount is within the allowed maximum\n * 4. Create a payment header using the provided wallet client\n * 5. Retry the request with the payment header\n *\n * @param fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param walletClient - The wallet client used to sign payment messages\n * @param maxValue - The maximum allowed payment amount in base units (defaults to 0.1 USDC)\n * @param paymentRequirementsSelector - A function that selects the payment requirements from the response\n * @param config - Optional configuration for X402 operations (e.g., custom RPC URLs)\n * @returns A wrapped fetch function that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * const wallet = new SignerWallet(...);\n * const fetchWithPay = wrapFetchWithPayment(fetch, wallet);\n *\n * // With custom RPC configuration\n * const fetchWithPay = wrapFetchWithPayment(fetch, wallet, undefined, undefined, {\n * svmConfig: { rpcUrl: \"http://localhost:8899\" }\n * });\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 the payment amount exceeds the maximum allowed value\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 walletClient: Signer | MultiNetworkSigner,\n maxValue: bigint = BigInt(0.1 * 10 ** 6), // Default to 0.10 USDC\n paymentRequirementsSelector: PaymentRequirementsSelector = selectPaymentRequirements,\n config?: X402Config,\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 const { x402Version, accepts } = (await response.json()) as {\n x402Version: number;\n accepts: unknown[];\n };\n const parsedPaymentRequirements = accepts.map(x => PaymentRequirementsSchema.parse(x));\n\n const network = isMultiNetworkSigner(walletClient)\n ? undefined\n : evm.isSignerWallet(walletClient as typeof evm.EvmSigner)\n ? ChainIdToNetwork[(walletClient as typeof evm.EvmSigner).chain?.id]\n : isSvmSignerWallet(walletClient)\n ? ([\"solana\", \"solana-devnet\"] as Network[])\n : undefined;\n\n const selectedPaymentRequirements = paymentRequirementsSelector(\n parsedPaymentRequirements,\n network,\n \"exact\",\n );\n\n if (BigInt(selectedPaymentRequirements.maxAmountRequired) > maxValue) {\n throw new Error(\"Payment amount exceeds maximum allowed\");\n }\n\n // 从响应 header 中获取支付类型\n const headerPaymentType = response.headers.get(PAYMENT_TYPE_HEADER);\n\n // 获取支付类型,优先级:header > paymentRequirements > 自动检测 > 默认\n const paymentType =\n selectedPaymentRequirements.paymentType ||\n headerPaymentType ||\n (await exact.evm.getRecommendedPaymentMethod(\n selectedPaymentRequirements.asset,\n walletClient as typeof evm.EvmSigner,\n )) ||\n \"eip3009\";\n\n // 根据支付类型创建支付头\n let paymentHeader: string;\n\n // 仅对 EVM 网络支持 permit 和 permit2\n const isEvmNetwork = network && ![\"solana\", \"solana-devnet\"].includes(network[0]);\n\n if (paymentType === \"permit\" && isEvmNetwork) {\n // 使用 EIP-2612 Permit\n if (!evm.isSignerWallet(walletClient as typeof evm.EvmSigner)) {\n throw new Error(\"Permit authorization requires an EVM signer wallet\");\n }\n paymentHeader = await exact.evm.permit.createPaymentHeader(\n walletClient as typeof evm.EvmSigner,\n x402Version,\n selectedPaymentRequirements,\n );\n } else if (paymentType === \"permit2\" && isEvmNetwork) {\n // 使用 Permit2\n if (!evm.isSignerWallet(walletClient as typeof evm.EvmSigner)) {\n throw new Error(\"Permit2 authorization requires an EVM signer wallet\");\n }\n paymentHeader = await exact.evm.permit2.createPaymentHeader(\n walletClient as typeof evm.EvmSigner,\n x402Version,\n selectedPaymentRequirements,\n );\n } else if (paymentType === \"eip3009\" || !paymentType) {\n // 默认使用 EIP-3009(统一的 createPaymentHeader)\n paymentHeader = await createPaymentHeader(\n walletClient,\n x402Version,\n selectedPaymentRequirements,\n config,\n );\n } else {\n throw new Error(`Unsupported payment type: ${paymentType}`);\n }\n\n if (!init) {\n throw new Error(\"Missing fetch request configuration\");\n }\n\n if ((init as { __is402Retry?: boolean }).__is402Retry) {\n throw new Error(\"Payment already attempted\");\n }\n\n const newInit = {\n ...init,\n headers: {\n ...(init.headers || {}),\n \"X-PAYMENT\": paymentHeader,\n \"Access-Control-Expose-Headers\": \"X-PAYMENT-RESPONSE\",\n },\n __is402Retry: true,\n };\n\n const secondResponse = await fetch(input, newInit);\n return secondResponse;\n };\n}\n\nexport { decodeXPaymentResponse } from \"@wtflabs/x402/shared\";\nexport {\n createSigner,\n createConnectedClient,\n withChain,\n type Signer,\n type ConnectedClient,\n type MultiNetworkSigner,\n type X402Config,\n type EvmChainConfig,\n} from \"@wtflabs/x402/types\";\nexport { type PaymentRequirementsSelector } from \"@wtflabs/x402/client\";\nexport type { Hex, Chain } from \"viem\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAUO;AACP,oBAIO;AACP,qBAAsB;AA4JtB,oBAAuC;AACvC,IAAAA,gBASO;AAjKA,IAAM,sBAAsB;AAuC5B,SAAS,qBACd,OACA,cACA,WAAmB,OAAO,MAAM,MAAM,CAAC,GACvC,8BAA2D,yCAC3D,QACA;AACA,SAAO,OAAO,OAAoB,SAAuB;AAnE3D;AAoEI,UAAM,WAAW,MAAM,MAAM,OAAO,IAAI;AAExC,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AAEA,UAAM,EAAE,aAAa,QAAQ,IAAK,MAAM,SAAS,KAAK;AAItD,UAAM,4BAA4B,QAAQ,IAAI,OAAK,uCAA0B,MAAM,CAAC,CAAC;AAErF,UAAM,cAAU,mCAAqB,YAAY,IAC7C,SACA,iBAAI,eAAe,YAAoC,IACrD,+BAAkB,kBAAsC,UAAtC,mBAA6C,EAAE,QACjE,gCAAkB,YAAY,IAC3B,CAAC,UAAU,eAAe,IAC3B;AAER,UAAM,8BAA8B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,OAAO,4BAA4B,iBAAiB,IAAI,UAAU;AACpE,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAGA,UAAM,oBAAoB,SAAS,QAAQ,IAAI,mBAAmB;AAGlE,UAAM,cACJ,4BAA4B,eAC5B,qBACC,MAAM,qBAAM,IAAI;AAAA,MACf,4BAA4B;AAAA,MAC5B;AAAA,IACF,KACA;AAGF,QAAI;AAGJ,UAAM,eAAe,WAAW,CAAC,CAAC,UAAU,eAAe,EAAE,SAAS,QAAQ,CAAC,CAAC;AAEhF,QAAI,gBAAgB,YAAY,cAAc;AAE5C,UAAI,CAAC,iBAAI,eAAe,YAAoC,GAAG;AAC7D,cAAM,IAAI,MAAM,oDAAoD;AAAA,MACtE;AACA,sBAAgB,MAAM,qBAAM,IAAI,OAAO;AAAA,QACrC;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,WAAW,gBAAgB,aAAa,cAAc;AAEpD,UAAI,CAAC,iBAAI,eAAe,YAAoC,GAAG;AAC7D,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACvE;AACA,sBAAgB,MAAM,qBAAM,IAAI,QAAQ;AAAA,QACtC;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,WAAW,gBAAgB,aAAa,CAAC,aAAa;AAEpD,sBAAgB,UAAM;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,IAAI,MAAM,6BAA6B,WAAW,EAAE;AAAA,IAC5D;AAEA,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAEA,QAAK,KAAoC,cAAc;AACrD,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAEA,UAAM,UAAU;AAAA,MACd,GAAG;AAAA,MACH,SAAS;AAAA,QACP,GAAI,KAAK,WAAW,CAAC;AAAA,QACrB,aAAa;AAAA,QACb,iCAAiC;AAAA,MACnC;AAAA,MACA,cAAc;AAAA,IAChB;AAEA,UAAM,iBAAiB,MAAM,MAAM,OAAO,OAAO;AACjD,WAAO;AAAA,EACT;AACF;","names":["import_types"]}
|
package/dist/esm/index.d.mts
CHANGED
|
@@ -5,6 +5,10 @@ export { PaymentRequirementsSelector } from '@wtflabs/x402/client';
|
|
|
5
5
|
export { decodeXPaymentResponse } from '@wtflabs/x402/shared';
|
|
6
6
|
export { Chain, Hex } from 'viem';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Header name for specifying payment type
|
|
10
|
+
*/
|
|
11
|
+
declare const PAYMENT_TYPE_HEADER: "x-payment-type";
|
|
8
12
|
/**
|
|
9
13
|
* Enables the payment of APIs using the x402 payment protocol.
|
|
10
14
|
*
|
|
@@ -45,4 +49,4 @@ export { Chain, Hex } from 'viem';
|
|
|
45
49
|
declare function wrapFetchWithPayment(fetch: typeof globalThis.fetch, walletClient: Signer | MultiNetworkSigner, maxValue?: bigint, // Default to 0.10 USDC
|
|
46
50
|
paymentRequirementsSelector?: PaymentRequirementsSelector, config?: X402Config): (input: RequestInfo, init?: RequestInit) => Promise<Response>;
|
|
47
51
|
|
|
48
|
-
export { wrapFetchWithPayment };
|
|
52
|
+
export { PAYMENT_TYPE_HEADER, wrapFetchWithPayment };
|
package/dist/esm/index.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
createConnectedClient,
|
|
18
18
|
withChain
|
|
19
19
|
} from "@wtflabs/x402/types";
|
|
20
|
+
var PAYMENT_TYPE_HEADER = "x-payment-type";
|
|
20
21
|
function wrapFetchWithPayment(fetch, walletClient, maxValue = BigInt(0.1 * 10 ** 6), paymentRequirementsSelector = selectPaymentRequirements, config) {
|
|
21
22
|
return async (input, init) => {
|
|
22
23
|
var _a;
|
|
@@ -35,7 +36,8 @@ function wrapFetchWithPayment(fetch, walletClient, maxValue = BigInt(0.1 * 10 **
|
|
|
35
36
|
if (BigInt(selectedPaymentRequirements.maxAmountRequired) > maxValue) {
|
|
36
37
|
throw new Error("Payment amount exceeds maximum allowed");
|
|
37
38
|
}
|
|
38
|
-
const
|
|
39
|
+
const headerPaymentType = response.headers.get(PAYMENT_TYPE_HEADER);
|
|
40
|
+
const paymentType = selectedPaymentRequirements.paymentType || headerPaymentType || await exact.evm.getRecommendedPaymentMethod(
|
|
39
41
|
selectedPaymentRequirements.asset,
|
|
40
42
|
walletClient
|
|
41
43
|
) || "eip3009";
|
|
@@ -89,6 +91,7 @@ function wrapFetchWithPayment(fetch, walletClient, maxValue = BigInt(0.1 * 10 **
|
|
|
89
91
|
};
|
|
90
92
|
}
|
|
91
93
|
export {
|
|
94
|
+
PAYMENT_TYPE_HEADER,
|
|
92
95
|
createConnectedClient,
|
|
93
96
|
createSigner,
|
|
94
97
|
decodeXPaymentResponse,
|
package/dist/esm/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import {\n ChainIdToNetwork,\n PaymentRequirementsSchema,\n Signer,\n evm,\n MultiNetworkSigner,\n isMultiNetworkSigner,\n isSvmSignerWallet,\n Network,\n X402Config,\n} from \"@wtflabs/x402/types\";\nimport {\n createPaymentHeader,\n PaymentRequirementsSelector,\n selectPaymentRequirements,\n} from \"@wtflabs/x402/client\";\nimport { exact } from \"@wtflabs/x402/schemes\";\n\n/**\n * Enables the payment of APIs using the x402 payment protocol.\n *\n * This function wraps the native fetch API to automatically handle 402 Payment Required responses\n * by creating and sending a payment header. It will:\n * 1. Make the initial request\n * 2. If a 402 response is received, parse the payment requirements\n * 3. Verify the payment amount is within the allowed maximum\n * 4. Create a payment header using the provided wallet client\n * 5. Retry the request with the payment header\n *\n * @param fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param walletClient - The wallet client used to sign payment messages\n * @param maxValue - The maximum allowed payment amount in base units (defaults to 0.1 USDC)\n * @param paymentRequirementsSelector - A function that selects the payment requirements from the response\n * @param config - Optional configuration for X402 operations (e.g., custom RPC URLs)\n * @returns A wrapped fetch function that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * const wallet = new SignerWallet(...);\n * const fetchWithPay = wrapFetchWithPayment(fetch, wallet);\n *\n * // With custom RPC configuration\n * const fetchWithPay = wrapFetchWithPayment(fetch, wallet, undefined, undefined, {\n * svmConfig: { rpcUrl: \"http://localhost:8899\" }\n * });\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 the payment amount exceeds the maximum allowed value\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 walletClient: Signer | MultiNetworkSigner,\n maxValue: bigint = BigInt(0.1 * 10 ** 6), // Default to 0.10 USDC\n paymentRequirementsSelector: PaymentRequirementsSelector = selectPaymentRequirements,\n config?: X402Config,\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 const { x402Version, accepts } = (await response.json()) as {\n x402Version: number;\n accepts: unknown[];\n };\n const parsedPaymentRequirements = accepts.map(x => PaymentRequirementsSchema.parse(x));\n\n const network = isMultiNetworkSigner(walletClient)\n ? undefined\n : evm.isSignerWallet(walletClient as typeof evm.EvmSigner)\n ? ChainIdToNetwork[(walletClient as typeof evm.EvmSigner).chain?.id]\n : isSvmSignerWallet(walletClient)\n ? ([\"solana\", \"solana-devnet\"] as Network[])\n : undefined;\n\n const selectedPaymentRequirements = paymentRequirementsSelector(\n parsedPaymentRequirements,\n network,\n \"exact\",\n );\n\n if (BigInt(selectedPaymentRequirements.maxAmountRequired) > maxValue) {\n throw new Error(\"Payment amount exceeds maximum allowed\");\n }\n\n //
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import {\n ChainIdToNetwork,\n PaymentRequirementsSchema,\n Signer,\n evm,\n MultiNetworkSigner,\n isMultiNetworkSigner,\n isSvmSignerWallet,\n Network,\n X402Config,\n} from \"@wtflabs/x402/types\";\nimport {\n createPaymentHeader,\n PaymentRequirementsSelector,\n selectPaymentRequirements,\n} from \"@wtflabs/x402/client\";\nimport { exact } from \"@wtflabs/x402/schemes\";\n\n/**\n * Header name for specifying payment type\n */\nexport const PAYMENT_TYPE_HEADER = \"x-payment-type\" as const;\n\n/**\n * Enables the payment of APIs using the x402 payment protocol.\n *\n * This function wraps the native fetch API to automatically handle 402 Payment Required responses\n * by creating and sending a payment header. It will:\n * 1. Make the initial request\n * 2. If a 402 response is received, parse the payment requirements\n * 3. Verify the payment amount is within the allowed maximum\n * 4. Create a payment header using the provided wallet client\n * 5. Retry the request with the payment header\n *\n * @param fetch - The fetch function to wrap (typically globalThis.fetch)\n * @param walletClient - The wallet client used to sign payment messages\n * @param maxValue - The maximum allowed payment amount in base units (defaults to 0.1 USDC)\n * @param paymentRequirementsSelector - A function that selects the payment requirements from the response\n * @param config - Optional configuration for X402 operations (e.g., custom RPC URLs)\n * @returns A wrapped fetch function that handles 402 responses automatically\n *\n * @example\n * ```typescript\n * const wallet = new SignerWallet(...);\n * const fetchWithPay = wrapFetchWithPayment(fetch, wallet);\n *\n * // With custom RPC configuration\n * const fetchWithPay = wrapFetchWithPayment(fetch, wallet, undefined, undefined, {\n * svmConfig: { rpcUrl: \"http://localhost:8899\" }\n * });\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 the payment amount exceeds the maximum allowed value\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 walletClient: Signer | MultiNetworkSigner,\n maxValue: bigint = BigInt(0.1 * 10 ** 6), // Default to 0.10 USDC\n paymentRequirementsSelector: PaymentRequirementsSelector = selectPaymentRequirements,\n config?: X402Config,\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 const { x402Version, accepts } = (await response.json()) as {\n x402Version: number;\n accepts: unknown[];\n };\n const parsedPaymentRequirements = accepts.map(x => PaymentRequirementsSchema.parse(x));\n\n const network = isMultiNetworkSigner(walletClient)\n ? undefined\n : evm.isSignerWallet(walletClient as typeof evm.EvmSigner)\n ? ChainIdToNetwork[(walletClient as typeof evm.EvmSigner).chain?.id]\n : isSvmSignerWallet(walletClient)\n ? ([\"solana\", \"solana-devnet\"] as Network[])\n : undefined;\n\n const selectedPaymentRequirements = paymentRequirementsSelector(\n parsedPaymentRequirements,\n network,\n \"exact\",\n );\n\n if (BigInt(selectedPaymentRequirements.maxAmountRequired) > maxValue) {\n throw new Error(\"Payment amount exceeds maximum allowed\");\n }\n\n // 从响应 header 中获取支付类型\n const headerPaymentType = response.headers.get(PAYMENT_TYPE_HEADER);\n\n // 获取支付类型,优先级:header > paymentRequirements > 自动检测 > 默认\n const paymentType =\n selectedPaymentRequirements.paymentType ||\n headerPaymentType ||\n (await exact.evm.getRecommendedPaymentMethod(\n selectedPaymentRequirements.asset,\n walletClient as typeof evm.EvmSigner,\n )) ||\n \"eip3009\";\n\n // 根据支付类型创建支付头\n let paymentHeader: string;\n\n // 仅对 EVM 网络支持 permit 和 permit2\n const isEvmNetwork = network && ![\"solana\", \"solana-devnet\"].includes(network[0]);\n\n if (paymentType === \"permit\" && isEvmNetwork) {\n // 使用 EIP-2612 Permit\n if (!evm.isSignerWallet(walletClient as typeof evm.EvmSigner)) {\n throw new Error(\"Permit authorization requires an EVM signer wallet\");\n }\n paymentHeader = await exact.evm.permit.createPaymentHeader(\n walletClient as typeof evm.EvmSigner,\n x402Version,\n selectedPaymentRequirements,\n );\n } else if (paymentType === \"permit2\" && isEvmNetwork) {\n // 使用 Permit2\n if (!evm.isSignerWallet(walletClient as typeof evm.EvmSigner)) {\n throw new Error(\"Permit2 authorization requires an EVM signer wallet\");\n }\n paymentHeader = await exact.evm.permit2.createPaymentHeader(\n walletClient as typeof evm.EvmSigner,\n x402Version,\n selectedPaymentRequirements,\n );\n } else if (paymentType === \"eip3009\" || !paymentType) {\n // 默认使用 EIP-3009(统一的 createPaymentHeader)\n paymentHeader = await createPaymentHeader(\n walletClient,\n x402Version,\n selectedPaymentRequirements,\n config,\n );\n } else {\n throw new Error(`Unsupported payment type: ${paymentType}`);\n }\n\n if (!init) {\n throw new Error(\"Missing fetch request configuration\");\n }\n\n if ((init as { __is402Retry?: boolean }).__is402Retry) {\n throw new Error(\"Payment already attempted\");\n }\n\n const newInit = {\n ...init,\n headers: {\n ...(init.headers || {}),\n \"X-PAYMENT\": paymentHeader,\n \"Access-Control-Expose-Headers\": \"X-PAYMENT-RESPONSE\",\n },\n __is402Retry: true,\n };\n\n const secondResponse = await fetch(input, newInit);\n return secondResponse;\n };\n}\n\nexport { decodeXPaymentResponse } from \"@wtflabs/x402/shared\";\nexport {\n createSigner,\n createConnectedClient,\n withChain,\n type Signer,\n type ConnectedClient,\n type MultiNetworkSigner,\n type X402Config,\n type EvmChainConfig,\n} from \"@wtflabs/x402/types\";\nexport { type PaymentRequirementsSelector } from \"@wtflabs/x402/client\";\nexport type { Hex, Chain } from \"viem\";\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EAEA;AAAA,OACK;AACP,SAAS,aAAa;AA4JtB,SAAS,8BAA8B;AACvC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AAjKA,IAAM,sBAAsB;AAuC5B,SAAS,qBACd,OACA,cACA,WAAmB,OAAO,MAAM,MAAM,CAAC,GACvC,8BAA2D,2BAC3D,QACA;AACA,SAAO,OAAO,OAAoB,SAAuB;AAnE3D;AAoEI,UAAM,WAAW,MAAM,MAAM,OAAO,IAAI;AAExC,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AAEA,UAAM,EAAE,aAAa,QAAQ,IAAK,MAAM,SAAS,KAAK;AAItD,UAAM,4BAA4B,QAAQ,IAAI,OAAK,0BAA0B,MAAM,CAAC,CAAC;AAErF,UAAM,UAAU,qBAAqB,YAAY,IAC7C,SACA,IAAI,eAAe,YAAoC,IACrD,kBAAkB,kBAAsC,UAAtC,mBAA6C,EAAE,IACjE,kBAAkB,YAAY,IAC3B,CAAC,UAAU,eAAe,IAC3B;AAER,UAAM,8BAA8B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,OAAO,4BAA4B,iBAAiB,IAAI,UAAU;AACpE,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAGA,UAAM,oBAAoB,SAAS,QAAQ,IAAI,mBAAmB;AAGlE,UAAM,cACJ,4BAA4B,eAC5B,qBACC,MAAM,MAAM,IAAI;AAAA,MACf,4BAA4B;AAAA,MAC5B;AAAA,IACF,KACA;AAGF,QAAI;AAGJ,UAAM,eAAe,WAAW,CAAC,CAAC,UAAU,eAAe,EAAE,SAAS,QAAQ,CAAC,CAAC;AAEhF,QAAI,gBAAgB,YAAY,cAAc;AAE5C,UAAI,CAAC,IAAI,eAAe,YAAoC,GAAG;AAC7D,cAAM,IAAI,MAAM,oDAAoD;AAAA,MACtE;AACA,sBAAgB,MAAM,MAAM,IAAI,OAAO;AAAA,QACrC;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,WAAW,gBAAgB,aAAa,cAAc;AAEpD,UAAI,CAAC,IAAI,eAAe,YAAoC,GAAG;AAC7D,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACvE;AACA,sBAAgB,MAAM,MAAM,IAAI,QAAQ;AAAA,QACtC;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,WAAW,gBAAgB,aAAa,CAAC,aAAa;AAEpD,sBAAgB,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,IAAI,MAAM,6BAA6B,WAAW,EAAE;AAAA,IAC5D;AAEA,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAEA,QAAK,KAAoC,cAAc;AACrD,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAEA,UAAM,UAAU;AAAA,MACd,GAAG;AAAA,MACH,SAAS;AAAA,QACP,GAAI,KAAK,WAAW,CAAC;AAAA,QACrB,aAAa;AAAA,QACb,iCAAiC;AAAA,MACnC;AAAA,MACA,cAAc;AAAA,IAChB;AAEA,UAAM,iBAAiB,MAAM,MAAM,OAAO,OAAO;AACjD,WAAO;AAAA,EACT;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtflabs/x402-fetch",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.12",
|
|
4
4
|
"main": "./dist/cjs/index.js",
|
|
5
5
|
"module": "./dist/esm/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "tsx --env-file=.env index.ts",
|
|
9
|
+
"test": "vitest run",
|
|
10
|
+
"test:watch": "vitest",
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"watch": "tsc --watch",
|
|
13
|
+
"format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"",
|
|
14
|
+
"format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"",
|
|
15
|
+
"lint": "eslint . --ext .ts --fix",
|
|
16
|
+
"lint:check": "eslint . --ext .ts"
|
|
17
|
+
},
|
|
7
18
|
"keywords": [],
|
|
8
19
|
"license": "Apache-2.0",
|
|
9
20
|
"author": "Coinbase Inc.",
|
|
@@ -29,7 +40,7 @@
|
|
|
29
40
|
"dependencies": {
|
|
30
41
|
"viem": "^2.21.26",
|
|
31
42
|
"zod": "^3.24.2",
|
|
32
|
-
"@wtflabs/x402": "
|
|
43
|
+
"@wtflabs/x402": "workspace:^"
|
|
33
44
|
},
|
|
34
45
|
"exports": {
|
|
35
46
|
".": {
|
|
@@ -45,16 +56,5 @@
|
|
|
45
56
|
},
|
|
46
57
|
"files": [
|
|
47
58
|
"dist"
|
|
48
|
-
]
|
|
49
|
-
|
|
50
|
-
"start": "tsx --env-file=.env index.ts",
|
|
51
|
-
"test": "vitest run",
|
|
52
|
-
"test:watch": "vitest",
|
|
53
|
-
"build": "tsup",
|
|
54
|
-
"watch": "tsc --watch",
|
|
55
|
-
"format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"",
|
|
56
|
-
"format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"",
|
|
57
|
-
"lint": "eslint . --ext .ts --fix",
|
|
58
|
-
"lint:check": "eslint . --ext .ts"
|
|
59
|
-
}
|
|
60
|
-
}
|
|
59
|
+
]
|
|
60
|
+
}
|