@devlab.group/agent-commerce 2.1.0 → 2.2.1

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 (75) hide show
  1. package/README.md +35 -5
  2. package/dist/ap2.js +3 -3
  3. package/dist/{chunk-LZS5BL3W.js → chunk-2DAJAJI7.js} +23 -5
  4. package/dist/chunk-2DAJAJI7.js.map +1 -0
  5. package/dist/{chunk-UHMYRV3J.js → chunk-BNUD4RBN.js} +22 -7
  6. package/dist/chunk-BNUD4RBN.js.map +1 -0
  7. package/dist/{chunk-IFGRCXME.js → chunk-REBY2IEP.js} +24 -20
  8. package/dist/chunk-REBY2IEP.js.map +1 -0
  9. package/dist/{chunk-SY6GUYSQ.js → chunk-XYHDQ22D.js} +3 -3
  10. package/dist/{chunk-SY6GUYSQ.js.map → chunk-XYHDQ22D.js.map} +1 -1
  11. package/dist/cli/ap2-HLBIUSTK.js +678 -0
  12. package/dist/cli/ap2-HLBIUSTK.js.map +1 -0
  13. package/dist/cli/chunk-2LN5PO5I.js +1352 -0
  14. package/dist/cli/chunk-2LN5PO5I.js.map +1 -0
  15. package/dist/cli/chunk-3EQBCFZY.js +53 -0
  16. package/dist/cli/chunk-3EQBCFZY.js.map +1 -0
  17. package/dist/cli/chunk-3M6U7ILB.js +8 -0
  18. package/dist/cli/chunk-3M6U7ILB.js.map +1 -0
  19. package/dist/cli/chunk-3MGAJ5FX.js +70 -0
  20. package/dist/cli/chunk-3MGAJ5FX.js.map +1 -0
  21. package/dist/cli/chunk-5K4XEAZV.js +113 -0
  22. package/dist/cli/chunk-5K4XEAZV.js.map +1 -0
  23. package/dist/cli/chunk-AA3FIEAR.js +27 -0
  24. package/dist/cli/chunk-AA3FIEAR.js.map +1 -0
  25. package/dist/cli/chunk-FHCFR2GS.js +17 -0
  26. package/dist/cli/chunk-FHCFR2GS.js.map +1 -0
  27. package/dist/cli/chunk-ILUYEQSV.js +1744 -0
  28. package/dist/cli/chunk-ILUYEQSV.js.map +1 -0
  29. package/dist/cli/chunk-KTV52MCU.js +338 -0
  30. package/dist/cli/chunk-KTV52MCU.js.map +1 -0
  31. package/dist/cli/chunk-OSTCU6ZK.js +44 -0
  32. package/dist/cli/chunk-OSTCU6ZK.js.map +1 -0
  33. package/dist/cli/chunk-OZ4LAWBK.js +256 -0
  34. package/dist/cli/chunk-OZ4LAWBK.js.map +1 -0
  35. package/dist/cli/chunk-QQ3WY5L3.js +271 -0
  36. package/dist/cli/chunk-QQ3WY5L3.js.map +1 -0
  37. package/dist/cli/chunk-QY3K6PEQ.js +8 -0
  38. package/dist/cli/chunk-QY3K6PEQ.js.map +1 -0
  39. package/dist/cli/chunk-QZ6TOMX6.js +1413 -0
  40. package/dist/cli/chunk-QZ6TOMX6.js.map +1 -0
  41. package/dist/cli/chunk-SNM3OVCY.js +625 -0
  42. package/dist/cli/chunk-SNM3OVCY.js.map +1 -0
  43. package/dist/cli/chunk-SPAYKVUP.js +118 -0
  44. package/dist/cli/chunk-SPAYKVUP.js.map +1 -0
  45. package/dist/cli/chunk-TPC4EJLT.js +11 -0
  46. package/dist/cli/chunk-TPC4EJLT.js.map +1 -0
  47. package/dist/cli/config-VYAJGZXE.js +11 -0
  48. package/dist/cli/config-VYAJGZXE.js.map +1 -0
  49. package/dist/cli/index.js +150 -3627
  50. package/dist/cli/index.js.map +1 -1
  51. package/dist/cli/mcp-HFD7ZNCQ.js +559 -0
  52. package/dist/cli/mcp-HFD7ZNCQ.js.map +1 -0
  53. package/dist/cli/near-5AY3HWYF.js +58 -0
  54. package/dist/cli/near-5AY3HWYF.js.map +1 -0
  55. package/dist/cli/provider-JV5HCQGR.js +396 -0
  56. package/dist/cli/provider-JV5HCQGR.js.map +1 -0
  57. package/dist/cli/run-WV44B62Y.js +7301 -0
  58. package/dist/cli/run-WV44B62Y.js.map +1 -0
  59. package/dist/cli/svm-3MMYFPC7.js +33 -0
  60. package/dist/cli/svm-3MMYFPC7.js.map +1 -0
  61. package/dist/cli/x402-NADFV5CD.js +96 -0
  62. package/dist/cli/x402-NADFV5CD.js.map +1 -0
  63. package/dist/index.d.ts +12 -3
  64. package/dist/index.js +82 -11
  65. package/dist/index.js.map +1 -1
  66. package/dist/mcp.js +6 -16
  67. package/dist/mcp.js.map +1 -1
  68. package/dist/mpp.js +3 -3
  69. package/dist/{networks-olfflCI_.d.ts → networks-DTWRlj-K.d.ts} +2 -2
  70. package/dist/x402.d.ts +7 -2
  71. package/dist/x402.js +4 -4
  72. package/package.json +2 -2
  73. package/dist/chunk-IFGRCXME.js.map +0 -1
  74. package/dist/chunk-LZS5BL3W.js.map +0 -1
  75. package/dist/chunk-UHMYRV3J.js.map +0 -1
@@ -0,0 +1,33 @@
1
+ import { computeSvmReplayKey } from './chunk-OSTCU6ZK.js';
2
+ import { isRecord } from './chunk-3M6U7ILB.js';
3
+ import { getAddressEncoder, getProgramDerivedAddress, address } from '@solana/kit';
4
+ import { transactionMessageHash, decodeTransactionFromPayload } from '@x402/svm';
5
+
6
+ var MAX_TRANSACTION_BASE64 = 1644;
7
+ var ASSOCIATED_TOKEN_PROGRAM = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
8
+ async function associatedTokenAccount(owner, mint, tokenProgram) {
9
+ const encoder = getAddressEncoder();
10
+ const [account] = await getProgramDerivedAddress({
11
+ programAddress: address(ASSOCIATED_TOKEN_PROGRAM),
12
+ seeds: [owner, tokenProgram, mint].map((key) => encoder.encode(address(key)))
13
+ });
14
+ return account;
15
+ }
16
+ function svmReplayKey(payload, network) {
17
+ if (!isRecord(payload)) return "invalid_exact_svm_payload_transaction";
18
+ const transaction = payload["transaction"];
19
+ if (typeof transaction !== "string" || transaction.length > MAX_TRANSACTION_BASE64) {
20
+ return "invalid_exact_svm_payload_transaction";
21
+ }
22
+ let messageHash;
23
+ try {
24
+ messageHash = transactionMessageHash(decodeTransactionFromPayload({ transaction }));
25
+ } catch {
26
+ return "invalid_exact_svm_payload_transaction_could_not_be_decoded";
27
+ }
28
+ return { replayKey: computeSvmReplayKey({ network, messageHash }) };
29
+ }
30
+
31
+ export { associatedTokenAccount, svmReplayKey };
32
+ //# sourceMappingURL=svm-3MMYFPC7.js.map
33
+ //# sourceMappingURL=svm-3MMYFPC7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/payments/x402/svm.ts"],"names":[],"mappings":";;;;;AAgBA,IAAM,sBAAA,GAAyB,IAAA;AAE/B,IAAM,wBAAA,GAA2B,8CAAA;AAMjC,eAAsB,sBAAA,CACpB,KAAA,EACA,IAAA,EACA,YAAA,EACiB;AACjB,EAAA,MAAM,UAAU,iBAAA,EAAkB;AAClC,EAAA,MAAM,CAAC,OAAO,CAAA,GAAI,MAAM,wBAAA,CAAyB;AAAA,IAC/C,cAAA,EAAgB,QAAQ,wBAAwB,CAAA;AAAA,IAChD,KAAA,EAAO,CAAC,KAAA,EAAO,YAAA,EAAc,IAAI,CAAA,CAAE,GAAA,CAAI,CAAC,GAAA,KAAQ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAC,CAAC;AAAA,GAC7E,CAAA;AACD,EAAA,OAAO,OAAA;AACT;AAMO,SAAS,YAAA,CAAa,SAAkB,OAAA,EAAiD;AAC9F,EAAA,IAAI,CAAC,QAAA,CAAS,OAAO,CAAA,EAAG,OAAO,uCAAA;AAC/B,EAAA,MAAM,WAAA,GAAc,QAAQ,aAAa,CAAA;AACzC,EAAA,IAAI,OAAO,WAAA,KAAgB,QAAA,IAAY,WAAA,CAAY,SAAS,sBAAA,EAAwB;AAClF,IAAA,OAAO,uCAAA;AAAA,EACT;AACA,EAAA,IAAI,WAAA;AACJ,EAAA,IAAI;AACF,IAAA,WAAA,GAAc,sBAAA,CAAuB,4BAAA,CAA6B,EAAE,WAAA,EAAa,CAAC,CAAA;AAAA,EACpF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,4DAAA;AAAA,EACT;AACA,EAAA,OAAO,EAAE,SAAA,EAAW,mBAAA,CAAoB,EAAE,OAAA,EAAS,WAAA,EAAa,CAAA,EAAE;AACpE","file":"svm-3MMYFPC7.js","sourcesContent":["/**\n * Solana `exact` payload inspection: bounded decoding and the replay identity.\n * The provider loads this module only for a Solana offer, so an EVM-only\n * deployment never imports `@x402/svm` or `@solana/kit`.\n *\n * The facilitator checks the transaction itself: the fee payer, signatures,\n * instruction layout, mint, recipient token account and amount, and a\n * simulation. Its smart-wallet path accepts layouts the gateway could not\n * parse, so the gateway does not read the transfer.\n */\nimport { address, getAddressEncoder, getProgramDerivedAddress } from '@solana/kit';\nimport { decodeTransactionFromPayload, transactionMessageHash } from '@x402/svm';\nimport { isRecord } from '../../core/is-record';\nimport { computeSvmReplayKey } from './replay-key';\n\n// A Solana transaction fits a 1232-byte packet, which is 1644 base64 characters\nconst MAX_TRANSACTION_BASE64 = 1644;\n\nconst ASSOCIATED_TOKEN_PROGRAM = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL';\n\n/**\n * The associated token account of `owner` for `mint`, where the SDK client\n * sends a Solana `exact` payment. Its transaction cannot create the account.\n */\nexport async function associatedTokenAccount(\n owner: string,\n mint: string,\n tokenProgram: string,\n): Promise<string> {\n const encoder = getAddressEncoder();\n const [account] = await getProgramDerivedAddress({\n programAddress: address(ASSOCIATED_TOKEN_PROGRAM),\n seeds: [owner, tokenProgram, mint].map((key) => encoder.encode(address(key))),\n });\n return account;\n}\n\n/**\n * Returns the Solana `exact` replay key, or an SDK refusal reason for a\n * missing, oversized or undecodable transaction.\n */\nexport function svmReplayKey(payload: unknown, network: string): { replayKey: string } | string {\n if (!isRecord(payload)) return 'invalid_exact_svm_payload_transaction';\n const transaction = payload['transaction'];\n if (typeof transaction !== 'string' || transaction.length > MAX_TRANSACTION_BASE64) {\n return 'invalid_exact_svm_payload_transaction';\n }\n let messageHash: string;\n try {\n messageHash = transactionMessageHash(decodeTransactionFromPayload({ transaction }));\n } catch {\n return 'invalid_exact_svm_payload_transaction_could_not_be_decoded';\n }\n return { replayKey: computeSvmReplayKey({ network, messageHash }) };\n}\n"]}
@@ -0,0 +1,96 @@
1
+ import { chainIdFromCaip2 } from './chunk-QZ6TOMX6.js';
2
+ export { createX402PaymentProvider } from './chunk-QZ6TOMX6.js';
3
+ import './chunk-KTV52MCU.js';
4
+ export { SUPPORTED_NETWORK_IDS } from './chunk-OZ4LAWBK.js';
5
+ import './chunk-OSTCU6ZK.js';
6
+ import './chunk-QY3K6PEQ.js';
7
+ import { CommerceError } from './chunk-QQ3WY5L3.js';
8
+ import './chunk-3M6U7ILB.js';
9
+ import { PaymentRequirementsV2Schema } from '@x402/core/schemas';
10
+ import { getAddress, toHex } from 'viem';
11
+ import { privateKeyToAccount } from 'viem/accounts';
12
+
13
+ var X402_VERSION = 2;
14
+ var TRANSFER_WITH_AUTHORIZATION_TYPES = {
15
+ TransferWithAuthorization: [
16
+ { name: "from", type: "address" },
17
+ { name: "to", type: "address" },
18
+ { name: "value", type: "uint256" },
19
+ { name: "validAfter", type: "uint256" },
20
+ { name: "validBefore", type: "uint256" },
21
+ { name: "nonce", type: "bytes32" }
22
+ ]
23
+ };
24
+ async function createPaymentProof(options) {
25
+ const requirements = PaymentRequirementsV2Schema.parse(options.accepts);
26
+ const method = requirements.extra?.["assetTransferMethod"];
27
+ if (method !== void 0 && method !== "eip3009") {
28
+ throw new CommerceError(
29
+ "INPUT_INVALID",
30
+ `createPaymentProof: signs EIP-3009 only, and this offer uses "${String(method)}"; sign it with the SDK's x402Client`
31
+ );
32
+ }
33
+ if (!requirements.extra || typeof requirements.extra["name"] !== "string" || typeof requirements.extra["version"] !== "string") {
34
+ throw new CommerceError(
35
+ "INPUT_INVALID",
36
+ "createPaymentProof: payment requirement is missing extra.name/extra.version, so the EIP-712 domain cannot be built"
37
+ );
38
+ }
39
+ const chainId = chainIdFromCaip2(requirements.network);
40
+ if (chainId === void 0) {
41
+ throw new CommerceError(
42
+ "INPUT_INVALID",
43
+ `createPaymentProof: network "${requirements.network}" is not a CAIP-2 eip155 identifier, so there is no chain id to sign against`
44
+ );
45
+ }
46
+ const account = privateKeyToAccount(options.buyerPrivateKey);
47
+ const nonce = options.overrides?.nonce ?? randomNonce();
48
+ const nowSeconds = Math.floor(Date.now() / 1e3);
49
+ const validAfter = options.overrides?.validAfter ?? 0;
50
+ const validBefore = options.overrides?.validBefore ?? nowSeconds + requirements.maxTimeoutSeconds;
51
+ const to = getAddress(options.overrides?.payTo ?? requirements.payTo);
52
+ const value = BigInt(options.overrides?.value ?? requirements.amount);
53
+ const signature = await account.signTypedData({
54
+ domain: {
55
+ name: requirements.extra["name"],
56
+ version: requirements.extra["version"],
57
+ chainId,
58
+ verifyingContract: getAddress(requirements.asset)
59
+ },
60
+ types: TRANSFER_WITH_AUTHORIZATION_TYPES,
61
+ primaryType: "TransferWithAuthorization",
62
+ message: {
63
+ from: account.address,
64
+ to,
65
+ value,
66
+ validAfter: BigInt(validAfter),
67
+ validBefore: BigInt(validBefore),
68
+ nonce
69
+ }
70
+ });
71
+ const payload = {
72
+ x402Version: X402_VERSION,
73
+ accepted: requirements,
74
+ payload: {
75
+ signature,
76
+ authorization: {
77
+ from: account.address,
78
+ to,
79
+ value: value.toString(),
80
+ validAfter: validAfter.toString(),
81
+ validBefore: validBefore.toString(),
82
+ nonce
83
+ }
84
+ }
85
+ };
86
+ return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
87
+ }
88
+ function randomNonce() {
89
+ const bytes = new Uint8Array(32);
90
+ crypto.getRandomValues(bytes);
91
+ return toHex(bytes);
92
+ }
93
+
94
+ export { createPaymentProof };
95
+ //# sourceMappingURL=x402-NADFV5CD.js.map
96
+ //# sourceMappingURL=x402-NADFV5CD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/payments/x402/client.ts"],"names":[],"mappings":"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","file":"x402-NADFV5CD.js","sourcesContent":["/**\n * Client-side payment helper: builds and EIP-712-signs an x402 v2 `exact`/EVM\n * authorization on the buyer's side. The demo buyer agent and the test suites\n * use it, and the `/x402` entry exports it. The gateway never calls it and\n * never holds a buyer key.\n *\n * It signs directly rather than through the SDK's `x402Client` because of\n * `overrides`: negative tests need deliberately wrong authorizations that a\n * conforming client will not produce. The x402 settlement E2E suite also\n * settles a payment built by `x402Client` itself to cover interoperability.\n */\n\nimport { PaymentRequirementsV2Schema } from '@x402/core/schemas';\nimport type { PaymentPayload, PaymentRequirements } from '@x402/core/types';\nimport { getAddress, toHex } from 'viem';\nimport { privateKeyToAccount } from 'viem/accounts';\nimport { CommerceError } from '../../core';\nimport { chainIdFromCaip2 } from './chain';\n\nexport interface CreatePaymentProofOptions {\n /** The buyer's private key. It signs locally and is never sent anywhere */\n readonly buyerPrivateKey: `0x${string}`;\n /** One entry from PaymentRequiredEnvelope.payment.accepts, verbatim */\n readonly accepts: Readonly<Record<string, unknown>>;\n /** For negative tests only: a wrong amount, recipient, nonce or validity window */\n readonly overrides?: {\n readonly value?: string;\n readonly payTo?: string;\n readonly nonce?: `0x${string}`;\n readonly validBefore?: number;\n readonly validAfter?: number;\n };\n}\n\nconst X402_VERSION = 2;\n\nconst TRANSFER_WITH_AUTHORIZATION_TYPES = {\n TransferWithAuthorization: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'validAfter', type: 'uint256' },\n { name: 'validBefore', type: 'uint256' },\n { name: 'nonce', type: 'bytes32' },\n ],\n} as const;\n\n/** Returns the base64 `PAYMENT-SIGNATURE` value to send back to the gateway */\nexport async function createPaymentProof(options: CreatePaymentProofOptions): Promise<string> {\n const requirements = PaymentRequirementsV2Schema.parse(options.accepts);\n const method = requirements.extra?.['assetTransferMethod'];\n if (method !== undefined && method !== 'eip3009') {\n throw new CommerceError(\n 'INPUT_INVALID',\n `createPaymentProof: signs EIP-3009 only, and this offer uses \"${String(method)}\"; sign it with the SDK's x402Client`,\n );\n }\n if (\n !requirements.extra ||\n typeof requirements.extra['name'] !== 'string' ||\n typeof requirements.extra['version'] !== 'string'\n ) {\n throw new CommerceError(\n 'INPUT_INVALID',\n 'createPaymentProof: payment requirement is missing extra.name/extra.version, so the EIP-712 domain cannot be built',\n );\n }\n\n const chainId = chainIdFromCaip2(requirements.network);\n if (chainId === undefined) {\n throw new CommerceError(\n 'INPUT_INVALID',\n `createPaymentProof: network \"${requirements.network}\" is not a CAIP-2 eip155 identifier, so there is no chain id to sign against`,\n );\n }\n\n const account = privateKeyToAccount(options.buyerPrivateKey);\n\n const nonce = options.overrides?.nonce ?? randomNonce();\n const nowSeconds = Math.floor(Date.now() / 1000);\n // 0, as in the SDK's own v2 client: nothing here wants the authorization\n // delayed\n const validAfter = options.overrides?.validAfter ?? 0;\n const validBefore = options.overrides?.validBefore ?? nowSeconds + requirements.maxTimeoutSeconds;\n const to = getAddress((options.overrides?.payTo ?? requirements.payTo) as `0x${string}`);\n const value = BigInt(options.overrides?.value ?? requirements.amount);\n\n const signature = await account.signTypedData({\n domain: {\n name: requirements.extra['name'],\n version: requirements.extra['version'],\n chainId,\n verifyingContract: getAddress(requirements.asset as `0x${string}`),\n },\n types: TRANSFER_WITH_AUTHORIZATION_TYPES,\n primaryType: 'TransferWithAuthorization',\n message: {\n from: account.address,\n to,\n value,\n validAfter: BigInt(validAfter),\n validBefore: BigInt(validBefore),\n nonce,\n },\n });\n\n // v2 echoes the chosen requirement back as `accepted` so a stateless\n // facilitator knows which offer was taken. The gateway verifies against its\n // own copy.\n const payload: PaymentPayload = {\n x402Version: X402_VERSION,\n accepted: requirements as PaymentRequirements,\n payload: {\n signature,\n authorization: {\n from: account.address,\n to,\n value: value.toString(),\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n };\n\n return Buffer.from(JSON.stringify(payload), 'utf8').toString('base64');\n}\n\nfunction randomNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return toHex(bytes);\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { I as IsoTimestamp, D as DecimalAmount, P as PaymentMethodName, a as Com
3
3
  export { f as AdapterHealthComponent, g as AuthorizationMethodName, h as BackendMethod, i as DEFAULT_BACKEND_TIMEOUT_MS, J as JsonSchema, N as NOOP_LOGGER, j as PAYMENT_METHOD_NAMES, k as PROTOCOL_NAMES, l as PaymentChallenge, m as PaymentContext, n as PaymentRequirement, o as PaymentResult, p as PaymentSettlementContext, q as PaymentVerificationContext, r as Pricing, s as ProtocolName, t as systemClock } from './runtime-7vLNYvmU.js';
4
4
  import { M as MppNetwork } from './constants-nackLItD.js';
5
5
  import { X as X402PaymentFlow, a as X402FacilitatorConfig } from './guardrails-CX_jYXvZ.js';
6
- import { C as CustomNetworks } from './networks-olfflCI_.js';
6
+ import { C as CustomNetworks } from './networks-DTWRlj-K.js';
7
7
  import { a as AuthorizationRequirement, b as AuthorizationSubmission, A as AuthorizationProvider } from './authorization-CMkIuAkO.js';
8
8
  export { c as AuthorizationFinalizeContext, d as AuthorizationRecord, e as AuthorizationVerification, f as AuthorizationVerificationContext } from './authorization-CMkIuAkO.js';
9
9
  import { D as DeliveredOutcome, P as PaymentRequiredOutcome, C as CommerceEvent, a as PaymentAttempt, b as CommerceReceipt, E as ExecutionPipeline, c as ProtocolAdapter, H as HttpProtocolAdapter, A as AdapterHttpRoute, d as ProtocolAdapterContext } from './protocol-adapter-CfxU8Z2T.js';
@@ -329,6 +329,13 @@ interface ListOptions {
329
329
  readonly limit?: number;
330
330
  readonly requestId?: string;
331
331
  }
332
+ interface ReceiptListOptions extends ListOptions {
333
+ /**
334
+ * When true, return only receipts counted by {@link ReceiptStore.countUndeliveredReceipts}.
335
+ * Stores ignoring this flag also return delivered receipts.
336
+ */
337
+ readonly undelivered?: boolean;
338
+ }
332
339
  interface ReceiptStore {
333
340
  init(): Promise<void>;
334
341
  /** Append a canonical event. Must not throw into the caller's flow */
@@ -347,7 +354,7 @@ interface ReceiptStore {
347
354
  updatePaymentAttempt(update: PaymentAttemptUpdate): Promise<void>;
348
355
  saveReceipt(receipt: CommerceReceipt): Promise<void>;
349
356
  getReceipt(id: string): Promise<CommerceReceipt | undefined>;
350
- listReceipts(options?: ListOptions): Promise<readonly CommerceReceipt[]>;
357
+ listReceipts(options?: ReceiptListOptions): Promise<readonly CommerceReceipt[]>;
351
358
  /**
352
359
  * Total receipts held. `listReceipts` clamps every page, so counting a list's
353
360
  * length would stop at the clamp.
@@ -496,6 +503,8 @@ interface GatewayConfig {
496
503
  readonly paymentFlow?: X402PaymentFlow;
497
504
  /** Resources whose `paymentFlow` overrides the rail's, by resource id */
498
505
  readonly resourcePaymentFlows?: Readonly<Record<string, X402PaymentFlow>>;
506
+ /** Resources that set `mimeType`, by resource id; others declare `application/json` */
507
+ readonly resourceMimeTypes?: Readonly<Record<string, string>>;
499
508
  readonly facilitator: X402FacilitatorConfig;
500
509
  readonly allowMainnet?: boolean;
501
510
  readonly allowUnauthenticatedFacilitator?: boolean;
@@ -716,4 +725,4 @@ interface SqliteReceiptStoreOptions {
716
725
  }
717
726
  declare function createSqliteReceiptStore(options: SqliteReceiptStoreOptions): ReceiptStore;
718
727
 
719
- export { A2A_AGENT_CARD_PATH, A2A_PROTOCOL_VERSION, A2A_SPEC_VERSION, type A2aAdapterOptions, ACP_API_VERSION, ACP_SPEC_VERSION, ACP_WELL_KNOWN_PATH, AUTHORIZATION_HEADER, AUTHORIZATION_INPUT_FIELD, type AcpAdapterOptions, AdapterDescriptor, AdapterHealth, AdapterHttpRoute, AuthorizationProvider, AuthorizationRequirement, AuthorizationSubmission, type BackendExecutor, BackendHandler, type BackendRequest, type BackendResponse, COMMERCE_ERROR_CODES, COMMERCE_ERROR_HTTP_STATUS, Clock, CommerceError, type CommerceErrorCode, type CommerceErrorInfo, type CommerceErrorOptions, CommerceEvent, CommerceReceipt, CommerceResource, DELIVERY_SUMMARY_META_KEY, DecimalAmount, DeliveredOutcome, type DeliverySummary, type ErrorEnvelope, ExecutionPipeline, type GatewayConfig, type GatewayInstance, type GatewayOptions, HttpProtocolAdapter, IdGenerator, IsoTimestamp, type ListOptions, Logger, MAX_AUTHORIZATION_HEADER_BYTES, PAYMENT_HEADER, PAYMENT_INPUT_FIELD, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PaymentAttempt, type PaymentAttemptReservation, type PaymentAttemptUpdate, PaymentMethodName, PaymentProvider, type PaymentRequiredEnvelope, PaymentRequiredOutcome, PaymentSubmission, ProtocolAdapter, ProtocolAdapterContext, RESERVED_INPUT_FIELDS, RETRYABLE_ERROR_CODES, type ReceiptStore, ResourceRegistry, createA2aAdapter, createAcpAdapter, createGateway, createSqliteReceiptStore, extractReservedInputFields, isCommerceError, isPaymentRequiredEnvelope, loadConfig, parseAuthorizationHeader, parseAuthorizationSubmission, parseConfig, createSqliteReceiptStore as receipts, toCommerceError, toDeliverySummary, toErrorEnvelope, toPaymentRequiredEnvelope };
728
+ export { A2A_AGENT_CARD_PATH, A2A_PROTOCOL_VERSION, A2A_SPEC_VERSION, type A2aAdapterOptions, ACP_API_VERSION, ACP_SPEC_VERSION, ACP_WELL_KNOWN_PATH, AUTHORIZATION_HEADER, AUTHORIZATION_INPUT_FIELD, type AcpAdapterOptions, AdapterDescriptor, AdapterHealth, AdapterHttpRoute, AuthorizationProvider, AuthorizationRequirement, AuthorizationSubmission, type BackendExecutor, BackendHandler, type BackendRequest, type BackendResponse, COMMERCE_ERROR_CODES, COMMERCE_ERROR_HTTP_STATUS, Clock, CommerceError, type CommerceErrorCode, type CommerceErrorInfo, type CommerceErrorOptions, CommerceEvent, CommerceReceipt, CommerceResource, DELIVERY_SUMMARY_META_KEY, DecimalAmount, DeliveredOutcome, type DeliverySummary, type ErrorEnvelope, ExecutionPipeline, type GatewayConfig, type GatewayInstance, type GatewayOptions, HttpProtocolAdapter, IdGenerator, IsoTimestamp, type ListOptions, Logger, MAX_AUTHORIZATION_HEADER_BYTES, PAYMENT_HEADER, PAYMENT_INPUT_FIELD, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PaymentAttempt, type PaymentAttemptReservation, type PaymentAttemptUpdate, PaymentMethodName, PaymentProvider, type PaymentRequiredEnvelope, PaymentRequiredOutcome, PaymentSubmission, ProtocolAdapter, ProtocolAdapterContext, RESERVED_INPUT_FIELDS, RETRYABLE_ERROR_CODES, type ReceiptListOptions, type ReceiptStore, ResourceRegistry, createA2aAdapter, createAcpAdapter, createGateway, createSqliteReceiptStore, extractReservedInputFields, isCommerceError, isPaymentRequiredEnvelope, loadConfig, parseAuthorizationHeader, parseAuthorizationSubmission, parseConfig, createSqliteReceiptStore as receipts, toCommerceError, toDeliverySummary, toErrorEnvelope, toPaymentRequiredEnvelope };
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { openSqliteDatabase, AP2_SPEC_VERSION, AP2_MODES, AP2_DEFAULT_CLOCK_SKEW_SECONDS, AP2_JWK_MEMBERS, AP2_KEY_TYPE, AP2_SIGNING_ALGORITHM, AP2_JWK_CURVE, AP2_JWK_COORDINATE_BYTES, AP2_MAX_CLOCK_SKEW_SECONDS } from './chunk-LZS5BL3W.js';
1
+ import { openSqliteDatabase, AP2_SPEC_VERSION, AP2_MODES, AP2_DEFAULT_CLOCK_SKEW_SECONDS, AP2_JWK_MEMBERS, AP2_KEY_TYPE, AP2_SIGNING_ALGORITHM, AP2_JWK_CURVE, AP2_JWK_COORDINATE_BYTES, AP2_MAX_CLOCK_SKEW_SECONDS } from './chunk-2DAJAJI7.js';
2
2
  import { readCappedBody, createBearerCheck, MCP_TOOL_NAME_PATTERN, settlementResponse, joinUrl, settlementResponseFromDetails, settlementFailure, x402ErrorCode, x402RefusalStatus } from './chunk-ES3V6ECS.js';
3
3
  import { MPP_DEFAULT_NETWORK, isMppNetwork, MPP_NETWORKS, MPP_DEFAULT_PAYMENT_FLOW, MPP_MIN_CHALLENGE_SECRET_LENGTH, MPP_PROFILE } from './chunk-6Z2H53CG.js';
4
4
  import { contentDigest, CONTENT_DIGEST_METADATA_KEY, mppProblem, mppProblemDetail } from './chunk-5ZYXBCDX.js';
5
- import { X402_PAYMENT_FLOWS, validateCustomNetworks, findX402Network, X402_DEFAULT_PAYMENT_FLOW, resolveX402Deployment, SETTLE_AFTER_BACKEND_METADATA_KEY, resolveDeploymentMode, requireX402Network, resolveX402Option, isEvmAddress, isEvmZeroAddress, x402OfferName, REUSE_REJECTED_AUTHORIZATION_METADATA_KEY } from './chunk-IFGRCXME.js';
6
- import { RESERVED_INPUT_FIELDS, PROTOCOL_NAMES, PAYMENT_METHOD_NAMES, PAYMENT_HEADER, AUTHORIZATION_HEADER, CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION, toCommerceError, DEFAULT_BACKEND_TIMEOUT_MS, isCommerceError, describeError, isHttpProtocolAdapter, toLogInfo, extractReservedInputFields, parseAuthorizationHeader, toPaymentRequiredEnvelope, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, toErrorEnvelope, DELIVERY_SUMMARY_META_KEY, toDeliverySummary, PAYMENT_INPUT_FIELD, AUTHORIZATION_INPUT_FIELD, parseAuthorizationSubmission } from './chunk-SY6GUYSQ.js';
7
- export { AUTHORIZATION_HEADER, AUTHORIZATION_INPUT_FIELD, COMMERCE_ERROR_CODES, COMMERCE_ERROR_HTTP_STATUS, COMMERCE_EVENT_TYPES, CommerceError, DEFAULT_BACKEND_TIMEOUT_MS, DELIVERY_SUMMARY_META_KEY, MAX_AUTHORIZATION_HEADER_BYTES, NOOP_LOGGER, PAYMENT_HEADER, PAYMENT_INPUT_FIELD, PAYMENT_METHOD_NAMES, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PROTOCOL_NAMES, RESERVED_INPUT_FIELDS, RETRYABLE_ERROR_CODES, extractReservedInputFields, isCommerceError, isHttpProtocolAdapter, isPaymentRequiredEnvelope, parseAuthorizationHeader, parseAuthorizationSubmission, systemClock, toCommerceError, toDeliverySummary, toErrorEnvelope, toPaymentRequiredEnvelope } from './chunk-SY6GUYSQ.js';
5
+ import { X402_PAYMENT_FLOWS, validateCustomNetworks, findX402Network, X402_DEFAULT_PAYMENT_FLOW, resolveX402Deployment, SETTLE_AFTER_BACKEND_METADATA_KEY, resolveDeploymentMode, requireX402Network, resolveX402Option, isEvmAddress, isEvmZeroAddress, x402OfferName, REUSE_REJECTED_AUTHORIZATION_METADATA_KEY } from './chunk-REBY2IEP.js';
6
+ import { RESERVED_INPUT_FIELDS, PROTOCOL_NAMES, PAYMENT_METHOD_NAMES, PAYMENT_HEADER, AUTHORIZATION_HEADER, CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION, toCommerceError, DEFAULT_BACKEND_TIMEOUT_MS, isCommerceError, describeError, isHttpProtocolAdapter, toLogInfo, extractReservedInputFields, parseAuthorizationHeader, toPaymentRequiredEnvelope, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, toErrorEnvelope, DELIVERY_SUMMARY_META_KEY, toDeliverySummary, PAYMENT_INPUT_FIELD, AUTHORIZATION_INPUT_FIELD, parseAuthorizationSubmission } from './chunk-XYHDQ22D.js';
7
+ export { AUTHORIZATION_HEADER, AUTHORIZATION_INPUT_FIELD, COMMERCE_ERROR_CODES, COMMERCE_ERROR_HTTP_STATUS, COMMERCE_EVENT_TYPES, CommerceError, DEFAULT_BACKEND_TIMEOUT_MS, DELIVERY_SUMMARY_META_KEY, MAX_AUTHORIZATION_HEADER_BYTES, NOOP_LOGGER, PAYMENT_HEADER, PAYMENT_INPUT_FIELD, PAYMENT_METHOD_NAMES, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PROTOCOL_NAMES, RESERVED_INPUT_FIELDS, RETRYABLE_ERROR_CODES, extractReservedInputFields, isCommerceError, isHttpProtocolAdapter, isPaymentRequiredEnvelope, parseAuthorizationHeader, parseAuthorizationSubmission, systemClock, toCommerceError, toDeliverySummary, toErrorEnvelope, toPaymentRequiredEnvelope } from './chunk-XYHDQ22D.js';
8
8
  import { isRecord } from './chunk-2CJNA7MS.js';
9
9
  import { promises, accessSync, constants } from 'fs';
10
10
  import * as path from 'path';
@@ -678,7 +678,9 @@ function normalizeX402(raw, resources) {
678
678
  facilitator,
679
679
  ...allowMainnet !== void 0 ? { allowMainnet } : {},
680
680
  ...allowUnauthenticatedFacilitator !== void 0 ? { allowUnauthenticatedFacilitator } : {},
681
- ...networks !== void 0 ? { customNetworks: networks } : {}
681
+ ...networks !== void 0 ? { customNetworks: networks } : {},
682
+ // resolveX402Option required the token's own metadata
683
+ allowOtherEvmToken: true
682
684
  });
683
685
  if (firstMode !== void 0 && mode !== firstMode) {
684
686
  throw x402Invalid(
@@ -810,6 +812,9 @@ function normalizeMpp(raw) {
810
812
  var SUPPORTED_CONFIG_VERSION = 1;
811
813
  var NumberOrString = z.union([z.number(), z.string()]);
812
814
  var BooleanOrString = z.union([z.boolean(), z.string()]);
815
+ var MediaType = z.string().regex(/^[A-Za-z0-9][\w!#$&^.+-]*\/[A-Za-z0-9][\w!#$&^.+-]*(?:[ \t]*;.*)?$/, {
816
+ message: "must be a media type such as application/json"
817
+ });
813
818
  var RpcUrl = z.string().min(1).refine(isHttpUrl, { message: "must be an http:// or https:// URL" });
814
819
  function isHttpUrl(value) {
815
820
  try {
@@ -955,6 +960,8 @@ var ResourceEntrySchema = z.object({
955
960
  description: z.string().optional(),
956
961
  input: JsonSchemaValueSchema.optional(),
957
962
  output: JsonSchemaValueSchema.optional(),
963
+ // What the backend returns; x402 challenges declare it, `application/json` by default
964
+ mimeType: MediaType.optional(),
958
965
  backend: BackendHandlerSchema,
959
966
  pricing: PricingSchema,
960
967
  expose: z.array(z.string().min(1)).min(1),
@@ -2803,6 +2810,13 @@ function normalizeResource(id, entry, protocols, x402, mpp, ap2) {
2803
2810
  { details: { path: `resources.${id}.paymentFlow`, resourceId: id } }
2804
2811
  );
2805
2812
  }
2813
+ if (entry.mimeType !== void 0 && (entry.pricing.type !== "fixed" || !paymentMethods.includes("x402"))) {
2814
+ throw new CommerceError(
2815
+ "CONFIG_INVALID",
2816
+ `Resource "${id}" sets mimeType, which requires fixed pricing and "x402" in payments`,
2817
+ { details: { path: `resources.${id}.mimeType`, resourceId: id } }
2818
+ );
2819
+ }
2806
2820
  const pricing = entry.pricing.type === "free" ? { type: "free" } : { type: "fixed", amount: entry.pricing.amount, currency: entry.pricing.currency };
2807
2821
  const authorization = normalizeResourceAuthorization(id, entry, pricing, ap2);
2808
2822
  return {
@@ -2897,7 +2911,17 @@ function normalize(raw) {
2897
2911
  );
2898
2912
  return Object.keys(flows).length > 0 ? { resourcePaymentFlows: flows } : {};
2899
2913
  };
2900
- const x402WithFlows = x402 !== void 0 ? { ...x402, ...flowOverrides2("x402") } : x402;
2914
+ const mimeTypes = Object.fromEntries(
2915
+ resources.flatMap((resource) => {
2916
+ const mimeType = raw.resources[resource.id]?.mimeType;
2917
+ return mimeType !== void 0 ? [[resource.id, mimeType]] : [];
2918
+ })
2919
+ );
2920
+ const x402WithFlows = x402 !== void 0 ? {
2921
+ ...x402,
2922
+ ...flowOverrides2("x402"),
2923
+ ...Object.keys(mimeTypes).length > 0 ? { resourceMimeTypes: mimeTypes } : {}
2924
+ } : x402;
2901
2925
  const mppWithFlows = mpp !== void 0 ? { ...mpp, ...flowOverrides2("mpp") } : mpp;
2902
2926
  if (protocols.acp.enabled) validateAcpCheckoutMapping(protocols.acp, resources);
2903
2927
  if (protocols.a2a.enabled && !resources.some((r) => r.exposedVia.includes("a2a"))) {
@@ -3716,7 +3740,12 @@ function registerRoutes(options) {
3716
3740
  server.get(
3717
3741
  "/api/receipts",
3718
3742
  { onRequest: tokenHook },
3719
- ledgerHandler("receipts", (list) => options.store.listReceipts(list))
3743
+ ledgerHandler(
3744
+ "receipts",
3745
+ (list, query) => options.store.listReceipts(
3746
+ parseFlag(query["undelivered"], "undelivered") ? { ...list, undelivered: true } : list
3747
+ )
3748
+ )
3720
3749
  );
3721
3750
  server.get(
3722
3751
  "/api/events",
@@ -3741,8 +3770,10 @@ function digestingStream(request) {
3741
3770
  function ledgerHandler(key, list) {
3742
3771
  return async (request, reply) => {
3743
3772
  try {
3744
- const limit = parseLimit(request.query["limit"]);
3745
- return { [key]: await list(limit !== void 0 ? { limit } : {}) };
3773
+ const query = request.query;
3774
+ const limit = parseLimit(query["limit"]);
3775
+ const page = await list(limit !== void 0 ? { limit } : {}, query);
3776
+ return { [key]: page };
3746
3777
  } catch (error) {
3747
3778
  const commerceError = toCommerceError(error);
3748
3779
  reply.status(commerceError.httpStatus).send(toErrorEnvelope(commerceError));
@@ -3819,11 +3850,32 @@ async function handleInvoke(request, reply, options) {
3819
3850
  }
3820
3851
  reply.header("cache-control", "private");
3821
3852
  }
3853
+ const contentType = relayedContentType(outcome.headers?.["content-type"], outcome.body);
3854
+ if (contentType !== void 0) reply.type(contentType);
3855
+ if (typeof outcome.body === "string") {
3856
+ reply.header("content-security-policy", "sandbox");
3857
+ reply.header("x-content-type-options", "nosniff");
3858
+ }
3822
3859
  reply.status(outcome.backendStatus).send(outcome.body);
3823
3860
  } catch (error) {
3824
3861
  sendInvokeError(reply, toCommerceError(error), paymentMethod);
3825
3862
  }
3826
3863
  }
3864
+ function relayedContentType(header2, body) {
3865
+ if (header2 === void 0) return void 0;
3866
+ const [essence = "", ...parameters] = (header2.match(/(?:[^;"]|"(?:[^"\\]|\\.)*"?)+/g) ?? []).map(
3867
+ (part) => part.trim()
3868
+ );
3869
+ const json = /[/+]json$/i.test(essence);
3870
+ if (!isTextType(essence) || json === (typeof body === "string")) return void 0;
3871
+ const kept = parameters.filter(
3872
+ (parameter) => parameter !== "" && !/^charset\s*=/i.test(parameter)
3873
+ );
3874
+ return [essence, ...kept, "charset=utf-8"].join("; ");
3875
+ }
3876
+ function isTextType(essence) {
3877
+ return /^text\//i.test(essence) || /[/+](?:json|xml)$/i.test(essence) || /^application\/(?:java|ecma)script$/i.test(essence);
3878
+ }
3827
3879
  var PROVIDER_UNAVAILABLE_CODES = /* @__PURE__ */ new Set([
3828
3880
  "PAYMENT_PROVIDER_UNAVAILABLE",
3829
3881
  "AUTHORIZATION_PROVIDER_UNAVAILABLE"
@@ -3909,6 +3961,14 @@ function parseLimit(value) {
3909
3961
  }
3910
3962
  return n;
3911
3963
  }
3964
+ function parseFlag(value, field) {
3965
+ if (Array.isArray(value)) return parseFlag(value[0], field);
3966
+ if (value === void 0 || value === "false") return false;
3967
+ if (value === "true") return true;
3968
+ throw new CommerceError("INPUT_INVALID", `Query parameter "${field}" must be true or false`, {
3969
+ details: { field }
3970
+ });
3971
+ }
3912
3972
 
3913
3973
  // src/gateway/server.ts
3914
3974
  var REQUEST_ID_HEADER = "x-request-id";
@@ -10399,6 +10459,7 @@ function clampListLimit(limit) {
10399
10459
  const base = limit !== void 0 && Number.isFinite(limit) ? limit : DEFAULT_LIST_LIMIT;
10400
10460
  return Math.min(Math.max(Math.trunc(base), 1), MAX_LIST_LIMIT);
10401
10461
  }
10462
+ var UNDELIVERED = "backend_status NOT BETWEEN 200 AND 299";
10402
10463
  var defaultIds = {
10403
10464
  next: (prefix) => prefix !== void 0 ? `${prefix}_${randomUUID()}` : randomUUID()
10404
10465
  };
@@ -10424,11 +10485,17 @@ function createSqliteReceiptStore(options) {
10424
10485
  const listReceiptsByRequestStmt = db.prepare(
10425
10486
  "SELECT * FROM receipts WHERE request_id = ? ORDER BY delivered_at DESC, seq DESC LIMIT ?"
10426
10487
  );
10488
+ const listUndeliveredReceiptsStmt = db.prepare(
10489
+ `SELECT * FROM receipts WHERE ${UNDELIVERED} ORDER BY delivered_at DESC, seq DESC LIMIT ?`
10490
+ );
10491
+ const listUndeliveredReceiptsByRequestStmt = db.prepare(
10492
+ `SELECT * FROM receipts WHERE request_id = ? AND ${UNDELIVERED} ORDER BY delivered_at DESC, seq DESC LIMIT ?`
10493
+ );
10427
10494
  const countReceiptsStmt = db.prepare(
10428
10495
  "SELECT COUNT(*) AS count FROM receipts"
10429
10496
  );
10430
10497
  const countUndeliveredReceiptsStmt = db.prepare(
10431
- "SELECT COUNT(*) AS count FROM receipts WHERE backend_status NOT BETWEEN 200 AND 299"
10498
+ `SELECT COUNT(*) AS count FROM receipts WHERE ${UNDELIVERED}`
10432
10499
  );
10433
10500
  const insertEventStmt = db.prepare(
10434
10501
  `INSERT INTO events (id, type, request_id, resource_id, at, adapter, payment_provider, duration_ms, status, data_json)
@@ -10587,7 +10654,11 @@ function createSqliteReceiptStore(options) {
10587
10654
  },
10588
10655
  async listReceipts(listOptions = {}) {
10589
10656
  const limit = clampListLimit(listOptions.limit);
10590
- const rows = listOptions.requestId !== void 0 ? listReceiptsByRequestStmt.all(listOptions.requestId, limit) : listReceiptsStmt.all(limit);
10657
+ const undelivered = listOptions.undelivered === true;
10658
+ const rows = listOptions.requestId !== void 0 ? (undelivered ? listUndeliveredReceiptsByRequestStmt : listReceiptsByRequestStmt).all(
10659
+ listOptions.requestId,
10660
+ limit
10661
+ ) : (undelivered ? listUndeliveredReceiptsStmt : listReceiptsStmt).all(limit);
10591
10662
  return rows.map(rowToReceipt);
10592
10663
  },
10593
10664
  // Exact total, not bounded by the listReceipts clamp (see ReceiptStore.countReceipts)