@devlab.group/agent-commerce 2.0.0 → 2.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.
Files changed (105) hide show
  1. package/README.md +137 -56
  2. package/dist/ap2.d.ts +2 -2
  3. package/dist/ap2.js +4 -3
  4. package/dist/ap2.js.map +1 -1
  5. package/dist/{authorization-BpbWGGrf.d.ts → authorization-CMkIuAkO.d.ts} +1 -1
  6. package/dist/chunk-2CJNA7MS.js +8 -0
  7. package/dist/chunk-2CJNA7MS.js.map +1 -0
  8. package/dist/{chunk-CKJRITWY.js → chunk-5ZYXBCDX.js} +3 -3
  9. package/dist/{chunk-CKJRITWY.js.map → chunk-5ZYXBCDX.js.map} +1 -1
  10. package/dist/{chunk-3LUJHVKX.js → chunk-6Z2H53CG.js} +5 -4
  11. package/dist/chunk-6Z2H53CG.js.map +1 -0
  12. package/dist/{chunk-53WXXIPR.js → chunk-7ZMMXZ4G.js} +6 -10
  13. package/dist/chunk-7ZMMXZ4G.js.map +1 -0
  14. package/dist/{chunk-HOZA3IWP.js → chunk-ES3V6ECS.js} +16 -6
  15. package/dist/chunk-ES3V6ECS.js.map +1 -0
  16. package/dist/chunk-HNRDZLSN.js +1398 -0
  17. package/dist/chunk-HNRDZLSN.js.map +1 -0
  18. package/dist/{chunk-SYEGCNJZ.js → chunk-IEW7NSP2.js} +23 -5
  19. package/dist/chunk-IEW7NSP2.js.map +1 -0
  20. package/dist/chunk-KA2AX5FH.js +44 -0
  21. package/dist/chunk-KA2AX5FH.js.map +1 -0
  22. package/dist/chunk-Y4RE3XYF.js +581 -0
  23. package/dist/chunk-Y4RE3XYF.js.map +1 -0
  24. package/dist/cli/ap2-MBMQHFX4.js +678 -0
  25. package/dist/cli/ap2-MBMQHFX4.js.map +1 -0
  26. package/dist/cli/chunk-2ZZOGI5I.js +1352 -0
  27. package/dist/cli/chunk-2ZZOGI5I.js.map +1 -0
  28. package/dist/cli/chunk-3EQBCFZY.js +53 -0
  29. package/dist/cli/chunk-3EQBCFZY.js.map +1 -0
  30. package/dist/cli/chunk-3M6U7ILB.js +8 -0
  31. package/dist/cli/chunk-3M6U7ILB.js.map +1 -0
  32. package/dist/cli/chunk-3MGAJ5FX.js +70 -0
  33. package/dist/cli/chunk-3MGAJ5FX.js.map +1 -0
  34. package/dist/cli/chunk-5K4XEAZV.js +113 -0
  35. package/dist/cli/chunk-5K4XEAZV.js.map +1 -0
  36. package/dist/cli/chunk-7JNYFUT3.js +256 -0
  37. package/dist/cli/chunk-7JNYFUT3.js.map +1 -0
  38. package/dist/cli/chunk-AA3FIEAR.js +27 -0
  39. package/dist/cli/chunk-AA3FIEAR.js.map +1 -0
  40. package/dist/cli/chunk-FHCFR2GS.js +17 -0
  41. package/dist/cli/chunk-FHCFR2GS.js.map +1 -0
  42. package/dist/cli/chunk-FRMLWGSS.js +8 -0
  43. package/dist/cli/chunk-FRMLWGSS.js.map +1 -0
  44. package/dist/cli/chunk-KLX2YZDG.js +1400 -0
  45. package/dist/cli/chunk-KLX2YZDG.js.map +1 -0
  46. package/dist/cli/chunk-NSPPEF5M.js +334 -0
  47. package/dist/cli/chunk-NSPPEF5M.js.map +1 -0
  48. package/dist/cli/chunk-OSTCU6ZK.js +44 -0
  49. package/dist/cli/chunk-OSTCU6ZK.js.map +1 -0
  50. package/dist/cli/chunk-QQ3WY5L3.js +271 -0
  51. package/dist/cli/chunk-QQ3WY5L3.js.map +1 -0
  52. package/dist/cli/chunk-RWVPYAKC.js +1742 -0
  53. package/dist/cli/chunk-RWVPYAKC.js.map +1 -0
  54. package/dist/cli/chunk-SPAYKVUP.js +118 -0
  55. package/dist/cli/chunk-SPAYKVUP.js.map +1 -0
  56. package/dist/cli/chunk-SS3QFF5N.js +614 -0
  57. package/dist/cli/chunk-SS3QFF5N.js.map +1 -0
  58. package/dist/cli/chunk-TPC4EJLT.js +11 -0
  59. package/dist/cli/chunk-TPC4EJLT.js.map +1 -0
  60. package/dist/cli/config-4IBGVFSP.js +11 -0
  61. package/dist/cli/config-4IBGVFSP.js.map +1 -0
  62. package/dist/cli/index.js +822 -3392
  63. package/dist/cli/index.js.map +1 -1
  64. package/dist/cli/mcp-CNWQ2MOE.js +559 -0
  65. package/dist/cli/mcp-CNWQ2MOE.js.map +1 -0
  66. package/dist/cli/near-5AY3HWYF.js +58 -0
  67. package/dist/cli/near-5AY3HWYF.js.map +1 -0
  68. package/dist/cli/provider-4BQDH56Y.js +396 -0
  69. package/dist/cli/provider-4BQDH56Y.js.map +1 -0
  70. package/dist/cli/run-5MB2D45X.js +7286 -0
  71. package/dist/cli/run-5MB2D45X.js.map +1 -0
  72. package/dist/cli/svm-3MMYFPC7.js +33 -0
  73. package/dist/cli/svm-3MMYFPC7.js.map +1 -0
  74. package/dist/cli/x402-NKR3WQDQ.js +96 -0
  75. package/dist/cli/x402-NKR3WQDQ.js.map +1 -0
  76. package/dist/{constants-BSBRlKRR.d.ts → constants-nackLItD.d.ts} +2 -1
  77. package/dist/index.d.ts +61 -40
  78. package/dist/index.js +2642 -2205
  79. package/dist/index.js.map +1 -1
  80. package/dist/mcp.d.ts +3 -3
  81. package/dist/mcp.js +15 -20
  82. package/dist/mcp.js.map +1 -1
  83. package/dist/mpp.d.ts +12 -5
  84. package/dist/mpp.js +69 -65
  85. package/dist/mpp.js.map +1 -1
  86. package/dist/near-D6C42VPE.js +58 -0
  87. package/dist/near-D6C42VPE.js.map +1 -0
  88. package/dist/networks-olfflCI_.d.ts +38 -0
  89. package/dist/{protocol-adapter-DonxfAwa.d.ts → protocol-adapter-CfxU8Z2T.d.ts} +2 -2
  90. package/dist/{runtime-CiYbgGpi.d.ts → runtime-7vLNYvmU.d.ts} +25 -3
  91. package/dist/svm-QEUAUNPQ.js +33 -0
  92. package/dist/svm-QEUAUNPQ.js.map +1 -0
  93. package/dist/x402.d.ts +76 -64
  94. package/dist/x402.js +13 -4
  95. package/dist/x402.js.map +1 -1
  96. package/package.json +22 -2
  97. package/dist/chunk-3LUJHVKX.js.map +0 -1
  98. package/dist/chunk-53WXXIPR.js.map +0 -1
  99. package/dist/chunk-HOZA3IWP.js.map +0 -1
  100. package/dist/chunk-RKBGCPCK.js +0 -733
  101. package/dist/chunk-RKBGCPCK.js.map +0 -1
  102. package/dist/chunk-SYEGCNJZ.js.map +0 -1
  103. package/dist/chunk-TWRUNWDR.js +0 -265
  104. package/dist/chunk-TWRUNWDR.js.map +0 -1
  105. package/dist/{payment-flow-DCS882tR.d.ts → guardrails-CX_jYXvZ.d.ts} +8 -8
@@ -1,733 +0,0 @@
1
- import { assertPayToIsNotDevAddress, resolveX402Deployment, assertDevKeyIsLocalOnly, describeRpc, X402_DEFAULT_PAYMENT_FLOW, SETTLE_AFTER_BACKEND_METADATA_KEY, LOCAL_CHAIN_ID, describeDeploymentMode } from './chunk-TWRUNWDR.js';
2
- import { CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION, redactedErrorText } from './chunk-53WXXIPR.js';
3
- import { encodeAbiParameters, keccak256, isAddress, getAddress, formatUnits, createWalletClient, http, publicActions, createPublicClient, HttpRequestError, TimeoutError, WaitForTransactionReceiptTimeoutError, BaseError, ContractFunctionRevertedError } from 'viem';
4
- import { privateKeyToAccount } from 'viem/accounts';
5
- import { x402Facilitator } from '@x402/core/facilitator';
6
- import { HTTPFacilitatorClient } from '@x402/core/http';
7
- import { SettleError, VerifyError } from '@x402/core/types';
8
- import { isEIP3009Payload, toFacilitatorEvmSigner } from '@x402/evm';
9
- import { registerExactEvmScheme } from '@x402/evm/exact/facilitator';
10
- import { PaymentPayloadV2Schema } from '@x402/core/schemas';
11
-
12
- // src/payments/x402/amount.ts
13
- var DECIMAL_STRING_PATTERN = /^\d+(?:\.\d+)?$/;
14
- function parseCanonicalAmount(amount, decimals) {
15
- if (!Number.isInteger(decimals) || decimals < 0) {
16
- throw new CommerceError("INTERNAL_ERROR", `Invalid asset decimals: ${decimals}`);
17
- }
18
- if (!DECIMAL_STRING_PATTERN.test(amount)) {
19
- throw new CommerceError(
20
- "PAYMENT_INVALID",
21
- `Amount "${amount}" is not a valid non-negative decimal string`,
22
- {
23
- details: { amount }
24
- }
25
- );
26
- }
27
- const [integerPart = "0", fractionPart = ""] = amount.split(".");
28
- if (fractionPart.length > decimals) {
29
- throw new CommerceError(
30
- "PAYMENT_INVALID",
31
- `Amount "${amount}" has more precision than the asset supports (${decimals} decimals)`,
32
- { details: { amount, assetDecimals: decimals } }
33
- );
34
- }
35
- const paddedFraction = fractionPart.padEnd(decimals, "0");
36
- const combined = `${integerPart}${paddedFraction}`;
37
- return BigInt(combined);
38
- }
39
- function chainIdFromCaip2(network) {
40
- const match = /^eip155:(\d+)$/.exec(network);
41
- if (!match?.[1]) return void 0;
42
- const chainId = Number(match[1]);
43
- return Number.isSafeInteger(chainId) && chainId > 0 ? chainId : void 0;
44
- }
45
- function buildLocalChain(rpcUrl, chainId = LOCAL_CHAIN_ID) {
46
- return {
47
- id: chainId,
48
- name: "agent-commerce-local",
49
- nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
50
- rpcUrls: {
51
- default: { http: [rpcUrl] }
52
- }
53
- };
54
- }
55
- function createLocalPublicClient(rpcUrl, timeoutMs, chainId) {
56
- return createPublicClient({
57
- chain: buildLocalChain(rpcUrl, chainId),
58
- transport: http(rpcUrl, { timeout: timeoutMs } )
59
- });
60
- }
61
- function createLocalFacilitatorClient(rpcUrl, signerPrivateKey) {
62
- const chain = buildLocalChain(rpcUrl);
63
- const account = privateKeyToAccount(signerPrivateKey);
64
- return createWalletClient({
65
- account,
66
- chain,
67
- transport: http(rpcUrl)
68
- }).extend(publicActions);
69
- }
70
- var SETTLEMENT_CONFIRMATION_TIMEOUT_MS = 6e4;
71
- function createLocalFacilitatorBinding(client, network, isTransportError) {
72
- const build = () => {
73
- let failed = false;
74
- const watch = (promise) => promise.catch((err) => {
75
- if (isTransportError(err)) failed = true;
76
- throw err;
77
- });
78
- const signer = {
79
- address: client.account.address,
80
- readContract: (args) => watch(client.readContract(args)),
81
- verifyTypedData: (args) => watch(client.verifyTypedData(args)),
82
- writeContract: (args) => watch(client.writeContract(args)),
83
- sendTransaction: (args) => watch(client.sendTransaction(args)),
84
- waitForTransactionReceipt: (args) => watch(client.waitForTransactionReceipt(args)),
85
- getCode: (args) => watch(client.getCode(args))
86
- };
87
- const facilitator = registerExactEvmScheme(new x402Facilitator(), {
88
- signer: toFacilitatorEvmSigner(signer, {
89
- confirmationTimeoutMs: SETTLEMENT_CONFIRMATION_TIMEOUT_MS
90
- }),
91
- networks: network
92
- });
93
- return { facilitator, failed: () => failed };
94
- };
95
- return {
96
- kind: "local",
97
- describe: "local (in-process)",
98
- open() {
99
- const { facilitator, failed } = build();
100
- return {
101
- verify: (payload, requirements) => facilitator.verify(payload, requirements),
102
- settle: (payload, requirements) => facilitator.settle(payload, requirements),
103
- transportFailed: failed
104
- };
105
- }
106
- };
107
- }
108
- function cdpAuthHeaders(apiKeyId, apiKeySecret) {
109
- const loading = import('@coinbase/x402').then(
110
- (mod) => mod.createCdpAuthHeaders(apiKeyId, apiKeySecret),
111
- (cause) => {
112
- throw new CommerceError(
113
- "CONFIG_INVALID",
114
- '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".',
115
- { cause }
116
- );
117
- }
118
- );
119
- loading.catch(() => {
120
- });
121
- return async () => {
122
- const create = await loading;
123
- if (!create) {
124
- throw new CommerceError(
125
- "PAYMENT_PROVIDER_UNAVAILABLE",
126
- "x402 provider: @coinbase/x402 returned no auth-header factory"
127
- );
128
- }
129
- return await create();
130
- };
131
- }
132
- function verdictFromVerifyError(err) {
133
- if (err instanceof VerifyError && err.statusCode === 400 && typeof err.invalidReason === "string") {
134
- return {
135
- isValid: false,
136
- invalidReason: err.invalidReason,
137
- ...err.payer !== void 0 ? { payer: err.payer } : {}
138
- };
139
- }
140
- throw err;
141
- }
142
- function verdictFromSettleError(err, network) {
143
- if (err instanceof SettleError && err.statusCode === 400 && typeof err.errorReason === "string" && err.errorReason !== "" && !err.transaction) {
144
- return {
145
- success: false,
146
- errorReason: err.errorReason,
147
- transaction: "",
148
- network: err.network ?? network,
149
- ...err.payer !== void 0 ? { payer: err.payer } : {}
150
- };
151
- }
152
- throw err;
153
- }
154
- function createRemoteFacilitatorBinding(options) {
155
- const auth = options.auth;
156
- let createAuthHeaders;
157
- if (auth.type === "bearer") {
158
- createAuthHeaders = async () => {
159
- const headers = { Authorization: `Bearer ${auth.token}` };
160
- return { verify: headers, settle: headers, supported: headers };
161
- };
162
- } else if (auth.type === "cdp") {
163
- createAuthHeaders = cdpAuthHeaders(auth.apiKeyId, auth.apiKeySecret);
164
- }
165
- const client = new HTTPFacilitatorClient({
166
- url: options.url,
167
- timeoutMs: SETTLEMENT_CONFIRMATION_TIMEOUT_MS,
168
- ...createAuthHeaders ? { createAuthHeaders } : {}
169
- });
170
- return {
171
- kind: "remote",
172
- describe: `remote ${new URL(options.url).origin} (auth=${auth.type})`,
173
- open() {
174
- let failed = false;
175
- const watch = async (call) => {
176
- try {
177
- return await call();
178
- } catch (err) {
179
- failed = true;
180
- throw err;
181
- }
182
- };
183
- return {
184
- verify: (payload, requirements) => watch(() => client.verify(payload, requirements).catch(verdictFromVerifyError)),
185
- settle: (payload, requirements) => watch(
186
- () => client.settle(payload, requirements).catch((err) => verdictFromSettleError(err, requirements.network))
187
- ),
188
- transportFailed: () => failed
189
- };
190
- },
191
- async supported() {
192
- const response = await client.getSupported();
193
- return response.kinds;
194
- }
195
- };
196
- }
197
- function decodePaymentSubmission(payloadBase64) {
198
- const json = decodeJson(payloadBase64);
199
- if (json === void 0) return void 0;
200
- const result = PaymentPayloadV2Schema.safeParse(json);
201
- return result.success ? result.data : void 0;
202
- }
203
- function declaredX402Version(payloadBase64) {
204
- const json = decodeJson(payloadBase64);
205
- return typeof json === "object" && json !== null ? json["x402Version"] : void 0;
206
- }
207
- function withoutResource(payload) {
208
- const { resource: _resource, ...rest } = payload;
209
- return rest;
210
- }
211
- function decodeJson(payloadBase64) {
212
- try {
213
- return JSON.parse(Buffer.from(payloadBase64, "base64").toString("utf8"));
214
- } catch {
215
- return void 0;
216
- }
217
- }
218
- function isExactEvmPayload(payload) {
219
- return payload.accepted.scheme === "exact" && typeof payload.payload === "object" && payload.payload !== null && isEIP3009Payload(payload.payload) && typeof payload.payload.signature === "string";
220
- }
221
- function computeReplayKey(input) {
222
- const encoded = encodeAbiParameters(
223
- [{ type: "uint256" }, { type: "address" }, { type: "address" }, { type: "bytes32" }],
224
- [BigInt(input.chainId), input.asset, input.from, input.nonce]
225
- );
226
- return keccak256(encoded);
227
- }
228
-
229
- // src/payments/x402/provider.ts
230
- var X402_VERSION = 2;
231
- var X402_PROTOCOL_VERSION = String(X402_VERSION);
232
- var DEFAULT_MAX_TIMEOUT_SECONDS = 60;
233
- var DEFAULT_MIME_TYPE = "application/json";
234
- var HEALTH_TIMEOUT_MS = 4e3;
235
- var SETTLEMENT_PENDING_REASON = "settlement_pending";
236
- var TRANSACTION_FAILED_REASON = "invalid_exact_evm_transaction_failed";
237
- var MAX_REASON_LENGTH = 64;
238
- var REASON_SHAPE = /^[a-z0-9_.-]+$/i;
239
- function sanitizeReason(reason, fallback) {
240
- if (reason === void 0) return fallback;
241
- const trimmed = reason.trim();
242
- if (trimmed.length === 0 || trimmed.length > MAX_REASON_LENGTH) return fallback;
243
- return REASON_SHAPE.test(trimmed) ? trimmed : fallback;
244
- }
245
- var DEFAULT_IDS = {
246
- next: (prefix) => `${prefix ? `${prefix}_` : ""}${crypto.randomUUID()}`
247
- };
248
- function createX402PaymentProvider(options) {
249
- if (!isAddress(options.asset)) {
250
- throw new CommerceError(
251
- "CONFIG_INVALID",
252
- `x402 provider: "asset" is not a valid EVM address: ${options.asset}`
253
- );
254
- }
255
- if (!isAddress(options.payTo)) {
256
- throw new CommerceError(
257
- "CONFIG_INVALID",
258
- `x402 provider: "payTo" is not a valid EVM address: ${options.payTo}`
259
- );
260
- }
261
- assertPayToIsNotDevAddress(options.rpcUrl, options.payTo);
262
- if (!Number.isInteger(options.assetDecimals) || options.assetDecimals < 0) {
263
- throw new CommerceError(
264
- "CONFIG_INVALID",
265
- `x402 provider: "assetDecimals" must be a non-negative integer`
266
- );
267
- }
268
- const { profile, mode } = resolveX402Deployment({
269
- network: options.network,
270
- payTo: options.payTo,
271
- asset: options.asset,
272
- assetName: options.assetName,
273
- assetVersion: options.assetVersion,
274
- facilitator: options.facilitator,
275
- ...options.allowMainnet !== void 0 ? { allowMainnet: options.allowMainnet } : {},
276
- ...options.allowUnauthenticatedFacilitator !== void 0 ? { allowUnauthenticatedFacilitator: options.allowUnauthenticatedFacilitator } : {}
277
- });
278
- const network = options.network;
279
- let binding;
280
- if (options.facilitator.mode === "local") {
281
- assertDevKeyIsLocalOnly(options.rpcUrl, options.facilitator.signerPrivateKey);
282
- let client;
283
- try {
284
- client = createLocalFacilitatorClient(
285
- options.rpcUrl,
286
- options.facilitator.signerPrivateKey
287
- );
288
- } catch (cause) {
289
- throw new CommerceError(
290
- "CONFIG_INVALID",
291
- "x402 provider: could not construct a local facilitator signer from facilitator.signerPrivateKey. It must be a valid 32-byte hex private key.",
292
- { cause }
293
- );
294
- }
295
- binding = createLocalFacilitatorBinding(client, network, isProviderUnavailableError);
296
- } else {
297
- binding = createRemoteFacilitatorBinding({
298
- url: options.facilitator.url,
299
- auth: options.facilitator.auth
300
- });
301
- }
302
- const rpcOrigin = describeRpc(options.rpcUrl);
303
- const healthPublicClient = createLocalPublicClient(
304
- options.rpcUrl,
305
- HEALTH_TIMEOUT_MS,
306
- profile.chainId
307
- );
308
- const clock = options.clock ?? systemClock;
309
- const ids = options.ids ?? DEFAULT_IDS;
310
- const logger = options.logger ?? NOOP_LOGGER;
311
- const maxTimeoutSeconds = options.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS;
312
- const descriptor = {
313
- name: "x402",
314
- kind: "payment",
315
- implementationVersion: PACKAGE_VERSION,
316
- supportedSpec: `x402/v${X402_VERSION} scheme=exact family=eip155`,
317
- capabilities: [
318
- "exact-evm",
319
- `${binding.kind}-facilitator`,
320
- "eip-3009",
321
- "caip-2",
322
- `mode=${mode}`,
323
- "authorization-flow",
324
- "upfront-flow"
325
- ],
326
- status: "stable",
327
- unsupported: [
328
- "svm",
329
- "permit2",
330
- "upto scheme",
331
- "batch-settlement scheme",
332
- "auth-capture scheme"
333
- ]
334
- };
335
- async function createRequirement(context) {
336
- const amount = parseCanonicalAmount(context.amount, options.assetDecimals).toString();
337
- const paymentFlow = options.resourcePaymentFlows?.[context.resource.id] ?? options.paymentFlow ?? X402_DEFAULT_PAYMENT_FLOW;
338
- const requirements = {
339
- scheme: "exact",
340
- network,
341
- asset: options.asset,
342
- amount,
343
- payTo: options.payTo,
344
- maxTimeoutSeconds,
345
- // `name`/`version` let the buyer and the facilitator build the same
346
- // EIP-712 domain without calling `version()` on the token.
347
- // `assetTransferMethod` names the one method this provider settles, so a
348
- // conforming client never picks the `exact` scheme's Permit2 path.
349
- // x402 requires an explicit non-default flow. Omit the default
350
- // `authorization` flow here.
351
- extra: {
352
- name: options.assetName,
353
- version: options.assetVersion,
354
- assetTransferMethod: "eip3009",
355
- ...paymentFlow === "upfront" ? { paymentFlow } : {}
356
- }
357
- };
358
- const envelope = {
359
- x402Version: X402_VERSION,
360
- resource: {
361
- url: `resource://agent-commerce/${encodeURIComponent(options.network)}/${options.payTo}/resources/${encodeURIComponent(context.resource.id)}`,
362
- description: context.resource.description ?? context.resource.name,
363
- mimeType: DEFAULT_MIME_TYPE
364
- },
365
- accepts: [requirements]
366
- };
367
- const expiresAt = new Date(clock.now().getTime() + maxTimeoutSeconds * 1e3).toISOString();
368
- return {
369
- id: ids.next("payreq"),
370
- requestId: context.requestId,
371
- resourceId: context.resource.id,
372
- provider: "x402",
373
- amount: context.amount,
374
- currency: context.currency,
375
- destination: options.payTo,
376
- network: options.network,
377
- asset: options.asset,
378
- expiresAt,
379
- challenge: {
380
- provider: "x402",
381
- version: X402_PROTOCOL_VERSION,
382
- accepts: [requirements],
383
- envelope
384
- },
385
- metadata: { [SETTLE_AFTER_BACKEND_METADATA_KEY]: paymentFlow === "authorization" }
386
- };
387
- }
388
- async function verify(context) {
389
- const { requirement, submission } = context;
390
- const rejected = (reason) => ({
391
- status: "rejected",
392
- provider: "x402",
393
- amount: requirement.amount,
394
- currency: requirement.currency,
395
- ...requirement.network !== void 0 ? { network: requirement.network } : {},
396
- ...requirement.asset !== void 0 ? { asset: requirement.asset } : {},
397
- rejectionReason: reason
398
- });
399
- if (requirement.provider !== "x402" || requirement.challenge.provider !== "x402") {
400
- return rejected("wrong_provider");
401
- }
402
- const requirements = requirement.challenge.accepts[0];
403
- if (!requirements) {
404
- return rejected("missing_payment_requirements");
405
- }
406
- if (requirement.expiresAt !== void 0 && Date.parse(requirement.expiresAt) < clock.now().getTime()) {
407
- return rejected("requirement_expired");
408
- }
409
- if (!isAddress(requirements.asset) || getAddress(requirements.asset) !== getAddress(options.asset)) {
410
- return rejected("wrong_asset");
411
- }
412
- const payload = decodePaymentSubmission(submission.payload);
413
- if (!payload) {
414
- const version = declaredX402Version(submission.payload);
415
- return rejected(
416
- typeof version === "number" && version !== X402_VERSION ? "invalid_x402_version" : "invalid_payload"
417
- );
418
- }
419
- if (payload.x402Version !== X402_VERSION) {
420
- return rejected("invalid_x402_version");
421
- }
422
- if (!isExactEvmPayload(payload)) {
423
- return rejected("unsupported_scheme");
424
- }
425
- const { authorization } = payload.payload;
426
- if (!isAddress(authorization.from) || !isAddress(authorization.to)) {
427
- return rejected("invalid_payload");
428
- }
429
- if (payload.accepted.network !== options.network) {
430
- return rejected("invalid_network");
431
- }
432
- const offeredUrl = requirement.challenge.envelope?.resource?.url;
433
- if (!acceptedMatchesOffer(requirements, payload.accepted) || payload.resource !== void 0 && payload.resource.url !== offeredUrl) {
434
- return rejected("invalid_payment_requirements");
435
- }
436
- if (getAddress(authorization.to) !== getAddress(options.payTo)) {
437
- return rejected("invalid_exact_evm_payload_recipient_mismatch");
438
- }
439
- let authorizedValue;
440
- let required;
441
- try {
442
- authorizedValue = BigInt(authorization.value);
443
- required = BigInt(requirements.amount);
444
- } catch {
445
- return rejected("invalid_payload");
446
- }
447
- if (authorizedValue !== required) {
448
- return rejected("invalid_exact_evm_payload_authorization_value_mismatch");
449
- }
450
- const scope = binding.open();
451
- let sdkResult;
452
- try {
453
- sdkResult = await scope.verify(withoutResource(payload), requirements);
454
- } catch (err) {
455
- if (!isProviderUnavailableError(err) && !scope.transportFailed()) {
456
- logger.warn({ err: redactedErrorText(err) }, "x402 verify(): unexpected SDK error");
457
- }
458
- throw new CommerceError(
459
- "PAYMENT_PROVIDER_UNAVAILABLE",
460
- `x402 provider: ${binding.kind} facilitator returned no verdict during verify()`,
461
- { cause: err }
462
- );
463
- }
464
- if (!sdkResult.isValid) {
465
- if (scope.transportFailed()) {
466
- if (sdkResult.invalidReason !== void 0) {
467
- logger.debug(
468
- { reportedReason: sdkResult.invalidReason },
469
- "x402 verify(): local facilitator transport failure reason"
470
- );
471
- }
472
- throw new CommerceError(
473
- "PAYMENT_PROVIDER_UNAVAILABLE",
474
- `x402 provider: ${binding.kind} facilitator unreachable during verify()`
475
- );
476
- }
477
- if (sdkResult.invalidReason !== void 0) {
478
- logger.debug(
479
- { reportedReason: sdkResult.invalidReason },
480
- "x402 verify(): facilitator rejection reason"
481
- );
482
- }
483
- return rejected(sanitizeReason(sdkResult.invalidReason, "invalid_payment"));
484
- }
485
- const replayKey = computeReplayKey({
486
- chainId: profile.chainId,
487
- asset: getAddress(requirements.asset),
488
- from: getAddress(authorization.from),
489
- nonce: authorization.nonce
490
- });
491
- return {
492
- status: "verified",
493
- provider: "x402",
494
- payer: getAddress(authorization.from),
495
- payee: getAddress(authorization.to),
496
- amount: formatUnits(authorizedValue, options.assetDecimals),
497
- currency: requirement.currency,
498
- network: payload.accepted.network,
499
- asset: getAddress(requirements.asset),
500
- replayKey
501
- };
502
- }
503
- async function settle(context) {
504
- const { requirement, submission, verification } = context;
505
- if (verification.status !== "verified") {
506
- throw new CommerceError(
507
- "PAYMENT_INVALID",
508
- "x402 provider: settle() called without a successful verify()"
509
- );
510
- }
511
- const requirements = requirement.challenge.accepts[0];
512
- if (!requirements) {
513
- throw new CommerceError(
514
- "PAYMENT_INVALID",
515
- "x402 provider: settle() found no payment requirements to settle against"
516
- );
517
- }
518
- const payload = decodePaymentSubmission(submission.payload);
519
- if (!payload || !isExactEvmPayload(payload)) {
520
- throw new CommerceError(
521
- "PAYMENT_INVALID",
522
- "x402 provider: settle() received an undecodable payment payload"
523
- );
524
- }
525
- const rejectedSettlement = (rejectionReason) => ({
526
- status: "rejected",
527
- provider: "x402",
528
- amount: verification.amount,
529
- currency: requirement.currency,
530
- ...verification.network !== void 0 ? { network: verification.network } : {},
531
- ...verification.asset !== void 0 ? { asset: verification.asset } : {},
532
- ...verification.replayKey !== void 0 ? { replayKey: verification.replayKey } : {},
533
- rejectionReason
534
- });
535
- const scope = binding.open();
536
- let sdkResult;
537
- try {
538
- sdkResult = await scope.settle(withoutResource(payload), requirements);
539
- } catch (err) {
540
- if (isProviderUnavailableError(err) || scope.transportFailed()) {
541
- throw new CommerceError(
542
- "PAYMENT_PROVIDER_UNAVAILABLE",
543
- `x402 provider: ${binding.kind} facilitator unreachable during settle()`,
544
- { cause: err }
545
- );
546
- }
547
- if (!isOnChainRevertError(err)) {
548
- logger.warn(
549
- { err: redactedErrorText(err) },
550
- "x402 settle(): settlement failed with an unclassified error; outcome unknown"
551
- );
552
- throw new CommerceError(
553
- "PAYMENT_PROVIDER_UNAVAILABLE",
554
- "x402 provider: settlement failed with an unclassified error; outcome unknown",
555
- { cause: err }
556
- );
557
- }
558
- logger.warn(
559
- { err: redactedErrorText(err), rejectionReason: "transaction_reverted" },
560
- "x402 settle(): settlement transaction reverted on chain"
561
- );
562
- return rejectedSettlement("transaction_reverted");
563
- }
564
- if (!sdkResult.success) {
565
- if (sdkResult.errorReason === TRANSACTION_FAILED_REASON && !/^0x[0-9a-f]{64}$/i.test(sdkResult.transaction)) {
566
- logger.warn(
567
- { reportedReason: sdkResult.errorReason },
568
- "x402 settle(): the broadcast failed without a transaction hash; outcome unknown"
569
- );
570
- throw new CommerceError(
571
- "PAYMENT_PROVIDER_UNAVAILABLE",
572
- "x402 provider: settlement failed with an unclassified error; outcome unknown"
573
- );
574
- }
575
- if (sdkResult.errorReason === SETTLEMENT_PENDING_REASON || scope.transportFailed()) {
576
- throw new CommerceError(
577
- "PAYMENT_PROVIDER_UNAVAILABLE",
578
- "x402 provider: settlement was broadcast but could not be confirmed",
579
- {
580
- ...sdkResult.transaction ? { details: { transactionHash: sdkResult.transaction } } : {}
581
- }
582
- );
583
- }
584
- if (sdkResult.errorReason !== void 0) {
585
- logger.debug(
586
- { reportedReason: sdkResult.errorReason },
587
- "x402 settle(): facilitator failure reason"
588
- );
589
- }
590
- return {
591
- ...rejectedSettlement(sanitizeReason(sdkResult.errorReason, "settlement_failed")),
592
- network: sdkResult.network,
593
- ...sdkResult.payer !== void 0 ? { payer: sdkResult.payer } : {}
594
- };
595
- }
596
- return {
597
- status: "settled",
598
- provider: "x402",
599
- externalReference: sdkResult.transaction,
600
- ...sdkResult.payer !== void 0 ? { payer: sdkResult.payer } : {},
601
- payee: requirements.payTo,
602
- amount: verification.amount,
603
- currency: requirement.currency,
604
- network: sdkResult.network,
605
- ...verification.asset !== void 0 ? { asset: verification.asset } : {},
606
- ...verification.replayKey !== void 0 ? { replayKey: verification.replayKey } : {},
607
- settledAt: clock.nowIso(),
608
- // `amount` is the display value; x402's settlement response reports base units
609
- metadata: { amountBaseUnits: payload.payload.authorization.value }
610
- };
611
- }
612
- async function computeHealth() {
613
- const startedAt = clock.monotonicMs();
614
- const checkedAt = clock.nowIso();
615
- try {
616
- const chainId = await healthPublicClient.getChainId();
617
- if (chainId !== profile.chainId) {
618
- return {
619
- status: "fail",
620
- detail: `RPC at ${rpcOrigin} reports chain id ${chainId}, expected ${profile.chainId} (${profile.displayName})`,
621
- checkedAt,
622
- durationMs: clock.monotonicMs() - startedAt
623
- };
624
- }
625
- const code = await healthPublicClient.getCode({ address: options.asset });
626
- if (!code || code === "0x") {
627
- return {
628
- status: "fail",
629
- detail: `No contract code found at configured asset address ${options.asset}`,
630
- checkedAt,
631
- durationMs: clock.monotonicMs() - startedAt
632
- };
633
- }
634
- if (binding.kind === "remote") {
635
- const kinds = await binding.supported();
636
- const supportsUs = kinds.some(
637
- (kind) => kind.x402Version === X402_VERSION && kind.scheme === "exact" && kind.network === options.network
638
- );
639
- if (!supportsUs) {
640
- return {
641
- status: "fail",
642
- detail: `Facilitator ${binding.describe} does not advertise x402 v${X402_VERSION} scheme=exact on ${options.network} (${profile.displayName}); no payment on this deployment can settle`,
643
- checkedAt,
644
- durationMs: clock.monotonicMs() - startedAt
645
- };
646
- }
647
- return {
648
- status: "pass",
649
- detail: `${describeDeploymentMode(mode)}: RPC ${rpcOrigin} reachable, chain id ${profile.chainId} (${profile.displayName}), asset ${options.asset} has code, facilitator ${binding.describe} supports exact/${options.network}`,
650
- checkedAt,
651
- durationMs: clock.monotonicMs() - startedAt
652
- };
653
- }
654
- const isAnvil = await probeIsAnvilNode(healthPublicClient);
655
- if (!isAnvil) {
656
- return {
657
- status: "fail",
658
- detail: `RPC at ${rpcOrigin} reports chain id ${profile.chainId} but does not answer "anvil_nodeInfo", so it does not look like a local Anvil dev node. Refusing to treat it as safe for a local-facilitator dev key.`,
659
- checkedAt,
660
- durationMs: clock.monotonicMs() - startedAt
661
- };
662
- }
663
- return {
664
- status: "pass",
665
- detail: `${describeDeploymentMode(mode)}: RPC ${rpcOrigin} reachable, chain id ${profile.chainId}, asset ${options.asset} has code, confirmed Anvil dev node`,
666
- checkedAt,
667
- durationMs: clock.monotonicMs() - startedAt
668
- };
669
- } catch (err) {
670
- return {
671
- status: "fail",
672
- detail: `x402 health check failed: ${redactedErrorText(err)}`,
673
- checkedAt,
674
- durationMs: clock.monotonicMs() - startedAt
675
- };
676
- }
677
- }
678
- const HEALTH_CACHE_MS = 5e3;
679
- let cachedHealth;
680
- let inFlightHealth;
681
- async function health() {
682
- const now = clock.monotonicMs();
683
- if (cachedHealth && now - cachedHealth.at < HEALTH_CACHE_MS) {
684
- return cachedHealth.value;
685
- }
686
- if (inFlightHealth) return inFlightHealth;
687
- inFlightHealth = computeHealth().then((value) => {
688
- cachedHealth = { at: clock.monotonicMs(), value };
689
- return value;
690
- }).finally(() => {
691
- inFlightHealth = void 0;
692
- });
693
- return inFlightHealth;
694
- }
695
- return {
696
- name: "x402",
697
- descriptor,
698
- createRequirement,
699
- verify,
700
- settle,
701
- health
702
- };
703
- }
704
- function acceptedMatchesOffer(offered, accepted) {
705
- const sameAddress = (a, b) => a.toLowerCase() === b.toLowerCase();
706
- const offeredExtra = offered.extra ?? {};
707
- const acceptedExtra = accepted.extra ?? {};
708
- const flow = (extra) => extra["paymentFlow"] ?? X402_DEFAULT_PAYMENT_FLOW;
709
- return accepted.scheme === offered.scheme && accepted.network === offered.network && accepted.amount === offered.amount && sameAddress(accepted.asset, offered.asset) && sameAddress(accepted.payTo, offered.payTo) && Object.entries(offeredExtra).every(([key, value]) => acceptedExtra[key] === value) && flow(acceptedExtra) === flow(offeredExtra);
710
- }
711
- function isOnChainRevertError(err) {
712
- return err instanceof BaseError && err.walk((e) => e instanceof ContractFunctionRevertedError) !== null;
713
- }
714
- function isProviderUnavailableError(err) {
715
- if (err instanceof HttpRequestError || err instanceof TimeoutError || err instanceof WaitForTransactionReceiptTimeoutError) {
716
- return true;
717
- }
718
- const message = redactedErrorText(err).toLowerCase();
719
- return message.includes("econnrefused") || message.includes("fetch failed") || message.includes("enotfound") || message.includes("etimedout") || message.includes("timed out") || message.includes("network error");
720
- }
721
- async function probeIsAnvilNode(client) {
722
- const request = client.request;
723
- try {
724
- await request({ method: "anvil_nodeInfo", params: [] });
725
- return true;
726
- } catch {
727
- return false;
728
- }
729
- }
730
-
731
- export { DEFAULT_IDS, chainIdFromCaip2, computeReplayKey, createX402PaymentProvider, parseCanonicalAmount };
732
- //# sourceMappingURL=chunk-RKBGCPCK.js.map
733
- //# sourceMappingURL=chunk-RKBGCPCK.js.map