@agent-score/commerce 2.6.3 → 2.6.4

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 (41) hide show
  1. package/dist/{checkout-C4RD7M0Z.d.ts → checkout-B-Z5_EQP.d.ts} +9 -0
  2. package/dist/{checkout-CzB9f_jf.d.mts → checkout-BtdHSF_w.d.mts} +9 -0
  3. package/dist/core.js +1 -1
  4. package/dist/core.mjs +1 -1
  5. package/dist/discovery/index.d.mts +1 -1
  6. package/dist/discovery/index.d.ts +1 -1
  7. package/dist/identity/express.js +1 -1
  8. package/dist/identity/express.js.map +1 -1
  9. package/dist/identity/express.mjs +1 -1
  10. package/dist/identity/express.mjs.map +1 -1
  11. package/dist/identity/fastify.js +1 -1
  12. package/dist/identity/fastify.js.map +1 -1
  13. package/dist/identity/fastify.mjs +1 -1
  14. package/dist/identity/fastify.mjs.map +1 -1
  15. package/dist/identity/hono.js +1 -1
  16. package/dist/identity/hono.js.map +1 -1
  17. package/dist/identity/hono.mjs +1 -1
  18. package/dist/identity/hono.mjs.map +1 -1
  19. package/dist/identity/nextjs.js +1 -1
  20. package/dist/identity/nextjs.js.map +1 -1
  21. package/dist/identity/nextjs.mjs +1 -1
  22. package/dist/identity/nextjs.mjs.map +1 -1
  23. package/dist/identity/web.js +1 -1
  24. package/dist/identity/web.js.map +1 -1
  25. package/dist/identity/web.mjs +1 -1
  26. package/dist/identity/web.mjs.map +1 -1
  27. package/dist/index.d.mts +35 -17
  28. package/dist/index.d.ts +35 -17
  29. package/dist/index.js +80 -9
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.mjs +78 -9
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/{network_kind-BIJM2peR.d.ts → network_kind-BmbWKNud.d.ts} +23 -1
  34. package/dist/{network_kind-C0EMkdzz.d.mts → network_kind-D2xpo2Fj.d.mts} +23 -1
  35. package/dist/payment/index.d.mts +27 -20
  36. package/dist/payment/index.d.ts +27 -20
  37. package/dist/payment/index.js +35 -0
  38. package/dist/payment/index.js.map +1 -1
  39. package/dist/payment/index.mjs +34 -0
  40. package/dist/payment/index.mjs.map +1 -1
  41. package/package.json +1 -1
@@ -34,6 +34,28 @@ declare function hasX402Header(input: Request | HeadersLike): boolean;
34
34
  /** True when the request carries an mppx payment credential
35
35
  * (`Authorization: Payment <jwt>`). Use to dispatch to the MPP settle path. */
36
36
  declare function hasMppxHeader(input: Request | HeadersLike): boolean;
37
+ interface MalformedPaymentCredential {
38
+ /** Which credential channel carried the malformed value. */
39
+ channel: 'x402' | 'mpp';
40
+ message: string;
41
+ }
42
+ /**
43
+ * Wire-shape gate for payment credentials, cheap enough to run before any
44
+ * merchant hook. A request whose payment header cannot possibly be a
45
+ * credential (not base64/base64url JSON, not a JWT-shaped token) is rejected
46
+ * up front, so junk headers never trigger per-request hooks (`preValidate`,
47
+ * pricing, recipient minting) or the identity-gate API call.
48
+ *
49
+ * This is deliberately a SHAPE check only. Signature verification, payTo
50
+ * binding, and challenge validation stay where they are (the x402 validator
51
+ * and the mppx settle path) — those need per-request state the hooks produce.
52
+ * A well-formed-but-invalid credential still reaches the real validators and
53
+ * fails there.
54
+ *
55
+ * Returns `null` when every present credential channel is plausibly shaped
56
+ * (or no payment header is present).
57
+ */
58
+ declare function malformedPaymentCredential(input: Request | HeadersLike): MalformedPaymentCredential | null;
37
59
 
38
60
  /**
39
61
  * USD ↔ atomic-unit conversion for token amounts.
@@ -209,4 +231,4 @@ declare function isEvmNetwork(input: NetworkLike): boolean;
209
231
  * network spec — this helper treats it as false. */
210
232
  declare function isSolanaNetwork(input: NetworkLike): boolean;
211
233
 
212
- export { type BuildDefaultCheckoutRailsOptions as B, type HeadersLike as H, type BuildMppxComposeRailsOptions as a, asHeaders as b, buildDefaultCheckoutRails as c, buildMppxComposeRails as d, hasPaymentHeader as e, formatUsdCents as f, hasX402Header as g, hasMppxHeader as h, isEvmNetwork as i, isSolanaNetwork as j, loadSolanaFeePayer as l, readHeader as r, usdToAtomic as u };
234
+ export { type BuildDefaultCheckoutRailsOptions as B, type HeadersLike as H, type MalformedPaymentCredential as M, type BuildMppxComposeRailsOptions as a, asHeaders as b, buildDefaultCheckoutRails as c, buildMppxComposeRails as d, hasPaymentHeader as e, formatUsdCents as f, hasX402Header as g, hasMppxHeader as h, isEvmNetwork as i, isSolanaNetwork as j, loadSolanaFeePayer as l, malformedPaymentCredential as m, readHeader as r, usdToAtomic as u };
@@ -34,6 +34,28 @@ declare function hasX402Header(input: Request | HeadersLike): boolean;
34
34
  /** True when the request carries an mppx payment credential
35
35
  * (`Authorization: Payment <jwt>`). Use to dispatch to the MPP settle path. */
36
36
  declare function hasMppxHeader(input: Request | HeadersLike): boolean;
37
+ interface MalformedPaymentCredential {
38
+ /** Which credential channel carried the malformed value. */
39
+ channel: 'x402' | 'mpp';
40
+ message: string;
41
+ }
42
+ /**
43
+ * Wire-shape gate for payment credentials, cheap enough to run before any
44
+ * merchant hook. A request whose payment header cannot possibly be a
45
+ * credential (not base64/base64url JSON, not a JWT-shaped token) is rejected
46
+ * up front, so junk headers never trigger per-request hooks (`preValidate`,
47
+ * pricing, recipient minting) or the identity-gate API call.
48
+ *
49
+ * This is deliberately a SHAPE check only. Signature verification, payTo
50
+ * binding, and challenge validation stay where they are (the x402 validator
51
+ * and the mppx settle path) — those need per-request state the hooks produce.
52
+ * A well-formed-but-invalid credential still reaches the real validators and
53
+ * fails there.
54
+ *
55
+ * Returns `null` when every present credential channel is plausibly shaped
56
+ * (or no payment header is present).
57
+ */
58
+ declare function malformedPaymentCredential(input: Request | HeadersLike): MalformedPaymentCredential | null;
37
59
 
38
60
  /**
39
61
  * USD ↔ atomic-unit conversion for token amounts.
@@ -209,4 +231,4 @@ declare function isEvmNetwork(input: NetworkLike): boolean;
209
231
  * network spec — this helper treats it as false. */
210
232
  declare function isSolanaNetwork(input: NetworkLike): boolean;
211
233
 
212
- export { type BuildDefaultCheckoutRailsOptions as B, type HeadersLike as H, type BuildMppxComposeRailsOptions as a, asHeaders as b, buildDefaultCheckoutRails as c, buildMppxComposeRails as d, hasPaymentHeader as e, formatUsdCents as f, hasX402Header as g, hasMppxHeader as h, isEvmNetwork as i, isSolanaNetwork as j, loadSolanaFeePayer as l, readHeader as r, usdToAtomic as u };
234
+ export { type BuildDefaultCheckoutRailsOptions as B, type HeadersLike as H, type MalformedPaymentCredential as M, type BuildMppxComposeRailsOptions as a, asHeaders as b, buildDefaultCheckoutRails as c, buildMppxComposeRails as d, hasPaymentHeader as e, formatUsdCents as f, hasX402Header as g, hasMppxHeader as h, isEvmNetwork as i, isSolanaNetwork as j, loadSolanaFeePayer as l, malformedPaymentCredential as m, readHeader as r, usdToAtomic as u };
@@ -5,7 +5,7 @@ export { B as BuildX402AcceptsForOptions, C as CreateX402ServerOptions, X as X40
5
5
  export { a as aliasAmountFields, p as paymentRequiredHeader, w as wwwAuthenticateHeader } from '../wwwauthenticate-Dgm-_af9.mjs';
6
6
  import { S as SignerNetwork } from '../signer-3FAit11j.mjs';
7
7
  export { P as PaymentSigner, e as extractPaymentSigner, a as extractPaymentSignerFromAuth, b as extractSignerForPrecheck, r as readX402PaymentHeader } from '../signer-3FAit11j.mjs';
8
- export { B as BuildDefaultCheckoutRailsOptions, a as BuildMppxComposeRailsOptions, H as HeadersLike, b as asHeaders, c as buildDefaultCheckoutRails, d as buildMppxComposeRails, f as formatUsdCents, h as hasMppxHeader, e as hasPaymentHeader, g as hasX402Header, i as isEvmNetwork, j as isSolanaNetwork, l as loadSolanaFeePayer, r as readHeader, u as usdToAtomic } from '../network_kind-C0EMkdzz.mjs';
8
+ export { B as BuildDefaultCheckoutRailsOptions, a as BuildMppxComposeRailsOptions, H as HeadersLike, M as MalformedPaymentCredential, b as asHeaders, c as buildDefaultCheckoutRails, d as buildMppxComposeRails, f as formatUsdCents, h as hasMppxHeader, e as hasPaymentHeader, g as hasX402Header, i as isEvmNetwork, j as isSolanaNetwork, l as loadSolanaFeePayer, m as malformedPaymentCredential, r as readHeader, u as usdToAtomic } from '../network_kind-D2xpo2Fj.mjs';
9
9
 
10
10
  /**
11
11
  * Build the base64-encoded `request` blob for an MPP Payment directive (per the
@@ -786,25 +786,32 @@ declare function settlementOverrideHeader(overrides: SettlementOverrides): {
786
786
  };
787
787
 
788
788
  /**
789
- * Zero-amount carve-out: skip upstream verify+settle for $0 orders.
790
- *
791
- * CDP rejects EIP-3009 `transferWithAuthorization` with `value=0` as
792
- * `invalid_payload`; `mppx`'s tempo intents accept only `hash` and
793
- * `transaction` payload types (rejecting the `proof` payload that gets
794
- * emitted for $0 settles). Both upstream verify+settle paths fail when the
795
- * authorized amount is zero, so merchants that drop the settle to $0 in a
796
- * redemption-code flow need a way to skip verify+settle entirely while
797
- * still recovering the signer for wallet-capture attribution.
798
- *
799
- * `zeroAmountCarveOut` is that path: parse the credential, lift the
800
- * signer, return `{ signerAddress, signerNetwork, txHash: null }`. Identity
801
- * is still authenticated by the merchant's gate above; the redemption code
802
- * is single-use; nothing on-chain to verify.
803
- *
804
- * The MPP path uses inline base64+JSON parsing (no `mppx` dependency at
805
- * runtime) so the zero-settle path stays dependency-free. The full
806
- * `extractPaymentSigner` path is still mppx-backed for production traffic
807
- * where the credential is a real mppx-shaped object.
789
+ * Zero-amount carve-out: skip upstream verify+settle for $0 orders on the
790
+ * rails that cannot settle $0 upstream.
791
+ *
792
+ * Scope (which rail takes the carve-out is decided in `Checkout.handleZeroSettle`):
793
+ *
794
+ * - **x402 Base**: CDP rejects EIP-3009 `transferWithAuthorization` with
795
+ * `value=0` as `invalid_payload`, so $0 x402 orders take the carve-out. The
796
+ * credential is still run through `verifyX402Request` (signature shape +
797
+ * payTo binding) before the carve-out is honored.
798
+ * - **Tempo (and other EVM MPP)**: NOT carved out. mppx >= 0.8 settles
799
+ * zero-amount challenges natively via the wallet-bound EIP-712 proof
800
+ * credential (full verification, access-key authorization, replay
801
+ * protection), so $0 Tempo orders flow through the normal MPP settle path.
802
+ * - **Solana MPP**: `@solana/mpp` has no proof-credential contract, so there
803
+ * is nothing upstream to verify a $0 credential against. The carve-out
804
+ * parses the credential and lifts the signer for wallet-capture
805
+ * attribution; that signer block is UNAUTHENTICATED (parse-only) and must
806
+ * not be trusted for anything beyond attribution hints. Identity is still
807
+ * authenticated by the merchant's gate above; redemption codes are
808
+ * single-use; nothing settles on-chain.
809
+ *
810
+ * `zeroAmountCarveOut` parses the credential, lifts the signer, and returns
811
+ * `{ signerAddress, signerNetwork, txHash: null }`. The MPP path uses inline
812
+ * base64+JSON parsing (no `mppx` dependency at runtime) so this module stays
813
+ * dependency-free; it is also how `handleZeroSettle` classifies the rail
814
+ * (Solana vs EVM did:pkh source) to decide carve-out vs delegation.
808
815
  */
809
816
 
810
817
  type ZeroSettleRail = 'x402-base' | 'tempo' | 'solana';
@@ -5,7 +5,7 @@ export { B as BuildX402AcceptsForOptions, C as CreateX402ServerOptions, X as X40
5
5
  export { a as aliasAmountFields, p as paymentRequiredHeader, w as wwwAuthenticateHeader } from '../wwwauthenticate-Dgm-_af9.js';
6
6
  import { S as SignerNetwork } from '../signer-3FAit11j.js';
7
7
  export { P as PaymentSigner, e as extractPaymentSigner, a as extractPaymentSignerFromAuth, b as extractSignerForPrecheck, r as readX402PaymentHeader } from '../signer-3FAit11j.js';
8
- export { B as BuildDefaultCheckoutRailsOptions, a as BuildMppxComposeRailsOptions, H as HeadersLike, b as asHeaders, c as buildDefaultCheckoutRails, d as buildMppxComposeRails, f as formatUsdCents, h as hasMppxHeader, e as hasPaymentHeader, g as hasX402Header, i as isEvmNetwork, j as isSolanaNetwork, l as loadSolanaFeePayer, r as readHeader, u as usdToAtomic } from '../network_kind-BIJM2peR.js';
8
+ export { B as BuildDefaultCheckoutRailsOptions, a as BuildMppxComposeRailsOptions, H as HeadersLike, M as MalformedPaymentCredential, b as asHeaders, c as buildDefaultCheckoutRails, d as buildMppxComposeRails, f as formatUsdCents, h as hasMppxHeader, e as hasPaymentHeader, g as hasX402Header, i as isEvmNetwork, j as isSolanaNetwork, l as loadSolanaFeePayer, m as malformedPaymentCredential, r as readHeader, u as usdToAtomic } from '../network_kind-BmbWKNud.js';
9
9
 
10
10
  /**
11
11
  * Build the base64-encoded `request` blob for an MPP Payment directive (per the
@@ -786,25 +786,32 @@ declare function settlementOverrideHeader(overrides: SettlementOverrides): {
786
786
  };
787
787
 
788
788
  /**
789
- * Zero-amount carve-out: skip upstream verify+settle for $0 orders.
790
- *
791
- * CDP rejects EIP-3009 `transferWithAuthorization` with `value=0` as
792
- * `invalid_payload`; `mppx`'s tempo intents accept only `hash` and
793
- * `transaction` payload types (rejecting the `proof` payload that gets
794
- * emitted for $0 settles). Both upstream verify+settle paths fail when the
795
- * authorized amount is zero, so merchants that drop the settle to $0 in a
796
- * redemption-code flow need a way to skip verify+settle entirely while
797
- * still recovering the signer for wallet-capture attribution.
798
- *
799
- * `zeroAmountCarveOut` is that path: parse the credential, lift the
800
- * signer, return `{ signerAddress, signerNetwork, txHash: null }`. Identity
801
- * is still authenticated by the merchant's gate above; the redemption code
802
- * is single-use; nothing on-chain to verify.
803
- *
804
- * The MPP path uses inline base64+JSON parsing (no `mppx` dependency at
805
- * runtime) so the zero-settle path stays dependency-free. The full
806
- * `extractPaymentSigner` path is still mppx-backed for production traffic
807
- * where the credential is a real mppx-shaped object.
789
+ * Zero-amount carve-out: skip upstream verify+settle for $0 orders on the
790
+ * rails that cannot settle $0 upstream.
791
+ *
792
+ * Scope (which rail takes the carve-out is decided in `Checkout.handleZeroSettle`):
793
+ *
794
+ * - **x402 Base**: CDP rejects EIP-3009 `transferWithAuthorization` with
795
+ * `value=0` as `invalid_payload`, so $0 x402 orders take the carve-out. The
796
+ * credential is still run through `verifyX402Request` (signature shape +
797
+ * payTo binding) before the carve-out is honored.
798
+ * - **Tempo (and other EVM MPP)**: NOT carved out. mppx >= 0.8 settles
799
+ * zero-amount challenges natively via the wallet-bound EIP-712 proof
800
+ * credential (full verification, access-key authorization, replay
801
+ * protection), so $0 Tempo orders flow through the normal MPP settle path.
802
+ * - **Solana MPP**: `@solana/mpp` has no proof-credential contract, so there
803
+ * is nothing upstream to verify a $0 credential against. The carve-out
804
+ * parses the credential and lifts the signer for wallet-capture
805
+ * attribution; that signer block is UNAUTHENTICATED (parse-only) and must
806
+ * not be trusted for anything beyond attribution hints. Identity is still
807
+ * authenticated by the merchant's gate above; redemption codes are
808
+ * single-use; nothing settles on-chain.
809
+ *
810
+ * `zeroAmountCarveOut` parses the credential, lifts the signer, and returns
811
+ * `{ signerAddress, signerNetwork, txHash: null }`. The MPP path uses inline
812
+ * base64+JSON parsing (no `mppx` dependency at runtime) so this module stays
813
+ * dependency-free; it is also how `handleZeroSettle` classifies the rail
814
+ * (Solana vs EVM did:pkh source) to decide carve-out vs delegation.
808
815
  */
809
816
 
810
817
  type ZeroSettleRail = 'x402-base' | 'tempo' | 'solana';
@@ -53,6 +53,7 @@ __export(payment_exports, {
53
53
  lazyX402Server: () => lazyX402Server,
54
54
  loadSolanaFeePayer: () => loadSolanaFeePayer,
55
55
  lookupRail: () => lookupRail,
56
+ malformedPaymentCredential: () => malformedPaymentCredential,
56
57
  mppxChallengeHeaders: () => mppxChallengeHeaders,
57
58
  networkFamily: () => networkFamily,
58
59
  networks: () => networks,
@@ -1427,6 +1428,39 @@ function hasMppxHeader(input) {
1427
1428
  const headers = asHeaders(input);
1428
1429
  return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
1429
1430
  }
1431
+ var JWT_SHAPE_RE = /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/;
1432
+ function decodesToJsonObject(token) {
1433
+ try {
1434
+ const parsed = JSON.parse(Buffer.from(token, "base64").toString("utf8"));
1435
+ return typeof parsed === "object" && parsed !== null;
1436
+ } catch {
1437
+ return false;
1438
+ }
1439
+ }
1440
+ function malformedPaymentCredential(input) {
1441
+ const headers = asHeaders(input);
1442
+ const x402Token = readHeader(headers, "payment-signature") ?? readHeader(headers, "x-payment");
1443
+ if (x402Token !== null && x402Token.length > 0) {
1444
+ if (!decodesToJsonObject(x402Token)) {
1445
+ return {
1446
+ channel: "x402",
1447
+ message: "X-Payment header is not decodable base64 JSON."
1448
+ };
1449
+ }
1450
+ return null;
1451
+ }
1452
+ const auth = readHeader(headers, "authorization");
1453
+ if (auth !== null && auth.startsWith("Payment ")) {
1454
+ const token = auth.slice("Payment ".length).trim();
1455
+ if (token.length === 0 || !decodesToJsonObject(token) && !JWT_SHAPE_RE.test(token)) {
1456
+ return {
1457
+ channel: "mpp",
1458
+ message: "Authorization: Payment credential is neither base64-encoded JSON nor a token-shaped value."
1459
+ };
1460
+ }
1461
+ }
1462
+ return null;
1463
+ }
1430
1464
 
1431
1465
  // src/payment/network_kind.ts
1432
1466
  function readNetwork(input) {
@@ -1478,6 +1512,7 @@ function isSolanaNetwork(input) {
1478
1512
  lazyX402Server,
1479
1513
  loadSolanaFeePayer,
1480
1514
  lookupRail,
1515
+ malformedPaymentCredential,
1481
1516
  mppxChallengeHeaders,
1482
1517
  networkFamily,
1483
1518
  networks,