@nullclear/x402-arbiter 1.1.1 → 1.2.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/dist/index.cjs CHANGED
@@ -38,9 +38,15 @@ async function signX402Payment(signer, option, resourceUrl) {
38
38
  const account = (0, import_accounts.privateKeyToAccount)(signer);
39
39
  accountAddress = account.address;
40
40
  signTypedDataFn = (params) => account.signTypedData(params);
41
- } else if (typeof signer === "object" && signer !== null && "signTypedData" in signer && "account" in signer && signer.account) {
42
- const rawAccount = signer.account;
43
- accountAddress = typeof rawAccount === "string" ? rawAccount : rawAccount.address;
41
+ } else if (typeof signer === "object" && signer !== null && "signTypedData" in signer) {
42
+ if ("account" in signer && signer.account) {
43
+ const rawAccount = signer.account;
44
+ accountAddress = typeof rawAccount === "string" ? rawAccount : rawAccount.address;
45
+ } else if ("address" in signer && signer.address) {
46
+ accountAddress = signer.address;
47
+ } else {
48
+ throw new Error("Signer object missing address");
49
+ }
44
50
  signTypedDataFn = (params) => signer.signTypedData(params);
45
51
  } else {
46
52
  throw new Error("Invalid signer provided to signX402Payment: must be private key or viem account/wallet client");
@@ -79,10 +85,14 @@ async function signX402Payment(signer, option, resourceUrl) {
79
85
  nonce: authorization.nonce
80
86
  }
81
87
  });
88
+ const acceptedOption = {
89
+ ...option,
90
+ extra: option.extra || { name: "USD Coin", version: "2" }
91
+ };
82
92
  const payload = {
83
93
  x402Version: 2,
84
94
  resource: resourceUrl ? { url: resourceUrl } : void 0,
85
- accepted: option,
95
+ accepted: acceptedOption,
86
96
  payload: {
87
97
  signature,
88
98
  authorization
@@ -97,7 +107,7 @@ var NullClearClient = class {
97
107
  defaultChainId;
98
108
  customFetch;
99
109
  constructor(config = {}) {
100
- this.arbiterUrl = (config.arbiterUrl || "https://arbiter.nullclear.dev").replace(/\/$/, "");
110
+ this.arbiterUrl = (config.arbiterUrl || "https://api.nullclear.dev").replace(/\/$/, "");
101
111
  this.defaultChainId = config.defaultChainId || 8453;
102
112
  this.customFetch = config.fetch || fetch;
103
113
  }
@@ -112,14 +122,29 @@ var NullClearClient = class {
112
122
  return data.data;
113
123
  }
114
124
  async clear(request) {
125
+ const headers = { "Content-Type": "application/json" };
126
+ if (!request.paymentSignatureHeader || request.paymentSignatureHeader === "free-trial") {
127
+ headers["x-nullclear-free-trial"] = "true";
128
+ }
115
129
  const res = await this.customFetch(`${this.arbiterUrl}/v1/clear`, {
116
130
  method: "POST",
117
- headers: { "Content-Type": "application/json" },
131
+ headers,
118
132
  body: JSON.stringify(request)
119
133
  });
120
134
  const data = await res.json();
121
135
  return data;
122
136
  }
137
+ async safeFetch(targetUrl, init) {
138
+ return this.customFetch(`${this.arbiterUrl}/${targetUrl}`, init);
139
+ }
140
+ async createGateway(params) {
141
+ const res = await this.customFetch(`${this.arbiterUrl}/v1/gateways`, {
142
+ method: "POST",
143
+ headers: { "Content-Type": "application/json" },
144
+ body: JSON.stringify(params)
145
+ });
146
+ return res.json();
147
+ }
123
148
  async getKya(agentId, chainId) {
124
149
  const targetChainId = chainId || this.defaultChainId;
125
150
  const res = await this.customFetch(`${this.arbiterUrl}/v1/kya/${targetChainId}/${agentId}`);
@@ -220,9 +245,9 @@ function zodToJsonSchema(schema) {
220
245
  return {};
221
246
  }
222
247
  }
223
- function createNullClearFetch(config) {
248
+ function createNullClearFetch(config = {}) {
224
249
  const chainId = config.chainId || 8453;
225
- const arbiterUrl = (config.arbiterUrl || "https://arbiter.nullclear.dev").replace(/\/$/, "");
250
+ const arbiterUrl = (config.arbiterUrl || "https://api.nullclear.dev").replace(/\/$/, "");
226
251
  const defaultMinTrustScore = config.defaultMinTrustScore || 50;
227
252
  const customFetch = config.customFetch || fetch;
228
253
  return async function nullclearFetch(input, init) {
@@ -234,29 +259,33 @@ function createNullClearFetch(config) {
234
259
  return initialRes;
235
260
  }
236
261
  const paymentRequiredHeader = initialRes.headers.get("PAYMENT-REQUIRED") || initialRes.headers.get("payment-required");
237
- if (!paymentRequiredHeader) {
238
- return initialRes;
239
- }
240
- let paymentRequired;
241
- try {
242
- paymentRequired = (0, import_shared2.decodeBase64Json)(paymentRequiredHeader);
243
- } catch {
244
- return initialRes;
245
- }
246
- const targetNetwork = `eip155:${chainId}`;
247
- const selectedOption = paymentRequired.accepts.find(
248
- (opt) => opt.network === targetNetwork && opt.scheme === "exact"
249
- );
250
- if (!selectedOption) {
251
- throw new Error(
252
- `Seller does not accept payments on network ${targetNetwork}. Accepted: ${paymentRequired.accepts.map((a) => a.network).join(", ")}`
262
+ let paymentSignatureHeader;
263
+ if (config.accountOrPrivateKey && paymentRequiredHeader) {
264
+ let paymentRequired;
265
+ try {
266
+ paymentRequired = (0, import_shared2.decodeBase64Json)(paymentRequiredHeader);
267
+ } catch {
268
+ return initialRes;
269
+ }
270
+ const targetNetwork = `eip155:${chainId}`;
271
+ const selectedOption = paymentRequired.accepts.find(
272
+ (opt) => opt.network === targetNetwork && opt.scheme === "exact"
273
+ );
274
+ if (!selectedOption) {
275
+ throw new Error(
276
+ `Seller does not accept payments on network ${targetNetwork}. Accepted: ${paymentRequired.accepts.map((a) => a.network).join(", ")}`
277
+ );
278
+ }
279
+ paymentSignatureHeader = await signX402Payment(
280
+ config.accountOrPrivateKey,
281
+ selectedOption,
282
+ targetUrl
253
283
  );
284
+ } else if (!config.accountOrPrivateKey) {
285
+ paymentSignatureHeader = "free-trial";
286
+ } else {
287
+ return initialRes;
254
288
  }
255
- const paymentSignatureHeader = await signX402Payment(
256
- config.accountOrPrivateKey,
257
- selectedOption,
258
- targetUrl
259
- );
260
289
  let jsonSchema;
261
290
  if (init?.nullclear?.schema) {
262
291
  if (init.nullclear.schema instanceof import_zod.z.ZodType) {
@@ -284,9 +313,13 @@ function createNullClearFetch(config) {
284
313
  fallbacks: init?.nullclear?.fallbacks,
285
314
  spendPolicy: init?.nullclear?.spendPolicy
286
315
  };
316
+ const clearHeaders = { "Content-Type": "application/json" };
317
+ if (paymentSignatureHeader === "free-trial") {
318
+ clearHeaders["x-nullclear-free-trial"] = "true";
319
+ }
287
320
  const arbiterRes = await customFetch(`${arbiterUrl}/v1/clear`, {
288
321
  method: "POST",
289
- headers: { "Content-Type": "application/json" },
322
+ headers: clearHeaders,
290
323
  body: JSON.stringify(clearPayload)
291
324
  });
292
325
  const arbiterData = await arbiterRes.json();
package/dist/index.d.cts CHANGED
@@ -24,7 +24,7 @@ interface ClearRequest {
24
24
  method?: "GET" | "POST" | "PUT" | "DELETE";
25
25
  headers?: Record<string, string>;
26
26
  body?: unknown;
27
- paymentSignatureHeader: string;
27
+ paymentSignatureHeader?: string;
28
28
  sellerAgentId?: string;
29
29
  minTrustScore?: number;
30
30
  twoPhaseRelease?: boolean;
@@ -35,12 +35,15 @@ interface ClearRequest {
35
35
  interface ClearResult<T = unknown> {
36
36
  cleared: boolean;
37
37
  settled: boolean;
38
+ tier?: string;
39
+ freeTrialRemaining?: number;
38
40
  clearingId?: string;
39
41
  buyerCharged: string;
40
42
  clearingFee?: string;
41
43
  settlementRouting?: string;
42
44
  transaction?: `0x${string}`;
43
45
  attestation?: unknown;
46
+ executionReceipt?: unknown;
44
47
  data?: T;
45
48
  stage?: string;
46
49
  error?: string;
@@ -61,6 +64,18 @@ declare class NullClearClient {
61
64
  constructor(config?: NullClearClientConfig);
62
65
  getScore(agentId: string, chainId?: number): Promise<any>;
63
66
  clear<T = unknown>(request: ClearRequest): Promise<ClearResult<T>>;
67
+ safeFetch(targetUrl: string, init?: RequestInit): Promise<Response>;
68
+ createGateway(params: {
69
+ upstreamUrl: string;
70
+ sellerAddress: string;
71
+ priceUsdc?: string;
72
+ priceAtomic?: string;
73
+ slug?: string;
74
+ description?: string;
75
+ category?: "data" | "security" | "oracle" | "ai";
76
+ validationPreset?: "DEFAULT_JSON" | "STRICT_NO_REFUSAL" | "CUSTOM";
77
+ customSchema?: Record<string, unknown>;
78
+ }): Promise<any>;
64
79
  getKya(agentId: string, chainId?: number): Promise<any>;
65
80
  attestKya(mandate: KYAMandate, chainId?: number, signature?: string, signerAddress?: `0x${string}`): Promise<any>;
66
81
  }
@@ -111,7 +126,7 @@ interface NullClearOptions {
111
126
  spendPolicy?: SpendPolicy;
112
127
  }
113
128
  interface NullClearFetchConfig {
114
- accountOrPrivateKey: SignerInput;
129
+ accountOrPrivateKey?: SignerInput;
115
130
  chainId?: number;
116
131
  arbiterUrl?: string;
117
132
  defaultMinTrustScore?: number;
@@ -124,6 +139,6 @@ type NullClearRequestInit = RequestInit & {
124
139
  * Creates an enhanced fetch client that autonomously intercepts HTTP 402 Payment Required
125
140
  * and safely wraps the call in NullClear Deferred Non-Custodial Schema Escrow
126
141
  */
127
- declare function createNullClearFetch(config: NullClearFetchConfig): (input: RequestInfo | URL, init?: NullClearRequestInit) => Promise<Response>;
142
+ declare function createNullClearFetch(config?: NullClearFetchConfig): (input: RequestInfo | URL, init?: NullClearRequestInit) => Promise<Response>;
128
143
 
129
144
  export { type ClearRequest, type ClearResult, NullClearClient, type NullClearClientConfig, NullClearEscrowAbortedError, type NullClearFetchConfig, type NullClearOptions, type NullClearRequestInit, type SignerInput, createNullClearFetch, signX402Payment, zodToJsonSchema };
package/dist/index.d.ts CHANGED
@@ -24,7 +24,7 @@ interface ClearRequest {
24
24
  method?: "GET" | "POST" | "PUT" | "DELETE";
25
25
  headers?: Record<string, string>;
26
26
  body?: unknown;
27
- paymentSignatureHeader: string;
27
+ paymentSignatureHeader?: string;
28
28
  sellerAgentId?: string;
29
29
  minTrustScore?: number;
30
30
  twoPhaseRelease?: boolean;
@@ -35,12 +35,15 @@ interface ClearRequest {
35
35
  interface ClearResult<T = unknown> {
36
36
  cleared: boolean;
37
37
  settled: boolean;
38
+ tier?: string;
39
+ freeTrialRemaining?: number;
38
40
  clearingId?: string;
39
41
  buyerCharged: string;
40
42
  clearingFee?: string;
41
43
  settlementRouting?: string;
42
44
  transaction?: `0x${string}`;
43
45
  attestation?: unknown;
46
+ executionReceipt?: unknown;
44
47
  data?: T;
45
48
  stage?: string;
46
49
  error?: string;
@@ -61,6 +64,18 @@ declare class NullClearClient {
61
64
  constructor(config?: NullClearClientConfig);
62
65
  getScore(agentId: string, chainId?: number): Promise<any>;
63
66
  clear<T = unknown>(request: ClearRequest): Promise<ClearResult<T>>;
67
+ safeFetch(targetUrl: string, init?: RequestInit): Promise<Response>;
68
+ createGateway(params: {
69
+ upstreamUrl: string;
70
+ sellerAddress: string;
71
+ priceUsdc?: string;
72
+ priceAtomic?: string;
73
+ slug?: string;
74
+ description?: string;
75
+ category?: "data" | "security" | "oracle" | "ai";
76
+ validationPreset?: "DEFAULT_JSON" | "STRICT_NO_REFUSAL" | "CUSTOM";
77
+ customSchema?: Record<string, unknown>;
78
+ }): Promise<any>;
64
79
  getKya(agentId: string, chainId?: number): Promise<any>;
65
80
  attestKya(mandate: KYAMandate, chainId?: number, signature?: string, signerAddress?: `0x${string}`): Promise<any>;
66
81
  }
@@ -111,7 +126,7 @@ interface NullClearOptions {
111
126
  spendPolicy?: SpendPolicy;
112
127
  }
113
128
  interface NullClearFetchConfig {
114
- accountOrPrivateKey: SignerInput;
129
+ accountOrPrivateKey?: SignerInput;
115
130
  chainId?: number;
116
131
  arbiterUrl?: string;
117
132
  defaultMinTrustScore?: number;
@@ -124,6 +139,6 @@ type NullClearRequestInit = RequestInit & {
124
139
  * Creates an enhanced fetch client that autonomously intercepts HTTP 402 Payment Required
125
140
  * and safely wraps the call in NullClear Deferred Non-Custodial Schema Escrow
126
141
  */
127
- declare function createNullClearFetch(config: NullClearFetchConfig): (input: RequestInfo | URL, init?: NullClearRequestInit) => Promise<Response>;
142
+ declare function createNullClearFetch(config?: NullClearFetchConfig): (input: RequestInfo | URL, init?: NullClearRequestInit) => Promise<Response>;
128
143
 
129
144
  export { type ClearRequest, type ClearResult, NullClearClient, type NullClearClientConfig, NullClearEscrowAbortedError, type NullClearFetchConfig, type NullClearOptions, type NullClearRequestInit, type SignerInput, createNullClearFetch, signX402Payment, zodToJsonSchema };
package/dist/index.js CHANGED
@@ -12,9 +12,15 @@ async function signX402Payment(signer, option, resourceUrl) {
12
12
  const account = privateKeyToAccount(signer);
13
13
  accountAddress = account.address;
14
14
  signTypedDataFn = (params) => account.signTypedData(params);
15
- } else if (typeof signer === "object" && signer !== null && "signTypedData" in signer && "account" in signer && signer.account) {
16
- const rawAccount = signer.account;
17
- accountAddress = typeof rawAccount === "string" ? rawAccount : rawAccount.address;
15
+ } else if (typeof signer === "object" && signer !== null && "signTypedData" in signer) {
16
+ if ("account" in signer && signer.account) {
17
+ const rawAccount = signer.account;
18
+ accountAddress = typeof rawAccount === "string" ? rawAccount : rawAccount.address;
19
+ } else if ("address" in signer && signer.address) {
20
+ accountAddress = signer.address;
21
+ } else {
22
+ throw new Error("Signer object missing address");
23
+ }
18
24
  signTypedDataFn = (params) => signer.signTypedData(params);
19
25
  } else {
20
26
  throw new Error("Invalid signer provided to signX402Payment: must be private key or viem account/wallet client");
@@ -53,10 +59,14 @@ async function signX402Payment(signer, option, resourceUrl) {
53
59
  nonce: authorization.nonce
54
60
  }
55
61
  });
62
+ const acceptedOption = {
63
+ ...option,
64
+ extra: option.extra || { name: "USD Coin", version: "2" }
65
+ };
56
66
  const payload = {
57
67
  x402Version: 2,
58
68
  resource: resourceUrl ? { url: resourceUrl } : void 0,
59
- accepted: option,
69
+ accepted: acceptedOption,
60
70
  payload: {
61
71
  signature,
62
72
  authorization
@@ -71,7 +81,7 @@ var NullClearClient = class {
71
81
  defaultChainId;
72
82
  customFetch;
73
83
  constructor(config = {}) {
74
- this.arbiterUrl = (config.arbiterUrl || "https://arbiter.nullclear.dev").replace(/\/$/, "");
84
+ this.arbiterUrl = (config.arbiterUrl || "https://api.nullclear.dev").replace(/\/$/, "");
75
85
  this.defaultChainId = config.defaultChainId || 8453;
76
86
  this.customFetch = config.fetch || fetch;
77
87
  }
@@ -86,14 +96,29 @@ var NullClearClient = class {
86
96
  return data.data;
87
97
  }
88
98
  async clear(request) {
99
+ const headers = { "Content-Type": "application/json" };
100
+ if (!request.paymentSignatureHeader || request.paymentSignatureHeader === "free-trial") {
101
+ headers["x-nullclear-free-trial"] = "true";
102
+ }
89
103
  const res = await this.customFetch(`${this.arbiterUrl}/v1/clear`, {
90
104
  method: "POST",
91
- headers: { "Content-Type": "application/json" },
105
+ headers,
92
106
  body: JSON.stringify(request)
93
107
  });
94
108
  const data = await res.json();
95
109
  return data;
96
110
  }
111
+ async safeFetch(targetUrl, init) {
112
+ return this.customFetch(`${this.arbiterUrl}/${targetUrl}`, init);
113
+ }
114
+ async createGateway(params) {
115
+ const res = await this.customFetch(`${this.arbiterUrl}/v1/gateways`, {
116
+ method: "POST",
117
+ headers: { "Content-Type": "application/json" },
118
+ body: JSON.stringify(params)
119
+ });
120
+ return res.json();
121
+ }
97
122
  async getKya(agentId, chainId) {
98
123
  const targetChainId = chainId || this.defaultChainId;
99
124
  const res = await this.customFetch(`${this.arbiterUrl}/v1/kya/${targetChainId}/${agentId}`);
@@ -196,9 +221,9 @@ function zodToJsonSchema(schema) {
196
221
  return {};
197
222
  }
198
223
  }
199
- function createNullClearFetch(config) {
224
+ function createNullClearFetch(config = {}) {
200
225
  const chainId = config.chainId || 8453;
201
- const arbiterUrl = (config.arbiterUrl || "https://arbiter.nullclear.dev").replace(/\/$/, "");
226
+ const arbiterUrl = (config.arbiterUrl || "https://api.nullclear.dev").replace(/\/$/, "");
202
227
  const defaultMinTrustScore = config.defaultMinTrustScore || 50;
203
228
  const customFetch = config.customFetch || fetch;
204
229
  return async function nullclearFetch(input, init) {
@@ -210,29 +235,33 @@ function createNullClearFetch(config) {
210
235
  return initialRes;
211
236
  }
212
237
  const paymentRequiredHeader = initialRes.headers.get("PAYMENT-REQUIRED") || initialRes.headers.get("payment-required");
213
- if (!paymentRequiredHeader) {
214
- return initialRes;
215
- }
216
- let paymentRequired;
217
- try {
218
- paymentRequired = decodeBase64Json(paymentRequiredHeader);
219
- } catch {
220
- return initialRes;
221
- }
222
- const targetNetwork = `eip155:${chainId}`;
223
- const selectedOption = paymentRequired.accepts.find(
224
- (opt) => opt.network === targetNetwork && opt.scheme === "exact"
225
- );
226
- if (!selectedOption) {
227
- throw new Error(
228
- `Seller does not accept payments on network ${targetNetwork}. Accepted: ${paymentRequired.accepts.map((a) => a.network).join(", ")}`
238
+ let paymentSignatureHeader;
239
+ if (config.accountOrPrivateKey && paymentRequiredHeader) {
240
+ let paymentRequired;
241
+ try {
242
+ paymentRequired = decodeBase64Json(paymentRequiredHeader);
243
+ } catch {
244
+ return initialRes;
245
+ }
246
+ const targetNetwork = `eip155:${chainId}`;
247
+ const selectedOption = paymentRequired.accepts.find(
248
+ (opt) => opt.network === targetNetwork && opt.scheme === "exact"
249
+ );
250
+ if (!selectedOption) {
251
+ throw new Error(
252
+ `Seller does not accept payments on network ${targetNetwork}. Accepted: ${paymentRequired.accepts.map((a) => a.network).join(", ")}`
253
+ );
254
+ }
255
+ paymentSignatureHeader = await signX402Payment(
256
+ config.accountOrPrivateKey,
257
+ selectedOption,
258
+ targetUrl
229
259
  );
260
+ } else if (!config.accountOrPrivateKey) {
261
+ paymentSignatureHeader = "free-trial";
262
+ } else {
263
+ return initialRes;
230
264
  }
231
- const paymentSignatureHeader = await signX402Payment(
232
- config.accountOrPrivateKey,
233
- selectedOption,
234
- targetUrl
235
- );
236
265
  let jsonSchema;
237
266
  if (init?.nullclear?.schema) {
238
267
  if (init.nullclear.schema instanceof z.ZodType) {
@@ -260,9 +289,13 @@ function createNullClearFetch(config) {
260
289
  fallbacks: init?.nullclear?.fallbacks,
261
290
  spendPolicy: init?.nullclear?.spendPolicy
262
291
  };
292
+ const clearHeaders = { "Content-Type": "application/json" };
293
+ if (paymentSignatureHeader === "free-trial") {
294
+ clearHeaders["x-nullclear-free-trial"] = "true";
295
+ }
263
296
  const arbiterRes = await customFetch(`${arbiterUrl}/v1/clear`, {
264
297
  method: "POST",
265
- headers: { "Content-Type": "application/json" },
298
+ headers: clearHeaders,
266
299
  body: JSON.stringify(clearPayload)
267
300
  });
268
301
  const arbiterData = await arbiterRes.json();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nullclear/x402-arbiter",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "NullClear Developer and Agent SDK for safe x402 calls with deferred schema escrow",
5
5
  "license": "MIT",
6
6
  "homepage": "https://nullclear.dev",
@@ -27,12 +27,12 @@
27
27
  }
28
28
  },
29
29
  "dependencies": {
30
- "@nullclear/shared": "1.1.1",
30
+ "@nullclear/shared": "1.2.0",
31
31
  "viem": "^2.23.0",
32
32
  "zod": "^3.24.2"
33
33
  },
34
34
  "devDependencies": {
35
- "@nullclear/worker-arbiter": "1.1.1",
35
+ "@nullclear/worker-arbiter": "1.2.0",
36
36
  "tsup": "^8.3.6",
37
37
  "typescript": "^5.7.3",
38
38
  "vitest": "^3.0.5"