@devlab.group/agent-commerce 1.4.0 → 1.5.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/x402.js CHANGED
@@ -1,48 +1,11 @@
1
- import { assertPayToIsNotDevAddress, resolveX402Deployment, assertDevKeyIsLocalOnly, describeDeploymentMode } from './chunk-IUR3Q7DE.js';
2
- export { SUPPORTED_NETWORK_IDS } from './chunk-IUR3Q7DE.js';
3
- import { CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION } from './chunk-ZDVJ7EVL.js';
4
- import { PaymentRequirementsV2Schema, PaymentPayloadV2Schema } from '@x402/core/schemas';
5
- import { getAddress, toHex, isAddress, createWalletClient, http, publicActions, createPublicClient, HttpRequestError, TimeoutError, WaitForTransactionReceiptTimeoutError, encodeAbiParameters, keccak256, ContractFunctionRevertedError, ContractFunctionExecutionError } from 'viem';
1
+ import { chainIdFromCaip2 } from './chunk-NKNXVDHN.js';
2
+ export { createX402PaymentProvider, createX402PaymentProvider as x402 } from './chunk-NKNXVDHN.js';
3
+ export { SUPPORTED_NETWORK_IDS } from './chunk-PBYN7EK2.js';
4
+ import './chunk-5GEWKNIH.js';
5
+ import { PaymentRequirementsV2Schema } from '@x402/core/schemas';
6
+ import { getAddress, toHex } from 'viem';
6
7
  import { privateKeyToAccount } from 'viem/accounts';
7
- import { x402Facilitator } from '@x402/core/facilitator';
8
- import { HTTPFacilitatorClient } from '@x402/core/http';
9
- import { isEIP3009Payload, toFacilitatorEvmSigner } from '@x402/evm';
10
- import { registerExactEvmScheme } from '@x402/evm/exact/facilitator';
11
8
 
12
- var LOCAL_CHAIN_ID = 84532;
13
- function chainIdFromCaip2(network) {
14
- const match = /^eip155:(\d+)$/.exec(network);
15
- if (!match?.[1]) return void 0;
16
- const chainId = Number(match[1]);
17
- return Number.isSafeInteger(chainId) && chainId > 0 ? chainId : void 0;
18
- }
19
- function buildLocalChain(rpcUrl, chainId = LOCAL_CHAIN_ID) {
20
- return {
21
- id: chainId,
22
- name: "agent-commerce-local",
23
- nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
24
- rpcUrls: {
25
- default: { http: [rpcUrl] }
26
- }
27
- };
28
- }
29
- function createLocalPublicClient(rpcUrl, timeoutMs, chainId) {
30
- return createPublicClient({
31
- chain: buildLocalChain(rpcUrl, chainId),
32
- transport: http(rpcUrl, { timeout: timeoutMs } )
33
- });
34
- }
35
- function createLocalFacilitatorClient(rpcUrl, signerPrivateKey) {
36
- const chain = buildLocalChain(rpcUrl);
37
- const account = privateKeyToAccount(signerPrivateKey);
38
- return createWalletClient({
39
- account,
40
- chain,
41
- transport: http(rpcUrl)
42
- }).extend(publicActions);
43
- }
44
-
45
- // src/payments/x402/client.ts
46
9
  var X402_VERSION = 2;
47
10
  var TRANSFER_WITH_AUTHORIZATION_TYPES = {
48
11
  TransferWithAuthorization: [
@@ -116,640 +79,6 @@ function randomNonce() {
116
79
  return toHex(bytes);
117
80
  }
118
81
 
119
- // src/payments/x402/amount.ts
120
- var DECIMAL_STRING_PATTERN = /^\d+(?:\.\d+)?$/;
121
- function parseCanonicalAmount(amount, decimals) {
122
- if (!Number.isInteger(decimals) || decimals < 0) {
123
- throw new CommerceError("INTERNAL_ERROR", `Invalid asset decimals: ${decimals}`);
124
- }
125
- if (!DECIMAL_STRING_PATTERN.test(amount)) {
126
- throw new CommerceError(
127
- "PAYMENT_INVALID",
128
- `Amount "${amount}" is not a valid non-negative decimal string`,
129
- {
130
- details: { amount }
131
- }
132
- );
133
- }
134
- const [integerPart = "0", fractionPart = ""] = amount.split(".");
135
- if (fractionPart.length > decimals) {
136
- throw new CommerceError(
137
- "PAYMENT_INVALID",
138
- `Amount "${amount}" has more precision than the asset supports (${decimals} decimals)`,
139
- { details: { amount, assetDecimals: decimals } }
140
- );
141
- }
142
- const paddedFraction = fractionPart.padEnd(decimals, "0");
143
- const combined = `${integerPart}${paddedFraction}`;
144
- return BigInt(combined);
145
- }
146
- function formatCanonicalAmount(baseUnits, decimals) {
147
- if (!Number.isInteger(decimals) || decimals < 0) {
148
- throw new CommerceError("INTERNAL_ERROR", `Invalid asset decimals: ${decimals}`);
149
- }
150
- const negative = baseUnits < 0n;
151
- const abs = negative ? -baseUnits : baseUnits;
152
- const digits = abs.toString().padStart(decimals + 1, "0");
153
- const integerPart = digits.slice(0, digits.length - decimals) || "0";
154
- const fractionPart = digits.slice(digits.length - decimals).replace(/0+$/, "");
155
- const sign = negative ? "-" : "";
156
- return fractionPart.length > 0 ? `${sign}${integerPart}.${fractionPart}` : `${sign}${integerPart}`;
157
- }
158
- var SETTLEMENT_CONFIRMATION_TIMEOUT_MS = 6e4;
159
- function createLocalFacilitatorBinding(client, network, isTransportError) {
160
- const build = () => {
161
- let failed = false;
162
- const watch = (promise) => promise.catch((err) => {
163
- if (isTransportError(err)) failed = true;
164
- throw err;
165
- });
166
- const signer = {
167
- address: client.account.address,
168
- readContract: (args) => watch(client.readContract(args)),
169
- verifyTypedData: (args) => watch(client.verifyTypedData(args)),
170
- writeContract: (args) => watch(client.writeContract(args)),
171
- sendTransaction: (args) => watch(client.sendTransaction(args)),
172
- waitForTransactionReceipt: (args) => watch(client.waitForTransactionReceipt(args)),
173
- getCode: (args) => watch(client.getCode(args))
174
- };
175
- const facilitator = registerExactEvmScheme(new x402Facilitator(), {
176
- signer: toFacilitatorEvmSigner(signer, {
177
- confirmationTimeoutMs: SETTLEMENT_CONFIRMATION_TIMEOUT_MS
178
- }),
179
- networks: network
180
- });
181
- return { facilitator, failed: () => failed };
182
- };
183
- return {
184
- kind: "local",
185
- describe: "local (in-process)",
186
- open() {
187
- const { facilitator, failed } = build();
188
- return {
189
- verify: (payload, requirements) => facilitator.verify(payload, requirements),
190
- settle: (payload, requirements) => facilitator.settle(payload, requirements),
191
- transportFailed: failed
192
- };
193
- },
194
- async supported() {
195
- return build().facilitator.getSupported().kinds;
196
- }
197
- };
198
- }
199
- function cdpAuthHeaders(apiKeyId, apiKeySecret) {
200
- const loading = import('@coinbase/x402').then(
201
- (mod) => mod.createCdpAuthHeaders(apiKeyId, apiKeySecret),
202
- (cause) => {
203
- throw new CommerceError(
204
- "CONFIG_INVALID",
205
- 'x402 provider: facilitator.auth.type is "cdp", which needs the optional peer "@coinbase/x402". Install it (npm install @coinbase/x402), or use a facilitator that accepts a static token with auth.type "bearer".',
206
- { cause }
207
- );
208
- }
209
- );
210
- loading.catch(() => {
211
- });
212
- return async () => {
213
- const create = await loading;
214
- if (!create) {
215
- throw new CommerceError(
216
- "PAYMENT_PROVIDER_UNAVAILABLE",
217
- "x402 provider: @coinbase/x402 returned no auth-header factory"
218
- );
219
- }
220
- return await create();
221
- };
222
- }
223
- function createRemoteFacilitatorBinding(options) {
224
- const auth = options.auth;
225
- let createAuthHeaders;
226
- if (auth.type === "bearer") {
227
- createAuthHeaders = async () => {
228
- const headers = { Authorization: `Bearer ${auth.token}` };
229
- return { verify: headers, settle: headers, supported: headers };
230
- };
231
- } else if (auth.type === "cdp") {
232
- createAuthHeaders = cdpAuthHeaders(auth.apiKeyId, auth.apiKeySecret);
233
- }
234
- const client = new HTTPFacilitatorClient({
235
- url: options.url,
236
- timeoutMs: options.timeoutMs ?? SETTLEMENT_CONFIRMATION_TIMEOUT_MS,
237
- ...createAuthHeaders ? { createAuthHeaders } : {}
238
- });
239
- return {
240
- kind: "remote",
241
- describe: `remote ${new URL(options.url).origin} (auth=${auth.type})`,
242
- open() {
243
- let failed = false;
244
- const watch = async (call) => {
245
- try {
246
- return await call();
247
- } catch (err) {
248
- failed = true;
249
- throw err;
250
- }
251
- };
252
- return {
253
- verify: (payload, requirements) => watch(() => client.verify(payload, requirements)),
254
- settle: (payload, requirements) => watch(() => client.settle(payload, requirements)),
255
- transportFailed: () => failed
256
- };
257
- },
258
- async supported() {
259
- const response = await client.getSupported();
260
- return response.kinds;
261
- }
262
- };
263
- }
264
- function decodePaymentSubmission(payloadBase64) {
265
- let json;
266
- try {
267
- const decoded = Buffer.from(payloadBase64, "base64").toString("utf8");
268
- json = JSON.parse(decoded);
269
- } catch {
270
- return void 0;
271
- }
272
- const result = PaymentPayloadV2Schema.safeParse(json);
273
- return result.success ? result.data : void 0;
274
- }
275
- function isExactEvmPayload(payload) {
276
- return payload.accepted.scheme === "exact" && typeof payload.payload === "object" && payload.payload !== null && isEIP3009Payload(payload.payload) && typeof payload.payload.signature === "string";
277
- }
278
- function computeReplayKey(input) {
279
- const encoded = encodeAbiParameters(
280
- [{ type: "uint256" }, { type: "address" }, { type: "address" }, { type: "bytes32" }],
281
- [BigInt(input.chainId), input.asset, input.from, input.nonce]
282
- );
283
- return keccak256(encoded);
284
- }
285
-
286
- // src/payments/x402/provider.ts
287
- var X402_VERSION2 = 2;
288
- var X402_PROTOCOL_VERSION = String(X402_VERSION2);
289
- var DEFAULT_MAX_TIMEOUT_SECONDS = 60;
290
- var DEFAULT_MIME_TYPE = "application/json";
291
- var HEALTH_TIMEOUT_MS = 4e3;
292
- var SETTLEMENT_PENDING_REASON = "settlement_pending";
293
- var MAX_REASON_LENGTH = 64;
294
- var REASON_SHAPE = /^[a-z0-9_.-]+$/i;
295
- function sanitiseReason(reason, fallback) {
296
- if (reason === void 0) return fallback;
297
- const trimmed = reason.trim();
298
- if (trimmed.length === 0 || trimmed.length > MAX_REASON_LENGTH) return fallback;
299
- return REASON_SHAPE.test(trimmed) ? trimmed : fallback;
300
- }
301
- var DEFAULT_IDS = {
302
- next: (prefix) => `${prefix ? `${prefix}_` : ""}${crypto.randomUUID()}`
303
- };
304
- function createX402PaymentProvider(options) {
305
- if (!isAddress(options.asset)) {
306
- throw new CommerceError(
307
- "CONFIG_INVALID",
308
- `x402 provider: "asset" is not a valid EVM address: ${options.asset}`
309
- );
310
- }
311
- if (!isAddress(options.payTo)) {
312
- throw new CommerceError(
313
- "CONFIG_INVALID",
314
- `x402 provider: "payTo" is not a valid EVM address: ${options.payTo}`
315
- );
316
- }
317
- assertPayToIsNotDevAddress(options.rpcUrl, options.payTo);
318
- if (!Number.isInteger(options.assetDecimals) || options.assetDecimals < 0) {
319
- throw new CommerceError(
320
- "CONFIG_INVALID",
321
- `x402 provider: "assetDecimals" must be a non-negative integer`
322
- );
323
- }
324
- const { profile, mode } = resolveX402Deployment({
325
- network: options.network,
326
- payTo: options.payTo,
327
- asset: options.asset,
328
- assetName: options.assetName,
329
- assetVersion: options.assetVersion,
330
- facilitator: options.facilitator,
331
- ...options.allowMainnet !== void 0 ? { allowMainnet: options.allowMainnet } : {},
332
- ...options.allowUnauthenticatedFacilitator !== void 0 ? { allowUnauthenticatedFacilitator: options.allowUnauthenticatedFacilitator } : {}
333
- });
334
- const network = options.network;
335
- let binding;
336
- if (options.facilitator.mode === "local") {
337
- assertDevKeyIsLocalOnly(options.rpcUrl, options.facilitator.signerPrivateKey);
338
- let client;
339
- try {
340
- client = createLocalFacilitatorClient(
341
- options.rpcUrl,
342
- options.facilitator.signerPrivateKey
343
- );
344
- } catch (cause) {
345
- throw new CommerceError(
346
- "CONFIG_INVALID",
347
- "x402 provider: could not construct a local facilitator signer from facilitator.signerPrivateKey \u2014 it must be a valid 32-byte hex private key",
348
- { cause }
349
- );
350
- }
351
- binding = createLocalFacilitatorBinding(client, network, isProviderUnavailableError);
352
- } else {
353
- binding = createRemoteFacilitatorBinding({
354
- url: options.facilitator.url,
355
- auth: options.facilitator.auth
356
- });
357
- }
358
- const healthPublicClient = createLocalPublicClient(
359
- options.rpcUrl,
360
- HEALTH_TIMEOUT_MS,
361
- profile.chainId
362
- );
363
- const clock = options.clock ?? systemClock;
364
- const ids = options.ids ?? DEFAULT_IDS;
365
- const logger = options.logger ?? NOOP_LOGGER;
366
- const maxTimeoutSeconds = options.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS;
367
- const descriptor = {
368
- name: "x402",
369
- kind: "payment",
370
- implementationVersion: PACKAGE_VERSION,
371
- supportedSpec: `x402/v${X402_VERSION2} scheme=exact family=eip155`,
372
- capabilities: [
373
- "exact-evm",
374
- `${binding.kind}-facilitator`,
375
- "eip-3009",
376
- "caip-2",
377
- `mode=${mode}`
378
- ],
379
- status: "stable",
380
- unsupported: [
381
- "svm",
382
- "permit2",
383
- "upto scheme",
384
- "per-request signed facilitator credentials (e.g. CDP JWT)"
385
- ]
386
- };
387
- async function createRequirement(context) {
388
- const amount = parseCanonicalAmount(context.amount, options.assetDecimals).toString();
389
- const requirements = {
390
- scheme: "exact",
391
- network,
392
- asset: options.asset,
393
- amount,
394
- payTo: options.payTo,
395
- maxTimeoutSeconds,
396
- // `name`/`version` are what let a buyer and the facilitator build the
397
- // same EIP-712 domain without an on-chain `version()` call, so
398
- // verification stays deterministic against a token that has none.
399
- //
400
- // `assetTransferMethod` is stated rather than left to default: x402 v2's
401
- // `exact`/EVM scheme also has a Permit2 path, and a client that picked it
402
- // would produce a payload this provider cannot settle. Declaring the one
403
- // supported method turns that into a client-side non-choice instead of a
404
- // server-side rejection.
405
- extra: {
406
- name: options.assetName,
407
- version: options.assetVersion,
408
- assetTransferMethod: "eip3009"
409
- }
410
- };
411
- const envelope = {
412
- x402Version: X402_VERSION2,
413
- resource: {
414
- url: `resource://agent-commerce/${encodeURIComponent(options.network)}/${options.payTo}/resources/${encodeURIComponent(context.resource.id)}`,
415
- description: context.resource.description ?? context.resource.name,
416
- mimeType: DEFAULT_MIME_TYPE
417
- },
418
- accepts: [requirements]
419
- };
420
- const expiresAt = new Date(clock.now().getTime() + maxTimeoutSeconds * 1e3).toISOString();
421
- return {
422
- id: ids.next("payreq"),
423
- requestId: context.requestId,
424
- resourceId: context.resource.id,
425
- provider: "x402",
426
- amount: context.amount,
427
- currency: context.currency,
428
- destination: options.payTo,
429
- network: options.network,
430
- asset: options.asset,
431
- expiresAt,
432
- challenge: {
433
- provider: "x402",
434
- version: X402_PROTOCOL_VERSION,
435
- accepts: [requirements],
436
- envelope
437
- }
438
- };
439
- }
440
- async function verify(context) {
441
- const { requirement, submission } = context;
442
- const rejected = (reason) => ({
443
- status: "rejected",
444
- provider: "x402",
445
- amount: requirement.amount,
446
- currency: requirement.currency,
447
- ...requirement.network !== void 0 ? { network: requirement.network } : {},
448
- ...requirement.asset !== void 0 ? { asset: requirement.asset } : {},
449
- rejectionReason: reason
450
- });
451
- if (requirement.provider !== "x402" || requirement.challenge.provider !== "x402") {
452
- return rejected("wrong_provider");
453
- }
454
- const requirements = requirement.challenge.accepts[0];
455
- if (!requirements) {
456
- return rejected("missing_payment_requirements");
457
- }
458
- if (requirement.expiresAt !== void 0 && Date.parse(requirement.expiresAt) < clock.now().getTime()) {
459
- return rejected("requirement_expired");
460
- }
461
- if (!isAddress(requirements.asset) || getAddress(requirements.asset) !== getAddress(options.asset)) {
462
- return rejected("wrong_asset");
463
- }
464
- const payload = decodePaymentSubmission(submission.payload);
465
- if (!payload) {
466
- return rejected("malformed_payment_payload");
467
- }
468
- if (payload.x402Version !== X402_VERSION2) {
469
- return rejected("unsupported_x402_version");
470
- }
471
- if (!isExactEvmPayload(payload)) {
472
- return rejected("unsupported_scheme");
473
- }
474
- const { authorization } = payload.payload;
475
- if (!isAddress(authorization.from) || !isAddress(authorization.to)) {
476
- return rejected("malformed_payment_payload");
477
- }
478
- if (payload.accepted.network !== options.network) {
479
- return rejected("wrong_network");
480
- }
481
- if (getAddress(authorization.to) !== getAddress(options.payTo)) {
482
- return rejected("wrong_recipient");
483
- }
484
- let authorizedValue;
485
- let required;
486
- try {
487
- authorizedValue = BigInt(authorization.value);
488
- required = BigInt(requirements.amount);
489
- } catch {
490
- return rejected("malformed_payment_payload");
491
- }
492
- if (authorizedValue !== required) {
493
- return rejected("wrong_amount");
494
- }
495
- const scope = binding.open();
496
- let sdkResult;
497
- try {
498
- sdkResult = await scope.verify(payload, requirements);
499
- } catch (err) {
500
- if (isProviderUnavailableError(err) || scope.transportFailed()) {
501
- throw new CommerceError(
502
- "PAYMENT_PROVIDER_UNAVAILABLE",
503
- `x402 provider: ${binding.kind} facilitator unreachable during verify()`,
504
- {
505
- cause: err
506
- }
507
- );
508
- }
509
- logger.warn({ err: describeError(err) }, "x402 verify(): unexpected SDK error");
510
- return rejected("unexpected_verify_error");
511
- }
512
- if (!sdkResult.isValid) {
513
- if (scope.transportFailed()) {
514
- throw new CommerceError(
515
- "PAYMENT_PROVIDER_UNAVAILABLE",
516
- `x402 provider: ${binding.kind} facilitator unreachable during verify()`,
517
- { details: { reportedReason: sdkResult.invalidReason ?? "invalid_payment" } }
518
- );
519
- }
520
- if (sdkResult.invalidReason !== void 0) {
521
- logger.debug(
522
- { reportedReason: sdkResult.invalidReason },
523
- "x402 verify(): facilitator rejection reason"
524
- );
525
- }
526
- return rejected(sanitiseReason(sdkResult.invalidReason, "invalid_payment"));
527
- }
528
- const payloadChainId = chainIdFromCaip2(payload.accepted.network);
529
- if (payloadChainId === void 0) {
530
- return rejected("wrong_network");
531
- }
532
- const replayKey = computeReplayKey({
533
- chainId: payloadChainId,
534
- asset: getAddress(requirements.asset),
535
- from: getAddress(authorization.from),
536
- nonce: authorization.nonce
537
- });
538
- return {
539
- status: "verified",
540
- provider: "x402",
541
- payer: getAddress(authorization.from),
542
- payee: getAddress(authorization.to),
543
- amount: formatCanonicalAmount(authorizedValue, options.assetDecimals),
544
- currency: requirement.currency,
545
- network: payload.accepted.network,
546
- asset: getAddress(requirements.asset),
547
- replayKey
548
- };
549
- }
550
- async function settle(context) {
551
- const { requirement, submission, verification } = context;
552
- if (verification.status !== "verified") {
553
- throw new CommerceError(
554
- "PAYMENT_INVALID",
555
- "x402 provider: settle() called without a successful verify()"
556
- );
557
- }
558
- const requirements = requirement.challenge.accepts[0];
559
- if (!requirements) {
560
- throw new CommerceError(
561
- "PAYMENT_INVALID",
562
- "x402 provider: settle() found no payment requirements to settle against"
563
- );
564
- }
565
- const payload = decodePaymentSubmission(submission.payload);
566
- if (!payload || !isExactEvmPayload(payload)) {
567
- throw new CommerceError(
568
- "PAYMENT_INVALID",
569
- "x402 provider: settle() received an undecodable payment payload"
570
- );
571
- }
572
- const rejectedSettlement = (rejectionReason) => ({
573
- status: "rejected",
574
- provider: "x402",
575
- amount: verification.amount,
576
- currency: requirement.currency,
577
- ...verification.network !== void 0 ? { network: verification.network } : {},
578
- ...verification.asset !== void 0 ? { asset: verification.asset } : {},
579
- ...verification.replayKey !== void 0 ? { replayKey: verification.replayKey } : {},
580
- rejectionReason
581
- });
582
- const scope = binding.open();
583
- let sdkResult;
584
- try {
585
- sdkResult = await scope.settle(payload, requirements);
586
- } catch (err) {
587
- if (isProviderUnavailableError(err) || scope.transportFailed()) {
588
- throw new CommerceError(
589
- "PAYMENT_PROVIDER_UNAVAILABLE",
590
- `x402 provider: ${binding.kind} facilitator unreachable during settle()`,
591
- { cause: err }
592
- );
593
- }
594
- const rejectionReason = isOnChainRevertError(err) ? "transaction_reverted" : "unexpected_settle_error";
595
- logger.warn(
596
- { err: describeError(err), rejectionReason },
597
- "x402 settle(): settlement transaction failed"
598
- );
599
- return rejectedSettlement(rejectionReason);
600
- }
601
- if (!sdkResult.success) {
602
- if (sdkResult.errorReason === SETTLEMENT_PENDING_REASON || scope.transportFailed()) {
603
- throw new CommerceError(
604
- "PAYMENT_PROVIDER_UNAVAILABLE",
605
- "x402 provider: settlement was broadcast but could not be confirmed",
606
- {
607
- ...sdkResult.transaction ? { details: { transactionHash: sdkResult.transaction } } : {}
608
- }
609
- );
610
- }
611
- if (sdkResult.errorReason !== void 0) {
612
- logger.debug(
613
- { reportedReason: sdkResult.errorReason },
614
- "x402 settle(): facilitator failure reason"
615
- );
616
- }
617
- return {
618
- ...rejectedSettlement(sanitiseReason(sdkResult.errorReason, "settlement_failed")),
619
- network: sdkResult.network,
620
- ...sdkResult.payer !== void 0 ? { payer: sdkResult.payer } : {}
621
- };
622
- }
623
- return {
624
- status: "settled",
625
- provider: "x402",
626
- externalReference: sdkResult.transaction,
627
- ...sdkResult.payer !== void 0 ? { payer: sdkResult.payer } : {},
628
- payee: requirements.payTo,
629
- amount: verification.amount,
630
- currency: requirement.currency,
631
- network: sdkResult.network,
632
- ...verification.asset !== void 0 ? { asset: verification.asset } : {},
633
- ...verification.replayKey !== void 0 ? { replayKey: verification.replayKey } : {},
634
- settledAt: clock.nowIso()
635
- };
636
- }
637
- async function computeHealth() {
638
- const startedAt = clock.monotonicMs();
639
- const checkedAt = clock.nowIso();
640
- try {
641
- const chainId = await healthPublicClient.getChainId();
642
- if (chainId !== profile.chainId) {
643
- return {
644
- status: "fail",
645
- detail: `RPC at ${options.rpcUrl} reports chain id ${chainId}, expected ${profile.chainId} (${profile.displayName})`,
646
- checkedAt,
647
- durationMs: clock.monotonicMs() - startedAt
648
- };
649
- }
650
- const code = await healthPublicClient.getCode({ address: options.asset });
651
- if (!code || code === "0x") {
652
- return {
653
- status: "fail",
654
- detail: `No contract code found at configured asset address ${options.asset}`,
655
- checkedAt,
656
- durationMs: clock.monotonicMs() - startedAt
657
- };
658
- }
659
- if (binding.kind === "remote") {
660
- const kinds = await binding.supported();
661
- const supportsUs = kinds.some(
662
- (kind) => kind.x402Version === X402_VERSION2 && kind.scheme === "exact" && kind.network === options.network
663
- );
664
- if (!supportsUs) {
665
- return {
666
- status: "fail",
667
- detail: `Facilitator ${binding.describe} does not advertise x402 v${X402_VERSION2} scheme=exact on ${options.network} (${profile.displayName}); no payment on this deployment can settle`,
668
- checkedAt,
669
- durationMs: clock.monotonicMs() - startedAt
670
- };
671
- }
672
- return {
673
- status: "pass",
674
- detail: `${describeDeploymentMode(mode)} \u2014 RPC ${options.rpcUrl} reachable, chain id ${profile.chainId} (${profile.displayName}), asset ${options.asset} has code, facilitator ${binding.describe} supports exact/${options.network}`,
675
- checkedAt,
676
- durationMs: clock.monotonicMs() - startedAt
677
- };
678
- }
679
- const isAnvil = await probeIsAnvilNode(healthPublicClient);
680
- if (!isAnvil) {
681
- return {
682
- status: "fail",
683
- detail: `RPC at ${options.rpcUrl} reports chain id ${profile.chainId} but does not answer "anvil_nodeInfo" \u2014 it does not look like a local Anvil dev node. Refusing to treat it as safe for a local-facilitator dev key.`,
684
- checkedAt,
685
- durationMs: clock.monotonicMs() - startedAt
686
- };
687
- }
688
- return {
689
- status: "pass",
690
- detail: `${describeDeploymentMode(mode)} \u2014 RPC ${options.rpcUrl} reachable, chain id ${profile.chainId}, asset ${options.asset} has code, confirmed Anvil dev node`,
691
- checkedAt,
692
- durationMs: clock.monotonicMs() - startedAt
693
- };
694
- } catch (err) {
695
- return {
696
- status: "fail",
697
- detail: `x402 health check failed: ${describeError(err)}`,
698
- checkedAt,
699
- durationMs: clock.monotonicMs() - startedAt
700
- };
701
- }
702
- }
703
- const HEALTH_CACHE_MS = 5e3;
704
- let cachedHealth;
705
- let inFlightHealth;
706
- async function health() {
707
- const now = clock.monotonicMs();
708
- if (cachedHealth && now - cachedHealth.at < HEALTH_CACHE_MS) {
709
- return cachedHealth.value;
710
- }
711
- if (inFlightHealth) return inFlightHealth;
712
- inFlightHealth = computeHealth().then((value) => {
713
- cachedHealth = { at: clock.monotonicMs(), value };
714
- return value;
715
- }).finally(() => {
716
- inFlightHealth = void 0;
717
- });
718
- return inFlightHealth;
719
- }
720
- return {
721
- name: "x402",
722
- descriptor,
723
- createRequirement,
724
- verify,
725
- settle,
726
- health
727
- };
728
- }
729
- function isOnChainRevertError(err) {
730
- return err instanceof ContractFunctionRevertedError || err instanceof ContractFunctionExecutionError;
731
- }
732
- function isProviderUnavailableError(err) {
733
- if (err instanceof HttpRequestError || err instanceof TimeoutError || err instanceof WaitForTransactionReceiptTimeoutError) {
734
- return true;
735
- }
736
- const message = describeError(err).toLowerCase();
737
- return message.includes("econnrefused") || message.includes("fetch failed") || message.includes("enotfound") || message.includes("etimedout") || message.includes("timed out") || message.includes("network error");
738
- }
739
- function describeError(err) {
740
- if (err instanceof Error) return `${err.name}: ${err.message}`;
741
- return String(err);
742
- }
743
- async function probeIsAnvilNode(client) {
744
- const request = client.request;
745
- try {
746
- await request({ method: "anvil_nodeInfo", params: [] });
747
- return true;
748
- } catch {
749
- return false;
750
- }
751
- }
752
-
753
- export { createPaymentProof, createX402PaymentProvider, createX402PaymentProvider as x402 };
82
+ export { createPaymentProof };
754
83
  //# sourceMappingURL=x402.js.map
755
84
  //# sourceMappingURL=x402.js.map