@devlab.group/agent-commerce 2.1.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 (73) hide show
  1. package/README.md +35 -5
  2. package/dist/ap2.js +3 -3
  3. package/dist/{chunk-SY6GUYSQ.js → chunk-7ZMMXZ4G.js} +3 -3
  4. package/dist/{chunk-SY6GUYSQ.js.map → chunk-7ZMMXZ4G.js.map} +1 -1
  5. package/dist/{chunk-UHMYRV3J.js → chunk-HNRDZLSN.js} +7 -5
  6. package/dist/chunk-HNRDZLSN.js.map +1 -0
  7. package/dist/{chunk-LZS5BL3W.js → chunk-IEW7NSP2.js} +23 -5
  8. package/dist/chunk-IEW7NSP2.js.map +1 -0
  9. package/dist/{chunk-IFGRCXME.js → chunk-Y4RE3XYF.js} +3 -3
  10. package/dist/{chunk-IFGRCXME.js.map → chunk-Y4RE3XYF.js.map} +1 -1
  11. package/dist/cli/ap2-MBMQHFX4.js +678 -0
  12. package/dist/cli/ap2-MBMQHFX4.js.map +1 -0
  13. package/dist/cli/chunk-2ZZOGI5I.js +1352 -0
  14. package/dist/cli/chunk-2ZZOGI5I.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-7JNYFUT3.js +256 -0
  24. package/dist/cli/chunk-7JNYFUT3.js.map +1 -0
  25. package/dist/cli/chunk-AA3FIEAR.js +27 -0
  26. package/dist/cli/chunk-AA3FIEAR.js.map +1 -0
  27. package/dist/cli/chunk-FHCFR2GS.js +17 -0
  28. package/dist/cli/chunk-FHCFR2GS.js.map +1 -0
  29. package/dist/cli/chunk-FRMLWGSS.js +8 -0
  30. package/dist/cli/chunk-FRMLWGSS.js.map +1 -0
  31. package/dist/cli/chunk-KLX2YZDG.js +1400 -0
  32. package/dist/cli/chunk-KLX2YZDG.js.map +1 -0
  33. package/dist/cli/chunk-NSPPEF5M.js +334 -0
  34. package/dist/cli/chunk-NSPPEF5M.js.map +1 -0
  35. package/dist/cli/chunk-OSTCU6ZK.js +44 -0
  36. package/dist/cli/chunk-OSTCU6ZK.js.map +1 -0
  37. package/dist/cli/chunk-QQ3WY5L3.js +271 -0
  38. package/dist/cli/chunk-QQ3WY5L3.js.map +1 -0
  39. package/dist/cli/chunk-RWVPYAKC.js +1742 -0
  40. package/dist/cli/chunk-RWVPYAKC.js.map +1 -0
  41. package/dist/cli/chunk-SPAYKVUP.js +118 -0
  42. package/dist/cli/chunk-SPAYKVUP.js.map +1 -0
  43. package/dist/cli/chunk-SS3QFF5N.js +614 -0
  44. package/dist/cli/chunk-SS3QFF5N.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-4IBGVFSP.js +11 -0
  48. package/dist/cli/config-4IBGVFSP.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-CNWQ2MOE.js +559 -0
  52. package/dist/cli/mcp-CNWQ2MOE.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-4BQDH56Y.js +396 -0
  56. package/dist/cli/provider-4BQDH56Y.js.map +1 -0
  57. package/dist/cli/run-5MB2D45X.js +7286 -0
  58. package/dist/cli/run-5MB2D45X.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-NKR3WQDQ.js +96 -0
  62. package/dist/cli/x402-NKR3WQDQ.js.map +1 -0
  63. package/dist/index.d.ts +2 -0
  64. package/dist/index.js +48 -5
  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/x402.d.ts +5 -0
  70. package/dist/x402.js +4 -4
  71. package/package.json +2 -2
  72. package/dist/chunk-LZS5BL3W.js.map +0 -1
  73. 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-KLX2YZDG.js';
2
+ export { createX402PaymentProvider } from './chunk-KLX2YZDG.js';
3
+ import './chunk-NSPPEF5M.js';
4
+ export { SUPPORTED_NETWORK_IDS } from './chunk-7JNYFUT3.js';
5
+ import './chunk-OSTCU6ZK.js';
6
+ import './chunk-FRMLWGSS.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-NKR3WQDQ.js.map
96
+ //# sourceMappingURL=x402-NKR3WQDQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/payments/x402/client.ts"],"names":[],"mappings":"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","file":"x402-NKR3WQDQ.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
@@ -496,6 +496,8 @@ interface GatewayConfig {
496
496
  readonly paymentFlow?: X402PaymentFlow;
497
497
  /** Resources whose `paymentFlow` overrides the rail's, by resource id */
498
498
  readonly resourcePaymentFlows?: Readonly<Record<string, X402PaymentFlow>>;
499
+ /** Resources that set `mimeType`, by resource id; others declare `application/json` */
500
+ readonly resourceMimeTypes?: Readonly<Record<string, string>>;
499
501
  readonly facilitator: X402FacilitatorConfig;
500
502
  readonly allowMainnet?: boolean;
501
503
  readonly allowUnauthenticatedFacilitator?: boolean;
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-IEW7NSP2.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-Y4RE3XYF.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-7ZMMXZ4G.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-7ZMMXZ4G.js';
8
8
  import { isRecord } from './chunk-2CJNA7MS.js';
9
9
  import { promises, accessSync, constants } from 'fs';
10
10
  import * as path from 'path';
@@ -810,6 +810,9 @@ function normalizeMpp(raw) {
810
810
  var SUPPORTED_CONFIG_VERSION = 1;
811
811
  var NumberOrString = z.union([z.number(), z.string()]);
812
812
  var BooleanOrString = z.union([z.boolean(), z.string()]);
813
+ var MediaType = z.string().regex(/^[A-Za-z0-9][\w!#$&^.+-]*\/[A-Za-z0-9][\w!#$&^.+-]*(?:[ \t]*;.*)?$/, {
814
+ message: "must be a media type such as application/json"
815
+ });
813
816
  var RpcUrl = z.string().min(1).refine(isHttpUrl, { message: "must be an http:// or https:// URL" });
814
817
  function isHttpUrl(value) {
815
818
  try {
@@ -955,6 +958,8 @@ var ResourceEntrySchema = z.object({
955
958
  description: z.string().optional(),
956
959
  input: JsonSchemaValueSchema.optional(),
957
960
  output: JsonSchemaValueSchema.optional(),
961
+ // What the backend returns; x402 challenges declare it, `application/json` by default
962
+ mimeType: MediaType.optional(),
958
963
  backend: BackendHandlerSchema,
959
964
  pricing: PricingSchema,
960
965
  expose: z.array(z.string().min(1)).min(1),
@@ -2803,6 +2808,13 @@ function normalizeResource(id, entry, protocols, x402, mpp, ap2) {
2803
2808
  { details: { path: `resources.${id}.paymentFlow`, resourceId: id } }
2804
2809
  );
2805
2810
  }
2811
+ if (entry.mimeType !== void 0 && (entry.pricing.type !== "fixed" || !paymentMethods.includes("x402"))) {
2812
+ throw new CommerceError(
2813
+ "CONFIG_INVALID",
2814
+ `Resource "${id}" sets mimeType, which requires fixed pricing and "x402" in payments`,
2815
+ { details: { path: `resources.${id}.mimeType`, resourceId: id } }
2816
+ );
2817
+ }
2806
2818
  const pricing = entry.pricing.type === "free" ? { type: "free" } : { type: "fixed", amount: entry.pricing.amount, currency: entry.pricing.currency };
2807
2819
  const authorization = normalizeResourceAuthorization(id, entry, pricing, ap2);
2808
2820
  return {
@@ -2897,7 +2909,17 @@ function normalize(raw) {
2897
2909
  );
2898
2910
  return Object.keys(flows).length > 0 ? { resourcePaymentFlows: flows } : {};
2899
2911
  };
2900
- const x402WithFlows = x402 !== void 0 ? { ...x402, ...flowOverrides2("x402") } : x402;
2912
+ const mimeTypes = Object.fromEntries(
2913
+ resources.flatMap((resource) => {
2914
+ const mimeType = raw.resources[resource.id]?.mimeType;
2915
+ return mimeType !== void 0 ? [[resource.id, mimeType]] : [];
2916
+ })
2917
+ );
2918
+ const x402WithFlows = x402 !== void 0 ? {
2919
+ ...x402,
2920
+ ...flowOverrides2("x402"),
2921
+ ...Object.keys(mimeTypes).length > 0 ? { resourceMimeTypes: mimeTypes } : {}
2922
+ } : x402;
2901
2923
  const mppWithFlows = mpp !== void 0 ? { ...mpp, ...flowOverrides2("mpp") } : mpp;
2902
2924
  if (protocols.acp.enabled) validateAcpCheckoutMapping(protocols.acp, resources);
2903
2925
  if (protocols.a2a.enabled && !resources.some((r) => r.exposedVia.includes("a2a"))) {
@@ -3819,11 +3841,32 @@ async function handleInvoke(request, reply, options) {
3819
3841
  }
3820
3842
  reply.header("cache-control", "private");
3821
3843
  }
3844
+ const contentType = relayedContentType(outcome.headers?.["content-type"], outcome.body);
3845
+ if (contentType !== void 0) reply.type(contentType);
3846
+ if (typeof outcome.body === "string") {
3847
+ reply.header("content-security-policy", "sandbox");
3848
+ reply.header("x-content-type-options", "nosniff");
3849
+ }
3822
3850
  reply.status(outcome.backendStatus).send(outcome.body);
3823
3851
  } catch (error) {
3824
3852
  sendInvokeError(reply, toCommerceError(error), paymentMethod);
3825
3853
  }
3826
3854
  }
3855
+ function relayedContentType(header2, body) {
3856
+ if (header2 === void 0) return void 0;
3857
+ const [essence = "", ...parameters] = (header2.match(/(?:[^;"]|"(?:[^"\\]|\\.)*"?)+/g) ?? []).map(
3858
+ (part) => part.trim()
3859
+ );
3860
+ const json = /[/+]json$/i.test(essence);
3861
+ if (!isTextType(essence) || json === (typeof body === "string")) return void 0;
3862
+ const kept = parameters.filter(
3863
+ (parameter) => parameter !== "" && !/^charset\s*=/i.test(parameter)
3864
+ );
3865
+ return [essence, ...kept, "charset=utf-8"].join("; ");
3866
+ }
3867
+ function isTextType(essence) {
3868
+ return /^text\//i.test(essence) || /[/+](?:json|xml)$/i.test(essence) || /^application\/(?:java|ecma)script$/i.test(essence);
3869
+ }
3827
3870
  var PROVIDER_UNAVAILABLE_CODES = /* @__PURE__ */ new Set([
3828
3871
  "PAYMENT_PROVIDER_UNAVAILABLE",
3829
3872
  "AUTHORIZATION_PROVIDER_UNAVAILABLE"