@devlab.group/agent-commerce 2.3.0 → 2.4.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.
- package/README.md +17 -13
- package/dist/ap2.d.ts +6 -5
- package/dist/ap2.js +3 -3
- package/dist/{authorization-CMkIuAkO.d.ts → authorization-DjAecwuW.d.ts} +1 -1
- package/dist/{chunk-TNS7U5Q4.js → chunk-CXWC5LWM.js} +200 -8
- package/dist/chunk-CXWC5LWM.js.map +1 -0
- package/dist/{chunk-Q5TII32R.js → chunk-DTKU3Z2M.js} +3 -3
- package/dist/{chunk-Q5TII32R.js.map → chunk-DTKU3Z2M.js.map} +1 -1
- package/dist/{chunk-XVU46YAH.js → chunk-QPV3EGJO.js} +4 -4
- package/dist/{chunk-XVU46YAH.js.map → chunk-QPV3EGJO.js.map} +1 -1
- package/dist/{chunk-4ZSE5DCH.js → chunk-WZW5ORZH.js} +3 -3
- package/dist/{chunk-4ZSE5DCH.js.map → chunk-WZW5ORZH.js.map} +1 -1
- package/dist/cli/{ap2-GINAXBFV.js → ap2-GWSP4LYY.js} +3 -3
- package/dist/cli/{ap2-GINAXBFV.js.map → ap2-GWSP4LYY.js.map} +1 -1
- package/dist/cli/{chunk-55N55KL4.js → chunk-G2JEY7MB.js} +22 -6
- package/dist/cli/chunk-G2JEY7MB.js.map +1 -0
- package/dist/cli/{chunk-KABFUZ6L.js → chunk-GJIMDMYT.js} +4 -4
- package/dist/cli/{chunk-KABFUZ6L.js.map → chunk-GJIMDMYT.js.map} +1 -1
- package/dist/cli/chunk-ITWNSS2B.js +8 -0
- package/dist/cli/{chunk-DYHVNKRB.js.map → chunk-ITWNSS2B.js.map} +1 -1
- package/dist/cli/{chunk-2LN5PO5I.js → chunk-PIMFPCNZ.js} +3 -2
- package/dist/cli/chunk-PIMFPCNZ.js.map +1 -0
- package/dist/cli/{chunk-BR7CMJOE.js → chunk-TNMLDPUO.js} +200 -8
- package/dist/cli/chunk-TNMLDPUO.js.map +1 -0
- package/dist/cli/{chunk-KTV52MCU.js → chunk-WYOGIANL.js} +3 -3
- package/dist/cli/{chunk-KTV52MCU.js.map → chunk-WYOGIANL.js.map} +1 -1
- package/dist/cli/{config-ZOFHJ5FB.js → config-UI4EDG4L.js} +5 -5
- package/dist/cli/{config-ZOFHJ5FB.js.map → config-UI4EDG4L.js.map} +1 -1
- package/dist/cli/index.js +87 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{mcp-V3BNRUWL.js → mcp-PGBRWZVA.js} +3 -3
- package/dist/cli/{mcp-V3BNRUWL.js.map → mcp-PGBRWZVA.js.map} +1 -1
- package/dist/cli/{provider-BTIFALIT.js → provider-I2ESL6RS.js} +9 -6
- package/dist/cli/provider-I2ESL6RS.js.map +1 -0
- package/dist/cli/{run-DS2KXUTW.js → run-JK4ERPJV.js} +23 -12
- package/dist/cli/run-JK4ERPJV.js.map +1 -0
- package/dist/cli/{x402-YTKFNWVQ.js → x402-7WBFZQXV.js} +6 -6
- package/dist/cli/{x402-YTKFNWVQ.js.map → x402-7WBFZQXV.js.map} +1 -1
- package/dist/{constants-nackLItD.d.ts → constants-BG22tE8S.d.ts} +2 -1
- package/dist/index.d.ts +19 -11
- package/dist/index.js +32 -7
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +5 -4
- package/dist/mcp.js +1 -1
- package/dist/mpp.d.ts +5 -4
- package/dist/mpp.js +7 -4
- package/dist/mpp.js.map +1 -1
- package/dist/{networks-DTWRlj-K.d.ts → networks-DDHYJLcg.d.ts} +2 -1
- package/dist/{protocol-adapter-CfxU8Z2T.d.ts → protocol-adapter-C9odYl6l.d.ts} +4 -3
- package/dist/{runtime-7vLNYvmU.d.ts → runtime-Cl_BLVZV.d.ts} +8 -1
- package/dist/{types-CVw6Sf46.d.ts → types-j7MnUXYN.d.ts} +2 -1
- package/dist/x402.d.ts +27 -18
- package/dist/x402.js +4 -4
- package/package.json +6 -6
- package/dist/chunk-TNS7U5Q4.js.map +0 -1
- package/dist/cli/chunk-2LN5PO5I.js.map +0 -1
- package/dist/cli/chunk-55N55KL4.js.map +0 -1
- package/dist/cli/chunk-BR7CMJOE.js.map +0 -1
- package/dist/cli/chunk-DYHVNKRB.js +0 -8
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/provider-BTIFALIT.js.map +0 -1
- package/dist/cli/run-DS2KXUTW.js.map +0 -1
package/README.md
CHANGED
|
@@ -279,16 +279,17 @@ See [docs/configuration.md](docs/configuration.md).
|
|
|
279
279
|
|
|
280
280
|
## Protocol support
|
|
281
281
|
|
|
282
|
-
| Protocol
|
|
283
|
-
|
|
|
284
|
-
| **HTTP**
|
|
285
|
-
| **MCP**
|
|
286
|
-
| **x402**
|
|
287
|
-
| **MPP**
|
|
288
|
-
| **A2A**
|
|
289
|
-
| **ACP**
|
|
290
|
-
| **AP2**
|
|
291
|
-
|
|
|
282
|
+
| Protocol | Status | Pinned revision |
|
|
283
|
+
| ------------ | ------------ | ------------------------------------------------------------------------------------------------------------ |
|
|
284
|
+
| **HTTP** | Supported | native routes |
|
|
285
|
+
| **MCP** | Supported | `2026-07-28` and `2025-11-25`, `@modelcontextprotocol/server@2.3.0` |
|
|
286
|
+
| **x402** | Supported | x402 v2 (`@x402/core`, `@x402/evm`, `@x402/svm`, `@x402/near`), scheme `exact`, EVM and Solana; NEAR partial |
|
|
287
|
+
| **MPP** | Experimental | `mppx@0.13.1`, `charge` + `evm` + EIP-3009, USDC on Base Sepolia and Base |
|
|
288
|
+
| **A2A** | Experimental | A2A v1.0.1, binding `JSONRPC`, method `SendMessage`, x402 extension |
|
|
289
|
+
| **ACP** | Experimental | ACP `2026-04-17`, REST checkout + discovery |
|
|
290
|
+
| **AP2** | Experimental | AP2 `v0.2.0`, Direct Checkout Mandate verification |
|
|
291
|
+
| **ERC-8409** | Experimental | draft `SergeevDmitry/ERCs@0ee33230`: signed quotes on x402 EVM offers |
|
|
292
|
+
| UCP | Planned | no implementation |
|
|
292
293
|
|
|
293
294
|
[AP2](docs/protocols/ap2.md) is an authorization method, not a transport. It verifies a
|
|
294
295
|
mandate before a paid resource settles; the gateway does not issue the mandate
|
|
@@ -296,7 +297,8 @@ or its Checkout Receipt.
|
|
|
296
297
|
|
|
297
298
|
The experimental entries above ship off by default with documented subsets:
|
|
298
299
|
[A2A](docs/protocols/a2a.md), [ACP](docs/protocols/acp.md),
|
|
299
|
-
[AP2](docs/protocols/ap2.md#not-implemented)
|
|
300
|
+
[AP2](docs/protocols/ap2.md#not-implemented), [MPP](docs/protocols/mpp.md) and
|
|
301
|
+
[ERC-8409 quotes](docs/protocols/x402.md#erc-8409-signed-quotes). Supported
|
|
300
302
|
[MCP](docs/protocols/mcp.md) and [x402](docs/protocols/x402.md) are also scoped.
|
|
301
303
|
ACP exposes only its five checkout operations; merchant `payment_data` is never
|
|
302
304
|
converted into a gateway payment proof.
|
|
@@ -308,7 +310,8 @@ prints the `unsupported` lists for A2A, ACP and AP2 when they are enabled.
|
|
|
308
310
|
### Versioning
|
|
309
311
|
|
|
310
312
|
Minor releases may break experimental configurations, integrations or types.
|
|
311
|
-
This applies to MPP, A2A, ACP, AP2
|
|
313
|
+
This applies to MPP, A2A, ACP, AP2, ERC-8409 quotes and
|
|
314
|
+
`agent-commerce import openapi`.
|
|
312
315
|
Runtime adapters and providers report `status: experimental` in
|
|
313
316
|
`GET /.well-known/agent-commerce`. Pin an exact version and test upgrades
|
|
314
317
|
before deploying them. Since 2.1, some supported x402 behavior and types
|
|
@@ -318,7 +321,8 @@ differ from 2.0; see [Upgrading from 2.0 to 2.x](docs/migration-2.1.md).
|
|
|
318
321
|
|
|
319
322
|
- **Non-custodial.** Buyer payments go directly to the merchant address in
|
|
320
323
|
`payTo` (`recipient` for MPP). The gateway does not require buyer or merchant
|
|
321
|
-
private keys. Local facilitator mode
|
|
324
|
+
private keys. Local facilitator mode uses a separate key to pay gas.
|
|
325
|
+
Experimental ERC-8409 quotes use a dedicated, unfunded signing key.
|
|
322
326
|
- **Fail closed.** Missing, malformed, expired, replayed, wrong-amount,
|
|
323
327
|
wrong-recipient, wrong-network and wrong-asset payments are rejected.
|
|
324
328
|
- **Replay-safe twice over.** The EIP-3009 or Permit2 nonce stops a double
|
package/dist/ap2.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { E as EnabledAp2Config } from './types-
|
|
2
|
-
export { A as AP2_CHECKOUT_MANDATE_VCT, a as AP2_CHECKOUT_PROFILE, b as AP2_DEFAULT_CLOCK_SKEW_SECONDS, c as AP2_MAX_CLOCK_SKEW_SECONDS, d as AP2_SIGNING_ALGORITHM, e as AP2_SPEC_VERSION, f as Ap2AuthorizationConfig, g as Ap2Mode, h as Ap2TrustedIssuer, i as Ap2TrustedKey } from './types-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { E as EnabledAp2Config } from './types-j7MnUXYN.js';
|
|
2
|
+
export { A as AP2_CHECKOUT_MANDATE_VCT, a as AP2_CHECKOUT_PROFILE, b as AP2_DEFAULT_CLOCK_SKEW_SECONDS, c as AP2_MAX_CLOCK_SKEW_SECONDS, d as AP2_SIGNING_ALGORITHM, e as AP2_SPEC_VERSION, f as Ap2AuthorizationConfig, g as Ap2Mode, h as Ap2TrustedIssuer, i as Ap2TrustedKey } from './types-j7MnUXYN.js';
|
|
3
|
+
import { AuthorizationProvider } from './index.js';
|
|
4
|
+
import { Clock, Logger } from './index.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* A private ES256 key: either a private JWK (the pair of the public one in the
|
|
@@ -158,4 +158,5 @@ interface Ap2AuthorizationProvider extends AuthorizationProvider {
|
|
|
158
158
|
}
|
|
159
159
|
declare function createAp2AuthorizationProvider(options: Ap2AuthorizationProviderOptions): Ap2AuthorizationProvider;
|
|
160
160
|
|
|
161
|
-
export { AP2_CAPABILITIES, AP2_REJECTION_REASONS, AP2_UNSUPPORTED,
|
|
161
|
+
export { AP2_CAPABILITIES, AP2_REJECTION_REASONS, AP2_UNSUPPORTED, EnabledAp2Config, createAp2AuthorizationProvider as ap2, createAp2AuthorizationProvider, createCheckoutJwt };
|
|
162
|
+
export type { Ap2AuthorizationProvider, Ap2AuthorizationProviderOptions, Ap2RejectionReason, Ap2SigningKey, CreateCheckoutJwtOptions };
|
package/dist/ap2.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AP2_CHECKOUT_MANDATE_VCT, AP2_SIGNING_ALGORITHM, AP2_DIGEST_ALGORITHM, AP2_CHECKOUT_PROFILE, AP2_SPEC_VERSION, AP2_KEY_TYPE, AP2_JWK_CURVE, openSqliteDatabase } from './chunk-
|
|
2
|
-
export { AP2_CHECKOUT_MANDATE_VCT, AP2_CHECKOUT_PROFILE, AP2_DEFAULT_CLOCK_SKEW_SECONDS, AP2_MAX_CLOCK_SKEW_SECONDS, AP2_SIGNING_ALGORITHM, AP2_SPEC_VERSION } from './chunk-
|
|
3
|
-
import { systemClock, NOOP_LOGGER, CommerceError, PACKAGE_VERSION } from './chunk-
|
|
1
|
+
import { AP2_CHECKOUT_MANDATE_VCT, AP2_SIGNING_ALGORITHM, AP2_DIGEST_ALGORITHM, AP2_CHECKOUT_PROFILE, AP2_SPEC_VERSION, AP2_KEY_TYPE, AP2_JWK_CURVE, openSqliteDatabase } from './chunk-WZW5ORZH.js';
|
|
2
|
+
export { AP2_CHECKOUT_MANDATE_VCT, AP2_CHECKOUT_PROFILE, AP2_DEFAULT_CLOCK_SKEW_SECONDS, AP2_MAX_CLOCK_SKEW_SECONDS, AP2_SIGNING_ALGORITHM, AP2_SPEC_VERSION } from './chunk-WZW5ORZH.js';
|
|
3
|
+
import { systemClock, NOOP_LOGGER, CommerceError, PACKAGE_VERSION } from './chunk-DTKU3Z2M.js';
|
|
4
4
|
import { isRecord } from './chunk-2CJNA7MS.js';
|
|
5
5
|
import { SignJWT, importPKCS8, importJWK, jwtVerify, decodeProtectedHeader, decodeJwt } from 'jose';
|
|
6
6
|
import canonicalize from 'canonicalize';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as AuthorizationMethodName, A as AdapterDescriptor, n as PaymentRequirement, c as AdapterHealth } from './runtime-
|
|
1
|
+
import { g as AuthorizationMethodName, A as AdapterDescriptor, n as PaymentRequirement, c as AdapterHealth } from './runtime-Cl_BLVZV.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Canonical authorization model. FROZEN CONTRACT.
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { findX402Network, normalizeAddress, assertPayToIsNotDevAddress, resolveX402Deployment, assertDevKeyIsLocalOnly, describeRpc, X402_DEFAULT_PAYMENT_FLOW, REUSE_REJECTED_AUTHORIZATION_METADATA_KEY, SETTLE_AFTER_BACKEND_METADATA_KEY, sameAddress, LOCAL_CHAIN_ID, isTransactionReference, x402OfferName, isEvmAddress, describeDeploymentMode } from './chunk-
|
|
2
|
-
import { CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION, redactedErrorText } from './chunk-
|
|
1
|
+
import { isWellKnownDevKey, findX402Network, normalizeAddress, assertPayToIsNotDevAddress, resolveX402Deployment, assertDevKeyIsLocalOnly, describeRpc, X402_DEFAULT_PAYMENT_FLOW, REUSE_REJECTED_AUTHORIZATION_METADATA_KEY, SETTLE_AFTER_BACKEND_METADATA_KEY, sameAddress, LOCAL_CHAIN_ID, isTransactionReference, x402OfferName, isEvmAddress, describeDeploymentMode } from './chunk-QPV3EGJO.js';
|
|
2
|
+
import { CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION, redactedErrorText } from './chunk-DTKU3Z2M.js';
|
|
3
3
|
import { computeReplayKey, computePermit2ReplayKey } from './chunk-KA2AX5FH.js';
|
|
4
4
|
import { isRecord } from './chunk-2CJNA7MS.js';
|
|
5
5
|
import { x402ExactPermit2ProxyAddress, toFacilitatorEvmSigner, PERMIT2_ADDRESS } from '@x402/evm';
|
|
6
|
-
import { isAddress, getAddress, formatUnits, createWalletClient, http, publicActions, createPublicClient, HttpRequestError, TimeoutError, WaitForTransactionReceiptTimeoutError, BaseError, ContractFunctionRevertedError, erc20Abi } from 'viem';
|
|
6
|
+
import { isAddress, keccak256, stringToBytes, getAddress, formatUnits, createWalletClient, http, publicActions, createPublicClient, HttpRequestError, TimeoutError, WaitForTransactionReceiptTimeoutError, BaseError, ContractFunctionRevertedError, erc20Abi } from 'viem';
|
|
7
7
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
8
8
|
import { HTTPFacilitatorClient } from '@x402/core/http';
|
|
9
9
|
import { SettleError, VerifyError } from '@x402/core/types';
|
|
10
10
|
import { x402Facilitator } from '@x402/core/facilitator';
|
|
11
11
|
import { registerExactEvmScheme } from '@x402/evm/exact/facilitator';
|
|
12
|
+
import { randomBytes } from 'crypto';
|
|
12
13
|
import { PaymentPayloadV2Schema } from '@x402/core/schemas';
|
|
13
14
|
|
|
14
15
|
// src/payments/x402/provider/constants.ts
|
|
@@ -770,6 +771,172 @@ function offerCurrency(offer, quoted) {
|
|
|
770
771
|
return canonical !== void 0 && sameAddress(offer.profile, offer.asset, canonical.address) ? canonical.symbol : quoted;
|
|
771
772
|
}
|
|
772
773
|
|
|
774
|
+
// src/core/canonical-json.ts
|
|
775
|
+
var LONE_SURROGATE = new RegExp("\\p{Cs}", "u");
|
|
776
|
+
function canonicalJson(value) {
|
|
777
|
+
if (typeof value === "string")
|
|
778
|
+
return LONE_SURROGATE.test(value) ? void 0 : JSON.stringify(value);
|
|
779
|
+
if (typeof value === "number") return Number.isFinite(value) ? JSON.stringify(value) : void 0;
|
|
780
|
+
if (value === null || typeof value === "boolean") return JSON.stringify(value);
|
|
781
|
+
if (Array.isArray(value)) {
|
|
782
|
+
const items = value.map(canonicalJson);
|
|
783
|
+
return items.includes(void 0) ? void 0 : `[${items.join(",")}]`;
|
|
784
|
+
}
|
|
785
|
+
if (typeof value !== "object") return void 0;
|
|
786
|
+
const members = [];
|
|
787
|
+
for (const key of Object.keys(value).sort()) {
|
|
788
|
+
const member = canonicalJson(value[key]);
|
|
789
|
+
if (member === void 0 || LONE_SURROGATE.test(key)) return void 0;
|
|
790
|
+
members.push(`${JSON.stringify(key)}:${member}`);
|
|
791
|
+
}
|
|
792
|
+
return `{${members.join(",")}}`;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/payments/x402/provider/quote.ts
|
|
796
|
+
var QUOTE_EXTENSION = "erc-8409";
|
|
797
|
+
var QUOTE_REQUEST_SCHEME = "agent-commerce/request/v1";
|
|
798
|
+
var QUOTE_DOMAIN = { name: "Signed Service Payment Quotes", version: "1" };
|
|
799
|
+
var QUOTE_TYPES = {
|
|
800
|
+
ServicePaymentQuote: [
|
|
801
|
+
{ name: "issuer", type: "address" },
|
|
802
|
+
{ name: "payer", type: "address" },
|
|
803
|
+
{ name: "recipient", type: "address" },
|
|
804
|
+
{ name: "asset", type: "address" },
|
|
805
|
+
{ name: "amount", type: "uint256" },
|
|
806
|
+
{ name: "requestScheme", type: "string" },
|
|
807
|
+
{ name: "requestHash", type: "bytes32" },
|
|
808
|
+
{ name: "quoteId", type: "bytes32" },
|
|
809
|
+
{ name: "validAfter", type: "uint64" },
|
|
810
|
+
{ name: "validUntil", type: "uint64" }
|
|
811
|
+
]
|
|
812
|
+
};
|
|
813
|
+
var BEARER = "0x0000000000000000000000000000000000000000";
|
|
814
|
+
var QUOTE_INFO_SCHEMA = {
|
|
815
|
+
type: "object",
|
|
816
|
+
required: ["quotes"],
|
|
817
|
+
properties: {
|
|
818
|
+
quotes: {
|
|
819
|
+
type: "array",
|
|
820
|
+
items: {
|
|
821
|
+
type: "object",
|
|
822
|
+
required: ["chainId", "quote", "signature"],
|
|
823
|
+
properties: {
|
|
824
|
+
chainId: { type: "string" },
|
|
825
|
+
// Every field is a string in the ERC's JSON encoding
|
|
826
|
+
quote: {
|
|
827
|
+
type: "object",
|
|
828
|
+
required: QUOTE_TYPES.ServicePaymentQuote.map((field) => field.name),
|
|
829
|
+
properties: Object.fromEntries(
|
|
830
|
+
QUOTE_TYPES.ServicePaymentQuote.map((field) => [field.name, { type: "string" }])
|
|
831
|
+
)
|
|
832
|
+
},
|
|
833
|
+
signature: { type: "string" }
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
var QUOTE_CACHE_LIMIT = 1024;
|
|
840
|
+
function createQuoteIssuer(options) {
|
|
841
|
+
const { signerPrivateKey, offers, deploymentMode, clock, maxTimeoutSeconds } = options;
|
|
842
|
+
let account;
|
|
843
|
+
try {
|
|
844
|
+
account = privateKeyToAccount(signerPrivateKey);
|
|
845
|
+
} catch (cause) {
|
|
846
|
+
throw new CommerceError(
|
|
847
|
+
"CONFIG_INVALID",
|
|
848
|
+
'x402 provider: quote.signerPrivateKey is not a valid private key (expected "0x" followed by 64 hex characters)',
|
|
849
|
+
{ cause }
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
if (deploymentMode !== "local" && isWellKnownDevKey(signerPrivateKey)) {
|
|
853
|
+
throw new CommerceError(
|
|
854
|
+
"CONFIG_INVALID",
|
|
855
|
+
"x402 provider: quote.signerPrivateKey is a well-known Anvil development key, so anyone could sign quotes as this gateway. Use a dedicated key outside the local chain."
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
const evmOffers = offers.filter((offer) => offer.family === "evm");
|
|
859
|
+
if (evmOffers.length === 0) {
|
|
860
|
+
throw new CommerceError(
|
|
861
|
+
"CONFIG_INVALID",
|
|
862
|
+
"x402 provider: quote needs an EVM offer; ERC-8409 quotes cover EVM networks only"
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
const issuer = account.address;
|
|
866
|
+
if (evmOffers.some((offer) => offer.payTo.toLowerCase() === issuer.toLowerCase())) {
|
|
867
|
+
throw new CommerceError(
|
|
868
|
+
"CONFIG_INVALID",
|
|
869
|
+
"x402 provider: quote.signerPrivateKey controls a payTo address. Use a dedicated key, not the merchant wallet."
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
const cache = /* @__PURE__ */ new Map();
|
|
873
|
+
async function quoteFor(offer, amount, requestHash) {
|
|
874
|
+
const now = Math.floor(clock.now().getTime() / 1e3);
|
|
875
|
+
const { chainId } = offer.profile;
|
|
876
|
+
const key = [
|
|
877
|
+
chainId,
|
|
878
|
+
offer.payTo.toLowerCase(),
|
|
879
|
+
offer.asset.toLowerCase(),
|
|
880
|
+
amount,
|
|
881
|
+
requestHash
|
|
882
|
+
].join("|");
|
|
883
|
+
const cached = cache.get(key);
|
|
884
|
+
if (cached !== void 0 && Number(cached.quote.validUntil) - now >= maxTimeoutSeconds) {
|
|
885
|
+
return cached;
|
|
886
|
+
}
|
|
887
|
+
const validUntil = now + 2 * maxTimeoutSeconds;
|
|
888
|
+
const quote = {
|
|
889
|
+
issuer,
|
|
890
|
+
payer: BEARER,
|
|
891
|
+
recipient: offer.payTo,
|
|
892
|
+
asset: offer.asset,
|
|
893
|
+
amount,
|
|
894
|
+
requestScheme: QUOTE_REQUEST_SCHEME,
|
|
895
|
+
requestHash,
|
|
896
|
+
// Use a new ID for each signed body, as the ERC requires
|
|
897
|
+
quoteId: `0x${randomBytes(32).toString("hex")}`,
|
|
898
|
+
validAfter: String(now),
|
|
899
|
+
validUntil: String(validUntil)
|
|
900
|
+
};
|
|
901
|
+
const signature = await account.signTypedData({
|
|
902
|
+
domain: { ...QUOTE_DOMAIN, chainId },
|
|
903
|
+
types: QUOTE_TYPES,
|
|
904
|
+
primaryType: "ServicePaymentQuote",
|
|
905
|
+
message: {
|
|
906
|
+
...quote,
|
|
907
|
+
amount: BigInt(amount),
|
|
908
|
+
validAfter: BigInt(now),
|
|
909
|
+
validUntil: BigInt(validUntil)
|
|
910
|
+
}
|
|
911
|
+
});
|
|
912
|
+
const signed = { chainId: String(chainId), quote, signature };
|
|
913
|
+
cache.delete(key);
|
|
914
|
+
if (cache.size >= QUOTE_CACHE_LIMIT) {
|
|
915
|
+
const oldest = cache.keys().next().value;
|
|
916
|
+
if (oldest !== void 0) cache.delete(oldest);
|
|
917
|
+
}
|
|
918
|
+
cache.set(key, signed);
|
|
919
|
+
return signed;
|
|
920
|
+
}
|
|
921
|
+
return {
|
|
922
|
+
issuer,
|
|
923
|
+
async extensionsFor(resourceId, input, quoted) {
|
|
924
|
+
if (quoted.length === 0) return void 0;
|
|
925
|
+
const requestHash = quoteRequestHash(resourceId, input);
|
|
926
|
+
if (requestHash === void 0) return void 0;
|
|
927
|
+
const quotes = [];
|
|
928
|
+
for (const { offer, amount } of quoted) {
|
|
929
|
+
quotes.push(await quoteFor(offer, amount, requestHash));
|
|
930
|
+
}
|
|
931
|
+
return { [QUOTE_EXTENSION]: { info: { quotes }, schema: QUOTE_INFO_SCHEMA } };
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
function quoteRequestHash(resourceId, input) {
|
|
936
|
+
const canonical = canonicalJson({ input, resource: resourceId });
|
|
937
|
+
return canonical === void 0 ? void 0 : keccak256(stringToBytes(canonical));
|
|
938
|
+
}
|
|
939
|
+
|
|
773
940
|
// src/payments/x402/amount.ts
|
|
774
941
|
var DECIMAL_STRING_PATTERN = /^\d+(?:\.\d+)?$/;
|
|
775
942
|
function parseCanonicalAmount(amount, decimals) {
|
|
@@ -883,6 +1050,14 @@ function createRequirementBuilders(ctx, svmFeePayer) {
|
|
|
883
1050
|
}))
|
|
884
1051
|
);
|
|
885
1052
|
const single = offers.length === 1 ? offers[0] : void 0;
|
|
1053
|
+
const extensions = await ctx.quotes?.extensionsFor(
|
|
1054
|
+
context.resource.id,
|
|
1055
|
+
context.input,
|
|
1056
|
+
offers.flatMap((offer, index) => {
|
|
1057
|
+
const accepted = accepts[index];
|
|
1058
|
+
return offer.family === "evm" && accepted ? [{ offer, amount: accepted.amount }] : [];
|
|
1059
|
+
})
|
|
1060
|
+
);
|
|
886
1061
|
const resourceId = encodeURIComponent(context.resource.id);
|
|
887
1062
|
const envelope = {
|
|
888
1063
|
x402Version: X402_VERSION,
|
|
@@ -893,7 +1068,8 @@ function createRequirementBuilders(ctx, svmFeePayer) {
|
|
|
893
1068
|
// delivery carries the backend's own type when it is text and fits the body
|
|
894
1069
|
mimeType: options.resourceMimeTypes?.[context.resource.id] ?? DEFAULT_MIME_TYPE
|
|
895
1070
|
},
|
|
896
|
-
accepts
|
|
1071
|
+
accepts,
|
|
1072
|
+
...extensions !== void 0 ? { extensions } : {}
|
|
897
1073
|
};
|
|
898
1074
|
const expiresAt = new Date(clock.now().getTime() + maxTimeoutSeconds * 1e3).toISOString();
|
|
899
1075
|
return {
|
|
@@ -1319,6 +1495,13 @@ function createX402PaymentProvider(options) {
|
|
|
1319
1495
|
const ids = options.ids ?? DEFAULT_IDS;
|
|
1320
1496
|
const logger = options.logger ?? NOOP_LOGGER;
|
|
1321
1497
|
const maxTimeoutSeconds = options.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS;
|
|
1498
|
+
const quotes = options.quote ? createQuoteIssuer({
|
|
1499
|
+
signerPrivateKey: options.quote.signerPrivateKey,
|
|
1500
|
+
offers,
|
|
1501
|
+
deploymentMode,
|
|
1502
|
+
clock,
|
|
1503
|
+
maxTimeoutSeconds
|
|
1504
|
+
}) : void 0;
|
|
1322
1505
|
const evmOffers = offers.filter((offer) => offer.family === "evm");
|
|
1323
1506
|
const hasSvm = offers.some((offer) => offer.family === "svm");
|
|
1324
1507
|
const hasNear = offers.some((offer) => offer.family === "near");
|
|
@@ -1342,7 +1525,8 @@ function createX402PaymentProvider(options) {
|
|
|
1342
1525
|
`mode=${deploymentMode}`,
|
|
1343
1526
|
"authorization-flow",
|
|
1344
1527
|
"upfront-flow",
|
|
1345
|
-
...severalOffers ? ["multiple-offers"] : []
|
|
1528
|
+
...severalOffers ? ["multiple-offers"] : [],
|
|
1529
|
+
...quotes ? ["erc-8409-quotes"] : []
|
|
1346
1530
|
],
|
|
1347
1531
|
status: "stable",
|
|
1348
1532
|
unsupported: [
|
|
@@ -1374,6 +1558,7 @@ function createX402PaymentProvider(options) {
|
|
|
1374
1558
|
ids,
|
|
1375
1559
|
logger,
|
|
1376
1560
|
maxTimeoutSeconds,
|
|
1561
|
+
quotes,
|
|
1377
1562
|
svm,
|
|
1378
1563
|
near
|
|
1379
1564
|
};
|
|
@@ -1392,7 +1577,14 @@ function createX402PaymentProvider(options) {
|
|
|
1392
1577
|
...severalOffers ? { selectRequirement } : {},
|
|
1393
1578
|
verify,
|
|
1394
1579
|
settle,
|
|
1395
|
-
health
|
|
1580
|
+
health,
|
|
1581
|
+
...quotes ? {
|
|
1582
|
+
quote: {
|
|
1583
|
+
issuer: quotes.issuer,
|
|
1584
|
+
requestScheme: QUOTE_REQUEST_SCHEME,
|
|
1585
|
+
extension: QUOTE_EXTENSION
|
|
1586
|
+
}
|
|
1587
|
+
} : {}
|
|
1396
1588
|
};
|
|
1397
1589
|
}
|
|
1398
1590
|
function loadOptionalModule(load, missing) {
|
|
@@ -1407,5 +1599,5 @@ function loadOptionalModule(load, missing) {
|
|
|
1407
1599
|
}
|
|
1408
1600
|
|
|
1409
1601
|
export { DEFAULT_IDS, chainIdFromCaip2, createX402PaymentProvider, parseCanonicalAmount };
|
|
1410
|
-
//# sourceMappingURL=chunk-
|
|
1411
|
-
//# sourceMappingURL=chunk-
|
|
1602
|
+
//# sourceMappingURL=chunk-CXWC5LWM.js.map
|
|
1603
|
+
//# sourceMappingURL=chunk-CXWC5LWM.js.map
|