@agent-score/commerce 1.8.1 → 2.0.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 (90) hide show
  1. package/README.md +73 -9
  2. package/dist/{_response-9yp6Fit2.d.mts → _response-BFYN3b6i.d.mts} +17 -19
  3. package/dist/{_response-CC6jNb8q.d.ts → _response-_iPD5AIj.d.ts} +17 -19
  4. package/dist/challenge/index.d.mts +106 -198
  5. package/dist/challenge/index.d.ts +106 -198
  6. package/dist/challenge/index.js +238 -111
  7. package/dist/challenge/index.js.map +1 -1
  8. package/dist/challenge/index.mjs +238 -111
  9. package/dist/challenge/index.mjs.map +1 -1
  10. package/dist/checkout-B1JuEcbx.d.ts +939 -0
  11. package/dist/checkout-BN5i1Fi7.d.mts +939 -0
  12. package/dist/core.d.mts +2 -2
  13. package/dist/core.d.ts +2 -2
  14. package/dist/core.js +1 -1
  15. package/dist/core.js.map +1 -1
  16. package/dist/core.mjs +1 -1
  17. package/dist/core.mjs.map +1 -1
  18. package/dist/discovery/index.d.mts +453 -51
  19. package/dist/discovery/index.d.ts +453 -51
  20. package/dist/discovery/index.js +1092 -58
  21. package/dist/discovery/index.js.map +1 -1
  22. package/dist/discovery/index.mjs +1060 -57
  23. package/dist/discovery/index.mjs.map +1 -1
  24. package/dist/identity/express.d.mts +3 -3
  25. package/dist/identity/express.d.ts +3 -3
  26. package/dist/identity/express.js +30 -19
  27. package/dist/identity/express.js.map +1 -1
  28. package/dist/identity/express.mjs +30 -19
  29. package/dist/identity/express.mjs.map +1 -1
  30. package/dist/identity/fastify.d.mts +4 -4
  31. package/dist/identity/fastify.d.ts +4 -4
  32. package/dist/identity/fastify.js +30 -19
  33. package/dist/identity/fastify.js.map +1 -1
  34. package/dist/identity/fastify.mjs +30 -19
  35. package/dist/identity/fastify.mjs.map +1 -1
  36. package/dist/identity/hono.d.mts +3 -3
  37. package/dist/identity/hono.d.ts +3 -3
  38. package/dist/identity/hono.js +30 -19
  39. package/dist/identity/hono.js.map +1 -1
  40. package/dist/identity/hono.mjs +30 -19
  41. package/dist/identity/hono.mjs.map +1 -1
  42. package/dist/identity/nextjs.d.mts +6 -7
  43. package/dist/identity/nextjs.d.ts +6 -7
  44. package/dist/identity/nextjs.js +30 -19
  45. package/dist/identity/nextjs.js.map +1 -1
  46. package/dist/identity/nextjs.mjs +30 -19
  47. package/dist/identity/nextjs.mjs.map +1 -1
  48. package/dist/identity/policy.d.mts +41 -4
  49. package/dist/identity/policy.d.ts +41 -4
  50. package/dist/identity/policy.js +23307 -18
  51. package/dist/identity/policy.js.map +1 -1
  52. package/dist/identity/policy.mjs +23313 -3
  53. package/dist/identity/policy.mjs.map +1 -1
  54. package/dist/identity/web.d.mts +3 -3
  55. package/dist/identity/web.d.ts +3 -3
  56. package/dist/identity/web.js +30 -19
  57. package/dist/identity/web.js.map +1 -1
  58. package/dist/identity/web.mjs +30 -19
  59. package/dist/identity/web.mjs.map +1 -1
  60. package/dist/index.d.mts +72 -329
  61. package/dist/index.d.ts +72 -329
  62. package/dist/index.js +23301 -378
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +23294 -362
  65. package/dist/index.mjs.map +1 -1
  66. package/dist/payment/index.d.mts +297 -265
  67. package/dist/payment/index.d.ts +297 -265
  68. package/dist/payment/index.js +605 -149
  69. package/dist/payment/index.js.map +1 -1
  70. package/dist/payment/index.mjs +590 -148
  71. package/dist/payment/index.mjs.map +1 -1
  72. package/dist/{agent_instructions-DiMSGkdm.d.mts → pricing-CQ9DIFaw.d.ts} +109 -56
  73. package/dist/{agent_instructions-DiMSGkdm.d.ts → pricing-CxzwyiO6.d.mts} +109 -56
  74. package/dist/rail_spec-XP0wKgJV.d.mts +132 -0
  75. package/dist/rail_spec-XP0wKgJV.d.ts +132 -0
  76. package/dist/{signer-CFVQsWjL.d.mts → signer-3FAit11j.d.mts} +27 -1
  77. package/dist/{signer-CFVQsWjL.d.ts → signer-3FAit11j.d.ts} +27 -1
  78. package/dist/solana-Cds87OTu.d.mts +67 -0
  79. package/dist/solana-Cds87OTu.d.ts +67 -0
  80. package/dist/stripe-multichain/index.d.mts +55 -66
  81. package/dist/stripe-multichain/index.d.ts +55 -66
  82. package/dist/stripe-multichain/index.js +68 -42
  83. package/dist/stripe-multichain/index.js.map +1 -1
  84. package/dist/stripe-multichain/index.mjs +68 -41
  85. package/dist/stripe-multichain/index.mjs.map +1 -1
  86. package/dist/{wwwauthenticate-CU1eNvMQ.d.mts → wwwauthenticate-D_FMnPgU.d.mts} +9 -10
  87. package/dist/{wwwauthenticate-CU1eNvMQ.d.ts → wwwauthenticate-D_FMnPgU.d.ts} +9 -10
  88. package/dist/x402_server-hgQzWQwB.d.mts +81 -0
  89. package/dist/x402_server-hgQzWQwB.d.ts +81 -0
  90. package/package.json +9 -7
@@ -1,7 +1,20 @@
1
- export { P as PaymentRequiredHeaderInput, a as aliasAmountFields, p as paymentRequiredHeader, w as wwwAuthenticateHeader } from '../wwwauthenticate-CU1eNvMQ.js';
2
- export { P as PaymentSigner, S as SignerNetwork, e as extractPaymentSigner, r as readX402PaymentHeader } from '../signer-CFVQsWjL.js';
1
+ import { T as TempoRailSpec, S as SolanaMppRailSpec, a as TempoSessionRailSpec, b as StripeRailSpec, X as X402BaseRailSpec } from '../rail_spec-XP0wKgJV.js';
2
+ export { R as RAIL_SPEC_DEFAULTS, c as RecipientLike, r as resolveRecipient } from '../rail_spec-XP0wKgJV.js';
3
+ import { X as X402Server } from '../x402_server-hgQzWQwB.js';
4
+ export { B as BuildX402AcceptsForOptions, C as CreateX402ServerOptions, a as X402FacilitatorChoice, b as X402SymbolicRail, c as buildX402AcceptsFor402, d as createX402Server } from '../x402_server-hgQzWQwB.js';
5
+ export { a as aliasAmountFields, p as paymentRequiredHeader, w as wwwAuthenticateHeader } from '../wwwauthenticate-D_FMnPgU.js';
6
+ import { S as SignerNetwork } from '../signer-3FAit11j.js';
7
+ export { P as PaymentSigner, e as extractPaymentSigner, a as extractPaymentSignerFromAuth, b as extractSignerForPrecheck, r as readX402PaymentHeader } from '../signer-3FAit11j.js';
8
+ export { f as formatUsdCents, l as loadSolanaFeePayer, u as usdToAtomic } from '../solana-Cds87OTu.js';
3
9
 
4
- interface PaymentRequestInput {
10
+ /**
11
+ * Build the base64-encoded `request` blob for an MPP Payment directive (per the
12
+ * paymentauth.org spec). Output shape matches what link-cli `mpp decode` expects:
13
+ *
14
+ * { amount: "<raw_integer>", currency: "<token>", recipient?: "<addr>",
15
+ * methodDetails?: { chainId?: number, networkId?: string } }
16
+ */
17
+ declare function buildPaymentRequestBlob({ rail, amountUsd, currency, decimals, recipient, chainId, networkId, }: {
5
18
  /** Symbolic rail name (e.g., 'tempo-mainnet', 'x402-base-mainnet') — fills in defaults */
6
19
  rail?: string;
7
20
  /** Amount in USD as a number or string. Converted to raw integer using `decimals`. */
@@ -16,16 +29,13 @@ interface PaymentRequestInput {
16
29
  chainId?: number;
17
30
  /** Stripe profile_id or similar (goes into methodDetails.networkId — note camelCase per link-cli's mpp decode validator). */
18
31
  networkId?: string;
19
- }
32
+ }): string;
20
33
  /**
21
- * Build the base64-encoded `request` blob for an MPP Payment directive (per the
22
- * paymentauth.org spec). Output shape matches what link-cli `mpp decode` expects:
23
- *
24
- * { amount: "<raw_integer>", currency: "<token>", recipient?: "<addr>",
25
- * methodDetails?: { chainId?: number, networkId?: string } }
34
+ * Format an MPP Payment directive string for the WWW-Authenticate header.
35
+ * Output shape: `Payment id="...", realm="...", method="...", intent="charge",
36
+ * expires="...", request="<base64>"`
26
37
  */
27
- declare function buildPaymentRequestBlob(input: PaymentRequestInput): string;
28
- interface PaymentDirectiveInput {
38
+ declare function paymentDirective({ rail, id, realm, method, intent, expires, request, }: {
29
39
  /** Symbolic rail name — sets `method` automatically */
30
40
  rail?: string;
31
41
  /** Challenge id (unique per request, used to correlate retries) */
@@ -40,21 +50,25 @@ interface PaymentDirectiveInput {
40
50
  expires?: string;
41
51
  /** Base64-encoded request blob. Pass the result of buildPaymentRequestBlob. */
42
52
  request: string;
43
- }
44
- /**
45
- * Format an MPP Payment directive string for the WWW-Authenticate header.
46
- * Output shape: `Payment id="...", realm="...", method="...", intent="charge",
47
- * expires="...", request="<base64>"`
48
- */
49
- declare function paymentDirective(input: PaymentDirectiveInput): string;
50
- interface BuildPaymentDirectiveInput extends Omit<PaymentRequestInput, 'rail'>, Omit<PaymentDirectiveInput, 'request'> {
51
- rail: string;
52
- }
53
+ }): string;
53
54
  /**
54
55
  * Convenience: build the request blob and the directive in one call. Most vendors
55
56
  * want this rather than the two-step form.
56
57
  */
57
- declare function buildPaymentDirective(input: BuildPaymentDirectiveInput): string;
58
+ declare function buildPaymentDirective({ rail, id, realm, amountUsd, currency, decimals, recipient, chainId, networkId, method, intent, expires, }: {
59
+ rail: string;
60
+ id: string;
61
+ realm: string;
62
+ amountUsd: string | number;
63
+ currency?: string;
64
+ decimals?: number;
65
+ recipient?: string;
66
+ chainId?: number;
67
+ networkId?: string;
68
+ method?: string;
69
+ intent?: string;
70
+ expires?: string;
71
+ }): string;
58
72
 
59
73
  /**
60
74
  * Named network registry. Vendors reference symbolic names (`networks.base.mainnet.caip2`)
@@ -244,86 +258,6 @@ interface X402ServerLike {
244
258
  */
245
259
  declare function registerX402SchemesV1V2(server: X402ServerLike, network: string, scheme: unknown): void;
246
260
 
247
- type X402SymbolicRail = 'x402-base-mainnet' | 'x402-base-sepolia' | 'x402-base-mainnet-upto' | 'x402-base-sepolia-upto';
248
- type X402FacilitatorChoice = 'coinbase' | 'http' | unknown;
249
- interface CreateX402ServerOptions {
250
- /**
251
- * Facilitator selection:
252
- * - 'coinbase' → Coinbase CDP facilitator (requires `@coinbase/x402` installed)
253
- * - 'http' → HTTP-only public testnet facilitator
254
- * - any object → custom facilitator instance, used directly
255
- * - omitted → defaults to 'http'
256
- */
257
- facilitator?: X402FacilitatorChoice;
258
- /**
259
- * Symbolic rail names to register schemes for. Each gets v1+v2 dual-register applied.
260
- * Requires `@x402/evm` peer dep installed.
261
- */
262
- rails?: X402SymbolicRail[];
263
- /** Advanced: register custom {network, scheme} pairs (in addition to or instead of `rails`). */
264
- schemes?: {
265
- network: string;
266
- scheme: unknown;
267
- }[];
268
- /** Register the Bazaar discovery extension. Requires `@x402/extensions` installed. */
269
- bazaar?: boolean;
270
- /** Initialize the server immediately (calls facilitator). Default true. */
271
- initialize?: boolean;
272
- }
273
- /**
274
- * Loose type for the x402 resource server. We name the methods commerce calls during
275
- * setup; everything else (settlePayment, buildPaymentRequirements, processPaymentRequest,
276
- * enrichExtensions, etc.) is callable via the index signature so vendor code can use the
277
- * full @x402/core surface without us having to mirror every method signature.
278
- */
279
- interface X402Server {
280
- register(network: string, scheme: unknown): void;
281
- registerV1?(network: string, scheme: unknown): void;
282
- registerExtension(ext: unknown): void;
283
- initialize(): Promise<void>;
284
- [key: string]: any;
285
- }
286
- /**
287
- * One-call x402 server setup. Resolves facilitator, constructs the server, registers
288
- * schemes per network with v1+v2 dual-register, optionally adds the Bazaar extension,
289
- * and initializes — replaces ~15 lines of boilerplate with a single config call.
290
- *
291
- * x402 packages are peer dependencies — vendors install only the schemes they use.
292
- * Throws a guiding error if a required peer is missing.
293
- *
294
- * const server = await createX402Server({
295
- * facilitator: 'coinbase',
296
- * rails: ['x402-base-mainnet'],
297
- * bazaar: true,
298
- * });
299
- */
300
- declare function createX402Server(opts?: CreateX402ServerOptions): Promise<X402Server>;
301
- interface BuildX402AcceptsForOptions {
302
- network: string;
303
- price: string;
304
- payTo: string;
305
- scheme?: string;
306
- maxTimeoutSeconds?: number;
307
- extensions?: string[];
308
- }
309
- /**
310
- * Build x402 `accepts[]` entries for a 402 challenge body.
311
- *
312
- * Wraps `server.buildPaymentRequirements(...)` so merchants don't have to:
313
- *
314
- * 1. Construct the resource-config object themselves
315
- * 2. Remember to serialize each Pydantic-equivalent requirement back to a
316
- * plain object before stitching it into the 402 body
317
- * 3. Hardcode `extra` (which differs by the actual on-chain contract — base
318
- * mainnet USDC has `name: "USD Coin"`, base sepolia USDC has `name: "USDC"`;
319
- * EIP-712 domain hashes differ, so getting this wrong silently breaks every
320
- * signature verify at the facilitator)
321
- *
322
- * Returns a list of plain objects in the shape that x402 expects on the wire —
323
- * drop them straight into the `accepts` field of the 402 challenge body.
324
- */
325
- declare function buildX402AcceptsFor402(server: X402Server, opts: BuildX402AcceptsForOptions): Promise<unknown[]>;
326
-
327
261
  /**
328
262
  * `processX402Settle`: single-call x402 verify+settle for merchants.
329
263
  *
@@ -341,26 +275,6 @@ declare function buildX402AcceptsFor402(server: X402Server, opts: BuildX402Accep
341
275
  * map the tagged result to a recommended HTTP response.
342
276
  */
343
277
 
344
- interface ProcessX402SettleInput {
345
- /** The x402 server instance from `createX402Server`. */
346
- x402Server: X402Server;
347
- /** The verified x402 payload extracted from the X-Payment header. */
348
- payload: unknown;
349
- /** Resource configuration the facilitator validates against (network, price, payTo,
350
- * asset, maxTimeoutSeconds, etc.). Shape is x402-server-specific. */
351
- resourceConfig: unknown;
352
- /** Resource metadata exposed to the facilitator (URL, description, mime type). */
353
- resourceMeta: {
354
- url: string;
355
- description: string;
356
- mimeType: string;
357
- };
358
- /** Optional extension to enrich during verify (e.g. Bazaar). */
359
- extension?: unknown;
360
- /** Transport context for the extension enrich step. Defaults to `{ method: 'POST',
361
- * adapter: { getPath: () => new URL(resourceMeta.url).pathname }, routePattern: <pathname> }`. */
362
- transportContext?: unknown;
363
- }
364
278
  type ProcessX402SettleResult = {
365
279
  success: true;
366
280
  /** The matched requirement passed to `settlePayment`. */
@@ -420,7 +334,7 @@ type ProcessX402SettleResult = {
420
334
  * so the agent can pick a different rail. */
421
335
  phase: 'facilitator_error';
422
336
  /** Which verify-stage step threw. */
423
- step: 'build_requirements' | 'enrich_extensions' | 'process_payment_request';
337
+ step: 'build_requirements' | 'enrich_extensions' | 'verify_payment';
424
338
  error: unknown;
425
339
  };
426
340
  /**
@@ -459,7 +373,49 @@ interface ClassifiedX402Error {
459
373
  * is intentionally facilitator-agnostic and never carries raw error detail.
460
374
  */
461
375
  declare function classifyX402SettleResult(result: ProcessX402SettleResult): ClassifiedX402Error | null;
462
- declare function processX402Settle(input: ProcessX402SettleInput): Promise<ProcessX402SettleResult>;
376
+ /**
377
+ * Classify a thrown error during the 402 orchestration.
378
+ *
379
+ * Catches errors that escape `processX402Settle` (e.g. raised by `mppx.compose`,
380
+ * a Stripe SDK call, or any other payment-side library code wrapped in a single
381
+ * `try/catch` around the full settle flow). Returns a `ClassifiedX402Error`
382
+ * when the error message matches a known pattern; `null` otherwise.
383
+ *
384
+ * Callers should rethrow on `null` — this helper never swallows unknown errors.
385
+ *
386
+ * Pattern matching is case-insensitive substring on the error message:
387
+ * - `"x402version"` / `"invalid payment"` / `"unsupported x402"` →
388
+ * 400 `payment_proof_invalid` / `regenerate_payment_credential`
389
+ * - `"stripe"` / `"facilitator"` / `"cdp"` →
390
+ * 503 `payment_provider_unavailable` / `retry_or_swap_method`
391
+ * - Anything else → `null` (caller rethrows)
392
+ *
393
+ * Substring matching is intentionally narrow. New error families should land
394
+ * here explicitly rather than have the helper grow opaque heuristics. For
395
+ * tagged failure results that already classify themselves, use
396
+ * `classifyX402SettleResult`.
397
+ */
398
+ declare function classifyOrchestrationError(err: unknown): ClassifiedX402Error | null;
399
+ declare function processX402Settle({ x402Server, payload, resourceConfig, resourceMeta, extension, transportContext, }: {
400
+ /** The x402 server instance from `createX402Server`. */
401
+ x402Server: X402Server;
402
+ /** The verified x402 payload extracted from the X-Payment header. */
403
+ payload: unknown;
404
+ /** Resource configuration the facilitator validates against (network, price, payTo,
405
+ * asset, maxTimeoutSeconds, etc.). Shape is x402-server-specific. */
406
+ resourceConfig: unknown;
407
+ /** Resource metadata exposed to the facilitator (URL, description, mime type). */
408
+ resourceMeta: {
409
+ url: string;
410
+ description: string;
411
+ mimeType: string;
412
+ };
413
+ /** Optional extension to enrich during verify (e.g. Bazaar). */
414
+ extension?: unknown;
415
+ /** Transport context for the extension enrich step. Defaults to `{ method: 'POST',
416
+ * adapter: { getPath: () => new URL(resourceMeta.url).pathname }, routePattern: <pathname> }`. */
417
+ transportContext?: unknown;
418
+ }): Promise<ProcessX402SettleResult>;
463
419
 
464
420
  /**
465
421
  * x402 boot-time + per-request validation helpers.
@@ -478,10 +434,6 @@ declare function processX402Settle(input: ProcessX402SettleInput): Promise<Proce
478
434
  */
479
435
  /** CAIP-2 networks the commerce SDK supports for x402 Base (EVM USDC). */
480
436
  declare const X402_SUPPORTED_BASE_NETWORKS: Set<string>;
481
- interface ValidateX402NetworkConfigInput {
482
- /** CAIP-2 base network string (e.g. `'eip155:8453'`). */
483
- baseNetwork: string;
484
- }
485
437
  /**
486
438
  * Boot-time guard: throws if the base network isn't supported. Call once at module
487
439
  * init / server boot.
@@ -490,17 +442,9 @@ interface ValidateX402NetworkConfigInput {
490
442
  * options — agents tracking down a misconfigured deploy don't need to grep for the
491
443
  * supported list.
492
444
  */
493
- declare function validateX402NetworkConfig(input: ValidateX402NetworkConfigInput): void;
494
- interface VerifyX402RequestInput {
495
- /** The incoming Request — `verifyX402Request` reads the X-Payment / payment-signature header. */
496
- request: Request;
497
- /** Async lookup that returns true when the address was minted by this merchant
498
- * (typically `piCache.hasAddress`). The check validates that the credential's
499
- * deposit address matches one the merchant actually minted. */
500
- isCachedAddress: (address: string) => Promise<boolean>;
501
- /** The merchant's accepted Base network. CAIP-2, e.g. `'eip155:8453'`. */
502
- acceptedNetwork: string;
503
- }
445
+ declare function validateX402NetworkConfig({ baseNetwork }: {
446
+ baseNetwork: string;
447
+ }): void;
504
448
  type VerifyX402RequestResult = {
505
449
  ok: true;
506
450
  /** The base64-decoded JSON payload from the X-Payment header. */
@@ -549,108 +493,43 @@ type VerifyX402RequestResult = {
549
493
  * Reads the header from `payment-signature` first, falling back to `x-payment` (both
550
494
  * are in the wild as the binary-friendly transport name evolved).
551
495
  */
552
- declare function verifyX402Request(input: VerifyX402RequestInput): Promise<VerifyX402RequestResult>;
496
+ declare function verifyX402Request({ request, isCachedAddress, acceptedNetwork, }: {
497
+ /** The incoming Request — `verifyX402Request` reads the X-Payment / payment-signature header. */
498
+ request: Request;
499
+ /** Async lookup that returns true when the address was minted by this merchant
500
+ * (typically `piCache.hasAddress`). The check validates that the credential's
501
+ * deposit address matches one the merchant actually minted. */
502
+ isCachedAddress: (address: string) => Promise<boolean>;
503
+ /** The merchant's accepted Base network. CAIP-2, e.g. `'eip155:8453'`. */
504
+ acceptedNetwork: string;
505
+ }): Promise<VerifyX402RequestResult>;
553
506
 
554
- type SolanaMppNetwork = 'mainnet-beta' | 'devnet' | 'localnet';
555
- interface CreateMppxServerOptions {
556
- /** Symbolic rail config — commerce wires the boilerplate (tempo.charge, mppStripe.charge, solana.charge, etc.). */
557
- rails?: {
558
- /** One-shot Tempo USDC charge (intent: 'charge'). */
559
- tempo?: {
560
- recipient: string;
561
- /** Custom currency token. Default: USDC on Tempo. */
562
- currency?: string;
563
- /** Use Tempo testnet (Moderato). Default false. */
564
- testnet?: boolean;
565
- };
566
- /**
567
- * Solana SPL charge (intent: 'charge'). Bakes createAssociatedTokenIdempotent
568
- * into the buyer's tx so payments work against any payTo, fresh or warmed.
569
- *
570
- * Requires `@solana/mpp` + `@solana/kit` peer deps.
571
- * Underlying spec: paymentauth.org/draft-solana-charge-00.
572
- */
573
- solana?: {
574
- /** Base58-encoded Solana recipient public key. */
575
- recipient: string;
576
- /** SPL token mint (base58). Default: USDC for the selected network. */
577
- currency?: string;
578
- /** Token decimals. Default 6 (USDC). */
579
- decimals?: number;
580
- /** Solana network. Default 'mainnet-beta'. */
581
- network?: SolanaMppNetwork;
582
- /** Custom RPC URL. Default: public RPC for the network. */
583
- rpcUrl?: string;
584
- /**
585
- * Optional fee-payer signer for server-side fee sponsorship. When provided,
586
- * the server's pubkey is advertised as `feePayerKey` in the 402 challenge and
587
- * the server co-signs settle txs as fee payer (so buyers don't need SOL, and
588
- * ATA-creation rent is server-funded). Construct via
589
- * `@solana/kit`'s `createKeyPairSignerFromBytes` or equivalent.
590
- *
591
- * Typed as `unknown` to avoid a hard dep on @solana/kit at this layer; pass any
592
- * `TransactionPartialSigner` from `@solana/kit`.
593
- */
594
- signer?: unknown;
595
- /** SPL token program hint (TOKEN_PROGRAM or TOKEN_2022_PROGRAM). Auto-detected when omitted. */
596
- tokenProgram?: string;
597
- };
598
- /**
599
- * Tempo session (intent: 'session') — pay-as-you-go channel for repeated calls or
600
- * SSE-streamed responses. Vendor brings their own ChannelStore (DB-backed implementation
601
- * tracking open channels + voucher state) and an `escrowContract` address.
602
- */
603
- tempo_session?: {
604
- recipient: string;
605
- currency?: string;
606
- testnet?: boolean;
607
- /**
608
- * On-chain escrow contract address that holds channel deposits and pays out
609
- * cumulative vouchers on settlement. Vendor-deployed.
610
- */
611
- escrowContract: string;
612
- /**
613
- * Channel store implementation tracking open channels + cumulative voucher state.
614
- * Pass an instance of mppx's `ChannelStore` interface (you can use the in-memory
615
- * default for dev or implement a Postgres/Redis-backed store for production).
616
- */
617
- store: unknown;
618
- /** Optional supported chains; defaults to mppx defaults. */
619
- chains?: unknown;
620
- };
621
- /** Stripe SPT (Shared Payment Token) — see also @agent-score/commerce/stripe-multichain. */
622
- stripe?: {
623
- profileId: string;
624
- secretKey: string;
625
- paymentMethodTypes?: string[];
626
- };
627
- };
628
- /** Advanced: pass mppx method instances directly (in addition to or instead of `rails`). */
629
- methods?: unknown[];
630
- /** MPP secret key (merchant's). */
631
- secretKey: string;
632
- }
507
+ type MppxRailSpec = TempoRailSpec | SolanaMppRailSpec | TempoSessionRailSpec | StripeRailSpec;
633
508
  /**
634
- * One-call mppx server setup. Wires `tempo.charge(...)`, `tempo.session(...)`, and Stripe SPT
635
- * (via createMppxStripe) from symbolic rail config, replacing the boilerplate of constructing
636
- * each method by hand.
509
+ * One-call mppx server setup. Wires `tempo.charge(...)`, `tempo.session(...)`,
510
+ * `@solana/mpp.charge(...)`, and Stripe SPT (via createMppxStripe) from canonical
511
+ * `*RailSpec` configs, replacing the boilerplate of constructing each method by
512
+ * hand.
637
513
  *
638
514
  * const mppx = await createMppxServer({
639
515
  * rails: {
640
- * tempo: { recipient: TEMPO_ADDR, testnet: false }, // intent: 'charge'
641
- * tempo_session: { // intent: 'session'
642
- * recipient: TEMPO_ADDR,
643
- * escrowContract: ESCROW_ADDR,
644
- * store: myChannelStore,
645
- * },
646
- * stripe: { profileId: STRIPE_PROFILE_ID, secretKey: STRIPE_SECRET_KEY },
516
+ * tempo: { recipient: TEMPO_ADDR } satisfies TempoRailSpec,
517
+ * solana: { recipient: SOL_ADDR } satisfies SolanaMppRailSpec,
518
+ * stripe: { profileId: STRIPE_PROFILE_ID, secretKey: STRIPE_SECRET_KEY } satisfies StripeRailSpec,
647
519
  * },
648
520
  * secretKey: MPP_SECRET_KEY,
649
521
  * });
650
522
  *
523
+ * Keys are rail names (`tempo` / `solana` / `tempo_session` / `stripe`); values
524
+ * are the matching `*RailSpec` types every other helper also consumes.
525
+ *
651
526
  * `mppx` is an OPTIONAL peer dependency — install it only if you accept MPP rails.
652
527
  */
653
- declare function createMppxServer(opts: CreateMppxServerOptions): Promise<unknown>;
528
+ declare function createMppxServer({ rails, methods: extraMethods, secretKey, }: {
529
+ rails?: Record<string, MppxRailSpec>;
530
+ methods?: unknown[];
531
+ secretKey: string;
532
+ }): Promise<unknown>;
654
533
  type SolanaChargeRequestArgs = {
655
534
  credential?: unknown;
656
535
  request?: unknown;
@@ -673,7 +552,66 @@ type SolanaChargeMethod = {
673
552
  * Fine for agent-driven flows; manual signing flows still have plenty of margin.
674
553
  */
675
554
  declare function wrapSolanaChargeWithFinalizedBlockhash(baseMethod: SolanaChargeMethod, rpcUrl: string): SolanaChargeMethod;
555
+ /**
556
+ * Result shape of `composeMppxRequest`. mppx's `mppx.compose(...)(request)`
557
+ * resolves to one of two variants — type-narrowed here so consumers can
558
+ * `if (result.status === 200) { result.withReceipt(...) }` without an
559
+ * `as any` cast.
560
+ */
561
+ type MppxComposeResult = {
562
+ status: 200;
563
+ /** Wraps a Response with the `Payment-Receipt` header attached. */
564
+ withReceipt: (response: Response) => Response;
565
+ [k: string]: unknown;
566
+ } | {
567
+ status: 402;
568
+ /** The 402 challenge Response mppx emitted (carries WWW-Authenticate). */
569
+ challenge: Response;
570
+ [k: string]: unknown;
571
+ };
572
+ /**
573
+ * Run `mppx.compose(...intents)(request)` with a typed return. Replaces the
574
+ * `(mppx as any).compose(...intents)(request)` cast every hand-rolled
575
+ * `composeMppx` hook ends up writing.
576
+ *
577
+ * @example
578
+ * ```ts
579
+ * const result = await composeMppxRequest(mppx, [
580
+ * ['tempo/charge', { amount, currency, decimals, recipient }],
581
+ * ['stripe/charge', { amount, currency: 'usd', decimals: 2 }],
582
+ * ], ctx.request.raw);
583
+ * if (result.status === 402) return { status: 402, headers: mppxChallengeHeaders(result) };
584
+ * return { status: 200, raw: result };
585
+ * ```
586
+ */
587
+ declare function composeMppxRequest(mppx: unknown, intents: readonly unknown[], request: Request): Promise<MppxComposeResult>;
588
+ /**
589
+ * Extract the 402 challenge response's headers as a plain `Record<string, string>`,
590
+ * the shape `MppxComposeOutcome.headers` accepts. Wraps the one-liner every
591
+ * hand-rolled compose hook writes.
592
+ */
593
+ declare function mppxChallengeHeaders(result: {
594
+ challenge: Response;
595
+ }): Record<string, string>;
676
596
 
597
+ /**
598
+ * Detect which payment-protocol family the inbound request carries.
599
+ *
600
+ * Returns `"mpp"` when an `Authorization` header starts with the `Payment`
601
+ * scheme (case-insensitive per RFC 7235). Returns `"x402"` when a non-empty
602
+ * `payment-signature` or `x-payment` header is present. Returns `null` otherwise.
603
+ *
604
+ * In practice a client constructs a request with exactly one protocol's headers;
605
+ * both arriving together is a client bug or misconfigured proxy. The helper checks
606
+ * MPP first so the rare degenerate case resolves to MPP. Empty header values are
607
+ * treated as absent. Header-name lookups are case-insensitive (RFC 7230 §3.2).
608
+ * The narrower rail naming (`"tempo"` vs `"solana"` inside MPP) is merchant-side,
609
+ * derived from the credential body, not this helper.
610
+ *
611
+ * Accepts either a Web Fetch `Headers` instance (case-insensitive lookup native)
612
+ * or a plain object (case-insensitive lookup applied internally).
613
+ */
614
+ declare function detectRailFromHeaders(headers: Headers | Record<string, string | string[] | undefined>): 'x402' | 'mpp' | null;
677
615
  interface SettlementHandlers<TPayload, TResult> {
678
616
  evm?: (payload: TPayload) => TResult | Promise<TResult>;
679
617
  svm?: (payload: TPayload) => TResult | Promise<TResult>;
@@ -726,28 +664,6 @@ interface PaymentHeadersRail {
726
664
  /** ISO-8601 expiry. Default now + 5 min. */
727
665
  expires?: string;
728
666
  }
729
- interface BuildPaymentHeadersInput {
730
- /** Rails the merchant accepts on this 402. Each becomes one `Payment` directive. */
731
- rails: PaymentHeadersRail[];
732
- /** Order id used as the directive challenge id (per-rail it becomes `${orderId}-${rail}`). */
733
- orderId: string;
734
- /** Realm — the host of the merchant URL (e.g. `agents.merchant.example`). */
735
- realm: string;
736
- /**
737
- * Optional x402 `accepts` array — included as the standard PAYMENT-REQUIRED header so
738
- * x402 clients (`@x402/fetch`, `@x402/core` HTTPClient, `agentscore-pay`) can parse the
739
- * base64-encoded JSON form instead of the WWW-Authenticate text directives. Pass
740
- * `undefined` (or omit) to skip the PAYMENT-REQUIRED header.
741
- */
742
- x402?: {
743
- accepts: unknown[];
744
- version?: 1 | 2;
745
- resource?: {
746
- url: string;
747
- mimeType?: string;
748
- };
749
- };
750
- }
751
667
  interface PaymentHeadersResult {
752
668
  'www-authenticate': string;
753
669
  'PAYMENT-REQUIRED'?: string;
@@ -772,7 +688,28 @@ interface PaymentHeadersResult {
772
688
  * return new Response(JSON.stringify(body), { status: 402, headers });
773
689
  * ```
774
690
  */
775
- declare function buildPaymentHeaders(input: BuildPaymentHeadersInput): PaymentHeadersResult;
691
+ declare function buildPaymentHeaders({ rails, orderId, realm, x402, }: {
692
+ /** Rails the merchant accepts on this 402. Each becomes one `Payment` directive. */
693
+ rails: PaymentHeadersRail[];
694
+ /** Order id used as the directive challenge id (per-rail it becomes `${orderId}-${rail}`). */
695
+ orderId: string;
696
+ /** Realm — the host of the merchant URL (e.g. `agents.merchant.example`). */
697
+ realm: string;
698
+ /**
699
+ * Optional x402 `accepts` array — included as the standard PAYMENT-REQUIRED header so
700
+ * x402 clients (`@x402/fetch`, `@x402/core` HTTPClient, `agentscore-pay`) can parse the
701
+ * base64-encoded JSON form instead of the WWW-Authenticate text directives. Pass
702
+ * `undefined` (or omit) to skip the PAYMENT-REQUIRED header.
703
+ */
704
+ x402?: {
705
+ accepts: unknown[];
706
+ version?: 1 | 2;
707
+ resource?: {
708
+ url: string;
709
+ mimeType?: string;
710
+ };
711
+ };
712
+ }): PaymentHeadersResult;
776
713
 
777
714
  /**
778
715
  * Idempotency-key composition.
@@ -789,16 +726,6 @@ declare function buildPaymentHeaders(input: BuildPaymentHeadersInput): PaymentHe
789
726
  * 3. Server caps idempotency keys at 200 chars; this helper warns when that boundary is
790
727
  * crossed so a future caller doesn't silently get truncation collisions.
791
728
  */
792
- interface BuildIdempotencyKeyInput {
793
- /** Upstream rail's stable payment id — Stripe PaymentIntent id, x402 tx hash, etc. Wins when present. */
794
- paymentIntentId?: string | null;
795
- /** Order id — used to compose a fallback key when no paymentIntentId exists. */
796
- orderId?: string | null;
797
- /** Amount in cents (or smallest currency unit) — added to the fallback for extra collision resistance. */
798
- amountCents?: number;
799
- /** Optional extra prefix to namespace the key (e.g. `"refund"`, `"void"`). */
800
- prefix?: string;
801
- }
802
729
  /**
803
730
  * Compose a stable idempotency key for AgentScore wallet capture and other retry-safe POSTs.
804
731
  *
@@ -814,7 +741,16 @@ interface BuildIdempotencyKeyInput {
814
741
  * buildIdempotencyKey({}); // → undefined
815
742
  * ```
816
743
  */
817
- declare function buildIdempotencyKey(input: BuildIdempotencyKeyInput): string | undefined;
744
+ declare function buildIdempotencyKey({ paymentIntentId, orderId, amountCents, prefix, }: {
745
+ /** Upstream rail's stable payment id — Stripe PaymentIntent id, x402 tx hash, etc. Wins when present. */
746
+ paymentIntentId?: string | null;
747
+ /** Order id — used to compose a fallback key when no paymentIntentId exists. */
748
+ orderId?: string | null;
749
+ /** Amount in cents (or smallest currency unit) — added to the fallback for extra collision resistance. */
750
+ amountCents?: number;
751
+ /** Optional extra prefix to namespace the key (e.g. `"refund"`, `"void"`). */
752
+ prefix?: string;
753
+ }): string | undefined;
818
754
 
819
755
  /**
820
756
  * x402 Settlement-Overrides header helpers — used with the `upto` scheme to specify the
@@ -847,4 +783,100 @@ declare function settlementOverrideHeader(overrides: SettlementOverrides): {
847
783
  value: string;
848
784
  };
849
785
 
850
- export { type BuildIdempotencyKeyInput, type BuildPaymentDirectiveInput, type BuildPaymentHeadersInput, type BuildX402AcceptsForOptions, type ClassifiedX402Error, type CreateMppxServerOptions, type CreateX402ServerOptions, type NetworkFamily, type PaymentDirectiveInput, type PaymentHeadersRail, type PaymentHeadersResult, type PaymentRequestInput, type ProcessX402SettleInput, type ProcessX402SettleResult, type RailDefinition, type RailName, SETTLEMENT_OVERRIDES_HEADER, type SettlementHandlers, type SettlementOverrides, type SettlementPayloadLike, type SolanaMppNetwork, USDC, type ValidateX402NetworkConfigInput, type VerifyX402RequestInput, type VerifyX402RequestResult, type X402FacilitatorChoice, type X402Server, type X402ServerLike, type X402SymbolicRail, X402_SUPPORTED_BASE_NETWORKS, buildIdempotencyKey, buildPaymentDirective, buildPaymentHeaders, buildPaymentRequestBlob, buildX402AcceptsFor402, classifyX402SettleResult, createMppxServer, createX402Server, dispatchSettlementByNetwork, lookupRail, networkFamily, networks, paymentDirective, processX402Settle, rails, registerX402SchemesV1V2, settlementOverrideHeader, validateX402NetworkConfig, verifyX402Request, wrapSolanaChargeWithFinalizedBlockhash };
786
+ /**
787
+ * Zero-amount carve-out: skip upstream verify+settle for $0 orders.
788
+ *
789
+ * CDP rejects EIP-3009 `transferWithAuthorization` with `value=0` as
790
+ * `invalid_payload`; `mppx`'s tempo intents accept only `hash` and
791
+ * `transaction` payload types (rejecting the `proof` payload that gets
792
+ * emitted for $0 settles). Both upstream verify+settle paths fail when the
793
+ * authorized amount is zero, so merchants that drop the settle to $0 in a
794
+ * redemption-code flow need a way to skip verify+settle entirely while
795
+ * still recovering the signer for wallet-capture attribution.
796
+ *
797
+ * `zeroAmountCarveOut` is that path: parse the credential, lift the
798
+ * signer, return `{ signerAddress, signerNetwork, txHash: null }`. Identity
799
+ * is still authenticated by the merchant's gate above; the redemption code
800
+ * is single-use; nothing on-chain to verify.
801
+ *
802
+ * The MPP path uses inline base64+JSON parsing (no `mppx` dependency at
803
+ * runtime) so the cross-language byte-parity fixtures with the Python
804
+ * sibling resolve to identical results. The full `extractPaymentSigner`
805
+ * path is still mppx-backed for production traffic where the credential
806
+ * is a real mppx-shaped object.
807
+ */
808
+
809
+ type ZeroSettleRail = 'x402-base' | 'tempo' | 'solana';
810
+ interface ZeroSettleResult {
811
+ /** Recovered signer address, or `null` when the credential is malformed
812
+ * or shaped wrong for the requested rail. */
813
+ signerAddress: string | null;
814
+ /** `"evm"` or `"solana"`, matching the recovered signer's key family.
815
+ * `null` when no signer was recoverable. */
816
+ signerNetwork: SignerNetwork | null;
817
+ /** Always `null`. A zero-amount carve-out skips on-chain settlement, so
818
+ * no transaction hash exists. The field is present so callers can use
819
+ * `ZeroSettleResult` interchangeably with the success path of
820
+ * `processX402Settle` etc. without branching on shape. */
821
+ txHash: null;
822
+ }
823
+ /**
824
+ * Skip verify+settle for a zero-amount order; recover the signer from the credential.
825
+ *
826
+ * Returns a `ZeroSettleResult`. `signerAddress` / `signerNetwork` are `null`
827
+ * when the credential is malformed, missing required fields, or shaped wrong
828
+ * for the requested rail. `txHash` is always `null` since no on-chain settle runs.
829
+ */
830
+ declare function zeroAmountCarveOut({ rail, payload, authorizationHeader, }: {
831
+ rail: ZeroSettleRail;
832
+ /** For `rail: 'x402-base'`: the verified x402 payload (decoded JSON
833
+ * from `verifyX402Request(...).payload`). Reads
834
+ * `payload.payload.authorization.from`. */
835
+ payload?: Record<string, unknown> | null;
836
+ /** For `rail: 'tempo'` / `'solana'`: the full `Authorization: Payment <base64>`
837
+ * header value. Reads the `did:pkh:*` source DID. */
838
+ authorizationHeader?: string | null;
839
+ }): ZeroSettleResult;
840
+
841
+ /**
842
+ * Lazy-init helpers for x402 + mppx servers.
843
+ *
844
+ * Every merchant accepting these rails writes the same singleton-with-lock
845
+ * pattern around `createX402Server` / `createMppxServer`. These helpers collapse
846
+ * the boilerplate to a single call; the returned getter is safe to call from
847
+ * any number of concurrent handlers; only one server instance is ever
848
+ * constructed per merchant.
849
+ *
850
+ * The x402 helper also derives the facilitator choice (`coinbase` vs `http`)
851
+ * from optional CDP credentials so merchants don't repeat the boot-time
852
+ * conditional.
853
+ */
854
+
855
+ /**
856
+ * Build a memoized async getter for an x402 server.
857
+ *
858
+ * First call constructs the server; subsequent calls return the cached
859
+ * instance. Concurrent first-callers serialize on a Promise lock so we never
860
+ * construct two and discard one.
861
+ *
862
+ * When both CDP creds are passed, the server uses Coinbase's facilitator;
863
+ * otherwise it falls back to the public HTTP facilitator. Merchants who only
864
+ * have one of the two creds get the HTTP fallback.
865
+ */
866
+ declare function lazyX402Server(opts: {
867
+ spec: X402BaseRailSpec;
868
+ cdpApiKeyId?: string;
869
+ cdpApiKeySecret?: string;
870
+ }): () => Promise<X402Server>;
871
+ /**
872
+ * Build a memoized async getter for an mppx server.
873
+ *
874
+ * Same singleton + lock semantics as {@link lazyX402Server}. Forwards `rails`
875
+ * + `secretKey` unchanged to {@link createMppxServer}.
876
+ */
877
+ declare function lazyMppxServer(opts: {
878
+ rails: Record<string, MppxRailSpec>;
879
+ secretKey: string;
880
+ }): () => Promise<unknown>;
881
+
882
+ export { type ClassifiedX402Error, type MppxComposeResult, type MppxRailSpec, type NetworkFamily, type PaymentHeadersRail, type PaymentHeadersResult, type ProcessX402SettleResult, type RailDefinition, type RailName, SETTLEMENT_OVERRIDES_HEADER, type SettlementHandlers, type SettlementOverrides, type SettlementPayloadLike, SignerNetwork, SolanaMppRailSpec, StripeRailSpec, TempoRailSpec, TempoSessionRailSpec, USDC, type VerifyX402RequestResult, X402BaseRailSpec, X402Server, type X402ServerLike, X402_SUPPORTED_BASE_NETWORKS, type ZeroSettleRail, type ZeroSettleResult, buildIdempotencyKey, buildPaymentDirective, buildPaymentHeaders, buildPaymentRequestBlob, classifyOrchestrationError, classifyX402SettleResult, composeMppxRequest, createMppxServer, detectRailFromHeaders, dispatchSettlementByNetwork, lazyMppxServer, lazyX402Server, lookupRail, mppxChallengeHeaders, networkFamily, networks, paymentDirective, processX402Settle, rails, registerX402SchemesV1V2, settlementOverrideHeader, validateX402NetworkConfig, verifyX402Request, wrapSolanaChargeWithFinalizedBlockhash, zeroAmountCarveOut };