x402z-client-web 0.0.18 → 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
@@ -35,12 +35,13 @@ const relayer = await createRelayer(relayerConfig);
35
35
  const signer = await createBrowserSigner(provider);
36
36
 
37
37
  const client = createX402zClient({
38
+ schemePreference: ["erc7984-mind-v1"],
38
39
  signer,
39
40
  relayer,
40
41
  });
41
42
 
42
- const response = await client.pay("https://example.com/demo");
43
- console.log(response.status);
43
+ const paid = await client.pay("https://example.com/demo");
44
+ console.log(paid.response.status);
44
45
  ```
45
46
 
46
47
  `createX402zClient` builds the confidential payment input automatically using the
@@ -50,13 +51,39 @@ console.log(response.status);
50
51
  ## API
51
52
 
52
53
  - `createX402zClient(config)`
53
- - `signer` (required): EIP-712 signer for x402 payloads
54
- - `relayer` (required): relayer instance (browser)
54
+ - `schemePreference` (required): ordered list of schemes to try (e.g. `["erc7984-mind-v1", "exact"]`)
55
+ - `signer` (required): signer used for both exact and confidential schemes
56
+ - `relayer` (required when using `erc7984-mind-v1`): relayer instance (browser)
55
57
  - `fetch` (optional): custom fetch implementation
56
58
  - `client.pay(url, options?)`: performs the 402 handshake and retries with payment headers
59
+ - returns `{ response, paymentRequired?, confidentialRequirements? }`
60
+
61
+ ## Examples
62
+
63
+ See `examples/README.md` for the full-process web examples (`examples/full-process/web-vite` and `examples/full-process/web-next`).
57
64
 
58
65
  ## Notes
59
66
 
60
67
  - Web builds use `@zama-fhe/relayer-sdk/web` (no CDN script tag or bundle).
61
68
  - Requires an injected wallet that supports `eth_signTypedData_v4` (e.g. MetaMask).
62
- - Scheme name: `erc7984-mind-v1`
69
+ - Confidential scheme name: `erc7984-mind-v1`
70
+ - Exact scheme name: `exact`
71
+
72
+ ## API surface
73
+
74
+ Exports:
75
+ - `createX402zClient`: convenience client wrapper for browser pay flows.
76
+ - `X402zEvmClientScheme`: client scheme implementation for erc7984-mind-v1.
77
+ - `registerX402zEvmClientScheme`: registers the scheme with x402 client.
78
+
79
+ Types:
80
+ - `X402zClient`: client instance type.
81
+ - `X402zClientOptions`: options for `createX402zClient`.
82
+ - `X402zConfidentialClientOptions`: options for confidential payments.
83
+ - `X402zExactClientOptions`: options for exact payments.
84
+ - `PayOptions`: per-request payment options.
85
+ - `X402zClientSchemeOptions`: scheme config for client registration.
86
+ - `X402zClientRegistrationOptions`: registration options for the scheme.
87
+ - `ConfidentialRequirementsExtra`: scheme requirements extension payload.
88
+ - `RelayerInstance`: relayer instance type.
89
+ - re-exported types from `@x402/core/types`: shared x402 types.
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { ConfidentialPaymentInput, RelayerInstance } from 'x402z-shared-web';
2
- export { ConfidentialRequirementsExtra, RelayerInstance } from 'x402z-shared-web';
3
- import { x402Client } from '@x402/core/client';
4
- import { PaymentRequirements, SchemeNetworkClient, PaymentPayload, Network } from '@x402/core/types';
1
+ import { PaymentRequirements, SchemeNetworkClient, PaymentPayload, Network, PaymentRequired } from '@x402/core/types';
5
2
  export * from '@x402/core/types';
3
+ import { SelectPaymentRequirements, PaymentPolicy, x402Client } from '@x402/core/client';
6
4
  import { ClientEvmSigner } from '@x402/evm';
5
+ import { ConfidentialPaymentInput, RelayerInstance } from 'x402z-shared-web';
6
+ export { ConfidentialRequirementsExtra, RelayerInstance } from 'x402z-shared-web';
7
7
 
8
8
  type X402zClientSchemeOptions = {
9
9
  signer: ClientEvmSigner;
@@ -24,23 +24,43 @@ declare class X402zEvmClientScheme implements SchemeNetworkClient {
24
24
  createPaymentPayload(x402Version: number, paymentRequirements: PaymentRequirements): Promise<Pick<PaymentPayload, "x402Version" | "payload">>;
25
25
  }
26
26
 
27
- type X402zClientRegistrationOptions = X402zClientSchemeOptions & {
28
- networks?: Network[];
29
- };
30
- declare function registerX402zEvmClientScheme(client: x402Client, config: X402zClientRegistrationOptions): x402Client;
31
-
32
- type X402zClientOptions = Omit<X402zClientRegistrationOptions, "buildPayment"> & {
33
- relayer: RelayerInstance;
27
+ type Scheme = "exact" | "erc7984-mind-v1";
28
+ type BaseClientOptions = {
34
29
  fetch?: typeof fetch;
35
30
  debug?: boolean;
36
31
  };
32
+ type X402zClientOptions = {
33
+ schemePreference: Scheme[];
34
+ signer: ClientEvmSigner;
35
+ relayer?: RelayerInstance;
36
+ networks?: Network[];
37
+ paymentRequirementsSelector?: SelectPaymentRequirements;
38
+ policies?: PaymentPolicy[];
39
+ eip712?: X402zClientSchemeOptions["eip712"];
40
+ hashEncryptedAmountInput?: X402zClientSchemeOptions["hashEncryptedAmountInput"];
41
+ clock?: X402zClientSchemeOptions["clock"];
42
+ onPaymentSelected?: (info: {
43
+ scheme: Scheme;
44
+ requirements: PaymentRequirements;
45
+ }) => void;
46
+ } & BaseClientOptions;
37
47
  type PayOptions = {
38
48
  headers?: Record<string, string>;
39
49
  };
50
+ type PayResult = {
51
+ response: Response;
52
+ paymentRequired?: PaymentRequired;
53
+ confidentialRequirements?: PaymentRequirements;
54
+ };
40
55
  type X402zClient = {
41
- relayer: RelayerInstance;
42
- pay: (url: string, options?: PayOptions) => Promise<Response>;
56
+ relayer?: RelayerInstance;
57
+ pay: (url: string, options?: PayOptions) => Promise<PayResult>;
43
58
  };
44
59
  declare function createX402zClient(config: X402zClientOptions): X402zClient;
45
60
 
46
- export { type PayOptions, type X402zClient, type X402zClientOptions, type X402zClientRegistrationOptions, type X402zClientSchemeOptions, X402zEvmClientScheme, createX402zClient, registerX402zEvmClientScheme };
61
+ type X402zClientRegistrationOptions = X402zClientSchemeOptions & {
62
+ networks?: Network[];
63
+ };
64
+ declare function registerX402zEvmClientScheme(client: x402Client, config: X402zClientRegistrationOptions): x402Client;
65
+
66
+ export { type PayOptions, type PayResult, type X402zClient, type X402zClientOptions, type X402zClientRegistrationOptions, type X402zClientSchemeOptions, X402zEvmClientScheme, createX402zClient, registerX402zEvmClientScheme };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { ConfidentialPaymentInput, RelayerInstance } from 'x402z-shared-web';
2
- export { ConfidentialRequirementsExtra, RelayerInstance } from 'x402z-shared-web';
3
- import { x402Client } from '@x402/core/client';
4
- import { PaymentRequirements, SchemeNetworkClient, PaymentPayload, Network } from '@x402/core/types';
1
+ import { PaymentRequirements, SchemeNetworkClient, PaymentPayload, Network, PaymentRequired } from '@x402/core/types';
5
2
  export * from '@x402/core/types';
3
+ import { SelectPaymentRequirements, PaymentPolicy, x402Client } from '@x402/core/client';
6
4
  import { ClientEvmSigner } from '@x402/evm';
5
+ import { ConfidentialPaymentInput, RelayerInstance } from 'x402z-shared-web';
6
+ export { ConfidentialRequirementsExtra, RelayerInstance } from 'x402z-shared-web';
7
7
 
8
8
  type X402zClientSchemeOptions = {
9
9
  signer: ClientEvmSigner;
@@ -24,23 +24,43 @@ declare class X402zEvmClientScheme implements SchemeNetworkClient {
24
24
  createPaymentPayload(x402Version: number, paymentRequirements: PaymentRequirements): Promise<Pick<PaymentPayload, "x402Version" | "payload">>;
25
25
  }
26
26
 
27
- type X402zClientRegistrationOptions = X402zClientSchemeOptions & {
28
- networks?: Network[];
29
- };
30
- declare function registerX402zEvmClientScheme(client: x402Client, config: X402zClientRegistrationOptions): x402Client;
31
-
32
- type X402zClientOptions = Omit<X402zClientRegistrationOptions, "buildPayment"> & {
33
- relayer: RelayerInstance;
27
+ type Scheme = "exact" | "erc7984-mind-v1";
28
+ type BaseClientOptions = {
34
29
  fetch?: typeof fetch;
35
30
  debug?: boolean;
36
31
  };
32
+ type X402zClientOptions = {
33
+ schemePreference: Scheme[];
34
+ signer: ClientEvmSigner;
35
+ relayer?: RelayerInstance;
36
+ networks?: Network[];
37
+ paymentRequirementsSelector?: SelectPaymentRequirements;
38
+ policies?: PaymentPolicy[];
39
+ eip712?: X402zClientSchemeOptions["eip712"];
40
+ hashEncryptedAmountInput?: X402zClientSchemeOptions["hashEncryptedAmountInput"];
41
+ clock?: X402zClientSchemeOptions["clock"];
42
+ onPaymentSelected?: (info: {
43
+ scheme: Scheme;
44
+ requirements: PaymentRequirements;
45
+ }) => void;
46
+ } & BaseClientOptions;
37
47
  type PayOptions = {
38
48
  headers?: Record<string, string>;
39
49
  };
50
+ type PayResult = {
51
+ response: Response;
52
+ paymentRequired?: PaymentRequired;
53
+ confidentialRequirements?: PaymentRequirements;
54
+ };
40
55
  type X402zClient = {
41
- relayer: RelayerInstance;
42
- pay: (url: string, options?: PayOptions) => Promise<Response>;
56
+ relayer?: RelayerInstance;
57
+ pay: (url: string, options?: PayOptions) => Promise<PayResult>;
43
58
  };
44
59
  declare function createX402zClient(config: X402zClientOptions): X402zClient;
45
60
 
46
- export { type PayOptions, type X402zClient, type X402zClientOptions, type X402zClientRegistrationOptions, type X402zClientSchemeOptions, X402zEvmClientScheme, createX402zClient, registerX402zEvmClientScheme };
61
+ type X402zClientRegistrationOptions = X402zClientSchemeOptions & {
62
+ networks?: Network[];
63
+ };
64
+ declare function registerX402zEvmClientScheme(client: x402Client, config: X402zClientRegistrationOptions): x402Client;
65
+
66
+ export { type PayOptions, type PayResult, type X402zClient, type X402zClientOptions, type X402zClientRegistrationOptions, type X402zClientSchemeOptions, X402zEvmClientScheme, createX402zClient, registerX402zEvmClientScheme };
package/dist/index.js CHANGED
@@ -29,6 +29,7 @@ module.exports = __toCommonJS(index_exports);
29
29
  // src/http/client.ts
30
30
  var import_client = require("@x402/core/client");
31
31
  var import_http = require("@x402/core/http");
32
+ var import_client2 = require("@x402/evm/exact/client");
32
33
  var import_viem2 = require("viem");
33
34
  var import_x402z_shared_web2 = require("x402z-shared-web");
34
35
 
@@ -128,16 +129,35 @@ function registerX402zEvmClientScheme(client, config) {
128
129
  }
129
130
 
130
131
  // src/http/client.ts
131
- function createX402zClient(config) {
132
- const { fetch: fetchOverride, ...registerConfig } = config;
133
- const fetchFn = fetchOverride ?? globalThis.fetch;
134
- const debugEnabled = config.debug ?? false;
135
- if (!fetchFn) {
136
- throw new Error("fetch is not available; provide a fetch implementation");
137
- }
132
+ function filterPaymentRequired(paymentRequired, scheme) {
133
+ const accepts = paymentRequired.accepts.filter((requirement) => requirement.scheme === scheme);
134
+ return { ...paymentRequired, accepts };
135
+ }
136
+ function createExactPayer(config, debugEnabled) {
137
+ const client = new import_client.x402Client(config.paymentRequirementsSelector);
138
+ (0, import_client2.registerExactEvmScheme)(client, {
139
+ signer: config.signer,
140
+ networks: config.networks,
141
+ policies: config.policies,
142
+ paymentRequirementsSelector: config.paymentRequirementsSelector
143
+ });
144
+ const httpClient = new import_http.x402HTTPClient(client);
145
+ return {
146
+ async buildHeaders(paymentRequired) {
147
+ const payload = await httpClient.createPaymentPayload(paymentRequired);
148
+ const payHeaders = httpClient.encodePaymentSignatureHeader(payload);
149
+ if (debugEnabled) {
150
+ console.debug("[x402z-client] payment payload", payload);
151
+ console.debug("[x402z-client] payment headers", payHeaders);
152
+ }
153
+ return { headers: payHeaders };
154
+ }
155
+ };
156
+ }
157
+ function createConfidentialPayer(config, debugEnabled) {
138
158
  const buildPayment = async (requirements) => {
139
159
  if (!(0, import_viem2.isAddress)(requirements.asset)) {
140
- throw new Error(`Invalid TOKEN_ADDRESS from requirements: ${requirements.asset}`);
160
+ throw new Error(`Invalid token address from requirements: ${requirements.asset}`);
141
161
  }
142
162
  const extra = requirements.extra;
143
163
  const batcherAddress = extra?.confidential?.batcherAddress;
@@ -164,47 +184,127 @@ function createX402zClient(config) {
164
184
  };
165
185
  const client = new import_client.x402Client();
166
186
  registerX402zEvmClientScheme(client, {
167
- ...registerConfig,
168
- buildPayment
187
+ signer: config.signer,
188
+ buildPayment,
189
+ eip712: config.eip712,
190
+ hashEncryptedAmountInput: config.hashEncryptedAmountInput,
191
+ clock: config.clock,
192
+ networks: config.networks
169
193
  });
170
194
  const httpClient = new import_http.x402HTTPClient(client);
195
+ const extractConfidentialRequirements = (paymentRequired) => {
196
+ const requirements = paymentRequired.accepts.find(
197
+ (requirement) => requirement.scheme === "erc7984-mind-v1"
198
+ );
199
+ if (!requirements) {
200
+ throw new Error("Missing erc7984-mind-v1 payment requirements");
201
+ }
202
+ return requirements;
203
+ };
171
204
  return {
172
205
  relayer: config.relayer,
173
- async pay(url, options) {
174
- const initial = await fetchFn(url, { headers: options?.headers });
175
- if (initial.status !== 402) {
176
- return initial;
177
- }
178
- const paymentRequired = httpClient.getPaymentRequiredResponse(
179
- (name) => initial.headers.get(name),
180
- await initial.json().catch(() => ({}))
181
- );
206
+ extractConfidentialRequirements,
207
+ async buildHeaders(paymentRequired) {
182
208
  const payload = await httpClient.createPaymentPayload(paymentRequired);
183
209
  const payHeaders = httpClient.encodePaymentSignatureHeader(payload);
184
210
  if (debugEnabled) {
185
211
  console.debug("[x402z-client] payment payload", payload);
186
212
  console.debug("[x402z-client] payment headers", payHeaders);
187
213
  }
188
- const mergedHeaders = { ...options?.headers ?? {}, ...payHeaders };
189
- const paidResponse = await fetchFn(url, { headers: mergedHeaders });
190
- if (debugEnabled) {
191
- try {
192
- const body = await paidResponse.clone().text();
193
- console.debug("[x402z-client] response", {
194
- status: paidResponse.status,
195
- headers: Object.fromEntries(paidResponse.headers.entries()),
196
- body
197
- });
198
- } catch (error) {
199
- console.debug("[x402z-client] response", {
200
- status: paidResponse.status,
201
- headers: Object.fromEntries(paidResponse.headers.entries()),
202
- body: "<unavailable>"
203
- });
204
- }
214
+ return { headers: payHeaders };
215
+ }
216
+ };
217
+ }
218
+ function createX402zClient(config) {
219
+ const fetchFn = config.fetch ?? globalThis.fetch;
220
+ const debugEnabled = config.debug ?? false;
221
+ if (!fetchFn) {
222
+ throw new Error("fetch is not available; provide a fetch implementation");
223
+ }
224
+ const schemePreference = config.schemePreference?.length ? config.schemePreference : ["exact"];
225
+ const exactPayer = createExactPayer(
226
+ {
227
+ signer: config.signer,
228
+ networks: config.networks,
229
+ paymentRequirementsSelector: config.paymentRequirementsSelector,
230
+ policies: config.policies
231
+ },
232
+ debugEnabled
233
+ );
234
+ const confidentialPayer = config.relayer ? createConfidentialPayer(
235
+ {
236
+ signer: config.signer,
237
+ relayer: config.relayer,
238
+ eip712: config.eip712,
239
+ hashEncryptedAmountInput: config.hashEncryptedAmountInput,
240
+ clock: config.clock,
241
+ networks: config.networks
242
+ },
243
+ debugEnabled
244
+ ) : void 0;
245
+ const parserClient = new import_client.x402Client();
246
+ const parserHttp = new import_http.x402HTTPClient(parserClient);
247
+ const pay = async (url, options) => {
248
+ const initial = await fetchFn(url, { headers: options?.headers });
249
+ if (initial.status !== 402) {
250
+ return { response: initial };
251
+ }
252
+ const paymentRequired = parserHttp.getPaymentRequiredResponse(
253
+ (name) => initial.headers.get(name),
254
+ await initial.json().catch(() => ({}))
255
+ );
256
+ const supportedSchemes = new Set(
257
+ paymentRequired.accepts.map((accept) => accept.scheme)
258
+ );
259
+ const selectedScheme = schemePreference.find(
260
+ (scheme) => supportedSchemes.has(scheme)
261
+ );
262
+ if (!selectedScheme) {
263
+ throw new Error("No preferred schemes are supported by payment requirements");
264
+ }
265
+ const filteredRequirements = filterPaymentRequired(paymentRequired, selectedScheme);
266
+ if (filteredRequirements.accepts.length === 0) {
267
+ throw new Error(`Missing ${selectedScheme} payment requirements`);
268
+ }
269
+ let headersResult;
270
+ let confidentialRequirements;
271
+ const selectedRequirements = filteredRequirements.accepts[0];
272
+ config.onPaymentSelected?.({
273
+ scheme: selectedScheme,
274
+ requirements: selectedRequirements
275
+ });
276
+ if (selectedScheme === "exact") {
277
+ headersResult = await exactPayer.buildHeaders(filteredRequirements);
278
+ } else {
279
+ if (!confidentialPayer) {
280
+ throw new Error("Confidential scheme is selected but relayer is missing");
205
281
  }
206
- return paidResponse;
282
+ confidentialRequirements = confidentialPayer.extractConfidentialRequirements(filteredRequirements);
283
+ headersResult = await confidentialPayer.buildHeaders(filteredRequirements);
207
284
  }
285
+ const mergedHeaders = { ...options?.headers ?? {}, ...headersResult.headers };
286
+ const paidResponse = await fetchFn(url, { headers: mergedHeaders });
287
+ if (debugEnabled) {
288
+ try {
289
+ const body = await paidResponse.clone().text();
290
+ console.debug("[x402z-client] response", {
291
+ status: paidResponse.status,
292
+ headers: Object.fromEntries(paidResponse.headers.entries()),
293
+ body
294
+ });
295
+ } catch (error) {
296
+ console.debug("[x402z-client] response", {
297
+ status: paidResponse.status,
298
+ headers: Object.fromEntries(paidResponse.headers.entries()),
299
+ body: "<unavailable>"
300
+ });
301
+ }
302
+ }
303
+ return { response: paidResponse, paymentRequired, confidentialRequirements };
304
+ };
305
+ return {
306
+ relayer: confidentialPayer?.relayer,
307
+ pay
208
308
  };
209
309
  }
210
310
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  // src/http/client.ts
2
2
  import { x402Client } from "@x402/core/client";
3
3
  import { x402HTTPClient } from "@x402/core/http";
4
+ import { registerExactEvmScheme } from "@x402/evm/exact/client";
4
5
  import { isAddress } from "viem";
5
6
  import {
6
7
  createEncryptedAmountInput
@@ -107,16 +108,35 @@ function registerX402zEvmClientScheme(client, config) {
107
108
  }
108
109
 
109
110
  // src/http/client.ts
110
- function createX402zClient(config) {
111
- const { fetch: fetchOverride, ...registerConfig } = config;
112
- const fetchFn = fetchOverride ?? globalThis.fetch;
113
- const debugEnabled = config.debug ?? false;
114
- if (!fetchFn) {
115
- throw new Error("fetch is not available; provide a fetch implementation");
116
- }
111
+ function filterPaymentRequired(paymentRequired, scheme) {
112
+ const accepts = paymentRequired.accepts.filter((requirement) => requirement.scheme === scheme);
113
+ return { ...paymentRequired, accepts };
114
+ }
115
+ function createExactPayer(config, debugEnabled) {
116
+ const client = new x402Client(config.paymentRequirementsSelector);
117
+ registerExactEvmScheme(client, {
118
+ signer: config.signer,
119
+ networks: config.networks,
120
+ policies: config.policies,
121
+ paymentRequirementsSelector: config.paymentRequirementsSelector
122
+ });
123
+ const httpClient = new x402HTTPClient(client);
124
+ return {
125
+ async buildHeaders(paymentRequired) {
126
+ const payload = await httpClient.createPaymentPayload(paymentRequired);
127
+ const payHeaders = httpClient.encodePaymentSignatureHeader(payload);
128
+ if (debugEnabled) {
129
+ console.debug("[x402z-client] payment payload", payload);
130
+ console.debug("[x402z-client] payment headers", payHeaders);
131
+ }
132
+ return { headers: payHeaders };
133
+ }
134
+ };
135
+ }
136
+ function createConfidentialPayer(config, debugEnabled) {
117
137
  const buildPayment = async (requirements) => {
118
138
  if (!isAddress(requirements.asset)) {
119
- throw new Error(`Invalid TOKEN_ADDRESS from requirements: ${requirements.asset}`);
139
+ throw new Error(`Invalid token address from requirements: ${requirements.asset}`);
120
140
  }
121
141
  const extra = requirements.extra;
122
142
  const batcherAddress = extra?.confidential?.batcherAddress;
@@ -143,47 +163,127 @@ function createX402zClient(config) {
143
163
  };
144
164
  const client = new x402Client();
145
165
  registerX402zEvmClientScheme(client, {
146
- ...registerConfig,
147
- buildPayment
166
+ signer: config.signer,
167
+ buildPayment,
168
+ eip712: config.eip712,
169
+ hashEncryptedAmountInput: config.hashEncryptedAmountInput,
170
+ clock: config.clock,
171
+ networks: config.networks
148
172
  });
149
173
  const httpClient = new x402HTTPClient(client);
174
+ const extractConfidentialRequirements = (paymentRequired) => {
175
+ const requirements = paymentRequired.accepts.find(
176
+ (requirement) => requirement.scheme === "erc7984-mind-v1"
177
+ );
178
+ if (!requirements) {
179
+ throw new Error("Missing erc7984-mind-v1 payment requirements");
180
+ }
181
+ return requirements;
182
+ };
150
183
  return {
151
184
  relayer: config.relayer,
152
- async pay(url, options) {
153
- const initial = await fetchFn(url, { headers: options?.headers });
154
- if (initial.status !== 402) {
155
- return initial;
156
- }
157
- const paymentRequired = httpClient.getPaymentRequiredResponse(
158
- (name) => initial.headers.get(name),
159
- await initial.json().catch(() => ({}))
160
- );
185
+ extractConfidentialRequirements,
186
+ async buildHeaders(paymentRequired) {
161
187
  const payload = await httpClient.createPaymentPayload(paymentRequired);
162
188
  const payHeaders = httpClient.encodePaymentSignatureHeader(payload);
163
189
  if (debugEnabled) {
164
190
  console.debug("[x402z-client] payment payload", payload);
165
191
  console.debug("[x402z-client] payment headers", payHeaders);
166
192
  }
167
- const mergedHeaders = { ...options?.headers ?? {}, ...payHeaders };
168
- const paidResponse = await fetchFn(url, { headers: mergedHeaders });
169
- if (debugEnabled) {
170
- try {
171
- const body = await paidResponse.clone().text();
172
- console.debug("[x402z-client] response", {
173
- status: paidResponse.status,
174
- headers: Object.fromEntries(paidResponse.headers.entries()),
175
- body
176
- });
177
- } catch (error) {
178
- console.debug("[x402z-client] response", {
179
- status: paidResponse.status,
180
- headers: Object.fromEntries(paidResponse.headers.entries()),
181
- body: "<unavailable>"
182
- });
183
- }
193
+ return { headers: payHeaders };
194
+ }
195
+ };
196
+ }
197
+ function createX402zClient(config) {
198
+ const fetchFn = config.fetch ?? globalThis.fetch;
199
+ const debugEnabled = config.debug ?? false;
200
+ if (!fetchFn) {
201
+ throw new Error("fetch is not available; provide a fetch implementation");
202
+ }
203
+ const schemePreference = config.schemePreference?.length ? config.schemePreference : ["exact"];
204
+ const exactPayer = createExactPayer(
205
+ {
206
+ signer: config.signer,
207
+ networks: config.networks,
208
+ paymentRequirementsSelector: config.paymentRequirementsSelector,
209
+ policies: config.policies
210
+ },
211
+ debugEnabled
212
+ );
213
+ const confidentialPayer = config.relayer ? createConfidentialPayer(
214
+ {
215
+ signer: config.signer,
216
+ relayer: config.relayer,
217
+ eip712: config.eip712,
218
+ hashEncryptedAmountInput: config.hashEncryptedAmountInput,
219
+ clock: config.clock,
220
+ networks: config.networks
221
+ },
222
+ debugEnabled
223
+ ) : void 0;
224
+ const parserClient = new x402Client();
225
+ const parserHttp = new x402HTTPClient(parserClient);
226
+ const pay = async (url, options) => {
227
+ const initial = await fetchFn(url, { headers: options?.headers });
228
+ if (initial.status !== 402) {
229
+ return { response: initial };
230
+ }
231
+ const paymentRequired = parserHttp.getPaymentRequiredResponse(
232
+ (name) => initial.headers.get(name),
233
+ await initial.json().catch(() => ({}))
234
+ );
235
+ const supportedSchemes = new Set(
236
+ paymentRequired.accepts.map((accept) => accept.scheme)
237
+ );
238
+ const selectedScheme = schemePreference.find(
239
+ (scheme) => supportedSchemes.has(scheme)
240
+ );
241
+ if (!selectedScheme) {
242
+ throw new Error("No preferred schemes are supported by payment requirements");
243
+ }
244
+ const filteredRequirements = filterPaymentRequired(paymentRequired, selectedScheme);
245
+ if (filteredRequirements.accepts.length === 0) {
246
+ throw new Error(`Missing ${selectedScheme} payment requirements`);
247
+ }
248
+ let headersResult;
249
+ let confidentialRequirements;
250
+ const selectedRequirements = filteredRequirements.accepts[0];
251
+ config.onPaymentSelected?.({
252
+ scheme: selectedScheme,
253
+ requirements: selectedRequirements
254
+ });
255
+ if (selectedScheme === "exact") {
256
+ headersResult = await exactPayer.buildHeaders(filteredRequirements);
257
+ } else {
258
+ if (!confidentialPayer) {
259
+ throw new Error("Confidential scheme is selected but relayer is missing");
184
260
  }
185
- return paidResponse;
261
+ confidentialRequirements = confidentialPayer.extractConfidentialRequirements(filteredRequirements);
262
+ headersResult = await confidentialPayer.buildHeaders(filteredRequirements);
186
263
  }
264
+ const mergedHeaders = { ...options?.headers ?? {}, ...headersResult.headers };
265
+ const paidResponse = await fetchFn(url, { headers: mergedHeaders });
266
+ if (debugEnabled) {
267
+ try {
268
+ const body = await paidResponse.clone().text();
269
+ console.debug("[x402z-client] response", {
270
+ status: paidResponse.status,
271
+ headers: Object.fromEntries(paidResponse.headers.entries()),
272
+ body
273
+ });
274
+ } catch (error) {
275
+ console.debug("[x402z-client] response", {
276
+ status: paidResponse.status,
277
+ headers: Object.fromEntries(paidResponse.headers.entries()),
278
+ body: "<unavailable>"
279
+ });
280
+ }
281
+ }
282
+ return { response: paidResponse, paymentRequired, confidentialRequirements };
283
+ };
284
+ return {
285
+ relayer: confidentialPayer?.relayer,
286
+ pay
187
287
  };
188
288
  }
189
289
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402z-client-web",
3
- "version": "0.0.18",
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-web": "0.0.18"
21
+ "x402z-shared-web": "0.1.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "jest": "^29.7.0",