x402z-client 0.0.10 → 0.1.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.
package/README.md CHANGED
@@ -26,6 +26,7 @@ const account = privateKeyToAccount("0x...");
26
26
  const relayer = await createRelayer(SepoliaConfig);
27
27
 
28
28
  const client = createX402zClient({
29
+ schemePreference: ["erc7984-mind-v1"],
29
30
  signer: {
30
31
  address: account.address,
31
32
  signTypedData: account.signTypedData,
@@ -33,8 +34,8 @@ const client = createX402zClient({
33
34
  relayer,
34
35
  });
35
36
 
36
- const response = await client.pay("https://example.com/demo");
37
- console.log(response.status);
37
+ const paid = await client.pay("https://example.com/demo");
38
+ console.log(paid.response.status);
38
39
  ```
39
40
 
40
41
  `createX402zClient` builds the confidential payment input automatically using the
@@ -43,13 +44,65 @@ console.log(response.status);
43
44
  ## API
44
45
 
45
46
  - `createX402zClient(config)`
46
- - `signer` (required): EIP-712 signer for x402 payloads
47
- - `relayer` (required): Zama relayer instance used to build encrypted inputs
47
+ - `schemePreference` (required): ordered list of schemes to try (e.g. `["erc7984-mind-v1", "exact"]`)
48
+ - `signer` (required): signer used for both exact and confidential schemes
49
+ - `relayer` (required when using `erc7984-mind-v1`): Zama relayer instance used to build encrypted inputs
48
50
  - `fetch` (optional): custom fetch implementation
49
51
  - `client.pay(url, options?)`: performs the 402 handshake and retries with payment headers
52
+ - returns `{ response, paymentRequired?, confidentialRequirements? }`
53
+
54
+ ## Examples
55
+
56
+ See `examples/README.md` for the full-process scripts (`client-pay.ts`, `client-wrap.ts`, `client-unwrap.ts`).
57
+
58
+ ## Exact scheme (ERC20) usage
59
+
60
+ ```ts
61
+ import { createX402zClient } from "x402z-client";
62
+ import { privateKeyToAccount } from "viem/accounts";
63
+
64
+ const account = privateKeyToAccount("0x...");
65
+ const client = createX402zClient({
66
+ schemePreference: ["exact"],
67
+ signer: account,
68
+ });
69
+
70
+ const paid = await client.pay("http://localhost:8090/erc20-demo");
71
+ console.log(paid.response.status);
72
+ ```
50
73
 
51
74
  ## Notes
52
75
 
53
- - Scheme name: `erc7984-mind-v1`
76
+ - Confidential scheme name: `erc7984-mind-v1`
77
+ - Exact scheme name: `exact`
54
78
  - The client does not expose balance helpers; use `x402z-shared` for that.
55
79
  - For browser usage, use `x402z-client-web` with `x402z-shared-web`.
80
+
81
+ ## API surface
82
+
83
+ Exports:
84
+ - `X402zEvmClientScheme`: client scheme implementation for erc7984-mind-v1.
85
+ - `registerX402zEvmClientScheme`: registers the scheme with x402 client.
86
+ - `buildPaymentInput`: builds encrypted payment input for a requirement.
87
+ - `createX402zClient`: convenience client wrapper for pay flows.
88
+ - `x402Client`: core x402 client constructor.
89
+ - `x402HTTPClient`: core HTTP client wrapper.
90
+
91
+ Types:
92
+ - `X402zClientSchemeOptions`: scheme config for client registration.
93
+ - `X402zClientRegistrationOptions`: registration options for the scheme.
94
+ - `X402zClientOptions`: options for `createX402zClient`.
95
+ - `X402zConfidentialClientOptions`: options for confidential payments.
96
+ - `X402zExactClientOptions`: options for exact payments.
97
+ - `PayOptions`: per-request payment options.
98
+ - `AfterPaymentCreationHook`: hook after a payment is built.
99
+ - `BeforePaymentCreationHook`: hook before a payment is built.
100
+ - `OnPaymentCreationFailureHook`: hook on payment build failures.
101
+ - `PaymentCreatedContext`: context for successful payment creation.
102
+ - `PaymentCreationContext`: context for payment creation.
103
+ - `PaymentCreationFailureContext`: context for payment errors.
104
+ - `PaymentPolicy`: policy for selecting payment requirements.
105
+ - `SchemeRegistration`: generic scheme registration type.
106
+ - `SelectPaymentRequirements`: selection callback for requirements.
107
+ - `x402ClientConfig`: x402 client configuration type.
108
+ - re-exported types from `@x402/core/types`: shared x402 types.
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { SchemeNetworkClient, PaymentRequirements, PaymentPayload, Network } from '@x402/core/types';
1
+ import { SchemeNetworkClient, PaymentRequirements, PaymentPayload, Network, PaymentRequired } from '@x402/core/types';
2
2
  export * from '@x402/core/types';
3
3
  import { ClientEvmSigner } from '@x402/evm';
4
4
  import { ConfidentialPaymentInput, RelayerInstance } from 'x402z-shared';
5
- import { x402Client } from '@x402/core/client';
5
+ import { x402Client, SelectPaymentRequirements, PaymentPolicy } from '@x402/core/client';
6
6
  export { AfterPaymentCreationHook, BeforePaymentCreationHook, OnPaymentCreationFailureHook, PaymentCreatedContext, PaymentCreationContext, PaymentCreationFailureContext, PaymentPolicy, SchemeRegistration, SelectPaymentRequirements, x402Client, x402ClientConfig, x402HTTPClient } from '@x402/core/client';
7
7
 
8
8
  type X402zClientSchemeOptions = {
@@ -31,16 +31,38 @@ declare function registerX402zEvmClientScheme(client: x402Client, config: X402zC
31
31
 
32
32
  declare function buildPaymentInput(relayer: RelayerInstance, requirements: PaymentRequirements, amount: number): Promise<ConfidentialPaymentInput>;
33
33
 
34
- type X402zClientOptions = Omit<X402zClientRegistrationOptions, "buildPayment"> & {
35
- relayer: RelayerInstance;
34
+ type Scheme = "exact" | "erc7984-mind-v1";
35
+ type BaseClientOptions = {
36
36
  fetch?: typeof fetch;
37
37
  debug?: boolean;
38
38
  };
39
+ type X402zClientOptions = {
40
+ schemePreference: Scheme[];
41
+ signer: ClientEvmSigner;
42
+ relayer?: RelayerInstance;
43
+ networks?: Network[];
44
+ paymentRequirementsSelector?: SelectPaymentRequirements;
45
+ policies?: PaymentPolicy[];
46
+ eip712?: X402zClientSchemeOptions["eip712"];
47
+ hashEncryptedAmountInput?: X402zClientSchemeOptions["hashEncryptedAmountInput"];
48
+ clock?: X402zClientSchemeOptions["clock"];
49
+ onPaymentSelected?: (info: {
50
+ scheme: Scheme;
51
+ requirements: PaymentRequirements;
52
+ }) => void;
53
+ } & BaseClientOptions;
39
54
  type PayOptions = {
40
55
  headers?: Record<string, string>;
41
56
  };
42
- declare function createX402zClient(config: X402zClientOptions): {
43
- pay(url: string, options?: PayOptions): Promise<Response>;
57
+ type PayResult = {
58
+ response: Response;
59
+ paymentRequired?: PaymentRequired;
60
+ confidentialRequirements?: PaymentRequirements;
61
+ };
62
+ type X402zClient = {
63
+ relayer?: RelayerInstance;
64
+ pay: (url: string, options?: PayOptions) => Promise<PayResult>;
44
65
  };
66
+ declare function createX402zClient(config: X402zClientOptions): X402zClient;
45
67
 
46
- export { type PayOptions, type X402zClientOptions, type X402zClientRegistrationOptions, type X402zClientSchemeOptions, X402zEvmClientScheme, buildPaymentInput, createX402zClient, registerX402zEvmClientScheme };
68
+ export { type PayOptions, type PayResult, type X402zClientOptions, type X402zClientRegistrationOptions, type X402zClientSchemeOptions, X402zEvmClientScheme, buildPaymentInput, createX402zClient, registerX402zEvmClientScheme };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { SchemeNetworkClient, PaymentRequirements, PaymentPayload, Network } from '@x402/core/types';
1
+ import { SchemeNetworkClient, PaymentRequirements, PaymentPayload, Network, PaymentRequired } from '@x402/core/types';
2
2
  export * from '@x402/core/types';
3
3
  import { ClientEvmSigner } from '@x402/evm';
4
4
  import { ConfidentialPaymentInput, RelayerInstance } from 'x402z-shared';
5
- import { x402Client } from '@x402/core/client';
5
+ import { x402Client, SelectPaymentRequirements, PaymentPolicy } from '@x402/core/client';
6
6
  export { AfterPaymentCreationHook, BeforePaymentCreationHook, OnPaymentCreationFailureHook, PaymentCreatedContext, PaymentCreationContext, PaymentCreationFailureContext, PaymentPolicy, SchemeRegistration, SelectPaymentRequirements, x402Client, x402ClientConfig, x402HTTPClient } from '@x402/core/client';
7
7
 
8
8
  type X402zClientSchemeOptions = {
@@ -31,16 +31,38 @@ declare function registerX402zEvmClientScheme(client: x402Client, config: X402zC
31
31
 
32
32
  declare function buildPaymentInput(relayer: RelayerInstance, requirements: PaymentRequirements, amount: number): Promise<ConfidentialPaymentInput>;
33
33
 
34
- type X402zClientOptions = Omit<X402zClientRegistrationOptions, "buildPayment"> & {
35
- relayer: RelayerInstance;
34
+ type Scheme = "exact" | "erc7984-mind-v1";
35
+ type BaseClientOptions = {
36
36
  fetch?: typeof fetch;
37
37
  debug?: boolean;
38
38
  };
39
+ type X402zClientOptions = {
40
+ schemePreference: Scheme[];
41
+ signer: ClientEvmSigner;
42
+ relayer?: RelayerInstance;
43
+ networks?: Network[];
44
+ paymentRequirementsSelector?: SelectPaymentRequirements;
45
+ policies?: PaymentPolicy[];
46
+ eip712?: X402zClientSchemeOptions["eip712"];
47
+ hashEncryptedAmountInput?: X402zClientSchemeOptions["hashEncryptedAmountInput"];
48
+ clock?: X402zClientSchemeOptions["clock"];
49
+ onPaymentSelected?: (info: {
50
+ scheme: Scheme;
51
+ requirements: PaymentRequirements;
52
+ }) => void;
53
+ } & BaseClientOptions;
39
54
  type PayOptions = {
40
55
  headers?: Record<string, string>;
41
56
  };
42
- declare function createX402zClient(config: X402zClientOptions): {
43
- pay(url: string, options?: PayOptions): Promise<Response>;
57
+ type PayResult = {
58
+ response: Response;
59
+ paymentRequired?: PaymentRequired;
60
+ confidentialRequirements?: PaymentRequirements;
61
+ };
62
+ type X402zClient = {
63
+ relayer?: RelayerInstance;
64
+ pay: (url: string, options?: PayOptions) => Promise<PayResult>;
44
65
  };
66
+ declare function createX402zClient(config: X402zClientOptions): X402zClient;
45
67
 
46
- export { type PayOptions, type X402zClientOptions, type X402zClientRegistrationOptions, type X402zClientSchemeOptions, X402zEvmClientScheme, buildPaymentInput, createX402zClient, registerX402zEvmClientScheme };
68
+ export { type PayOptions, type PayResult, type X402zClientOptions, type X402zClientRegistrationOptions, type X402zClientSchemeOptions, X402zEvmClientScheme, buildPaymentInput, createX402zClient, registerX402zEvmClientScheme };
package/dist/index.js CHANGED
@@ -24,8 +24,8 @@ __export(index_exports, {
24
24
  buildPaymentInput: () => buildPaymentInput,
25
25
  createX402zClient: () => createX402zClient,
26
26
  registerX402zEvmClientScheme: () => registerX402zEvmClientScheme,
27
- x402Client: () => import_client3.x402Client,
28
- x402HTTPClient: () => import_client3.x402HTTPClient
27
+ x402Client: () => import_client4.x402Client,
28
+ x402HTTPClient: () => import_client4.x402HTTPClient
29
29
  });
30
30
  module.exports = __toCommonJS(index_exports);
31
31
 
@@ -147,18 +147,38 @@ async function buildPaymentInput(relayer, requirements, amount) {
147
147
  // src/http/client.ts
148
148
  var import_client = require("@x402/core/client");
149
149
  var import_http = require("@x402/core/http");
150
+ var import_client2 = require("@x402/evm/exact/client");
150
151
  var import_viem2 = require("viem");
151
152
  var import_x402z_shared3 = require("x402z-shared");
152
- function createX402zClient(config) {
153
- const { fetch: fetchOverride, ...registerConfig } = config;
154
- const fetchFn = fetchOverride ?? globalThis.fetch;
155
- const debugEnabled = config.debug ?? process.env.X402Z_DEBUG === "1";
156
- if (!fetchFn) {
157
- throw new Error("fetch is not available; provide a fetch implementation");
158
- }
153
+ function filterPaymentRequired(paymentRequired, scheme) {
154
+ const accepts = paymentRequired.accepts.filter((requirement) => requirement.scheme === scheme);
155
+ return { ...paymentRequired, accepts };
156
+ }
157
+ function createExactPayer(config, debugEnabled) {
158
+ const client = new import_client.x402Client(config.paymentRequirementsSelector);
159
+ (0, import_client2.registerExactEvmScheme)(client, {
160
+ signer: config.signer,
161
+ networks: config.networks,
162
+ policies: config.policies,
163
+ paymentRequirementsSelector: config.paymentRequirementsSelector
164
+ });
165
+ const httpClient = new import_http.x402HTTPClient(client);
166
+ return {
167
+ async buildHeaders(paymentRequired) {
168
+ const payload = await httpClient.createPaymentPayload(paymentRequired);
169
+ const payHeaders = httpClient.encodePaymentSignatureHeader(payload);
170
+ if (debugEnabled) {
171
+ console.debug("[x402z-client] payment payload", payload);
172
+ console.debug("[x402z-client] payment headers", payHeaders);
173
+ }
174
+ return { headers: payHeaders };
175
+ }
176
+ };
177
+ }
178
+ function createConfidentialPayer(config, debugEnabled) {
159
179
  const buildPayment = async (requirements) => {
160
180
  if (!(0, import_viem2.isAddress)(requirements.asset)) {
161
- throw new Error(`Invalid TOKEN_ADDRESS from requirements: ${requirements.asset}`);
181
+ throw new Error(`Invalid token address from requirements: ${requirements.asset}`);
162
182
  }
163
183
  const extra = requirements.extra;
164
184
  const batcherAddress = extra?.confidential?.batcherAddress;
@@ -185,51 +205,132 @@ function createX402zClient(config) {
185
205
  };
186
206
  const client = new import_client.x402Client();
187
207
  registerX402zEvmClientScheme(client, {
188
- ...registerConfig,
189
- buildPayment
208
+ signer: config.signer,
209
+ buildPayment,
210
+ eip712: config.eip712,
211
+ hashEncryptedAmountInput: config.hashEncryptedAmountInput,
212
+ clock: config.clock,
213
+ networks: config.networks
190
214
  });
191
215
  const httpClient = new import_http.x402HTTPClient(client);
216
+ const extractConfidentialRequirements = (paymentRequired) => {
217
+ const requirements = paymentRequired.accepts.find(
218
+ (requirement) => requirement.scheme === "erc7984-mind-v1"
219
+ );
220
+ if (!requirements) {
221
+ throw new Error("Missing erc7984-mind-v1 payment requirements");
222
+ }
223
+ return requirements;
224
+ };
192
225
  return {
193
- async pay(url, options) {
194
- const initial = await fetchFn(url, { headers: options?.headers });
195
- if (initial.status !== 402) {
196
- return initial;
197
- }
198
- const paymentRequired = httpClient.getPaymentRequiredResponse(
199
- (name) => initial.headers.get(name),
200
- await initial.json().catch(() => ({}))
201
- );
226
+ relayer: config.relayer,
227
+ extractConfidentialRequirements,
228
+ async buildHeaders(paymentRequired) {
202
229
  const payload = await httpClient.createPaymentPayload(paymentRequired);
203
230
  const payHeaders = httpClient.encodePaymentSignatureHeader(payload);
204
231
  if (debugEnabled) {
205
232
  console.debug("[x402z-client] payment payload", payload);
206
233
  console.debug("[x402z-client] payment headers", payHeaders);
207
234
  }
208
- const mergedHeaders = { ...options?.headers ?? {}, ...payHeaders };
209
- const paidResponse = await fetchFn(url, { headers: mergedHeaders });
210
- if (debugEnabled) {
211
- try {
212
- const body = await paidResponse.clone().text();
213
- console.debug("[x402z-client] response", {
214
- status: paidResponse.status,
215
- headers: Object.fromEntries(paidResponse.headers.entries()),
216
- body
217
- });
218
- } catch (error) {
219
- console.debug("[x402z-client] response", {
220
- status: paidResponse.status,
221
- headers: Object.fromEntries(paidResponse.headers.entries()),
222
- body: "<unavailable>"
223
- });
224
- }
235
+ return { headers: payHeaders };
236
+ }
237
+ };
238
+ }
239
+ function createX402zClient(config) {
240
+ const fetchFn = config.fetch ?? globalThis.fetch;
241
+ const debugEnabled = config.debug ?? process.env.X402Z_DEBUG === "1";
242
+ if (!fetchFn) {
243
+ throw new Error("fetch is not available; provide a fetch implementation");
244
+ }
245
+ const schemePreference = config.schemePreference?.length ? config.schemePreference : ["exact"];
246
+ const exactPayer = createExactPayer(
247
+ {
248
+ signer: config.signer,
249
+ networks: config.networks,
250
+ paymentRequirementsSelector: config.paymentRequirementsSelector,
251
+ policies: config.policies
252
+ },
253
+ debugEnabled
254
+ );
255
+ const confidentialPayer = config.relayer ? createConfidentialPayer(
256
+ {
257
+ signer: config.signer,
258
+ relayer: config.relayer,
259
+ eip712: config.eip712,
260
+ hashEncryptedAmountInput: config.hashEncryptedAmountInput,
261
+ clock: config.clock,
262
+ networks: config.networks
263
+ },
264
+ debugEnabled
265
+ ) : void 0;
266
+ const parserClient = new import_client.x402Client();
267
+ const parserHttp = new import_http.x402HTTPClient(parserClient);
268
+ const pay = async (url, options) => {
269
+ const initial = await fetchFn(url, { headers: options?.headers });
270
+ if (initial.status !== 402) {
271
+ return { response: initial };
272
+ }
273
+ const paymentRequired = parserHttp.getPaymentRequiredResponse(
274
+ (name) => initial.headers.get(name),
275
+ await initial.json().catch(() => ({}))
276
+ );
277
+ const supportedSchemes = new Set(
278
+ paymentRequired.accepts.map((accept) => accept.scheme)
279
+ );
280
+ const selectedScheme = schemePreference.find(
281
+ (scheme) => supportedSchemes.has(scheme)
282
+ );
283
+ if (!selectedScheme) {
284
+ throw new Error("No preferred schemes are supported by payment requirements");
285
+ }
286
+ const filteredRequirements = filterPaymentRequired(paymentRequired, selectedScheme);
287
+ if (filteredRequirements.accepts.length === 0) {
288
+ throw new Error(`Missing ${selectedScheme} payment requirements`);
289
+ }
290
+ let headersResult;
291
+ let confidentialRequirements;
292
+ const selectedRequirements = filteredRequirements.accepts[0];
293
+ config.onPaymentSelected?.({
294
+ scheme: selectedScheme,
295
+ requirements: selectedRequirements
296
+ });
297
+ if (selectedScheme === "exact") {
298
+ headersResult = await exactPayer.buildHeaders(filteredRequirements);
299
+ } else {
300
+ if (!confidentialPayer) {
301
+ throw new Error("Confidential scheme is selected but relayer is missing");
225
302
  }
226
- return paidResponse;
303
+ confidentialRequirements = confidentialPayer.extractConfidentialRequirements(filteredRequirements);
304
+ headersResult = await confidentialPayer.buildHeaders(filteredRequirements);
227
305
  }
306
+ const mergedHeaders = { ...options?.headers ?? {}, ...headersResult.headers };
307
+ const paidResponse = await fetchFn(url, { headers: mergedHeaders });
308
+ if (debugEnabled) {
309
+ try {
310
+ const body = await paidResponse.clone().text();
311
+ console.debug("[x402z-client] response", {
312
+ status: paidResponse.status,
313
+ headers: Object.fromEntries(paidResponse.headers.entries()),
314
+ body
315
+ });
316
+ } catch (error) {
317
+ console.debug("[x402z-client] response", {
318
+ status: paidResponse.status,
319
+ headers: Object.fromEntries(paidResponse.headers.entries()),
320
+ body: "<unavailable>"
321
+ });
322
+ }
323
+ }
324
+ return { response: paidResponse, paymentRequired, confidentialRequirements };
325
+ };
326
+ return {
327
+ relayer: confidentialPayer?.relayer,
328
+ pay
228
329
  };
229
330
  }
230
331
 
231
332
  // src/index.ts
232
- var import_client3 = require("@x402/core/client");
333
+ var import_client4 = require("@x402/core/client");
233
334
  // Annotate the CommonJS export names for ESM import in node:
234
335
  0 && (module.exports = {
235
336
  X402zEvmClientScheme,
package/dist/index.mjs CHANGED
@@ -121,20 +121,40 @@ async function buildPaymentInput(relayer, requirements, amount) {
121
121
  // src/http/client.ts
122
122
  import { x402Client } from "@x402/core/client";
123
123
  import { x402HTTPClient } from "@x402/core/http";
124
+ import { registerExactEvmScheme } from "@x402/evm/exact/client";
124
125
  import { isAddress } from "viem";
125
126
  import {
126
127
  createEncryptedAmountInput as createEncryptedAmountInput2
127
128
  } from "x402z-shared";
128
- function createX402zClient(config) {
129
- const { fetch: fetchOverride, ...registerConfig } = config;
130
- const fetchFn = fetchOverride ?? globalThis.fetch;
131
- const debugEnabled = config.debug ?? process.env.X402Z_DEBUG === "1";
132
- if (!fetchFn) {
133
- throw new Error("fetch is not available; provide a fetch implementation");
134
- }
129
+ function filterPaymentRequired(paymentRequired, scheme) {
130
+ const accepts = paymentRequired.accepts.filter((requirement) => requirement.scheme === scheme);
131
+ return { ...paymentRequired, accepts };
132
+ }
133
+ function createExactPayer(config, debugEnabled) {
134
+ const client = new x402Client(config.paymentRequirementsSelector);
135
+ registerExactEvmScheme(client, {
136
+ signer: config.signer,
137
+ networks: config.networks,
138
+ policies: config.policies,
139
+ paymentRequirementsSelector: config.paymentRequirementsSelector
140
+ });
141
+ const httpClient = new x402HTTPClient(client);
142
+ return {
143
+ async buildHeaders(paymentRequired) {
144
+ const payload = await httpClient.createPaymentPayload(paymentRequired);
145
+ const payHeaders = httpClient.encodePaymentSignatureHeader(payload);
146
+ if (debugEnabled) {
147
+ console.debug("[x402z-client] payment payload", payload);
148
+ console.debug("[x402z-client] payment headers", payHeaders);
149
+ }
150
+ return { headers: payHeaders };
151
+ }
152
+ };
153
+ }
154
+ function createConfidentialPayer(config, debugEnabled) {
135
155
  const buildPayment = async (requirements) => {
136
156
  if (!isAddress(requirements.asset)) {
137
- throw new Error(`Invalid TOKEN_ADDRESS from requirements: ${requirements.asset}`);
157
+ throw new Error(`Invalid token address from requirements: ${requirements.asset}`);
138
158
  }
139
159
  const extra = requirements.extra;
140
160
  const batcherAddress = extra?.confidential?.batcherAddress;
@@ -161,46 +181,127 @@ function createX402zClient(config) {
161
181
  };
162
182
  const client = new x402Client();
163
183
  registerX402zEvmClientScheme(client, {
164
- ...registerConfig,
165
- buildPayment
184
+ signer: config.signer,
185
+ buildPayment,
186
+ eip712: config.eip712,
187
+ hashEncryptedAmountInput: config.hashEncryptedAmountInput,
188
+ clock: config.clock,
189
+ networks: config.networks
166
190
  });
167
191
  const httpClient = new x402HTTPClient(client);
192
+ const extractConfidentialRequirements = (paymentRequired) => {
193
+ const requirements = paymentRequired.accepts.find(
194
+ (requirement) => requirement.scheme === "erc7984-mind-v1"
195
+ );
196
+ if (!requirements) {
197
+ throw new Error("Missing erc7984-mind-v1 payment requirements");
198
+ }
199
+ return requirements;
200
+ };
168
201
  return {
169
- async pay(url, options) {
170
- const initial = await fetchFn(url, { headers: options?.headers });
171
- if (initial.status !== 402) {
172
- return initial;
173
- }
174
- const paymentRequired = httpClient.getPaymentRequiredResponse(
175
- (name) => initial.headers.get(name),
176
- await initial.json().catch(() => ({}))
177
- );
202
+ relayer: config.relayer,
203
+ extractConfidentialRequirements,
204
+ async buildHeaders(paymentRequired) {
178
205
  const payload = await httpClient.createPaymentPayload(paymentRequired);
179
206
  const payHeaders = httpClient.encodePaymentSignatureHeader(payload);
180
207
  if (debugEnabled) {
181
208
  console.debug("[x402z-client] payment payload", payload);
182
209
  console.debug("[x402z-client] payment headers", payHeaders);
183
210
  }
184
- const mergedHeaders = { ...options?.headers ?? {}, ...payHeaders };
185
- const paidResponse = await fetchFn(url, { headers: mergedHeaders });
186
- if (debugEnabled) {
187
- try {
188
- const body = await paidResponse.clone().text();
189
- console.debug("[x402z-client] response", {
190
- status: paidResponse.status,
191
- headers: Object.fromEntries(paidResponse.headers.entries()),
192
- body
193
- });
194
- } catch (error) {
195
- console.debug("[x402z-client] response", {
196
- status: paidResponse.status,
197
- headers: Object.fromEntries(paidResponse.headers.entries()),
198
- body: "<unavailable>"
199
- });
200
- }
211
+ return { headers: payHeaders };
212
+ }
213
+ };
214
+ }
215
+ function createX402zClient(config) {
216
+ const fetchFn = config.fetch ?? globalThis.fetch;
217
+ const debugEnabled = config.debug ?? process.env.X402Z_DEBUG === "1";
218
+ if (!fetchFn) {
219
+ throw new Error("fetch is not available; provide a fetch implementation");
220
+ }
221
+ const schemePreference = config.schemePreference?.length ? config.schemePreference : ["exact"];
222
+ const exactPayer = createExactPayer(
223
+ {
224
+ signer: config.signer,
225
+ networks: config.networks,
226
+ paymentRequirementsSelector: config.paymentRequirementsSelector,
227
+ policies: config.policies
228
+ },
229
+ debugEnabled
230
+ );
231
+ const confidentialPayer = config.relayer ? createConfidentialPayer(
232
+ {
233
+ signer: config.signer,
234
+ relayer: config.relayer,
235
+ eip712: config.eip712,
236
+ hashEncryptedAmountInput: config.hashEncryptedAmountInput,
237
+ clock: config.clock,
238
+ networks: config.networks
239
+ },
240
+ debugEnabled
241
+ ) : void 0;
242
+ const parserClient = new x402Client();
243
+ const parserHttp = new x402HTTPClient(parserClient);
244
+ const pay = async (url, options) => {
245
+ const initial = await fetchFn(url, { headers: options?.headers });
246
+ if (initial.status !== 402) {
247
+ return { response: initial };
248
+ }
249
+ const paymentRequired = parserHttp.getPaymentRequiredResponse(
250
+ (name) => initial.headers.get(name),
251
+ await initial.json().catch(() => ({}))
252
+ );
253
+ const supportedSchemes = new Set(
254
+ paymentRequired.accepts.map((accept) => accept.scheme)
255
+ );
256
+ const selectedScheme = schemePreference.find(
257
+ (scheme) => supportedSchemes.has(scheme)
258
+ );
259
+ if (!selectedScheme) {
260
+ throw new Error("No preferred schemes are supported by payment requirements");
261
+ }
262
+ const filteredRequirements = filterPaymentRequired(paymentRequired, selectedScheme);
263
+ if (filteredRequirements.accepts.length === 0) {
264
+ throw new Error(`Missing ${selectedScheme} payment requirements`);
265
+ }
266
+ let headersResult;
267
+ let confidentialRequirements;
268
+ const selectedRequirements = filteredRequirements.accepts[0];
269
+ config.onPaymentSelected?.({
270
+ scheme: selectedScheme,
271
+ requirements: selectedRequirements
272
+ });
273
+ if (selectedScheme === "exact") {
274
+ headersResult = await exactPayer.buildHeaders(filteredRequirements);
275
+ } else {
276
+ if (!confidentialPayer) {
277
+ throw new Error("Confidential scheme is selected but relayer is missing");
201
278
  }
202
- return paidResponse;
279
+ confidentialRequirements = confidentialPayer.extractConfidentialRequirements(filteredRequirements);
280
+ headersResult = await confidentialPayer.buildHeaders(filteredRequirements);
203
281
  }
282
+ const mergedHeaders = { ...options?.headers ?? {}, ...headersResult.headers };
283
+ const paidResponse = await fetchFn(url, { headers: mergedHeaders });
284
+ if (debugEnabled) {
285
+ try {
286
+ const body = await paidResponse.clone().text();
287
+ console.debug("[x402z-client] response", {
288
+ status: paidResponse.status,
289
+ headers: Object.fromEntries(paidResponse.headers.entries()),
290
+ body
291
+ });
292
+ } catch (error) {
293
+ console.debug("[x402z-client] response", {
294
+ status: paidResponse.status,
295
+ headers: Object.fromEntries(paidResponse.headers.entries()),
296
+ body: "<unavailable>"
297
+ });
298
+ }
299
+ }
300
+ return { response: paidResponse, paymentRequired, confidentialRequirements };
301
+ };
302
+ return {
303
+ relayer: confidentialPayer?.relayer,
304
+ pay
204
305
  };
205
306
  }
206
307
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402z-client",
3
- "version": "0.0.10",
3
+ "version": "0.1.0",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -18,7 +18,7 @@
18
18
  "@x402/core": "^2.0.0",
19
19
  "@x402/evm": "^2.0.0",
20
20
  "viem": "^2.39.3",
21
- "x402z-shared": "0.0.10"
21
+ "x402z-shared": "0.1.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "jest": "^29.7.0",