@agent-score/commerce 2.1.1 → 2.3.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 (66) hide show
  1. package/README.md +2 -2
  2. package/dist/challenge/index.d.mts +3 -3
  3. package/dist/challenge/index.d.ts +3 -3
  4. package/dist/challenge/index.js +7 -5
  5. package/dist/challenge/index.js.map +1 -1
  6. package/dist/challenge/index.mjs +7 -5
  7. package/dist/challenge/index.mjs.map +1 -1
  8. package/dist/{checkout-BRw_caGr.d.mts → checkout-Ceo1_rVJ.d.mts} +38 -2
  9. package/dist/{checkout-CuSNUJFX.d.ts → checkout-ChyOi7aU.d.ts} +38 -2
  10. package/dist/core.js +4 -3
  11. package/dist/core.js.map +1 -1
  12. package/dist/core.mjs +4 -3
  13. package/dist/core.mjs.map +1 -1
  14. package/dist/{default_rails-C5gKZJMI.d.ts → default_rails-DtR_E9N9.d.ts} +1 -1
  15. package/dist/{default_rails-XFCuRddA.d.mts → default_rails-K25PtWrL.d.mts} +1 -1
  16. package/dist/discovery/index.d.mts +4 -4
  17. package/dist/discovery/index.d.ts +4 -4
  18. package/dist/identity/express.d.mts +4 -3
  19. package/dist/identity/express.d.ts +4 -3
  20. package/dist/identity/express.js +4 -3
  21. package/dist/identity/express.js.map +1 -1
  22. package/dist/identity/express.mjs +4 -3
  23. package/dist/identity/express.mjs.map +1 -1
  24. package/dist/identity/fastify.d.mts +4 -3
  25. package/dist/identity/fastify.d.ts +4 -3
  26. package/dist/identity/fastify.js +4 -3
  27. package/dist/identity/fastify.js.map +1 -1
  28. package/dist/identity/fastify.mjs +4 -3
  29. package/dist/identity/fastify.mjs.map +1 -1
  30. package/dist/identity/hono.d.mts +4 -3
  31. package/dist/identity/hono.d.ts +4 -3
  32. package/dist/identity/hono.js +4 -3
  33. package/dist/identity/hono.js.map +1 -1
  34. package/dist/identity/hono.mjs +4 -3
  35. package/dist/identity/hono.mjs.map +1 -1
  36. package/dist/identity/nextjs.js +4 -3
  37. package/dist/identity/nextjs.js.map +1 -1
  38. package/dist/identity/nextjs.mjs +4 -3
  39. package/dist/identity/nextjs.mjs.map +1 -1
  40. package/dist/identity/web.js +4 -3
  41. package/dist/identity/web.js.map +1 -1
  42. package/dist/identity/web.mjs +4 -3
  43. package/dist/identity/web.mjs.map +1 -1
  44. package/dist/index.d.mts +7 -7
  45. package/dist/index.d.ts +7 -7
  46. package/dist/index.js +139 -13
  47. package/dist/index.js.map +1 -1
  48. package/dist/index.mjs +139 -13
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/payment/index.d.mts +3 -3
  51. package/dist/payment/index.d.ts +3 -3
  52. package/dist/payment/index.js +2 -0
  53. package/dist/payment/index.js.map +1 -1
  54. package/dist/payment/index.mjs +2 -0
  55. package/dist/payment/index.mjs.map +1 -1
  56. package/dist/{pricing-DHfH3ogG.d.ts → pricing-B3-aKxSz.d.ts} +5 -3
  57. package/dist/{pricing-4n5Ota0D.d.mts → pricing-BReyZiqN.d.mts} +5 -3
  58. package/dist/{rail_spec-D6qzh3J0.d.mts → rail_spec-B1239jPp.d.mts} +25 -0
  59. package/dist/{rail_spec-D6qzh3J0.d.ts → rail_spec-B1239jPp.d.ts} +25 -0
  60. package/dist/stripe-multichain/index.d.mts +61 -11
  61. package/dist/stripe-multichain/index.d.ts +61 -11
  62. package/dist/stripe-multichain/index.js +84 -43
  63. package/dist/stripe-multichain/index.js.map +1 -1
  64. package/dist/stripe-multichain/index.mjs +83 -43
  65. package/dist/stripe-multichain/index.mjs.map +1 -1
  66. package/package.json +9 -9
@@ -1,4 +1,4 @@
1
- import { T as TempoRailSpec, X as X402BaseRailSpec, S as SolanaMppRailSpec, b as StripeRailSpec } from './rail_spec-D6qzh3J0.js';
1
+ import { T as TempoRailSpec, X as X402BaseRailSpec, S as SolanaMppRailSpec, b as StripeRailSpec } from './rail_spec-B1239jPp.js';
2
2
 
3
3
  interface HowToPayRailEntry {
4
4
  setup?: string[];
@@ -43,8 +43,10 @@ declare function buildHowToPay({ url, retryBodyJson, totalUsd, rails, opTokenPla
43
43
  totalUsd: string | number;
44
44
  /** Per-rail config — each is optional. Pass only the rails you support. */
45
45
  rails: HowToPayRails;
46
- /** Placeholder text for the operator token in commands. Defaults to '<your_opc_token>'. */
47
- opTokenPlaceholder?: string;
46
+ /** Placeholder text for the operator token in commands. Defaults to '<your_opc_token>'.
47
+ * Pass `null` (gateless merchants) to strip the `-H 'X-Operator-Token: ...'` line entirely
48
+ * from each rail command — appropriate when the merchant doesn't run an identity gate. */
49
+ opTokenPlaceholder?: string | null;
48
50
  /** Override max-spend value used in commands. Default: `ceil(totalUsd) + 1`
49
51
  * (for prices ≥ $1) or `totalUsd.toFixed(decimals)` (for sub-dollar prices,
50
52
  * so the command flags reflect the real amount instead of `1.00`). */
@@ -1,4 +1,4 @@
1
- import { T as TempoRailSpec, X as X402BaseRailSpec, S as SolanaMppRailSpec, b as StripeRailSpec } from './rail_spec-D6qzh3J0.mjs';
1
+ import { T as TempoRailSpec, X as X402BaseRailSpec, S as SolanaMppRailSpec, b as StripeRailSpec } from './rail_spec-B1239jPp.mjs';
2
2
 
3
3
  interface HowToPayRailEntry {
4
4
  setup?: string[];
@@ -43,8 +43,10 @@ declare function buildHowToPay({ url, retryBodyJson, totalUsd, rails, opTokenPla
43
43
  totalUsd: string | number;
44
44
  /** Per-rail config — each is optional. Pass only the rails you support. */
45
45
  rails: HowToPayRails;
46
- /** Placeholder text for the operator token in commands. Defaults to '<your_opc_token>'. */
47
- opTokenPlaceholder?: string;
46
+ /** Placeholder text for the operator token in commands. Defaults to '<your_opc_token>'.
47
+ * Pass `null` (gateless merchants) to strip the `-H 'X-Operator-Token: ...'` line entirely
48
+ * from each rail command — appropriate when the merchant doesn't run an identity gate. */
49
+ opTokenPlaceholder?: string | null;
48
50
  /** Override max-spend value used in commands. Default: `ceil(totalUsd) + 1`
49
51
  * (for prices ≥ $1) or `totalUsd.toFixed(decimals)` (for sub-dollar prices,
50
52
  * so the command flags reflect the real amount instead of `1.00`). */
@@ -58,6 +58,31 @@ interface SolanaMppRailSpec {
58
58
  rpcUrl?: string;
59
59
  signer?: unknown;
60
60
  tokenProgram?: string;
61
+ /** Whether the recipient's ATA may be auto-created on first payment. **Default `true`.**
62
+ *
63
+ * When `true` (default), the SDK passes
64
+ * `splits: [{ recipient, amount: '0', ataCreationRequired: true }]` to
65
+ * `solana.charge`, which puts the recipient in the MPP spec §13.6
66
+ * `allowedAtaOwners` allow-list. Required on `@solana/mpp >= 0.6.0` with a
67
+ * sponsored (fee-payer) setup — without it, every settle that emits a
68
+ * `CreateIdempotent` ATA instruction is rejected. On `@solana/mpp 0.5.x`
69
+ * the field is unknown and silently ignored, so the default is safe across
70
+ * versions.
71
+ *
72
+ * Opt out (`false`) only when every recipient's ATA is guaranteed to exist
73
+ * out-of-band — typically when the merchant pre-creates the ATA from an
74
+ * external wallet (one-time USDC transfer of any amount) and refuses to
75
+ * let the fee-payer fund creation. Rare; mainly useful for low-margin
76
+ * endpoints that use a stable merchant-owned recipient via
77
+ * `staticRecipients` and want to guarantee zero rent per call.
78
+ *
79
+ * Economic note: with rotating recipients (Stripe-multichain per-PI deposit
80
+ * addresses), the sponsor pays ~0.002 SOL (~$0.50) of rent per call into
81
+ * accounts the merchant can't close. Acceptable when settle amounts
82
+ * dominate ($50+ transactions); not viable for sub-dollar merchants —
83
+ * those should pair `ataCreationRequired: false` with a static recipient
84
+ * whose ATA has been pre-created (one-time external USDC transfer). */
85
+ ataCreationRequired?: boolean;
61
86
  }
62
87
  /**
63
88
  * Canonical config for the Stripe SPT rail.
@@ -58,6 +58,31 @@ interface SolanaMppRailSpec {
58
58
  rpcUrl?: string;
59
59
  signer?: unknown;
60
60
  tokenProgram?: string;
61
+ /** Whether the recipient's ATA may be auto-created on first payment. **Default `true`.**
62
+ *
63
+ * When `true` (default), the SDK passes
64
+ * `splits: [{ recipient, amount: '0', ataCreationRequired: true }]` to
65
+ * `solana.charge`, which puts the recipient in the MPP spec §13.6
66
+ * `allowedAtaOwners` allow-list. Required on `@solana/mpp >= 0.6.0` with a
67
+ * sponsored (fee-payer) setup — without it, every settle that emits a
68
+ * `CreateIdempotent` ATA instruction is rejected. On `@solana/mpp 0.5.x`
69
+ * the field is unknown and silently ignored, so the default is safe across
70
+ * versions.
71
+ *
72
+ * Opt out (`false`) only when every recipient's ATA is guaranteed to exist
73
+ * out-of-band — typically when the merchant pre-creates the ATA from an
74
+ * external wallet (one-time USDC transfer of any amount) and refuses to
75
+ * let the fee-payer fund creation. Rare; mainly useful for low-margin
76
+ * endpoints that use a stable merchant-owned recipient via
77
+ * `staticRecipients` and want to guarantee zero rent per call.
78
+ *
79
+ * Economic note: with rotating recipients (Stripe-multichain per-PI deposit
80
+ * addresses), the sponsor pays ~0.002 SOL (~$0.50) of rent per call into
81
+ * accounts the merchant can't close. Acceptable when settle amounts
82
+ * dominate ($50+ transactions); not viable for sub-dollar merchants —
83
+ * those should pair `ataCreationRequired: false` with a static recipient
84
+ * whose ATA has been pre-created (one-time external USDC transfer). */
85
+ ataCreationRequired?: boolean;
61
86
  }
62
87
  /**
63
88
  * Canonical config for the Stripe SPT rail.
@@ -112,15 +112,22 @@ declare function createPiCache({ redisUrl, ttlSeconds, keyPrefix, }?: {
112
112
  * the 402 advertises a stable per-order deposit address.
113
113
  * - **Settle leg** (MPP credential attached): reuse the buyer's
114
114
  * signed-against payTo from the credential (after verifying it's in the
115
- * local cache) otherwise the verify leg would compare against a
116
- * freshly-rotated address and reject the credential.
115
+ * local cache OR matches a configured `staticRecipients` entry)
116
+ * otherwise the verify leg would compare against a freshly-rotated
117
+ * address and reject the credential.
117
118
  *
118
119
  * Stripe SPT and card methods don't carry an on-chain recipient, so the
119
120
  * settle leg still mints a fresh PaymentIntent for them.
120
121
  *
121
- * Mirrors the hand-rolled `createPayToAddress` block consumers wrote in
122
- * `lib/payment.ts`. Lifts the structural branching; merchants keep
123
- * env-driven config (network list, default network, metadata) at the call site.
122
+ * Two public entrypoints share the same options and internal helpers:
123
+ * - `createPayToAddressFromStripePI` returns a single string (the
124
+ * `preferredNetwork`'s address). Convenient when the merchant only needs
125
+ * one rail's payTo back.
126
+ * - `mintMultichainRecipients` returns the full per-rail map plus the PI
127
+ * id. Preferred for multi-rail merchants — avoids the second pi-cache
128
+ * lookup to stitch sibling addresses back together.
129
+ *
130
+ * Mirrors the python `pay_to_address.py` factoring.
124
131
  */
125
132
 
126
133
  interface CreatePayToAddressFromStripePIOptions {
@@ -132,8 +139,26 @@ interface CreatePayToAddressFromStripePIOptions {
132
139
  stripe: StripeClientLike;
133
140
  /** Cache backing the merchant's minted addresses + PI lookups. */
134
141
  piCache: PiCache;
135
- /** Networks to advertise to Stripe `deposit_options`. Default ['tempo', 'base', 'solana']. */
142
+ /** Networks to advertise to Stripe `deposit_options`. Default ['tempo', 'base', 'solana'].
143
+ * Networks present as a key in `staticRecipients` are removed from this list
144
+ * automatically — Stripe is not asked to mint a per-PI address for them. */
136
145
  networks?: string[];
146
+ /** Merchant-owned static deposit addresses, keyed by network. Use this to bypass
147
+ * Stripe per-PI rotation on chains where a rotating recipient is expensive
148
+ * (Solana: each new recipient address costs ~0.002 SOL of ATA rent locked on
149
+ * an account the merchant can't close — see MPP spec §13.6 "ATA Rent Drain").
150
+ *
151
+ * The SDK handles everything: (a) excludes these networks from the Stripe mint,
152
+ * (b) registers them with `piCache.cacheAddress` on every call (so settle-leg
153
+ * `hasAddress` checks pass during the TTL window), (c) merges them into the
154
+ * per-PI network map (so `getNetworkDepositAddress(piId, network)` returns the
155
+ * static address transparently), and (d) accepts the credential's signed-against
156
+ * recipient on the settle leg when it matches a configured static address
157
+ * (bypassing the `hasAddress` TTL window since merchant-owned addresses are
158
+ * always valid).
159
+ *
160
+ * Example: `{ solana: 'FR96wd96urHJdMnYayFrPYmDeAjKvwi3rQ2wkgXXTSP8' }` */
161
+ staticRecipients?: Record<string, string>;
137
162
  /** Optional Stripe metadata. */
138
163
  metadata?: Record<string, string>;
139
164
  /** Pending-order id; used as the Stripe idempotency key seed so retries
@@ -143,14 +168,39 @@ interface CreatePayToAddressFromStripePIOptions {
143
168
  * picks `tempo`, falls back to `base`. */
144
169
  preferredNetwork?: string;
145
170
  }
146
- /** Returns the on-chain `pay_to` address the agent should be told to pay
147
- * (in the 402 challenge or the bound MPP credential).
171
+ /** Structured result for `mintMultichainRecipients` exposes the full per-network
172
+ * deposit map plus the PI id, so merchants can stop guessing "is the returned
173
+ * string the tempo address or the solana static". */
174
+ interface MintMultichainRecipientsResult {
175
+ /** Per-network deposit address map (e.g. `{ tempo: '0x...', base: '0x...', solana: 'FR96...' }`).
176
+ * Merges Stripe-minted addresses with any `staticRecipients` overrides. */
177
+ recipients: Record<string, string>;
178
+ /** Stripe PaymentIntent id (when a PI was minted on this call) or undefined
179
+ * if all networks were covered by staticRecipients. */
180
+ paymentIntentId?: string;
181
+ /** True when the settle leg short-circuited to the credential-bound recipient
182
+ * instead of minting a new PI. The merchant's downstream sibling-address
183
+ * lookups (e.g. for the 402 retry body) should fall back to the PI cache. */
184
+ reusedFromCredential: boolean;
185
+ }
186
+ /** Returns the on-chain `pay_to` address the agent should be told to pay.
148
187
  *
149
188
  * On the settle leg, when the inbound `Authorization: Payment` credential
150
189
  * binds a `tempo` or `solana` recipient, the helper returns THAT address
151
- * (after verifying it's still in `piCache`). Otherwise it mints a fresh
152
- * `createMultichainPaymentIntent` and caches the addresses + PI mapping. */
190
+ * (after verifying it's still in `piCache` OR matches a configured
191
+ * `staticRecipients` entry). Otherwise it mints a fresh
192
+ * `createMultichainPaymentIntent` and caches the addresses + PI mapping.
193
+ *
194
+ * When `staticRecipients` is configured, prefer `mintMultichainRecipients`
195
+ * instead — its structured return avoids the "is this string the tempo or
196
+ * the solana static" ambiguity on the settle leg. */
153
197
  declare function createPayToAddressFromStripePI(opts: CreatePayToAddressFromStripePIOptions): Promise<string>;
198
+ /** Structured variant of `createPayToAddressFromStripePI`: returns the full
199
+ * per-rail map plus the PI id. Preferred when the merchant's `mintRecipients`
200
+ * hook needs all rail addresses (typical multi-rail merchant) — saves the
201
+ * pi-cache lookups + sidesteps the "returned-string-is-ambiguous" trap on
202
+ * the settle leg when `staticRecipients` is configured. */
203
+ declare function mintMultichainRecipients(opts: CreatePayToAddressFromStripePIOptions): Promise<MintMultichainRecipientsResult>;
154
204
 
155
205
  /**
156
206
  * Stripe's documented magic test_helpers transaction hash that resolves the
@@ -310,4 +360,4 @@ interface SimulateDepositForOutcomeOptions {
310
360
  * `simulateDepositIfTestnet` wrapper pattern. */
311
361
  declare function simulateDepositForOutcome(opts: SimulateDepositForOutcomeOptions): Promise<void>;
312
362
 
313
- export { type CreatePayToAddressFromStripePIOptions, type MultichainPaymentIntentResult, type PiCache, STRIPE_TEST_TX_HASH_FAILED, STRIPE_TEST_TX_HASH_SUCCESS, type SimulateDepositForOutcomeOptions, type SimulateNetwork, type StripeClientLike, type StripePaymentIntent, createMppxStripe, createMultichainPaymentIntent, createPayToAddressFromStripePI, createPiCache, networkForOutcome, simulateCryptoDeposit, simulateDepositForOutcome, simulateDepositIfTestMode };
363
+ export { type CreatePayToAddressFromStripePIOptions, type MintMultichainRecipientsResult, type MultichainPaymentIntentResult, type PiCache, STRIPE_TEST_TX_HASH_FAILED, STRIPE_TEST_TX_HASH_SUCCESS, type SimulateDepositForOutcomeOptions, type SimulateNetwork, type StripeClientLike, type StripePaymentIntent, createMppxStripe, createMultichainPaymentIntent, createPayToAddressFromStripePI, createPiCache, mintMultichainRecipients, networkForOutcome, simulateCryptoDeposit, simulateDepositForOutcome, simulateDepositIfTestMode };
@@ -112,15 +112,22 @@ declare function createPiCache({ redisUrl, ttlSeconds, keyPrefix, }?: {
112
112
  * the 402 advertises a stable per-order deposit address.
113
113
  * - **Settle leg** (MPP credential attached): reuse the buyer's
114
114
  * signed-against payTo from the credential (after verifying it's in the
115
- * local cache) otherwise the verify leg would compare against a
116
- * freshly-rotated address and reject the credential.
115
+ * local cache OR matches a configured `staticRecipients` entry)
116
+ * otherwise the verify leg would compare against a freshly-rotated
117
+ * address and reject the credential.
117
118
  *
118
119
  * Stripe SPT and card methods don't carry an on-chain recipient, so the
119
120
  * settle leg still mints a fresh PaymentIntent for them.
120
121
  *
121
- * Mirrors the hand-rolled `createPayToAddress` block consumers wrote in
122
- * `lib/payment.ts`. Lifts the structural branching; merchants keep
123
- * env-driven config (network list, default network, metadata) at the call site.
122
+ * Two public entrypoints share the same options and internal helpers:
123
+ * - `createPayToAddressFromStripePI` returns a single string (the
124
+ * `preferredNetwork`'s address). Convenient when the merchant only needs
125
+ * one rail's payTo back.
126
+ * - `mintMultichainRecipients` returns the full per-rail map plus the PI
127
+ * id. Preferred for multi-rail merchants — avoids the second pi-cache
128
+ * lookup to stitch sibling addresses back together.
129
+ *
130
+ * Mirrors the python `pay_to_address.py` factoring.
124
131
  */
125
132
 
126
133
  interface CreatePayToAddressFromStripePIOptions {
@@ -132,8 +139,26 @@ interface CreatePayToAddressFromStripePIOptions {
132
139
  stripe: StripeClientLike;
133
140
  /** Cache backing the merchant's minted addresses + PI lookups. */
134
141
  piCache: PiCache;
135
- /** Networks to advertise to Stripe `deposit_options`. Default ['tempo', 'base', 'solana']. */
142
+ /** Networks to advertise to Stripe `deposit_options`. Default ['tempo', 'base', 'solana'].
143
+ * Networks present as a key in `staticRecipients` are removed from this list
144
+ * automatically — Stripe is not asked to mint a per-PI address for them. */
136
145
  networks?: string[];
146
+ /** Merchant-owned static deposit addresses, keyed by network. Use this to bypass
147
+ * Stripe per-PI rotation on chains where a rotating recipient is expensive
148
+ * (Solana: each new recipient address costs ~0.002 SOL of ATA rent locked on
149
+ * an account the merchant can't close — see MPP spec §13.6 "ATA Rent Drain").
150
+ *
151
+ * The SDK handles everything: (a) excludes these networks from the Stripe mint,
152
+ * (b) registers them with `piCache.cacheAddress` on every call (so settle-leg
153
+ * `hasAddress` checks pass during the TTL window), (c) merges them into the
154
+ * per-PI network map (so `getNetworkDepositAddress(piId, network)` returns the
155
+ * static address transparently), and (d) accepts the credential's signed-against
156
+ * recipient on the settle leg when it matches a configured static address
157
+ * (bypassing the `hasAddress` TTL window since merchant-owned addresses are
158
+ * always valid).
159
+ *
160
+ * Example: `{ solana: 'FR96wd96urHJdMnYayFrPYmDeAjKvwi3rQ2wkgXXTSP8' }` */
161
+ staticRecipients?: Record<string, string>;
137
162
  /** Optional Stripe metadata. */
138
163
  metadata?: Record<string, string>;
139
164
  /** Pending-order id; used as the Stripe idempotency key seed so retries
@@ -143,14 +168,39 @@ interface CreatePayToAddressFromStripePIOptions {
143
168
  * picks `tempo`, falls back to `base`. */
144
169
  preferredNetwork?: string;
145
170
  }
146
- /** Returns the on-chain `pay_to` address the agent should be told to pay
147
- * (in the 402 challenge or the bound MPP credential).
171
+ /** Structured result for `mintMultichainRecipients` exposes the full per-network
172
+ * deposit map plus the PI id, so merchants can stop guessing "is the returned
173
+ * string the tempo address or the solana static". */
174
+ interface MintMultichainRecipientsResult {
175
+ /** Per-network deposit address map (e.g. `{ tempo: '0x...', base: '0x...', solana: 'FR96...' }`).
176
+ * Merges Stripe-minted addresses with any `staticRecipients` overrides. */
177
+ recipients: Record<string, string>;
178
+ /** Stripe PaymentIntent id (when a PI was minted on this call) or undefined
179
+ * if all networks were covered by staticRecipients. */
180
+ paymentIntentId?: string;
181
+ /** True when the settle leg short-circuited to the credential-bound recipient
182
+ * instead of minting a new PI. The merchant's downstream sibling-address
183
+ * lookups (e.g. for the 402 retry body) should fall back to the PI cache. */
184
+ reusedFromCredential: boolean;
185
+ }
186
+ /** Returns the on-chain `pay_to` address the agent should be told to pay.
148
187
  *
149
188
  * On the settle leg, when the inbound `Authorization: Payment` credential
150
189
  * binds a `tempo` or `solana` recipient, the helper returns THAT address
151
- * (after verifying it's still in `piCache`). Otherwise it mints a fresh
152
- * `createMultichainPaymentIntent` and caches the addresses + PI mapping. */
190
+ * (after verifying it's still in `piCache` OR matches a configured
191
+ * `staticRecipients` entry). Otherwise it mints a fresh
192
+ * `createMultichainPaymentIntent` and caches the addresses + PI mapping.
193
+ *
194
+ * When `staticRecipients` is configured, prefer `mintMultichainRecipients`
195
+ * instead — its structured return avoids the "is this string the tempo or
196
+ * the solana static" ambiguity on the settle leg. */
153
197
  declare function createPayToAddressFromStripePI(opts: CreatePayToAddressFromStripePIOptions): Promise<string>;
198
+ /** Structured variant of `createPayToAddressFromStripePI`: returns the full
199
+ * per-rail map plus the PI id. Preferred when the merchant's `mintRecipients`
200
+ * hook needs all rail addresses (typical multi-rail merchant) — saves the
201
+ * pi-cache lookups + sidesteps the "returned-string-is-ambiguous" trap on
202
+ * the settle leg when `staticRecipients` is configured. */
203
+ declare function mintMultichainRecipients(opts: CreatePayToAddressFromStripePIOptions): Promise<MintMultichainRecipientsResult>;
154
204
 
155
205
  /**
156
206
  * Stripe's documented magic test_helpers transaction hash that resolves the
@@ -310,4 +360,4 @@ interface SimulateDepositForOutcomeOptions {
310
360
  * `simulateDepositIfTestnet` wrapper pattern. */
311
361
  declare function simulateDepositForOutcome(opts: SimulateDepositForOutcomeOptions): Promise<void>;
312
362
 
313
- export { type CreatePayToAddressFromStripePIOptions, type MultichainPaymentIntentResult, type PiCache, STRIPE_TEST_TX_HASH_FAILED, STRIPE_TEST_TX_HASH_SUCCESS, type SimulateDepositForOutcomeOptions, type SimulateNetwork, type StripeClientLike, type StripePaymentIntent, createMppxStripe, createMultichainPaymentIntent, createPayToAddressFromStripePI, createPiCache, networkForOutcome, simulateCryptoDeposit, simulateDepositForOutcome, simulateDepositIfTestMode };
363
+ export { type CreatePayToAddressFromStripePIOptions, type MintMultichainRecipientsResult, type MultichainPaymentIntentResult, type PiCache, STRIPE_TEST_TX_HASH_FAILED, STRIPE_TEST_TX_HASH_SUCCESS, type SimulateDepositForOutcomeOptions, type SimulateNetwork, type StripeClientLike, type StripePaymentIntent, createMppxStripe, createMultichainPaymentIntent, createPayToAddressFromStripePI, createPiCache, mintMultichainRecipients, networkForOutcome, simulateCryptoDeposit, simulateDepositForOutcome, simulateDepositIfTestMode };
@@ -19434,11 +19434,12 @@ function toClient(method, options) {
19434
19434
  };
19435
19435
  }
19436
19436
  function toServer(method, options) {
19437
- const { authorize, defaults, html, request, respond, stableBinding, transport, verify: verify3 } = options;
19437
+ const { authorize, defaults, extensions, html, request, respond, stableBinding, transport, verify: verify3 } = options;
19438
19438
  return {
19439
19439
  ...method,
19440
19440
  authorize,
19441
19441
  defaults,
19442
+ extensions,
19442
19443
  html,
19443
19444
  request,
19444
19445
  respond,
@@ -19653,6 +19654,7 @@ __export(stripe_multichain_exports, {
19653
19654
  createMultichainPaymentIntent: () => createMultichainPaymentIntent,
19654
19655
  createPayToAddressFromStripePI: () => createPayToAddressFromStripePI,
19655
19656
  createPiCache: () => createPiCache,
19657
+ mintMultichainRecipients: () => mintMultichainRecipients,
19656
19658
  networkForOutcome: () => networkForOutcome,
19657
19659
  simulateCryptoDeposit: () => simulateCryptoDeposit,
19658
19660
  simulateDepositForOutcome: () => simulateDepositForOutcome,
@@ -19719,50 +19721,76 @@ async function createMultichainPaymentIntent({
19719
19721
  }
19720
19722
 
19721
19723
  // src/stripe-multichain/pay_to_address.ts
19724
+ var DEFAULT_NETWORKS = ["tempo", "base", "solana"];
19722
19725
  async function createPayToAddressFromStripePI(opts) {
19726
+ const fromCredential = await tryResolveFromCredential(opts);
19727
+ if (fromCredential !== null) return fromCredential;
19728
+ const { preferred } = await mintAndCache(opts);
19729
+ return preferred;
19730
+ }
19731
+ async function mintMultichainRecipients(opts) {
19732
+ const fromCredential = await tryResolveFromCredential(opts);
19733
+ if (fromCredential !== null) {
19734
+ const piId = opts.piCache.getPaymentIntentId(fromCredential);
19735
+ const networkMap = piId ? readNetworkMapFromCache(opts.piCache, piId) : {};
19736
+ const merged2 = { ...networkMap, ...opts.staticRecipients ?? {} };
19737
+ return {
19738
+ recipients: merged2,
19739
+ ...piId !== void 0 && { paymentIntentId: piId },
19740
+ reusedFromCredential: true
19741
+ };
19742
+ }
19743
+ const { merged, paymentIntentId } = await mintAndCache(opts);
19744
+ return { recipients: merged, paymentIntentId, reusedFromCredential: false };
19745
+ }
19746
+ async function tryResolveFromCredential(opts) {
19723
19747
  const authHeader = opts.request.headers.get("authorization");
19724
- if (authHeader) {
19725
- const { Credential } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
19726
- if (Credential.extractPaymentScheme(authHeader)) {
19727
- let credential;
19728
- try {
19729
- credential = Credential.fromRequest(opts.request);
19730
- } catch {
19731
- throw new CheckoutValidationError({
19732
- code: "invalid_credential",
19733
- message: "The Authorization: Payment header is not a valid MPP credential.",
19734
- action: "retry_without_credential",
19735
- status: 401
19736
- });
19737
- }
19738
- const method = credential.challenge.method;
19739
- if (method === "tempo" || method === "solana") {
19740
- const toAddress = credential.challenge.request.recipient;
19741
- if (typeof toAddress !== "string" || !toAddress) {
19742
- throw new CheckoutValidationError({
19743
- code: "invalid_credential",
19744
- message: "The MPP credential is missing its recipient field.",
19745
- action: "retry_without_credential",
19746
- status: 401
19747
- });
19748
- }
19749
- if (!await opts.piCache.hasAddress(toAddress)) {
19750
- throw new CheckoutValidationError({
19751
- code: "invalid_credential",
19752
- message: "The signed-against payTo recipient is not in this merchant's cache (unknown or expired). Retry without the Authorization: Payment header to receive a fresh 402 challenge.",
19753
- action: "retry_without_credential",
19754
- status: 401
19755
- });
19756
- }
19757
- return toAddress;
19758
- }
19759
- }
19748
+ if (!authHeader) return null;
19749
+ const { Credential } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
19750
+ if (!Credential.extractPaymentScheme(authHeader)) return null;
19751
+ let credential;
19752
+ try {
19753
+ credential = Credential.fromRequest(opts.request);
19754
+ } catch {
19755
+ throw new CheckoutValidationError({
19756
+ code: "invalid_credential",
19757
+ message: "The Authorization: Payment header is not a valid MPP credential.",
19758
+ action: "retry_without_credential",
19759
+ status: 401
19760
+ });
19761
+ }
19762
+ const method = credential.challenge.method;
19763
+ if (method !== "tempo" && method !== "solana") return null;
19764
+ const toAddress = credential.challenge.request.recipient;
19765
+ if (typeof toAddress !== "string" || !toAddress) {
19766
+ throw new CheckoutValidationError({
19767
+ code: "invalid_credential",
19768
+ message: "The MPP credential is missing its recipient field.",
19769
+ action: "retry_without_credential",
19770
+ status: 401
19771
+ });
19772
+ }
19773
+ const staticForMethod = opts.staticRecipients?.[method];
19774
+ if (staticForMethod && staticForMethod === toAddress) return toAddress;
19775
+ if (!await opts.piCache.hasAddress(toAddress)) {
19776
+ throw new CheckoutValidationError({
19777
+ code: "invalid_credential",
19778
+ message: "The signed-against payTo recipient is not in this merchant's cache (unknown or expired). Retry without the Authorization: Payment header to receive a fresh 402 challenge.",
19779
+ action: "retry_without_credential",
19780
+ status: 401
19781
+ });
19760
19782
  }
19783
+ return toAddress;
19784
+ }
19785
+ async function mintAndCache(opts) {
19786
+ const staticRecipients = opts.staticRecipients ?? {};
19787
+ const requestedNetworks = opts.networks ?? [...DEFAULT_NETWORKS];
19788
+ const stripeNetworks = requestedNetworks.filter((n) => !(n in staticRecipients));
19761
19789
  const idempotencyKey = opts.orderId ? `pi-${opts.orderId}-${opts.amountCents}` : void 0;
19762
19790
  const { paymentIntentId, depositAddresses } = await createMultichainPaymentIntent({
19763
19791
  stripe: opts.stripe,
19764
19792
  amount: opts.amountCents,
19765
- networks: opts.networks ?? ["tempo", "base", "solana"],
19793
+ networks: stripeNetworks,
19766
19794
  ...opts.metadata ? { metadata: opts.metadata } : {},
19767
19795
  ...idempotencyKey ? { idempotencyKey } : {}
19768
19796
  });
@@ -19770,10 +19798,14 @@ async function createPayToAddressFromStripePI(opts) {
19770
19798
  await opts.piCache.cacheAddress(address2);
19771
19799
  opts.piCache.cachePaymentIntent(address2, paymentIntentId);
19772
19800
  }
19773
- opts.piCache.cacheNetworkAddresses(paymentIntentId, depositAddresses);
19774
- const preferred = opts.preferredNetwork ?? "tempo";
19775
- const payTo = depositAddresses[preferred] ?? depositAddresses.base ?? depositAddresses.tempo;
19776
- if (!payTo) {
19801
+ for (const address2 of Object.values(staticRecipients)) {
19802
+ await opts.piCache.cacheAddress(address2);
19803
+ }
19804
+ const merged = { ...depositAddresses, ...staticRecipients };
19805
+ opts.piCache.cacheNetworkAddresses(paymentIntentId, merged);
19806
+ const preferredKey = opts.preferredNetwork ?? "tempo";
19807
+ const preferred = merged[preferredKey] ?? merged.base ?? merged.tempo;
19808
+ if (!preferred) {
19777
19809
  throw new CheckoutValidationError({
19778
19810
  code: "payment_provider_unavailable",
19779
19811
  message: "Stripe returned deposit addresses but none matched the requested network (tempo / base / solana). The account may have only a subset of multichain networks enabled.",
@@ -19781,7 +19813,15 @@ async function createPayToAddressFromStripePI(opts) {
19781
19813
  status: 503
19782
19814
  });
19783
19815
  }
19784
- return payTo;
19816
+ return { preferred, merged, paymentIntentId };
19817
+ }
19818
+ function readNetworkMapFromCache(piCache, paymentIntentId) {
19819
+ const entries = [];
19820
+ for (const n of DEFAULT_NETWORKS) {
19821
+ const addr = piCache.getNetworkDepositAddress(paymentIntentId, n);
19822
+ if (addr) entries.push([n, addr]);
19823
+ }
19824
+ return Object.fromEntries(entries);
19785
19825
  }
19786
19826
 
19787
19827
  // src/stripe-multichain/simulate_deposit.ts
@@ -20006,6 +20046,7 @@ async function simulateDepositForOutcome(opts) {
20006
20046
  createMultichainPaymentIntent,
20007
20047
  createPayToAddressFromStripePI,
20008
20048
  createPiCache,
20049
+ mintMultichainRecipients,
20009
20050
  networkForOutcome,
20010
20051
  simulateCryptoDeposit,
20011
20052
  simulateDepositForOutcome,