@agent-score/commerce 1.8.0 → 2.0.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 (90) hide show
  1. package/README.md +73 -9
  2. package/dist/{_response-BMt2y4Or.d.mts → _response-BFYN3b6i.d.mts} +19 -22
  3. package/dist/{_response-DyJ3mWI3.d.ts → _response-_iPD5AIj.d.ts} +19 -22
  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-BoFwnVsj.d.ts +931 -0
  11. package/dist/checkout-DRbQ0Fsh.d.mts +931 -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 +3662 -18
  51. package/dist/identity/policy.js.map +1 -1
  52. package/dist/identity/policy.mjs +3648 -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 +3651 -373
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +3628 -361
  65. package/dist/index.mjs.map +1 -1
  66. package/dist/payment/index.d.mts +257 -266
  67. package/dist/payment/index.d.ts +257 -266
  68. package/dist/payment/index.js +586 -149
  69. package/dist/payment/index.js.map +1 -1
  70. package/dist/payment/index.mjs +573 -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 +56 -67
  81. package/dist/stripe-multichain/index.d.ts +56 -67
  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 +13 -9
@@ -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;
@@ -674,6 +553,24 @@ type SolanaChargeMethod = {
674
553
  */
675
554
  declare function wrapSolanaChargeWithFinalizedBlockhash(baseMethod: SolanaChargeMethod, rpcUrl: string): SolanaChargeMethod;
676
555
 
556
+ /**
557
+ * Detect which payment-protocol family the inbound request carries.
558
+ *
559
+ * Returns `"mpp"` when an `Authorization` header starts with the `Payment`
560
+ * scheme (case-insensitive per RFC 7235). Returns `"x402"` when a non-empty
561
+ * `payment-signature` or `x-payment` header is present. Returns `null` otherwise.
562
+ *
563
+ * In practice a client constructs a request with exactly one protocol's headers;
564
+ * both arriving together is a client bug or misconfigured proxy. The helper checks
565
+ * MPP first so the rare degenerate case resolves to MPP. Empty header values are
566
+ * treated as absent. Header-name lookups are case-insensitive (RFC 7230 §3.2).
567
+ * The narrower rail naming (`"tempo"` vs `"solana"` inside MPP) is merchant-side,
568
+ * derived from the credential body, not this helper.
569
+ *
570
+ * Accepts either a Web Fetch `Headers` instance (case-insensitive lookup native)
571
+ * or a plain object (case-insensitive lookup applied internally).
572
+ */
573
+ declare function detectRailFromHeaders(headers: Headers | Record<string, string | string[] | undefined>): 'x402' | 'mpp' | null;
677
574
  interface SettlementHandlers<TPayload, TResult> {
678
575
  evm?: (payload: TPayload) => TResult | Promise<TResult>;
679
576
  svm?: (payload: TPayload) => TResult | Promise<TResult>;
@@ -726,28 +623,6 @@ interface PaymentHeadersRail {
726
623
  /** ISO-8601 expiry. Default now + 5 min. */
727
624
  expires?: string;
728
625
  }
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
626
  interface PaymentHeadersResult {
752
627
  'www-authenticate': string;
753
628
  'PAYMENT-REQUIRED'?: string;
@@ -772,7 +647,28 @@ interface PaymentHeadersResult {
772
647
  * return new Response(JSON.stringify(body), { status: 402, headers });
773
648
  * ```
774
649
  */
775
- declare function buildPaymentHeaders(input: BuildPaymentHeadersInput): PaymentHeadersResult;
650
+ declare function buildPaymentHeaders({ rails, orderId, realm, x402, }: {
651
+ /** Rails the merchant accepts on this 402. Each becomes one `Payment` directive. */
652
+ rails: PaymentHeadersRail[];
653
+ /** Order id used as the directive challenge id (per-rail it becomes `${orderId}-${rail}`). */
654
+ orderId: string;
655
+ /** Realm — the host of the merchant URL (e.g. `agents.merchant.example`). */
656
+ realm: string;
657
+ /**
658
+ * Optional x402 `accepts` array — included as the standard PAYMENT-REQUIRED header so
659
+ * x402 clients (`@x402/fetch`, `@x402/core` HTTPClient, `agentscore-pay`) can parse the
660
+ * base64-encoded JSON form instead of the WWW-Authenticate text directives. Pass
661
+ * `undefined` (or omit) to skip the PAYMENT-REQUIRED header.
662
+ */
663
+ x402?: {
664
+ accepts: unknown[];
665
+ version?: 1 | 2;
666
+ resource?: {
667
+ url: string;
668
+ mimeType?: string;
669
+ };
670
+ };
671
+ }): PaymentHeadersResult;
776
672
 
777
673
  /**
778
674
  * Idempotency-key composition.
@@ -781,7 +677,7 @@ declare function buildPaymentHeaders(input: BuildPaymentHeadersInput): PaymentHe
781
677
  * `/v1/credentials/wallets` capture endpoint dedupes correctly and the operator's
782
678
  * `transaction_count` doesn't inflate.
783
679
  *
784
- * Convention (matches what martin-estate uses today):
680
+ * Convention:
785
681
  * 1. Prefer the upstream payment-rail's stable identifier (Stripe PaymentIntent id, x402
786
682
  * tx hash) when one exists — those are already idempotent on their side.
787
683
  * 2. Fall back to a synthesized `pi-{orderId}-{amountCents}` key when no upstream id is
@@ -789,16 +685,6 @@ declare function buildPaymentHeaders(input: BuildPaymentHeadersInput): PaymentHe
789
685
  * 3. Server caps idempotency keys at 200 chars; this helper warns when that boundary is
790
686
  * crossed so a future caller doesn't silently get truncation collisions.
791
687
  */
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
688
  /**
803
689
  * Compose a stable idempotency key for AgentScore wallet capture and other retry-safe POSTs.
804
690
  *
@@ -814,7 +700,16 @@ interface BuildIdempotencyKeyInput {
814
700
  * buildIdempotencyKey({}); // → undefined
815
701
  * ```
816
702
  */
817
- declare function buildIdempotencyKey(input: BuildIdempotencyKeyInput): string | undefined;
703
+ declare function buildIdempotencyKey({ paymentIntentId, orderId, amountCents, prefix, }: {
704
+ /** Upstream rail's stable payment id — Stripe PaymentIntent id, x402 tx hash, etc. Wins when present. */
705
+ paymentIntentId?: string | null;
706
+ /** Order id — used to compose a fallback key when no paymentIntentId exists. */
707
+ orderId?: string | null;
708
+ /** Amount in cents (or smallest currency unit) — added to the fallback for extra collision resistance. */
709
+ amountCents?: number;
710
+ /** Optional extra prefix to namespace the key (e.g. `"refund"`, `"void"`). */
711
+ prefix?: string;
712
+ }): string | undefined;
818
713
 
819
714
  /**
820
715
  * x402 Settlement-Overrides header helpers — used with the `upto` scheme to specify the
@@ -847,4 +742,100 @@ declare function settlementOverrideHeader(overrides: SettlementOverrides): {
847
742
  value: string;
848
743
  };
849
744
 
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 };
745
+ /**
746
+ * Zero-amount carve-out: skip upstream verify+settle for $0 orders.
747
+ *
748
+ * CDP rejects EIP-3009 `transferWithAuthorization` with `value=0` as
749
+ * `invalid_payload`; `mppx`'s tempo intents accept only `hash` and
750
+ * `transaction` payload types (rejecting the `proof` payload that gets
751
+ * emitted for $0 settles). Both upstream verify+settle paths fail when the
752
+ * authorized amount is zero, so merchants that drop the settle to $0 in a
753
+ * redemption-code flow need a way to skip verify+settle entirely while
754
+ * still recovering the signer for wallet-capture attribution.
755
+ *
756
+ * `zeroAmountCarveOut` is that path: parse the credential, lift the
757
+ * signer, return `{ signerAddress, signerNetwork, txHash: null }`. Identity
758
+ * is still authenticated by the merchant's gate above; the redemption code
759
+ * is single-use; nothing on-chain to verify.
760
+ *
761
+ * The MPP path uses inline base64+JSON parsing (no `mppx` dependency at
762
+ * runtime) so the cross-language byte-parity fixtures with the Python
763
+ * sibling resolve to identical results. The full `extractPaymentSigner`
764
+ * path is still mppx-backed for production traffic where the credential
765
+ * is a real mppx-shaped object.
766
+ */
767
+
768
+ type ZeroSettleRail = 'x402-base' | 'tempo' | 'solana';
769
+ interface ZeroSettleResult {
770
+ /** Recovered signer address, or `null` when the credential is malformed
771
+ * or shaped wrong for the requested rail. */
772
+ signerAddress: string | null;
773
+ /** `"evm"` or `"solana"`, matching the recovered signer's key family.
774
+ * `null` when no signer was recoverable. */
775
+ signerNetwork: SignerNetwork | null;
776
+ /** Always `null`. A zero-amount carve-out skips on-chain settlement, so
777
+ * no transaction hash exists. The field is present so callers can use
778
+ * `ZeroSettleResult` interchangeably with the success path of
779
+ * `processX402Settle` etc. without branching on shape. */
780
+ txHash: null;
781
+ }
782
+ /**
783
+ * Skip verify+settle for a zero-amount order; recover the signer from the credential.
784
+ *
785
+ * Returns a `ZeroSettleResult`. `signerAddress` / `signerNetwork` are `null`
786
+ * when the credential is malformed, missing required fields, or shaped wrong
787
+ * for the requested rail. `txHash` is always `null` since no on-chain settle runs.
788
+ */
789
+ declare function zeroAmountCarveOut({ rail, payload, authorizationHeader, }: {
790
+ rail: ZeroSettleRail;
791
+ /** For `rail: 'x402-base'`: the verified x402 payload (decoded JSON
792
+ * from `verifyX402Request(...).payload`). Reads
793
+ * `payload.payload.authorization.from`. */
794
+ payload?: Record<string, unknown> | null;
795
+ /** For `rail: 'tempo'` / `'solana'`: the full `Authorization: Payment <base64>`
796
+ * header value. Reads the `did:pkh:*` source DID. */
797
+ authorizationHeader?: string | null;
798
+ }): ZeroSettleResult;
799
+
800
+ /**
801
+ * Lazy-init helpers for x402 + mppx servers.
802
+ *
803
+ * Every merchant accepting these rails writes the same singleton-with-lock
804
+ * pattern around `createX402Server` / `createMppxServer`. These helpers collapse
805
+ * the boilerplate to a single call; the returned getter is safe to call from
806
+ * any number of concurrent handlers; only one server instance is ever
807
+ * constructed per merchant.
808
+ *
809
+ * The x402 helper also derives the facilitator choice (`coinbase` vs `http`)
810
+ * from optional CDP credentials so merchants don't repeat the boot-time
811
+ * conditional.
812
+ */
813
+
814
+ /**
815
+ * Build a memoized async getter for an x402 server.
816
+ *
817
+ * First call constructs the server; subsequent calls return the cached
818
+ * instance. Concurrent first-callers serialize on a Promise lock so we never
819
+ * construct two and discard one.
820
+ *
821
+ * When both CDP creds are passed, the server uses Coinbase's facilitator;
822
+ * otherwise it falls back to the public HTTP facilitator. Merchants who only
823
+ * have one of the two creds get the HTTP fallback.
824
+ */
825
+ declare function lazyX402Server(opts: {
826
+ spec: X402BaseRailSpec;
827
+ cdpApiKeyId?: string;
828
+ cdpApiKeySecret?: string;
829
+ }): () => Promise<X402Server>;
830
+ /**
831
+ * Build a memoized async getter for an mppx server.
832
+ *
833
+ * Same singleton + lock semantics as {@link lazyX402Server}. Forwards `rails`
834
+ * + `secretKey` unchanged to {@link createMppxServer}.
835
+ */
836
+ declare function lazyMppxServer(opts: {
837
+ rails: Record<string, MppxRailSpec>;
838
+ secretKey: string;
839
+ }): () => Promise<unknown>;
840
+
841
+ export { type ClassifiedX402Error, 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, createMppxServer, detectRailFromHeaders, dispatchSettlementByNetwork, lazyMppxServer, lazyX402Server, lookupRail, networkFamily, networks, paymentDirective, processX402Settle, rails, registerX402SchemesV1V2, settlementOverrideHeader, validateX402NetworkConfig, verifyX402Request, wrapSolanaChargeWithFinalizedBlockhash, zeroAmountCarveOut };