@happyvertical/payments 0.105.2 → 0.105.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,13 +34,50 @@ import { StripeAdapter } from '@happyvertical/payments/stripe';
34
34
  Greenfield client for billing integrations — see
35
35
  [BTCPay Greenfield client](#btcpay-greenfield-client).
36
36
  - `StripeAdapter`: Stripe Checkout URL settlement, webhook verification,
37
- refunds, Stripe Connect transfers, saved payment methods / card-on-file
37
+ refunds, Stripe Connect Standard direct charges, transfers, saved payment methods / card-on-file
38
38
  (`createSetupSession` / `getSetupResult`), and the manual-capture card
39
39
  lifecycle (`authorizePayment` / `capturePayment` / `voidPayment`).
40
40
 
41
41
  The package does not depend on SMRT or a database. Consumers own quote
42
42
  persistence, webhook routing, and operational policy.
43
43
 
44
+ ### Stripe Connect Standard direct charges
45
+
46
+ Pass `stripeAccount` to a `StripeAdapter` for a fixed connected-account scope,
47
+ or to an individual Checkout, PaymentIntent, refund, status, or setup
48
+ call. The adapter sends it as Stripe's `Stripe-Account` header. With no account
49
+ configured or supplied, requests retain platform-account behavior.
50
+
51
+ ```ts
52
+ const workerCoopPayments = new StripeAdapter({
53
+ secretKey: process.env.STRIPE_SECRET_KEY!,
54
+ stripeAccount: 'acct_worker_coop',
55
+ successUrl,
56
+ cancelUrl,
57
+ });
58
+
59
+ await workerCoopPayments.createPaymentOption({
60
+ quoteId: 'project-revenue-42',
61
+ amount: 10_000,
62
+ currency: 'USD',
63
+ expiresAt,
64
+ applicationFeeAmount: 500,
65
+ });
66
+
67
+ await workerCoopPayments.refundPayment({
68
+ paymentId: 'pi_123',
69
+ amount: 10_000,
70
+ refundApplicationFee: true,
71
+ });
72
+ ```
73
+
74
+ Amounts, including `applicationFeeAmount`, are integer minor units. The fee is
75
+ collected by Stripe from the direct charge; downstream accounting must offset
76
+ the matching platform allocation so it is never a second payable. The SDK only
77
+ propagates provider flags and account scope; it does not calculate allocations
78
+ or post accounting entries. `refundApplicationFee` and `reverseTransfer` are
79
+ sent only when explicitly requested.
80
+
44
81
  ### BTCPay Greenfield client
45
82
 
46
83
  `BtcpayClient` is a stateless client for one BTCPay Server store (Greenfield
@@ -15,6 +15,39 @@ export interface StripeAdapterOptions {
15
15
  pollIntervalMs?: number;
16
16
  maxStoredPaymentOptions?: number;
17
17
  maxStoredWebhookEventIds?: number;
18
+ /** Default Stripe Connect account for this adapter's provider requests. */
19
+ stripeAccount?: string;
20
+ }
21
+ /** Stripe Connect account scope for a request; omit it for the platform. */
22
+ export interface StripeAccountScope {
23
+ stripeAccount?: string;
24
+ }
25
+ export interface StripeCreatePaymentOptionInput extends CreatePaymentOptionInput, StripeAccountScope {
26
+ /** Stripe application fee in integer minor units for this direct charge. */
27
+ applicationFeeAmount?: number;
28
+ }
29
+ export interface StripePaymentStatusContext extends PaymentStatusContext, StripeAccountScope {
30
+ }
31
+ export interface StripeRefundPaymentInput extends RefundPaymentInput, StripeAccountScope {
32
+ /** Refund a Stripe application fee collected with the charge. */
33
+ refundApplicationFee?: boolean;
34
+ /** Reverse a destination transfer when the provider supports one. */
35
+ reverseTransfer?: boolean;
36
+ }
37
+ export interface StripeAuthorizePaymentInput extends AuthorizePaymentInput, StripeAccountScope {
38
+ /** Stripe application fee in integer minor units for this PaymentIntent. */
39
+ applicationFeeAmount?: number;
40
+ }
41
+ export interface StripeCapturePaymentInput extends CapturePaymentInput, StripeAccountScope {
42
+ }
43
+ export interface StripeVoidPaymentInput extends VoidPaymentInput, StripeAccountScope {
44
+ }
45
+ export interface StripeCreateSetupSessionInput extends CreateSetupSessionInput, StripeAccountScope {
46
+ }
47
+ export interface StripeGetSetupResultInput extends GetSetupResultInput, StripeAccountScope {
48
+ }
49
+ export interface StripeWatchPaymentInput extends Omit<WatchPaymentInput, 'statusContext'> {
50
+ statusContext?: StripePaymentStatusContext;
18
51
  }
19
52
  export interface StripeWebhookEvent extends PaymentWebhookEvent {
20
53
  id: string;
@@ -35,25 +68,28 @@ export declare class StripeAdapter implements PaymentBackend {
35
68
  private readonly supportedCurrencies;
36
69
  private readonly checkoutMode;
37
70
  private readonly webhookSecret;
71
+ private readonly stripeAccount;
38
72
  private readonly maxStoredPaymentOptions;
39
73
  private readonly maxStoredWebhookEventIds;
40
74
  private readonly optionsByQuote;
41
75
  private readonly seenWebhookEventIds;
42
76
  constructor(options: StripeAdapterOptions);
43
- createPaymentOption(input: CreatePaymentOptionInput): Promise<PaymentOption>;
44
- watchPayment(input: WatchPaymentInput): AsyncIterable<PaymentEvent>;
45
- getStatus(quoteId: string, payTo: string, context?: PaymentStatusContext): Promise<PaymentStatusResult>;
77
+ createPaymentOption(input: StripeCreatePaymentOptionInput): Promise<PaymentOption>;
78
+ watchPayment(input: StripeWatchPaymentInput): AsyncIterable<PaymentEvent>;
79
+ getStatus(quoteId: string, payTo: string, context?: StripePaymentStatusContext): Promise<PaymentStatusResult>;
46
80
  sendPayout(input: SendPayoutInput): Promise<PayoutResult>;
47
- refundPayment(input: RefundPaymentInput): Promise<RefundResult>;
48
- authorizePayment(input: AuthorizePaymentInput): Promise<AuthorizationResult>;
49
- capturePayment(input: CapturePaymentInput): Promise<CaptureResult>;
50
- voidPayment(input: VoidPaymentInput): Promise<VoidResult>;
51
- createSetupSession(input: CreateSetupSessionInput): Promise<SetupSession>;
52
- getSetupResult(input: GetSetupResultInput): Promise<SavedPaymentMethod>;
81
+ refundPayment(input: StripeRefundPaymentInput): Promise<RefundResult>;
82
+ authorizePayment(input: StripeAuthorizePaymentInput): Promise<AuthorizationResult>;
83
+ capturePayment(input: StripeCapturePaymentInput): Promise<CaptureResult>;
84
+ voidPayment(input: StripeVoidPaymentInput): Promise<VoidResult>;
85
+ createSetupSession(input: StripeCreateSetupSessionInput): Promise<SetupSession>;
86
+ getSetupResult(input: StripeGetSetupResultInput): Promise<SavedPaymentMethod>;
53
87
  parseWebhookEvent(payload: string, signature?: string): StripeWebhookEvent;
54
88
  private stripeRequest;
55
89
  private assertSupportedCurrency;
56
90
  private resolveStripeRefundReferenceParam;
91
+ private resolveStripeAccount;
92
+ private findStoredOptionBySessionId;
57
93
  }
58
94
  export declare function verifyStripeWebhookSignature(payload: string, signatureHeader: string, secret: string, toleranceSeconds?: number): void;
59
95
  //# sourceMappingURL=stripe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../../src/adapters/stripe.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,SAAS,EAaf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACV,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAErB,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAM1C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,kBAAmB,SAAQ,mBAAmB;IAC7D,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,GAAG,EAAE,OAAO,CAAC;CACd;AAED,qBAAa,aAAc,YAAW,cAAc;IAgBtC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAfpC,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAAC;IAElD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAc;IAClD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAS;IACjD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAS;IAClD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoC;IACnE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;gBAE5B,OAAO,EAAE,oBAAoB;IA8FpD,mBAAmB,CACvB,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,aAAa,CAAC;IA2FzB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,aAAa,CAAC,YAAY,CAAC;IAW7D,SAAS,CACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,mBAAmB,CAAC;IA2FzB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;IA+CzD,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;IA6D/D,gBAAgB,CACpB,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,mBAAmB,CAAC;IA0FzB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAwClE,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IA+BzD,kBAAkB,CACtB,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,YAAY,CAAC;IAiGlB,cAAc,CAClB,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,kBAAkB,CAAC;IAyD9B,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,kBAAkB;YAoE5D,aAAa;IA2B3B,OAAO,CAAC,uBAAuB;YAQjB,iCAAiC;CAsBhD;AAsED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,gBAAgB,SAAM,GACrB,IAAI,CA2FN"}
1
+ {"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../../src/adapters/stripe.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,7 @@ var StripeAdapter = class {
18
18
  supportedCurrencies;
19
19
  checkoutMode;
20
20
  webhookSecret;
21
+ stripeAccount;
21
22
  maxStoredPaymentOptions;
22
23
  maxStoredWebhookEventIds;
23
24
  optionsByQuote = /* @__PURE__ */ new Map();
@@ -44,6 +45,7 @@ var StripeAdapter = class {
44
45
  this.checkoutMode = options.checkoutMode ?? "payment";
45
46
  if (this.checkoutMode !== "payment") throw new PaymentConfigurationError("StripeAdapter only supports payment Checkout mode.");
46
47
  this.webhookSecret = options.webhookSecret?.trim();
48
+ this.stripeAccount = normalizeOptionalStripeAccount(options.stripeAccount, "StripeAdapter stripeAccount");
47
49
  this.capabilities = {
48
50
  id: STRIPE_BACKEND_ID,
49
51
  displayName: "Stripe Checkout",
@@ -75,6 +77,7 @@ var StripeAdapter = class {
75
77
  const currency = normalizeStripeCurrency(input.currency);
76
78
  this.assertSupportedCurrency(currency);
77
79
  const amount = normalizePositivePaymentAmount(input.amount, currency, "Stripe Checkout amount");
80
+ const applicationFeeAmount = normalizeApplicationFeeAmount(input.applicationFeeAmount, amount, "Stripe Checkout applicationFeeAmount");
78
81
  const stripeExpiresAt = normalizeStripeCheckoutExpiresAt(normalizeDate(input.expiresAt));
79
82
  const params = {
80
83
  mode: this.checkoutMode,
@@ -89,12 +92,15 @@ var StripeAdapter = class {
89
92
  "line_items[0][price_data][currency]": currency,
90
93
  "line_items[0][price_data][unit_amount]": amount,
91
94
  "line_items[0][price_data][product_data][name]": input.description ?? `Quote ${quoteId}`,
95
+ ...applicationFeeAmount === void 0 ? {} : { "payment_intent_data[application_fee_amount]": applicationFeeAmount },
92
96
  ...flattenStripeMetadata(input.metadata),
93
97
  "metadata[quoteId]": quoteId
94
98
  };
99
+ const stripeAccount = this.resolveStripeAccount(input.stripeAccount);
95
100
  const session = await this.stripeRequest("/checkout/sessions", {
96
101
  method: "POST",
97
102
  idempotencyKey: input.idempotencyKey,
103
+ stripeAccount,
98
104
  body: formEncode(params)
99
105
  });
100
106
  const sessionId = normalizeOptionalProviderString(readProviderString(session, "id"));
@@ -114,10 +120,11 @@ var StripeAdapter = class {
114
120
  paymentUri: checkoutUrl,
115
121
  metadata: {
116
122
  sessionId,
123
+ stripeAccount,
117
124
  paymentIntent: normalizeOptionalProviderString(readProviderString(session, "payment_intent"))
118
125
  }
119
126
  };
120
- rememberPaymentOption(this.optionsByQuote, quoteId, option, this.maxStoredPaymentOptions);
127
+ rememberPaymentOption(this.optionsByQuote, stripePaymentOptionKey(quoteId, stripeAccount), option, this.maxStoredPaymentOptions);
121
128
  return option;
122
129
  }
123
130
  watchPayment(input) {
@@ -130,14 +137,19 @@ var StripeAdapter = class {
130
137
  const normalizedQuoteId = normalizeNonEmptyString(quoteId, "Stripe quoteId");
131
138
  const normalizedPayTo = normalizeNonEmptyString(payTo, "Stripe payTo");
132
139
  const contextProviderPaymentId = context.providerPaymentId === void 0 ? void 0 : normalizeNonEmptyString(context.providerPaymentId, "Stripe providerPaymentId");
133
- const sessionId = this.optionsByQuote.get(normalizedQuoteId)?.providerPaymentId ?? contextProviderPaymentId ?? extractStripeSessionId(normalizedPayTo);
140
+ const contextStripeAccount = normalizeOptionalStripeAccount(context.stripeAccount, "Stripe stripeAccount");
141
+ const scopedOption = this.optionsByQuote.get(stripePaymentOptionKey(normalizedQuoteId, contextStripeAccount ?? this.stripeAccount));
142
+ const sessionId = contextProviderPaymentId ?? extractStripeSessionId(normalizedPayTo) ?? scopedOption?.providerPaymentId;
134
143
  if (!sessionId) throw new PaymentConfigurationError("Stripe getStatus requires a Checkout Session id or URL.");
135
- const session = await this.stripeRequest(`/checkout/sessions/${encodeURIComponent(sessionId)}`);
144
+ const storedOption = this.findStoredOptionBySessionId(sessionId);
145
+ const stripeAccount = contextStripeAccount ?? readStripeOptionAccount(storedOption) ?? this.stripeAccount;
146
+ const cachedOption = this.optionsByQuote.get(stripePaymentOptionKey(normalizedQuoteId, stripeAccount));
147
+ const option = cachedOption?.providerPaymentId === sessionId ? cachedOption : void 0;
148
+ const session = await this.stripeRequest(`/checkout/sessions/${encodeURIComponent(sessionId)}`, { stripeAccount });
136
149
  const sessionQuoteId = readStripeSessionQuoteId(session);
137
150
  if (sessionQuoteId !== void 0 && sessionQuoteId !== normalizedQuoteId) throw new PaymentVerificationError(`Stripe Checkout Session quoteId ${sessionQuoteId} did not match ${normalizedQuoteId}.`);
138
151
  const paymentStatus = readString(session, "payment_status");
139
152
  const status = mapStripeStatus(readString(session, "status"), paymentStatus);
140
- const option = this.optionsByQuote.get(normalizedQuoteId);
141
153
  const contextAmount = context.amount === void 0 ? void 0 : normalizeMinorUnitAmount(context.amount, "Stripe status");
142
154
  const contextCurrency = context.currency === void 0 ? void 0 : normalizeStripeCurrency(context.currency).toUpperCase();
143
155
  const sessionCurrency = readString(session, "currency") === void 0 ? void 0 : normalizeStripeCurrency(readString(session, "currency") ?? "").toUpperCase();
@@ -194,15 +206,19 @@ var StripeAdapter = class {
194
206
  const currency = normalizeStripeCurrency(input.currency ?? this.defaultCurrency);
195
207
  this.assertSupportedCurrency(currency);
196
208
  const amount = input.amount === void 0 ? void 0 : normalizePositivePaymentAmount(input.amount, currency, "Stripe refund amount");
209
+ const stripeAccount = this.resolveStripeAccount(input.stripeAccount);
197
210
  const refundParams = {
198
- ...await this.resolveStripeRefundReferenceParam(paymentReference),
211
+ ...await this.resolveStripeRefundReferenceParam(paymentReference, stripeAccount),
199
212
  amount: amount === void 0 ? void 0 : amount,
200
213
  reason: input.reason,
214
+ refund_application_fee: input.refundApplicationFee,
215
+ reverse_transfer: input.reverseTransfer,
201
216
  ...flattenStripeMetadata(input.metadata)
202
217
  };
203
218
  const refund = await this.stripeRequest("/refunds", {
204
219
  method: "POST",
205
220
  idempotencyKey: input.idempotencyKey,
221
+ stripeAccount,
206
222
  body: formEncode(refundParams)
207
223
  });
208
224
  return {
@@ -222,15 +238,18 @@ var StripeAdapter = class {
222
238
  const paymentMethod = normalizeNonEmptyString(input.providerPaymentMethodId, "Stripe authorize providerPaymentMethodId");
223
239
  const providerCustomerId = input.providerCustomerId === void 0 ? void 0 : normalizeNonEmptyString(input.providerCustomerId, "Stripe authorize providerCustomerId");
224
240
  const quoteId = input.quoteId === void 0 ? void 0 : normalizeNonEmptyString(input.quoteId, "Stripe authorize quoteId");
241
+ const applicationFeeAmount = normalizeApplicationFeeAmount(input.applicationFeeAmount, amount, "Stripe PaymentIntent applicationFeeAmount");
225
242
  const intent = await this.stripeRequest("/payment_intents", {
226
243
  method: "POST",
227
244
  idempotencyKey: input.idempotencyKey,
245
+ stripeAccount: this.resolveStripeAccount(input.stripeAccount),
228
246
  body: formEncode({
229
247
  amount,
230
248
  currency,
231
249
  confirm: true,
232
250
  "payment_method_types[]": "card",
233
251
  description: input.description,
252
+ application_fee_amount: applicationFeeAmount,
234
253
  ...Object.fromEntries([
235
254
  ["payment_method", paymentMethod],
236
255
  ["capture_method", "manual"],
@@ -262,6 +281,7 @@ var StripeAdapter = class {
262
281
  const intent = await this.stripeRequest(`/payment_intents/${encodeURIComponent(providerPaymentId)}/capture`, {
263
282
  method: "POST",
264
283
  idempotencyKey: input.idempotencyKey,
284
+ stripeAccount: this.resolveStripeAccount(input.stripeAccount),
265
285
  body: formEncode({
266
286
  ...Object.fromEntries([["amount_to_capture", amount]]),
267
287
  ...flattenStripeMetadata(input.metadata)
@@ -282,6 +302,7 @@ var StripeAdapter = class {
282
302
  const intent = await this.stripeRequest(`/payment_intents/${encodeURIComponent(providerPaymentId)}/cancel`, {
283
303
  method: "POST",
284
304
  idempotencyKey: input.idempotencyKey,
305
+ stripeAccount: this.resolveStripeAccount(input.stripeAccount),
285
306
  body: formEncode(Object.fromEntries([["cancellation_reason", reason]]))
286
307
  });
287
308
  return {
@@ -322,6 +343,7 @@ var StripeAdapter = class {
322
343
  const session = await this.stripeRequest("/checkout/sessions", {
323
344
  method: "POST",
324
345
  idempotencyKey: input.idempotencyKey,
346
+ stripeAccount: this.resolveStripeAccount(input.stripeAccount),
325
347
  body: formEncode(params)
326
348
  });
327
349
  const sessionId = normalizeOptionalProviderString(readProviderString(session, "id"));
@@ -339,7 +361,7 @@ var StripeAdapter = class {
339
361
  const sessionId = normalizeNonEmptyString(input.sessionId, "Stripe setup sessionId");
340
362
  const query = new URLSearchParams();
341
363
  query.append("expand[]", "setup_intent.payment_method");
342
- const session = await this.stripeRequest(`/checkout/sessions/${encodeURIComponent(sessionId)}?${query.toString()}`);
364
+ const session = await this.stripeRequest(`/checkout/sessions/${encodeURIComponent(sessionId)}?${query.toString()}`, { stripeAccount: this.resolveStripeAccount(input.stripeAccount) });
343
365
  const setupIntent = readObject(session, "setup_intent");
344
366
  const paymentMethod = readObject(setupIntent, "payment_method");
345
367
  const card = readObject(paymentMethod, "card");
@@ -393,8 +415,9 @@ var StripeAdapter = class {
393
415
  headers.set("Content-Type", "application/x-www-form-urlencoded");
394
416
  headers.set("Accept", "application/json");
395
417
  headers.set("Stripe-Version", this.apiVersion);
418
+ if (init.stripeAccount !== void 0) headers.set("Stripe-Account", init.stripeAccount);
396
419
  if (init.idempotencyKey !== void 0) headers.set("Idempotency-Key", normalizeNonEmptyString(init.idempotencyKey, "Stripe idempotencyKey"));
397
- const { idempotencyKey: _idempotencyKey, ...requestInit } = init;
420
+ const { idempotencyKey: _idempotencyKey, stripeAccount: _stripeAccount, ...requestInit } = init;
398
421
  return readJsonResponse(await this.fetch(`${this.apiBaseUrl}${path}`, {
399
422
  ...requestInit,
400
423
  method: init.method ?? "GET",
@@ -404,15 +427,37 @@ var StripeAdapter = class {
404
427
  assertSupportedCurrency(currency) {
405
428
  if (!this.supportedCurrencies.has(currency)) throw new PaymentConfigurationError(`StripeAdapter currency ${currency.toUpperCase()} is not configured as supported.`);
406
429
  }
407
- async resolveStripeRefundReferenceParam(paymentReference) {
430
+ async resolveStripeRefundReferenceParam(paymentReference, stripeAccount) {
408
431
  if (paymentReference.startsWith("cs_")) {
409
- const paymentIntent = normalizeOptionalProviderString(readProviderString(await this.stripeRequest(`/checkout/sessions/${encodeURIComponent(paymentReference)}`), "payment_intent"));
432
+ const paymentIntent = normalizeOptionalProviderString(readProviderString(await this.stripeRequest(`/checkout/sessions/${encodeURIComponent(paymentReference)}`, { stripeAccount }), "payment_intent"));
410
433
  if (!paymentIntent) throw new PaymentProviderError("Stripe Checkout Session did not include payment_intent for refund.");
411
434
  return Object.fromEntries([["payment_intent", paymentIntent]]);
412
435
  }
413
436
  return stripeRefundReferenceParam(paymentReference);
414
437
  }
438
+ resolveStripeAccount(override) {
439
+ return normalizeOptionalStripeAccount(override, "Stripe stripeAccount") ?? this.stripeAccount;
440
+ }
441
+ findStoredOptionBySessionId(sessionId) {
442
+ for (const option of this.optionsByQuote.values()) if (option.providerPaymentId === sessionId) return option;
443
+ }
415
444
  };
445
+ function readStripeOptionAccount(option) {
446
+ const value = option?.metadata?.stripeAccount;
447
+ return typeof value === "string" ? value : void 0;
448
+ }
449
+ function normalizeOptionalStripeAccount(value, context) {
450
+ return value === void 0 ? void 0 : normalizeNonEmptyString(value, context);
451
+ }
452
+ function normalizeApplicationFeeAmount(value, chargeAmount, context) {
453
+ if (value === void 0) return void 0;
454
+ const fee = normalizePositiveMinorUnitAmount(value, context);
455
+ if (fee > chargeAmount) throw new PaymentConfigurationError(`${context} must not exceed the charge amount.`);
456
+ return fee;
457
+ }
458
+ function stripePaymentOptionKey(quoteId, stripeAccount) {
459
+ return stripeAccount === void 0 ? quoteId : `${stripeAccount}\0${quoteId}`;
460
+ }
416
461
  function stripeRefundReferenceParam(paymentReference) {
417
462
  if (paymentReference.startsWith("pi_")) return Object.fromEntries([["payment_intent", paymentReference]]);
418
463
  if (paymentReference.startsWith("ch_")) return { charge: paymentReference };
@@ -1 +1 @@
1
- {"version":3,"file":"stripe.js","names":[],"sources":["../../src/adapters/stripe.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from 'node:crypto';\nimport {\n PaymentConfigurationError,\n PaymentProviderError,\n PaymentVerificationError,\n} from '../errors.js';\nimport {\n applyExpiryToPendingStatus,\n type FetchLike,\n formEncode,\n getFetch,\n normalizeDate,\n normalizeMaxStoredPaymentOptions,\n normalizeMinorUnitAmount,\n normalizeNonEmptyString,\n normalizePositiveMinorUnitAmount,\n normalizePositivePaymentAmount,\n normalizeUrlString,\n pollPaymentStatus,\n readJsonResponse,\n rememberPaymentOption,\n} from '../shared.js';\nimport type {\n AuthorizationResult,\n AuthorizePaymentInput,\n CapturePaymentInput,\n CaptureResult,\n CreatePaymentOptionInput,\n CreateSetupSessionInput,\n GetSetupResultInput,\n PaymentBackend,\n PaymentBackendCapabilities,\n PaymentEvent,\n PaymentOption,\n PaymentStatus,\n PaymentStatusContext,\n PaymentStatusResult,\n PaymentWebhookEvent,\n PayoutResult,\n RefundPaymentInput,\n RefundResult,\n SavedPaymentMethod,\n SendPayoutInput,\n SetupSession,\n VoidPaymentInput,\n VoidResult,\n WatchPaymentInput,\n} from '../types.js';\n\nexport const STRIPE_BACKEND_ID = 'stripe';\nconst STRIPE_CHECKOUT_MIN_EXPIRY_MS = 30 * 60 * 1_000;\nconst STRIPE_CHECKOUT_MAX_EXPIRY_MS = 24 * 60 * 60 * 1_000;\nconst DEFAULT_STRIPE_API_VERSION = '2024-06-20';\nconst DEFAULT_MAX_STORED_WEBHOOK_EVENT_IDS = 50_000;\n\nexport interface StripeAdapterOptions {\n secretKey: string;\n fetch?: FetchLike;\n apiBaseUrl?: string;\n apiVersion?: string;\n defaultCurrency?: string;\n supportedCurrencies?: string[];\n successUrl?: string;\n cancelUrl?: string;\n checkoutMode?: string;\n webhookSecret?: string;\n pollIntervalMs?: number;\n maxStoredPaymentOptions?: number;\n maxStoredWebhookEventIds?: number;\n}\n\nexport interface StripeWebhookEvent extends PaymentWebhookEvent {\n id: string;\n type: string;\n status: PaymentStatus;\n quoteId?: string;\n providerPaymentId?: string;\n raw: unknown;\n}\n\nexport class StripeAdapter implements PaymentBackend {\n readonly capabilities: PaymentBackendCapabilities;\n\n private readonly fetch: FetchLike;\n private readonly secretKey: string;\n private readonly apiBaseUrl: string;\n private readonly apiVersion: string;\n private readonly defaultCurrency: string;\n private readonly supportedCurrencies: Set<string>;\n private readonly checkoutMode: string;\n private readonly webhookSecret: string | undefined;\n private readonly maxStoredPaymentOptions: number;\n private readonly maxStoredWebhookEventIds: number;\n private readonly optionsByQuote = new Map<string, PaymentOption>();\n private readonly seenWebhookEventIds = new Set<string>();\n\n constructor(private readonly options: StripeAdapterOptions) {\n if (typeof options.secretKey !== 'string' || !options.secretKey.trim()) {\n throw new PaymentConfigurationError('StripeAdapter requires secretKey.');\n }\n\n if (options.webhookSecret !== undefined) {\n if (typeof options.webhookSecret !== 'string') {\n throw new PaymentConfigurationError(\n 'StripeAdapter webhookSecret must be a string when configured.',\n );\n }\n\n if (!options.webhookSecret.trim()) {\n throw new PaymentConfigurationError(\n 'StripeAdapter webhookSecret must not be empty when configured.',\n );\n }\n }\n\n if (options.apiBaseUrl !== undefined) {\n if (typeof options.apiBaseUrl !== 'string') {\n throw new PaymentConfigurationError(\n 'StripeAdapter apiBaseUrl must be a string when configured.',\n );\n }\n\n if (!options.apiBaseUrl.trim()) {\n throw new PaymentConfigurationError(\n 'StripeAdapter apiBaseUrl must not be empty when configured.',\n );\n }\n }\n\n this.fetch = getFetch(options.fetch);\n this.maxStoredPaymentOptions = normalizeMaxStoredPaymentOptions(\n options.maxStoredPaymentOptions,\n 'StripeAdapter maxStoredPaymentOptions',\n );\n this.maxStoredWebhookEventIds = normalizeMaxStoredPaymentOptions(\n options.maxStoredWebhookEventIds ?? DEFAULT_MAX_STORED_WEBHOOK_EVENT_IDS,\n 'StripeAdapter maxStoredWebhookEventIds',\n );\n this.secretKey = options.secretKey.trim();\n this.apiBaseUrl = normalizeUrlString(\n options.apiBaseUrl ?? 'https://api.stripe.com/v1',\n 'StripeAdapter apiBaseUrl',\n ).replace(/\\/$/, '');\n this.apiVersion = normalizeNonEmptyString(\n options.apiVersion ?? DEFAULT_STRIPE_API_VERSION,\n 'StripeAdapter apiVersion',\n );\n this.defaultCurrency = normalizeStripeCurrency(\n options.defaultCurrency ?? 'usd',\n );\n this.supportedCurrencies = normalizeSupportedStripeCurrencies(\n options.supportedCurrencies,\n this.defaultCurrency,\n );\n this.checkoutMode = options.checkoutMode ?? 'payment';\n\n if (this.checkoutMode !== 'payment') {\n throw new PaymentConfigurationError(\n 'StripeAdapter only supports payment Checkout mode.',\n );\n }\n\n this.webhookSecret = options.webhookSecret?.trim();\n this.capabilities = {\n id: STRIPE_BACKEND_ID,\n displayName: 'Stripe Checkout',\n settlementCurrency: this.defaultCurrency.toUpperCase(),\n supportedSettlementCurrencies: [...this.supportedCurrencies].map(\n (currency) => currency.toUpperCase(),\n ),\n chain: 'stripe',\n settlementShape: 'url',\n x402Capable: false,\n confirmationLatency: {\n expectedSeconds: 5,\n maxExpectedSeconds: 600,\n description:\n 'Card payments usually confirm in seconds; bank debits can remain processing while Stripe settles them.',\n },\n supportsRefunds: true,\n supportsPayouts: true,\n supportsWebhooks: true,\n supportsManualCapture: true,\n supportsSavedPaymentMethods: true,\n metadata: {\n provider: 'stripe',\n },\n };\n }\n\n async createPaymentOption(\n input: CreatePaymentOptionInput,\n ): Promise<PaymentOption> {\n const quoteId = normalizeNonEmptyString(input.quoteId, 'Stripe quoteId');\n const rawSuccessUrl = input.successUrl ?? this.options.successUrl;\n const rawCancelUrl = input.cancelUrl ?? this.options.cancelUrl;\n\n if (rawSuccessUrl === undefined || rawCancelUrl === undefined) {\n throw new PaymentConfigurationError(\n 'StripeAdapter createPaymentOption requires successUrl and cancelUrl.',\n );\n }\n\n const successUrl = normalizeUrlString(rawSuccessUrl, 'Stripe successUrl');\n const cancelUrl = normalizeUrlString(rawCancelUrl, 'Stripe cancelUrl');\n const currency = normalizeStripeCurrency(input.currency);\n this.assertSupportedCurrency(currency);\n const amount = normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe Checkout amount',\n );\n const expiresAt = normalizeDate(input.expiresAt);\n const stripeExpiresAt = normalizeStripeCheckoutExpiresAt(expiresAt);\n const params: Record<string, unknown> = {\n mode: this.checkoutMode,\n ...Object.fromEntries([\n ['success_url', successUrl],\n ['cancel_url', cancelUrl],\n ['client_reference_id', quoteId],\n ['customer_email', input.buyerEmail],\n ['expires_at', Math.floor(stripeExpiresAt.getTime() / 1_000)],\n ]),\n 'line_items[0][quantity]': 1,\n 'line_items[0][price_data][currency]': currency,\n 'line_items[0][price_data][unit_amount]': amount,\n 'line_items[0][price_data][product_data][name]':\n input.description ?? `Quote ${quoteId}`,\n ...flattenStripeMetadata(input.metadata),\n 'metadata[quoteId]': quoteId,\n };\n\n const session = await this.stripeRequest<Record<string, unknown>>(\n '/checkout/sessions',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode(params),\n },\n );\n const sessionId = normalizeOptionalProviderString(\n readProviderString(session, 'id'),\n );\n const checkoutUrl = normalizeOptionalProviderString(\n readProviderString(session, 'url'),\n );\n\n if (!sessionId || !checkoutUrl) {\n throw new PaymentProviderError(\n 'Stripe Checkout Session response did not include id and url.',\n );\n }\n\n const option: PaymentOption = {\n backendId: this.capabilities.id,\n quoteId,\n payTo: checkoutUrl,\n settlementShape: 'url',\n settlementCurrency: currency.toUpperCase(),\n settlementAmount: amount,\n amount,\n currency: currency.toUpperCase(),\n expiresAt: stripeExpiresAt,\n providerPaymentId: sessionId,\n paymentUri: checkoutUrl,\n metadata: {\n sessionId,\n paymentIntent: normalizeOptionalProviderString(\n readProviderString(session, 'payment_intent'),\n ),\n },\n };\n\n rememberPaymentOption(\n this.optionsByQuote,\n quoteId,\n option,\n this.maxStoredPaymentOptions,\n );\n\n return option;\n }\n\n watchPayment(input: WatchPaymentInput): AsyncIterable<PaymentEvent> {\n return pollPaymentStatus(\n {\n ...input,\n pollIntervalMs:\n input.pollIntervalMs ?? this.options.pollIntervalMs ?? 5_000,\n },\n () => this.getStatus(input.quoteId, input.payTo, input.statusContext),\n );\n }\n\n async getStatus(\n quoteId: string,\n payTo: string,\n context: PaymentStatusContext = {},\n ): Promise<PaymentStatusResult> {\n const normalizedQuoteId = normalizeNonEmptyString(\n quoteId,\n 'Stripe quoteId',\n );\n const normalizedPayTo = normalizeNonEmptyString(payTo, 'Stripe payTo');\n const contextProviderPaymentId =\n context.providerPaymentId === undefined\n ? undefined\n : normalizeNonEmptyString(\n context.providerPaymentId,\n 'Stripe providerPaymentId',\n );\n const sessionId =\n this.optionsByQuote.get(normalizedQuoteId)?.providerPaymentId ??\n contextProviderPaymentId ??\n extractStripeSessionId(normalizedPayTo);\n\n if (!sessionId) {\n throw new PaymentConfigurationError(\n 'Stripe getStatus requires a Checkout Session id or URL.',\n );\n }\n\n const session = await this.stripeRequest<Record<string, unknown>>(\n `/checkout/sessions/${encodeURIComponent(sessionId)}`,\n );\n const sessionQuoteId = readStripeSessionQuoteId(session);\n\n if (sessionQuoteId !== undefined && sessionQuoteId !== normalizedQuoteId) {\n throw new PaymentVerificationError(\n `Stripe Checkout Session quoteId ${sessionQuoteId} did not match ${normalizedQuoteId}.`,\n );\n }\n\n const paymentStatus = readString(session, 'payment_status');\n const status = mapStripeStatus(\n readString(session, 'status'),\n paymentStatus,\n );\n\n const option = this.optionsByQuote.get(normalizedQuoteId);\n const contextAmount =\n context.amount === undefined\n ? undefined\n : normalizeMinorUnitAmount(context.amount, 'Stripe status');\n const contextCurrency =\n context.currency === undefined\n ? undefined\n : normalizeStripeCurrency(context.currency).toUpperCase();\n const sessionCurrency =\n readString(session, 'currency') === undefined\n ? undefined\n : normalizeStripeCurrency(\n readString(session, 'currency') ?? '',\n ).toUpperCase();\n const sessionAmount = readSafeInteger(session, 'amount_total');\n const expiresAt =\n option?.expiresAt ??\n (context.expiresAt === undefined\n ? undefined\n : normalizeDate(context.expiresAt));\n const effectiveStatus = applyExpiryToPendingStatus(status, expiresAt);\n\n return {\n backendId: this.capabilities.id,\n quoteId: normalizedQuoteId,\n payTo: normalizedPayTo,\n status: effectiveStatus,\n settlementCurrency:\n sessionCurrency ??\n option?.settlementCurrency ??\n contextCurrency ??\n this.defaultCurrency.toUpperCase(),\n settlementAmount:\n sessionAmount ?? option?.settlementAmount ?? contextAmount,\n receivedAmount:\n paymentStatus === 'paid' || paymentStatus === 'no_payment_required'\n ? (sessionAmount ?? option?.settlementAmount ?? contextAmount)\n : undefined,\n amount: option?.amount ?? contextAmount,\n currency: option?.currency ?? contextCurrency,\n providerPaymentId: sessionId,\n transactionId: normalizeOptionalProviderString(\n readProviderString(session, 'payment_intent'),\n ),\n updatedAt: new Date(),\n raw: session,\n };\n }\n\n async sendPayout(input: SendPayoutInput): Promise<PayoutResult> {\n const currency = normalizeStripeCurrency(\n input.currency ?? this.defaultCurrency,\n );\n this.assertSupportedCurrency(currency);\n const destination = normalizeNonEmptyString(\n input.destination,\n 'Stripe payout destination',\n );\n const quoteId =\n input.quoteId === undefined\n ? undefined\n : normalizeNonEmptyString(input.quoteId, 'Stripe payout quoteId');\n const amount = normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe payout amount',\n );\n const transfer = await this.stripeRequest<Record<string, unknown>>(\n '/transfers',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode({\n amount,\n currency,\n destination,\n description: input.memo,\n ...flattenStripeMetadata(input.metadata),\n ...(quoteId === undefined ? {} : { 'metadata[quoteId]': quoteId }),\n }),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: 'submitted',\n payoutId: normalizeOptionalProviderString(\n readProviderString(transfer, 'id'),\n ),\n destination,\n amount,\n currency: currency.toUpperCase(),\n raw: transfer,\n };\n }\n\n async refundPayment(input: RefundPaymentInput): Promise<RefundResult> {\n const rawPaymentReference = input.paymentId ?? input.transactionId;\n\n if (!rawPaymentReference) {\n throw new PaymentConfigurationError(\n 'Stripe refunds require paymentId or transactionId.',\n );\n }\n\n const paymentReference = normalizeNonEmptyString(\n rawPaymentReference,\n 'Stripe refund payment reference',\n );\n const currency = normalizeStripeCurrency(\n input.currency ?? this.defaultCurrency,\n );\n this.assertSupportedCurrency(currency);\n const amount =\n input.amount === undefined\n ? undefined\n : normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe refund amount',\n );\n const refundReferenceParam =\n await this.resolveStripeRefundReferenceParam(paymentReference);\n const refundParams: Record<string, unknown> = {\n ...refundReferenceParam,\n amount: amount === undefined ? undefined : amount,\n reason: input.reason,\n ...flattenStripeMetadata(input.metadata),\n };\n\n const refund = await this.stripeRequest<Record<string, unknown>>(\n '/refunds',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode(refundParams),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: mapStripeRefundStatus(readString(refund, 'status')),\n refundId: normalizeOptionalProviderString(\n readProviderString(refund, 'id'),\n ),\n transactionId: paymentReference,\n // Read the settled amount and currency back from the refund object\n // (mirrors capturePayment) so a full refund — no `input.amount` supplied,\n // and possibly a currency differing from the adapter default when\n // `input.currency` is omitted — surfaces what Stripe actually refunded\n // instead of the request defaults.\n amount: readSafeInteger(refund, 'amount') ?? amount,\n currency: readStripeResultCurrency(refund) ?? currency.toUpperCase(),\n raw: refund,\n };\n }\n\n async authorizePayment(\n input: AuthorizePaymentInput,\n ): Promise<AuthorizationResult> {\n const currency = normalizeStripeCurrency(input.currency);\n this.assertSupportedCurrency(currency);\n const amount = normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe authorize amount',\n );\n const paymentMethod = normalizeNonEmptyString(\n input.providerPaymentMethodId,\n 'Stripe authorize providerPaymentMethodId',\n );\n const providerCustomerId =\n input.providerCustomerId === undefined\n ? undefined\n : normalizeNonEmptyString(\n input.providerCustomerId,\n 'Stripe authorize providerCustomerId',\n );\n const quoteId =\n input.quoteId === undefined\n ? undefined\n : normalizeNonEmptyString(input.quoteId, 'Stripe authorize quoteId');\n\n const intent = await this.stripeRequest<Record<string, unknown>>(\n '/payment_intents',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode({\n amount,\n currency,\n confirm: true,\n 'payment_method_types[]': 'card',\n description: input.description,\n ...Object.fromEntries([\n ['payment_method', paymentMethod],\n ['capture_method', 'manual'],\n // Off-session (merchant-initiated) by default — the primary use is\n // charging a saved card while the buyer is absent. Without this,\n // Stripe treats it as on-session and may raise an SCA challenge the\n // absent buyer can't complete, so the hold is never placed.\n ['off_session', input.offSession ?? true],\n ]),\n ...(providerCustomerId === undefined\n ? {}\n : { customer: providerCustomerId }),\n ...flattenStripeMetadata(input.metadata),\n ...(quoteId === undefined ? {} : { 'metadata[quoteId]': quoteId }),\n }),\n },\n );\n\n const providerPaymentId = normalizeOptionalProviderString(\n readProviderString(intent, 'id'),\n );\n\n if (!providerPaymentId) {\n throw new PaymentProviderError(\n 'Stripe PaymentIntent response did not include an id.',\n );\n }\n\n const status = mapStripeAuthorizationStatus(readString(intent, 'status'));\n // Only surface the SCA fields when authentication is actually required — the\n // documented contract — even though Stripe returns client_secret regardless.\n // (Authorization progress is observed via `parseWebhookEvent`, which surfaces\n // the ready-to-capture transition as `processing` — there is no distinct\n // `requires_capture` webhook status; `getStatus` handles Checkout sessions,\n // not PaymentIntents.)\n const actionRequired = status === 'requires_action';\n\n return {\n backendId: this.capabilities.id,\n status,\n providerPaymentId,\n amount: readSafeInteger(intent, 'amount') ?? amount,\n currency: (readString(intent, 'currency') ?? currency).toUpperCase(),\n clientSecret: actionRequired\n ? normalizeOptionalProviderString(\n readProviderString(intent, 'client_secret'),\n )\n : undefined,\n nextAction: actionRequired\n ? (intent.next_action ?? undefined)\n : undefined,\n raw: intent,\n };\n }\n\n async capturePayment(input: CapturePaymentInput): Promise<CaptureResult> {\n const providerPaymentId = normalizeNonEmptyString(\n input.providerPaymentId,\n 'Stripe capture providerPaymentId',\n );\n const amount =\n input.amount === undefined\n ? undefined\n : normalizePositiveMinorUnitAmount(\n input.amount,\n 'Stripe capture amount',\n );\n\n const intent = await this.stripeRequest<Record<string, unknown>>(\n `/payment_intents/${encodeURIComponent(providerPaymentId)}/capture`,\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode({\n ...Object.fromEntries([['amount_to_capture', amount]]),\n ...flattenStripeMetadata(input.metadata),\n }),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: mapStripeCaptureStatus(readString(intent, 'status')),\n providerPaymentId:\n normalizeOptionalProviderString(readProviderString(intent, 'id')) ??\n providerPaymentId,\n amount:\n readSafeInteger(intent, 'amount_received') ??\n readSafeInteger(intent, 'amount') ??\n amount,\n currency: readStripeResultCurrency(intent),\n raw: intent,\n };\n }\n\n async voidPayment(input: VoidPaymentInput): Promise<VoidResult> {\n const providerPaymentId = normalizeNonEmptyString(\n input.providerPaymentId,\n 'Stripe void providerPaymentId',\n );\n const reason =\n input.reason === undefined\n ? undefined\n : normalizeNonEmptyString(input.reason, 'Stripe void reason');\n\n const intent = await this.stripeRequest<Record<string, unknown>>(\n `/payment_intents/${encodeURIComponent(providerPaymentId)}/cancel`,\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode(Object.fromEntries([['cancellation_reason', reason]])),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: mapStripeVoidStatus(readString(intent, 'status')),\n providerPaymentId:\n normalizeOptionalProviderString(readProviderString(intent, 'id')) ??\n providerPaymentId,\n amount: readSafeInteger(intent, 'amount'),\n currency: readStripeResultCurrency(intent),\n raw: intent,\n };\n }\n\n async createSetupSession(\n input: CreateSetupSessionInput,\n ): Promise<SetupSession> {\n const rawSuccessUrl = input.successUrl ?? this.options.successUrl;\n const rawCancelUrl = input.cancelUrl ?? this.options.cancelUrl;\n\n if (rawSuccessUrl === undefined || rawCancelUrl === undefined) {\n throw new PaymentConfigurationError(\n 'StripeAdapter createSetupSession requires successUrl and cancelUrl.',\n );\n }\n\n const successUrl = normalizeUrlString(rawSuccessUrl, 'Stripe successUrl');\n const cancelUrl = normalizeUrlString(rawCancelUrl, 'Stripe cancelUrl');\n // Currency for the setup-mode session (defaults to the backend currency).\n // Redundant now that payment_method_types is always set, but harmless and\n // kept so the session is well-formed if that restriction is ever relaxed.\n const currency = normalizeStripeCurrency(\n input.currency ?? this.defaultCurrency,\n );\n this.assertSupportedCurrency(currency);\n const providerCustomerId =\n input.providerCustomerId === undefined\n ? undefined\n : normalizeNonEmptyString(\n input.providerCustomerId,\n 'Stripe setup customer',\n );\n\n // Either attach to an existing customer, or force Stripe to create one so\n // the saved method comes back with a reusable `cus_` reference. Setup-mode\n // sessions do NOT create a customer on their own — `customer_creation` must\n // be `always`. All snake_case keys go through Object.fromEntries.\n const customerParams: [string, unknown][] = [];\n if (providerCustomerId !== undefined) {\n customerParams.push(['customer', providerCustomerId]);\n } else {\n customerParams.push(['customer_creation', 'always']);\n if (input.customerEmail !== undefined) {\n customerParams.push([\n 'customer_email',\n normalizeNonEmptyString(\n input.customerEmail,\n 'Stripe setup customerEmail',\n ),\n ]);\n }\n }\n\n const params: Record<string, unknown> = {\n mode: 'setup',\n currency,\n // Restrict to cards: SavedPaymentMethod exposes card display fields\n // (brand/last4/expiry), so allowing SEPA/Bacs/etc. would yield saved\n // methods with no usable display detail.\n 'payment_method_types[]': 'card',\n ...Object.fromEntries([\n ['success_url', successUrl],\n ['cancel_url', cancelUrl],\n ...customerParams,\n ]),\n ...flattenStripeMetadata(input.metadata),\n };\n\n const session = await this.stripeRequest<Record<string, unknown>>(\n '/checkout/sessions',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode(params),\n },\n );\n\n const sessionId = normalizeOptionalProviderString(\n readProviderString(session, 'id'),\n );\n const url = normalizeOptionalProviderString(\n readProviderString(session, 'url'),\n );\n\n if (!sessionId || !url) {\n throw new PaymentProviderError(\n 'Stripe setup Checkout Session response did not include id and url.',\n );\n }\n\n return {\n backendId: this.capabilities.id,\n sessionId,\n url,\n providerCustomerId:\n providerCustomerId ??\n normalizeOptionalProviderString(\n readProviderString(session, 'customer'),\n ),\n raw: session,\n };\n }\n\n async getSetupResult(\n input: GetSetupResultInput,\n ): Promise<SavedPaymentMethod> {\n const sessionId = normalizeNonEmptyString(\n input.sessionId,\n 'Stripe setup sessionId',\n );\n\n const query = new URLSearchParams();\n query.append('expand[]', 'setup_intent.payment_method');\n\n const session = await this.stripeRequest<Record<string, unknown>>(\n `/checkout/sessions/${encodeURIComponent(sessionId)}?${query.toString()}`,\n );\n\n const setupIntent = readObject(session, 'setup_intent');\n const paymentMethod = readObject(setupIntent, 'payment_method');\n const card = readObject(paymentMethod, 'card');\n\n // `customer` is a bare `cus_` string on the request path (only\n // setup_intent.payment_method is expanded), but read tolerantly of an\n // expanded object so a future `expand[]=customer` can't wrongly downgrade a\n // completed setup to a permanent `pending`.\n const providerCustomerId = normalizeOptionalProviderString(\n readProviderString(session, 'customer') ??\n readProviderString(readObject(session, 'customer'), 'id'),\n );\n const providerPaymentMethodId = normalizeOptionalProviderString(\n readProviderString(paymentMethod, 'id'),\n );\n\n let status = mapStripeSetupStatus(\n readString(session, 'status'),\n readString(setupIntent, 'status'),\n );\n // Never report `complete` without the reusable references a caller needs to\n // charge the method later — a `pm_` with no `cus_` can't be charged\n // off-session, so treat that as not-yet-ready rather than a false success.\n if (\n status === 'complete' &&\n (!providerCustomerId || !providerPaymentMethodId)\n ) {\n status = 'pending';\n }\n\n return {\n backendId: this.capabilities.id,\n status,\n providerCustomerId,\n providerPaymentMethodId,\n type: readString(paymentMethod, 'type'),\n brand: readString(card, 'brand'),\n last4: readString(card, 'last4'),\n expMonth: readSafeInteger(card, 'exp_month'),\n expYear: readSafeInteger(card, 'exp_year'),\n raw: session,\n };\n }\n\n parseWebhookEvent(payload: string, signature?: string): StripeWebhookEvent {\n if (!this.webhookSecret) {\n throw new PaymentConfigurationError(\n 'StripeAdapter parseWebhookEvent requires webhookSecret.',\n );\n }\n\n if (!signature) {\n throw new PaymentProviderError('Missing Stripe webhook signature.');\n }\n\n verifyStripeWebhookSignature(payload, signature, this.webhookSecret);\n\n const event = parseStripeWebhookPayload(payload);\n const id = readRequiredWebhookString(\n event,\n 'id',\n 'Stripe webhook event id',\n );\n const type = readRequiredWebhookString(\n event,\n 'type',\n 'Stripe webhook event type',\n );\n\n const duplicate = this.seenWebhookEventIds.has(id);\n\n if (!duplicate) {\n this.seenWebhookEventIds.add(id);\n while (this.seenWebhookEventIds.size > this.maxStoredWebhookEventIds) {\n const oldest = this.seenWebhookEventIds.values().next().value;\n\n if (oldest === undefined) {\n break;\n }\n\n this.seenWebhookEventIds.delete(oldest);\n }\n }\n\n const data = (\n event.data as { object?: Record<string, unknown> } | undefined\n )?.object;\n\n return {\n id,\n type,\n status: mapStripeWebhookStatus(type, data),\n quoteId: normalizeOptionalWebhookString(\n // `client_reference_id` is a Checkout Session-only field; honor it only\n // for session events so a non-session object (a PaymentIntent / Charge /\n // Transfer, possibly from a malicious Connect account) can't spoof\n // correlation to another quote's id. Non-session events correlate only\n // via our own `metadata.quoteId`.\n (type.startsWith('checkout.session.')\n ? readString(data, 'client_reference_id')\n : undefined) ??\n readString(\n (data?.metadata as Record<string, unknown>) ?? {},\n 'quoteId',\n ),\n ),\n providerPaymentId: normalizeOptionalWebhookString(readString(data, 'id')),\n duplicate,\n raw: event,\n };\n }\n\n private async stripeRequest<T>(\n path: string,\n init: RequestInit & { idempotencyKey?: string } = {},\n ): Promise<T> {\n const headers = new Headers(init.headers);\n headers.set('Authorization', `Bearer ${this.secretKey}`);\n headers.set('Content-Type', 'application/x-www-form-urlencoded');\n headers.set('Accept', 'application/json');\n headers.set('Stripe-Version', this.apiVersion);\n\n if (init.idempotencyKey !== undefined) {\n headers.set(\n 'Idempotency-Key',\n normalizeNonEmptyString(init.idempotencyKey, 'Stripe idempotencyKey'),\n );\n }\n\n const { idempotencyKey: _idempotencyKey, ...requestInit } = init;\n const response = await this.fetch(`${this.apiBaseUrl}${path}`, {\n ...requestInit,\n method: init.method ?? 'GET',\n headers,\n });\n\n return readJsonResponse<T>(response, `Stripe ${path}`);\n }\n\n private assertSupportedCurrency(currency: string): void {\n if (!this.supportedCurrencies.has(currency)) {\n throw new PaymentConfigurationError(\n `StripeAdapter currency ${currency.toUpperCase()} is not configured as supported.`,\n );\n }\n }\n\n private async resolveStripeRefundReferenceParam(\n paymentReference: string,\n ): Promise<Record<string, string>> {\n if (paymentReference.startsWith('cs_')) {\n const session = await this.stripeRequest<Record<string, unknown>>(\n `/checkout/sessions/${encodeURIComponent(paymentReference)}`,\n );\n const paymentIntent = normalizeOptionalProviderString(\n readProviderString(session, 'payment_intent'),\n );\n\n if (!paymentIntent) {\n throw new PaymentProviderError(\n 'Stripe Checkout Session did not include payment_intent for refund.',\n );\n }\n\n return Object.fromEntries([['payment_intent', paymentIntent]]);\n }\n\n return stripeRefundReferenceParam(paymentReference);\n }\n}\n\nfunction stripeRefundReferenceParam(\n paymentReference: string,\n): Record<string, string> {\n if (paymentReference.startsWith('pi_')) {\n return Object.fromEntries([['payment_intent', paymentReference]]);\n }\n\n if (paymentReference.startsWith('ch_')) {\n return { charge: paymentReference };\n }\n\n throw new PaymentConfigurationError(\n 'Stripe refunds require a Checkout Session (cs_), payment_intent (pi_), or charge (ch_) reference.',\n );\n}\n\nfunction normalizeStripeCurrency(value: string): string {\n if (typeof value !== 'string') {\n throw new PaymentConfigurationError(\n `StripeAdapter currency must be a three-letter ISO currency code, received ${String(value)}.`,\n );\n }\n\n const normalized = value.trim().toLowerCase();\n\n if (!/^[a-z]{3}$/.test(normalized)) {\n throw new PaymentConfigurationError(\n `StripeAdapter currency must be a three-letter ISO currency code, received ${String(value)}.`,\n );\n }\n\n return normalized;\n}\n\nfunction normalizeSupportedStripeCurrencies(\n configuredCurrencies: string[] | undefined,\n defaultCurrency: string,\n): Set<string> {\n const normalized = new Set(\n (configuredCurrencies ?? ['usd', 'eur', 'gbp', 'cad']).map(\n normalizeStripeCurrency,\n ),\n );\n normalized.add(defaultCurrency);\n\n return normalized;\n}\n\nfunction normalizeStripeCheckoutExpiresAt(\n expiresAt: Date,\n now = Date.now(),\n): Date {\n if (expiresAt.getTime() <= now) {\n throw new PaymentProviderError('Stripe Checkout expiry is in the past.');\n }\n\n const min = now + STRIPE_CHECKOUT_MIN_EXPIRY_MS;\n const max = now + STRIPE_CHECKOUT_MAX_EXPIRY_MS;\n\n if (expiresAt.getTime() < min || expiresAt.getTime() > max) {\n throw new PaymentConfigurationError(\n 'Stripe Checkout expiry must be at least 30 minutes and no more than 24 hours from now.',\n );\n }\n\n return expiresAt;\n}\n\nexport function verifyStripeWebhookSignature(\n payload: string,\n signatureHeader: string,\n secret: string,\n toleranceSeconds = 300,\n): void {\n if (typeof payload !== 'string') {\n throw new PaymentProviderError('Stripe webhook payload must be a string.');\n }\n\n const normalizedSignatureHeader = normalizeNonEmptyString(\n signatureHeader,\n 'Stripe signature header',\n );\n const normalizedSecret = normalizeNonEmptyString(\n secret,\n 'Stripe webhook secret',\n );\n\n if (!Number.isFinite(toleranceSeconds) || toleranceSeconds < 0) {\n throw new PaymentConfigurationError(\n `Stripe webhook toleranceSeconds must be a non-negative finite number, received ${String(toleranceSeconds)}.`,\n );\n }\n\n const timestampCandidates: string[] = [];\n const signatures: string[] = [];\n\n for (const part of normalizedSignatureHeader.split(',')) {\n const [rawKey, ...rawValue] = part.split('=');\n const key = rawKey?.trim();\n const value = rawValue.join('=').trim();\n\n if (!key || !value) {\n continue;\n }\n\n if (key === 't') {\n timestampCandidates.push(value);\n }\n\n if (key === 'v1') {\n signatures.push(value);\n }\n }\n\n if (timestampCandidates.length !== 1 || signatures.length === 0) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const timestamp = timestampCandidates[0] ?? '';\n\n if (!/^\\d+$/.test(timestamp)) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const timestampSeconds = Number(timestamp);\n\n if (!Number.isSafeInteger(timestampSeconds)) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const nowSeconds = Date.now() / 1_000;\n const ageSeconds = nowSeconds - timestampSeconds;\n\n if (ageSeconds < -5) {\n throw new PaymentProviderError(\n 'Stripe webhook signature timestamp is in the future.',\n );\n }\n\n if (ageSeconds > toleranceSeconds) {\n throw new PaymentProviderError('Stripe webhook signature is too old.');\n }\n\n const expected = createHmac('sha256', normalizedSecret)\n .update(`${timestamp}.${payload}`)\n .digest('hex');\n const expectedBuffer = Buffer.from(expected, 'hex');\n\n for (const signature of signatures) {\n if (!/^[0-9a-f]+$/i.test(signature)) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const actualBuffer = Buffer.from(signature, 'hex');\n\n if (\n expectedBuffer.length === actualBuffer.length &&\n timingSafeEqual(expectedBuffer, actualBuffer)\n ) {\n return;\n }\n }\n\n throw new PaymentProviderError('Invalid Stripe webhook signature.');\n}\n\nfunction parseStripeWebhookPayload(payload: string): Record<string, unknown> {\n try {\n const event = JSON.parse(payload);\n\n if (!event || typeof event !== 'object' || Array.isArray(event)) {\n throw new PaymentProviderError('Invalid Stripe webhook JSON payload.');\n }\n\n return event as Record<string, unknown>;\n } catch (error) {\n if (error instanceof PaymentProviderError) {\n throw error;\n }\n\n throw new PaymentProviderError('Invalid Stripe webhook JSON payload.', {\n cause: error,\n });\n }\n}\n\nfunction normalizeOptionalWebhookString(\n value: string | undefined,\n): string | undefined {\n const normalized = value?.trim();\n\n return normalized ? normalized : undefined;\n}\n\nfunction normalizeOptionalProviderString(\n value: string | undefined,\n): string | undefined {\n const normalized = value?.trim();\n\n return normalized ? normalized : undefined;\n}\n\nfunction readProviderString(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const item = value[key];\n\n return typeof item === 'string' ? item : undefined;\n}\n\nfunction readRequiredWebhookString(\n value: Record<string, unknown>,\n key: string,\n context: string,\n): string {\n const item = value[key];\n\n if (typeof item !== 'string') {\n throw new PaymentProviderError(`${context} must be a string.`);\n }\n\n return normalizeNonEmptyString(item, context);\n}\n\nfunction readStripeSessionQuoteId(\n session: Record<string, unknown>,\n): string | undefined {\n return normalizeOptionalWebhookString(\n readString(session, 'client_reference_id') ??\n readString(\n (session.metadata as Record<string, unknown>) ?? {},\n 'quoteId',\n ),\n );\n}\n\nfunction mapStripeStatus(\n checkoutStatus: string | undefined,\n paymentStatus: string | undefined,\n): PaymentStatus {\n if (paymentStatus === 'paid' || paymentStatus === 'no_payment_required') {\n return 'confirmed';\n }\n\n if (checkoutStatus === 'expired') {\n return 'expired';\n }\n\n if (paymentStatus === 'unpaid' || checkoutStatus === 'open') {\n return 'pending';\n }\n\n if (checkoutStatus === 'complete') {\n return 'processing';\n }\n\n return 'pending';\n}\n\nfunction mapStripeWebhookStatus(\n type: string | undefined,\n object: Record<string, unknown> | undefined,\n): PaymentStatus {\n if (type === 'checkout.session.completed') {\n return mapStripeStatus(\n readString(object, 'status'),\n readString(object, 'payment_status'),\n );\n }\n\n if (type === 'checkout.session.async_payment_succeeded') {\n return 'confirmed';\n }\n\n if (type === 'checkout.session.async_payment_failed') {\n return 'failed';\n }\n\n if (type === 'checkout.session.expired') {\n return 'expired';\n }\n\n // Manual-capture PaymentIntent lifecycle (authorize → capture / void). Only\n // treat these as terminal for intents WE created and can correlate — i.e.\n // ones carrying our `quoteId` in metadata. Checkout Sessions create their own\n // PaymentIntents (which fire these same events with no quoteId on the intent);\n // those are handled via the `checkout.session.*` events above, so here they\n // stay non-terminal (`processing`) rather than emitting a spurious,\n // uncorrelatable terminal event. Handled before the generic `failed` catch\n // below so an un-owned `payment_intent.payment_failed` isn't reclassified.\n if (\n type === 'payment_intent.succeeded' ||\n type === 'payment_intent.canceled' ||\n type === 'payment_intent.payment_failed'\n ) {\n const metadata = (object?.metadata as Record<string, unknown>) ?? {};\n // Match parseWebhookEvent's normalization so an empty/blank quoteId is\n // treated as un-owned by both — gate and reporter must agree on ownership.\n const owned =\n normalizeOptionalWebhookString(readString(metadata, 'quoteId')) !==\n undefined;\n if (owned) {\n if (type === 'payment_intent.succeeded') {\n return 'confirmed';\n }\n // A manual-capture hold Stripe released automatically (it lapsed) is\n // `expired`, distinct from a deliberate void or hard decline (`failed`);\n // the shared PaymentStatus union has no `canceled`.\n if (\n type === 'payment_intent.canceled' &&\n readString(object, 'cancellation_reason') === 'automatic'\n ) {\n return 'expired';\n }\n return 'failed';\n }\n return 'processing';\n }\n\n // Terminal failure/refund only for payment-in objects (Checkout Session,\n // PaymentIntent, Charge). Money-out / unrelated events (transfer.failed,\n // payout.failed, refund.failed, application_fee.refunded, …) also match a\n // naive substring scan — and a failed Transfer even carries our quoteId\n // (sendPayout stamps it), which would miscorrelate a payout failure as a\n // payment failure — so they must not surface as a terminal payment status.\n const isPaymentInEvent =\n type?.startsWith('checkout.session.') === true ||\n type?.startsWith('payment_intent.') === true ||\n type?.startsWith('charge.') === true;\n\n if (isPaymentInEvent && type?.includes('refunded')) {\n return 'refunded';\n }\n\n if (isPaymentInEvent && type?.includes('failed')) {\n return 'failed';\n }\n\n return 'processing';\n}\n\nfunction mapStripeRefundStatus(\n status: string | undefined,\n): RefundResult['status'] {\n switch (status) {\n case 'succeeded':\n return 'succeeded';\n case 'failed':\n case 'canceled':\n return 'failed';\n case 'requires_action':\n return 'requires_action';\n default:\n return 'submitted';\n }\n}\n\nfunction mapStripeAuthorizationStatus(\n status: string | undefined,\n): AuthorizationResult['status'] {\n switch (status) {\n case 'requires_capture':\n return 'requires_capture';\n case 'succeeded':\n return 'succeeded';\n case 'requires_action':\n return 'requires_action';\n case 'processing':\n return 'processing';\n default:\n return 'failed';\n }\n}\n\nfunction mapStripeCaptureStatus(\n status: string | undefined,\n): CaptureResult['status'] {\n switch (status) {\n case 'succeeded':\n return 'succeeded';\n // Capturing an authorized intent shouldn't re-enter authentication; treat\n // any in-flight/action state as still processing rather than a failure.\n case 'processing':\n case 'requires_action':\n return 'processing';\n default:\n return 'failed';\n }\n}\n\nfunction mapStripeVoidStatus(status: string | undefined): VoidResult['status'] {\n return status === 'canceled' ? 'canceled' : 'failed';\n}\n\nfunction readStripeResultCurrency(\n value: Record<string, unknown>,\n): string | undefined {\n const currency = readString(value, 'currency');\n\n return currency === undefined ? undefined : currency.toUpperCase();\n}\n\nfunction mapStripeSetupStatus(\n sessionStatus: string | undefined,\n setupIntentStatus: string | undefined,\n): SavedPaymentMethod['status'] {\n if (sessionStatus === 'expired') {\n return 'expired';\n }\n\n if (sessionStatus === 'complete') {\n // The method is reusable only once the SetupIntent itself has succeeded —\n // the Session can be `complete` while the intent is still `processing`\n // (async setup methods via dynamic payment methods).\n if (setupIntentStatus === 'succeeded') {\n return 'complete';\n }\n // A finished session whose SetupIntent didn't succeed is a terminal\n // failure (card declined → `requires_payment_method`, or `canceled`), so\n // callers can stop polling instead of waiting on a `pending` that will\n // never resolve. Still-in-flight states (`processing`, `requires_action`)\n // remain `pending`.\n if (\n setupIntentStatus === 'canceled' ||\n setupIntentStatus === 'requires_payment_method'\n ) {\n return 'failed';\n }\n }\n\n return 'pending';\n}\n\nfunction readObject(\n value: Record<string, unknown> | undefined,\n key: string,\n): Record<string, unknown> | undefined {\n const item = value?.[key];\n\n return item && typeof item === 'object' && !Array.isArray(item)\n ? (item as Record<string, unknown>)\n : undefined;\n}\n\nfunction extractStripeSessionId(payTo: string): string | undefined {\n if (/^cs_(test_|live_)?[A-Za-z0-9_]+$/.test(payTo)) {\n return payTo;\n }\n\n try {\n const url = new URL(payTo);\n const match = url.pathname.match(/\\/pay\\/([^/?#]+)/);\n\n const sessionId = match?.[1];\n\n return sessionId && /^cs_(test_|live_)?[A-Za-z0-9_]+$/.test(sessionId)\n ? sessionId\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction flattenStripeMetadata(\n metadata:\n | Record<string, string | number | boolean | null | undefined>\n | undefined,\n): Record<string, string | number | boolean> {\n const result: Record<string, string | number | boolean> = {};\n\n for (const [key, value] of Object.entries(metadata ?? {})) {\n if (value !== undefined && value !== null) {\n result[`metadata[${key}]`] = value;\n }\n }\n\n return result;\n}\n\nfunction readString(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const item = value[key];\n\n if (typeof item === 'string') {\n return item;\n }\n\n if (typeof item === 'number') {\n return String(item);\n }\n\n return undefined;\n}\n\nfunction readSafeInteger(\n value: Record<string, unknown> | undefined,\n key: string,\n): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const item = value[key];\n\n return typeof item === 'number' && Number.isSafeInteger(item) && item >= 0\n ? item\n : undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stripe.js","names":[],"sources":["../../src/adapters/stripe.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from 'node:crypto';\nimport {\n PaymentConfigurationError,\n PaymentProviderError,\n PaymentVerificationError,\n} from '../errors.js';\nimport {\n applyExpiryToPendingStatus,\n type FetchLike,\n formEncode,\n getFetch,\n normalizeDate,\n normalizeMaxStoredPaymentOptions,\n normalizeMinorUnitAmount,\n normalizeNonEmptyString,\n normalizePositiveMinorUnitAmount,\n normalizePositivePaymentAmount,\n normalizeUrlString,\n pollPaymentStatus,\n readJsonResponse,\n rememberPaymentOption,\n} from '../shared.js';\nimport type {\n AuthorizationResult,\n AuthorizePaymentInput,\n CapturePaymentInput,\n CaptureResult,\n CreatePaymentOptionInput,\n CreateSetupSessionInput,\n GetSetupResultInput,\n PaymentBackend,\n PaymentBackendCapabilities,\n PaymentEvent,\n PaymentOption,\n PaymentStatus,\n PaymentStatusContext,\n PaymentStatusResult,\n PaymentWebhookEvent,\n PayoutResult,\n RefundPaymentInput,\n RefundResult,\n SavedPaymentMethod,\n SendPayoutInput,\n SetupSession,\n VoidPaymentInput,\n VoidResult,\n WatchPaymentInput,\n} from '../types.js';\n\nexport const STRIPE_BACKEND_ID = 'stripe';\nconst STRIPE_CHECKOUT_MIN_EXPIRY_MS = 30 * 60 * 1_000;\nconst STRIPE_CHECKOUT_MAX_EXPIRY_MS = 24 * 60 * 60 * 1_000;\nconst DEFAULT_STRIPE_API_VERSION = '2024-06-20';\nconst DEFAULT_MAX_STORED_WEBHOOK_EVENT_IDS = 50_000;\n\nexport interface StripeAdapterOptions {\n secretKey: string;\n fetch?: FetchLike;\n apiBaseUrl?: string;\n apiVersion?: string;\n defaultCurrency?: string;\n supportedCurrencies?: string[];\n successUrl?: string;\n cancelUrl?: string;\n checkoutMode?: string;\n webhookSecret?: string;\n pollIntervalMs?: number;\n maxStoredPaymentOptions?: number;\n maxStoredWebhookEventIds?: number;\n /** Default Stripe Connect account for this adapter's provider requests. */\n stripeAccount?: string;\n}\n\n/** Stripe Connect account scope for a request; omit it for the platform. */\nexport interface StripeAccountScope {\n stripeAccount?: string;\n}\n\nexport interface StripeCreatePaymentOptionInput\n extends CreatePaymentOptionInput,\n StripeAccountScope {\n /** Stripe application fee in integer minor units for this direct charge. */\n applicationFeeAmount?: number;\n}\n\nexport interface StripePaymentStatusContext\n extends PaymentStatusContext,\n StripeAccountScope {}\n\nexport interface StripeRefundPaymentInput\n extends RefundPaymentInput,\n StripeAccountScope {\n /** Refund a Stripe application fee collected with the charge. */\n refundApplicationFee?: boolean;\n /** Reverse a destination transfer when the provider supports one. */\n reverseTransfer?: boolean;\n}\n\nexport interface StripeAuthorizePaymentInput\n extends AuthorizePaymentInput,\n StripeAccountScope {\n /** Stripe application fee in integer minor units for this PaymentIntent. */\n applicationFeeAmount?: number;\n}\n\nexport interface StripeCapturePaymentInput\n extends CapturePaymentInput,\n StripeAccountScope {}\n\nexport interface StripeVoidPaymentInput\n extends VoidPaymentInput,\n StripeAccountScope {}\n\nexport interface StripeCreateSetupSessionInput\n extends CreateSetupSessionInput,\n StripeAccountScope {}\n\nexport interface StripeGetSetupResultInput\n extends GetSetupResultInput,\n StripeAccountScope {}\n\nexport interface StripeWatchPaymentInput\n extends Omit<WatchPaymentInput, 'statusContext'> {\n statusContext?: StripePaymentStatusContext;\n}\n\nexport interface StripeWebhookEvent extends PaymentWebhookEvent {\n id: string;\n type: string;\n status: PaymentStatus;\n quoteId?: string;\n providerPaymentId?: string;\n raw: unknown;\n}\n\nexport class StripeAdapter implements PaymentBackend {\n readonly capabilities: PaymentBackendCapabilities;\n\n private readonly fetch: FetchLike;\n private readonly secretKey: string;\n private readonly apiBaseUrl: string;\n private readonly apiVersion: string;\n private readonly defaultCurrency: string;\n private readonly supportedCurrencies: Set<string>;\n private readonly checkoutMode: string;\n private readonly webhookSecret: string | undefined;\n private readonly stripeAccount: string | undefined;\n private readonly maxStoredPaymentOptions: number;\n private readonly maxStoredWebhookEventIds: number;\n private readonly optionsByQuote = new Map<string, PaymentOption>();\n private readonly seenWebhookEventIds = new Set<string>();\n\n constructor(private readonly options: StripeAdapterOptions) {\n if (typeof options.secretKey !== 'string' || !options.secretKey.trim()) {\n throw new PaymentConfigurationError('StripeAdapter requires secretKey.');\n }\n\n if (options.webhookSecret !== undefined) {\n if (typeof options.webhookSecret !== 'string') {\n throw new PaymentConfigurationError(\n 'StripeAdapter webhookSecret must be a string when configured.',\n );\n }\n\n if (!options.webhookSecret.trim()) {\n throw new PaymentConfigurationError(\n 'StripeAdapter webhookSecret must not be empty when configured.',\n );\n }\n }\n\n if (options.apiBaseUrl !== undefined) {\n if (typeof options.apiBaseUrl !== 'string') {\n throw new PaymentConfigurationError(\n 'StripeAdapter apiBaseUrl must be a string when configured.',\n );\n }\n\n if (!options.apiBaseUrl.trim()) {\n throw new PaymentConfigurationError(\n 'StripeAdapter apiBaseUrl must not be empty when configured.',\n );\n }\n }\n\n this.fetch = getFetch(options.fetch);\n this.maxStoredPaymentOptions = normalizeMaxStoredPaymentOptions(\n options.maxStoredPaymentOptions,\n 'StripeAdapter maxStoredPaymentOptions',\n );\n this.maxStoredWebhookEventIds = normalizeMaxStoredPaymentOptions(\n options.maxStoredWebhookEventIds ?? DEFAULT_MAX_STORED_WEBHOOK_EVENT_IDS,\n 'StripeAdapter maxStoredWebhookEventIds',\n );\n this.secretKey = options.secretKey.trim();\n this.apiBaseUrl = normalizeUrlString(\n options.apiBaseUrl ?? 'https://api.stripe.com/v1',\n 'StripeAdapter apiBaseUrl',\n ).replace(/\\/$/, '');\n this.apiVersion = normalizeNonEmptyString(\n options.apiVersion ?? DEFAULT_STRIPE_API_VERSION,\n 'StripeAdapter apiVersion',\n );\n this.defaultCurrency = normalizeStripeCurrency(\n options.defaultCurrency ?? 'usd',\n );\n this.supportedCurrencies = normalizeSupportedStripeCurrencies(\n options.supportedCurrencies,\n this.defaultCurrency,\n );\n this.checkoutMode = options.checkoutMode ?? 'payment';\n\n if (this.checkoutMode !== 'payment') {\n throw new PaymentConfigurationError(\n 'StripeAdapter only supports payment Checkout mode.',\n );\n }\n\n this.webhookSecret = options.webhookSecret?.trim();\n this.stripeAccount = normalizeOptionalStripeAccount(\n options.stripeAccount,\n 'StripeAdapter stripeAccount',\n );\n this.capabilities = {\n id: STRIPE_BACKEND_ID,\n displayName: 'Stripe Checkout',\n settlementCurrency: this.defaultCurrency.toUpperCase(),\n supportedSettlementCurrencies: [...this.supportedCurrencies].map(\n (currency) => currency.toUpperCase(),\n ),\n chain: 'stripe',\n settlementShape: 'url',\n x402Capable: false,\n confirmationLatency: {\n expectedSeconds: 5,\n maxExpectedSeconds: 600,\n description:\n 'Card payments usually confirm in seconds; bank debits can remain processing while Stripe settles them.',\n },\n supportsRefunds: true,\n supportsPayouts: true,\n supportsWebhooks: true,\n supportsManualCapture: true,\n supportsSavedPaymentMethods: true,\n metadata: {\n provider: 'stripe',\n },\n };\n }\n\n async createPaymentOption(\n input: StripeCreatePaymentOptionInput,\n ): Promise<PaymentOption> {\n const quoteId = normalizeNonEmptyString(input.quoteId, 'Stripe quoteId');\n const rawSuccessUrl = input.successUrl ?? this.options.successUrl;\n const rawCancelUrl = input.cancelUrl ?? this.options.cancelUrl;\n\n if (rawSuccessUrl === undefined || rawCancelUrl === undefined) {\n throw new PaymentConfigurationError(\n 'StripeAdapter createPaymentOption requires successUrl and cancelUrl.',\n );\n }\n\n const successUrl = normalizeUrlString(rawSuccessUrl, 'Stripe successUrl');\n const cancelUrl = normalizeUrlString(rawCancelUrl, 'Stripe cancelUrl');\n const currency = normalizeStripeCurrency(input.currency);\n this.assertSupportedCurrency(currency);\n const amount = normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe Checkout amount',\n );\n const applicationFeeAmount = normalizeApplicationFeeAmount(\n input.applicationFeeAmount,\n amount,\n 'Stripe Checkout applicationFeeAmount',\n );\n const expiresAt = normalizeDate(input.expiresAt);\n const stripeExpiresAt = normalizeStripeCheckoutExpiresAt(expiresAt);\n const params: Record<string, unknown> = {\n mode: this.checkoutMode,\n ...Object.fromEntries([\n ['success_url', successUrl],\n ['cancel_url', cancelUrl],\n ['client_reference_id', quoteId],\n ['customer_email', input.buyerEmail],\n ['expires_at', Math.floor(stripeExpiresAt.getTime() / 1_000)],\n ]),\n 'line_items[0][quantity]': 1,\n 'line_items[0][price_data][currency]': currency,\n 'line_items[0][price_data][unit_amount]': amount,\n 'line_items[0][price_data][product_data][name]':\n input.description ?? `Quote ${quoteId}`,\n ...(applicationFeeAmount === undefined\n ? {}\n : {\n 'payment_intent_data[application_fee_amount]': applicationFeeAmount,\n }),\n ...flattenStripeMetadata(input.metadata),\n 'metadata[quoteId]': quoteId,\n };\n\n const stripeAccount = this.resolveStripeAccount(input.stripeAccount);\n const session = await this.stripeRequest<Record<string, unknown>>(\n '/checkout/sessions',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n stripeAccount,\n body: formEncode(params),\n },\n );\n const sessionId = normalizeOptionalProviderString(\n readProviderString(session, 'id'),\n );\n const checkoutUrl = normalizeOptionalProviderString(\n readProviderString(session, 'url'),\n );\n\n if (!sessionId || !checkoutUrl) {\n throw new PaymentProviderError(\n 'Stripe Checkout Session response did not include id and url.',\n );\n }\n\n const option: PaymentOption = {\n backendId: this.capabilities.id,\n quoteId,\n payTo: checkoutUrl,\n settlementShape: 'url',\n settlementCurrency: currency.toUpperCase(),\n settlementAmount: amount,\n amount,\n currency: currency.toUpperCase(),\n expiresAt: stripeExpiresAt,\n providerPaymentId: sessionId,\n paymentUri: checkoutUrl,\n metadata: {\n sessionId,\n stripeAccount,\n paymentIntent: normalizeOptionalProviderString(\n readProviderString(session, 'payment_intent'),\n ),\n },\n };\n\n rememberPaymentOption(\n this.optionsByQuote,\n stripePaymentOptionKey(quoteId, stripeAccount),\n option,\n this.maxStoredPaymentOptions,\n );\n\n return option;\n }\n\n watchPayment(input: StripeWatchPaymentInput): AsyncIterable<PaymentEvent> {\n return pollPaymentStatus(\n {\n ...input,\n pollIntervalMs:\n input.pollIntervalMs ?? this.options.pollIntervalMs ?? 5_000,\n },\n () => this.getStatus(input.quoteId, input.payTo, input.statusContext),\n );\n }\n\n async getStatus(\n quoteId: string,\n payTo: string,\n context: StripePaymentStatusContext = {},\n ): Promise<PaymentStatusResult> {\n const normalizedQuoteId = normalizeNonEmptyString(\n quoteId,\n 'Stripe quoteId',\n );\n const normalizedPayTo = normalizeNonEmptyString(payTo, 'Stripe payTo');\n const contextProviderPaymentId =\n context.providerPaymentId === undefined\n ? undefined\n : normalizeNonEmptyString(\n context.providerPaymentId,\n 'Stripe providerPaymentId',\n );\n const contextStripeAccount = normalizeOptionalStripeAccount(\n context.stripeAccount,\n 'Stripe stripeAccount',\n );\n const scopedOption = this.optionsByQuote.get(\n stripePaymentOptionKey(\n normalizedQuoteId,\n contextStripeAccount ?? this.stripeAccount,\n ),\n );\n const sessionId =\n contextProviderPaymentId ??\n extractStripeSessionId(normalizedPayTo) ??\n scopedOption?.providerPaymentId;\n\n if (!sessionId) {\n throw new PaymentConfigurationError(\n 'Stripe getStatus requires a Checkout Session id or URL.',\n );\n }\n\n const storedOption = this.findStoredOptionBySessionId(sessionId);\n const stripeAccount =\n contextStripeAccount ??\n readStripeOptionAccount(storedOption) ??\n this.stripeAccount;\n const cachedOption = this.optionsByQuote.get(\n stripePaymentOptionKey(normalizedQuoteId, stripeAccount),\n );\n\n // A caller-supplied session id can deliberately select a later checkout\n // for the same quote. Cache-derived amount, currency, and expiry describe\n // only the session we created, never an explicitly selected replacement.\n const option =\n cachedOption?.providerPaymentId === sessionId ? cachedOption : undefined;\n\n const session = await this.stripeRequest<Record<string, unknown>>(\n `/checkout/sessions/${encodeURIComponent(sessionId)}`,\n { stripeAccount },\n );\n const sessionQuoteId = readStripeSessionQuoteId(session);\n\n if (sessionQuoteId !== undefined && sessionQuoteId !== normalizedQuoteId) {\n throw new PaymentVerificationError(\n `Stripe Checkout Session quoteId ${sessionQuoteId} did not match ${normalizedQuoteId}.`,\n );\n }\n\n const paymentStatus = readString(session, 'payment_status');\n const status = mapStripeStatus(\n readString(session, 'status'),\n paymentStatus,\n );\n\n const contextAmount =\n context.amount === undefined\n ? undefined\n : normalizeMinorUnitAmount(context.amount, 'Stripe status');\n const contextCurrency =\n context.currency === undefined\n ? undefined\n : normalizeStripeCurrency(context.currency).toUpperCase();\n const sessionCurrency =\n readString(session, 'currency') === undefined\n ? undefined\n : normalizeStripeCurrency(\n readString(session, 'currency') ?? '',\n ).toUpperCase();\n const sessionAmount = readSafeInteger(session, 'amount_total');\n const expiresAt =\n option?.expiresAt ??\n (context.expiresAt === undefined\n ? undefined\n : normalizeDate(context.expiresAt));\n const effectiveStatus = applyExpiryToPendingStatus(status, expiresAt);\n\n return {\n backendId: this.capabilities.id,\n quoteId: normalizedQuoteId,\n payTo: normalizedPayTo,\n status: effectiveStatus,\n settlementCurrency:\n sessionCurrency ??\n option?.settlementCurrency ??\n contextCurrency ??\n this.defaultCurrency.toUpperCase(),\n settlementAmount:\n sessionAmount ?? option?.settlementAmount ?? contextAmount,\n receivedAmount:\n paymentStatus === 'paid' || paymentStatus === 'no_payment_required'\n ? (sessionAmount ?? option?.settlementAmount ?? contextAmount)\n : undefined,\n amount: option?.amount ?? contextAmount,\n currency: option?.currency ?? contextCurrency,\n providerPaymentId: sessionId,\n transactionId: normalizeOptionalProviderString(\n readProviderString(session, 'payment_intent'),\n ),\n updatedAt: new Date(),\n raw: session,\n };\n }\n\n async sendPayout(input: SendPayoutInput): Promise<PayoutResult> {\n const currency = normalizeStripeCurrency(\n input.currency ?? this.defaultCurrency,\n );\n this.assertSupportedCurrency(currency);\n const destination = normalizeNonEmptyString(\n input.destination,\n 'Stripe payout destination',\n );\n const quoteId =\n input.quoteId === undefined\n ? undefined\n : normalizeNonEmptyString(input.quoteId, 'Stripe payout quoteId');\n const amount = normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe payout amount',\n );\n const transfer = await this.stripeRequest<Record<string, unknown>>(\n '/transfers',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode({\n amount,\n currency,\n destination,\n description: input.memo,\n ...flattenStripeMetadata(input.metadata),\n ...(quoteId === undefined ? {} : { 'metadata[quoteId]': quoteId }),\n }),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: 'submitted',\n payoutId: normalizeOptionalProviderString(\n readProviderString(transfer, 'id'),\n ),\n destination,\n amount,\n currency: currency.toUpperCase(),\n raw: transfer,\n };\n }\n\n async refundPayment(input: StripeRefundPaymentInput): Promise<RefundResult> {\n const rawPaymentReference = input.paymentId ?? input.transactionId;\n\n if (!rawPaymentReference) {\n throw new PaymentConfigurationError(\n 'Stripe refunds require paymentId or transactionId.',\n );\n }\n\n const paymentReference = normalizeNonEmptyString(\n rawPaymentReference,\n 'Stripe refund payment reference',\n );\n const currency = normalizeStripeCurrency(\n input.currency ?? this.defaultCurrency,\n );\n this.assertSupportedCurrency(currency);\n const amount =\n input.amount === undefined\n ? undefined\n : normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe refund amount',\n );\n const stripeAccount = this.resolveStripeAccount(input.stripeAccount);\n const refundReferenceParam = await this.resolveStripeRefundReferenceParam(\n paymentReference,\n stripeAccount,\n );\n const refundParams: Record<string, unknown> = {\n ...refundReferenceParam,\n amount: amount === undefined ? undefined : amount,\n reason: input.reason,\n refund_application_fee: input.refundApplicationFee,\n reverse_transfer: input.reverseTransfer,\n ...flattenStripeMetadata(input.metadata),\n };\n\n const refund = await this.stripeRequest<Record<string, unknown>>(\n '/refunds',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n stripeAccount,\n body: formEncode(refundParams),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: mapStripeRefundStatus(readString(refund, 'status')),\n refundId: normalizeOptionalProviderString(\n readProviderString(refund, 'id'),\n ),\n transactionId: paymentReference,\n // Read the settled amount and currency back from the refund object\n // (mirrors capturePayment) so a full refund — no `input.amount` supplied,\n // and possibly a currency differing from the adapter default when\n // `input.currency` is omitted — surfaces what Stripe actually refunded\n // instead of the request defaults.\n amount: readSafeInteger(refund, 'amount') ?? amount,\n currency: readStripeResultCurrency(refund) ?? currency.toUpperCase(),\n raw: refund,\n };\n }\n\n async authorizePayment(\n input: StripeAuthorizePaymentInput,\n ): Promise<AuthorizationResult> {\n const currency = normalizeStripeCurrency(input.currency);\n this.assertSupportedCurrency(currency);\n const amount = normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe authorize amount',\n );\n const paymentMethod = normalizeNonEmptyString(\n input.providerPaymentMethodId,\n 'Stripe authorize providerPaymentMethodId',\n );\n const providerCustomerId =\n input.providerCustomerId === undefined\n ? undefined\n : normalizeNonEmptyString(\n input.providerCustomerId,\n 'Stripe authorize providerCustomerId',\n );\n const quoteId =\n input.quoteId === undefined\n ? undefined\n : normalizeNonEmptyString(input.quoteId, 'Stripe authorize quoteId');\n const applicationFeeAmount = normalizeApplicationFeeAmount(\n input.applicationFeeAmount,\n amount,\n 'Stripe PaymentIntent applicationFeeAmount',\n );\n\n const intent = await this.stripeRequest<Record<string, unknown>>(\n '/payment_intents',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n stripeAccount: this.resolveStripeAccount(input.stripeAccount),\n body: formEncode({\n amount,\n currency,\n confirm: true,\n 'payment_method_types[]': 'card',\n description: input.description,\n application_fee_amount: applicationFeeAmount,\n ...Object.fromEntries([\n ['payment_method', paymentMethod],\n ['capture_method', 'manual'],\n // Off-session (merchant-initiated) by default — the primary use is\n // charging a saved card while the buyer is absent. Without this,\n // Stripe treats it as on-session and may raise an SCA challenge the\n // absent buyer can't complete, so the hold is never placed.\n ['off_session', input.offSession ?? true],\n ]),\n ...(providerCustomerId === undefined\n ? {}\n : { customer: providerCustomerId }),\n ...flattenStripeMetadata(input.metadata),\n ...(quoteId === undefined ? {} : { 'metadata[quoteId]': quoteId }),\n }),\n },\n );\n\n const providerPaymentId = normalizeOptionalProviderString(\n readProviderString(intent, 'id'),\n );\n\n if (!providerPaymentId) {\n throw new PaymentProviderError(\n 'Stripe PaymentIntent response did not include an id.',\n );\n }\n\n const status = mapStripeAuthorizationStatus(readString(intent, 'status'));\n // Only surface the SCA fields when authentication is actually required — the\n // documented contract — even though Stripe returns client_secret regardless.\n // (Authorization progress is observed via `parseWebhookEvent`, which surfaces\n // the ready-to-capture transition as `processing` — there is no distinct\n // `requires_capture` webhook status; `getStatus` handles Checkout sessions,\n // not PaymentIntents.)\n const actionRequired = status === 'requires_action';\n\n return {\n backendId: this.capabilities.id,\n status,\n providerPaymentId,\n amount: readSafeInteger(intent, 'amount') ?? amount,\n currency: (readString(intent, 'currency') ?? currency).toUpperCase(),\n clientSecret: actionRequired\n ? normalizeOptionalProviderString(\n readProviderString(intent, 'client_secret'),\n )\n : undefined,\n nextAction: actionRequired\n ? (intent.next_action ?? undefined)\n : undefined,\n raw: intent,\n };\n }\n\n async capturePayment(\n input: StripeCapturePaymentInput,\n ): Promise<CaptureResult> {\n const providerPaymentId = normalizeNonEmptyString(\n input.providerPaymentId,\n 'Stripe capture providerPaymentId',\n );\n const amount =\n input.amount === undefined\n ? undefined\n : normalizePositiveMinorUnitAmount(\n input.amount,\n 'Stripe capture amount',\n );\n\n const intent = await this.stripeRequest<Record<string, unknown>>(\n `/payment_intents/${encodeURIComponent(providerPaymentId)}/capture`,\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n stripeAccount: this.resolveStripeAccount(input.stripeAccount),\n body: formEncode({\n ...Object.fromEntries([['amount_to_capture', amount]]),\n ...flattenStripeMetadata(input.metadata),\n }),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: mapStripeCaptureStatus(readString(intent, 'status')),\n providerPaymentId:\n normalizeOptionalProviderString(readProviderString(intent, 'id')) ??\n providerPaymentId,\n amount:\n readSafeInteger(intent, 'amount_received') ??\n readSafeInteger(intent, 'amount') ??\n amount,\n currency: readStripeResultCurrency(intent),\n raw: intent,\n };\n }\n\n async voidPayment(input: StripeVoidPaymentInput): Promise<VoidResult> {\n const providerPaymentId = normalizeNonEmptyString(\n input.providerPaymentId,\n 'Stripe void providerPaymentId',\n );\n const reason =\n input.reason === undefined\n ? undefined\n : normalizeNonEmptyString(input.reason, 'Stripe void reason');\n\n const intent = await this.stripeRequest<Record<string, unknown>>(\n `/payment_intents/${encodeURIComponent(providerPaymentId)}/cancel`,\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n stripeAccount: this.resolveStripeAccount(input.stripeAccount),\n body: formEncode(Object.fromEntries([['cancellation_reason', reason]])),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: mapStripeVoidStatus(readString(intent, 'status')),\n providerPaymentId:\n normalizeOptionalProviderString(readProviderString(intent, 'id')) ??\n providerPaymentId,\n amount: readSafeInteger(intent, 'amount'),\n currency: readStripeResultCurrency(intent),\n raw: intent,\n };\n }\n\n async createSetupSession(\n input: StripeCreateSetupSessionInput,\n ): Promise<SetupSession> {\n const rawSuccessUrl = input.successUrl ?? this.options.successUrl;\n const rawCancelUrl = input.cancelUrl ?? this.options.cancelUrl;\n\n if (rawSuccessUrl === undefined || rawCancelUrl === undefined) {\n throw new PaymentConfigurationError(\n 'StripeAdapter createSetupSession requires successUrl and cancelUrl.',\n );\n }\n\n const successUrl = normalizeUrlString(rawSuccessUrl, 'Stripe successUrl');\n const cancelUrl = normalizeUrlString(rawCancelUrl, 'Stripe cancelUrl');\n // Currency for the setup-mode session (defaults to the backend currency).\n // Redundant now that payment_method_types is always set, but harmless and\n // kept so the session is well-formed if that restriction is ever relaxed.\n const currency = normalizeStripeCurrency(\n input.currency ?? this.defaultCurrency,\n );\n this.assertSupportedCurrency(currency);\n const providerCustomerId =\n input.providerCustomerId === undefined\n ? undefined\n : normalizeNonEmptyString(\n input.providerCustomerId,\n 'Stripe setup customer',\n );\n\n // Either attach to an existing customer, or force Stripe to create one so\n // the saved method comes back with a reusable `cus_` reference. Setup-mode\n // sessions do NOT create a customer on their own — `customer_creation` must\n // be `always`. All snake_case keys go through Object.fromEntries.\n const customerParams: [string, unknown][] = [];\n if (providerCustomerId !== undefined) {\n customerParams.push(['customer', providerCustomerId]);\n } else {\n customerParams.push(['customer_creation', 'always']);\n if (input.customerEmail !== undefined) {\n customerParams.push([\n 'customer_email',\n normalizeNonEmptyString(\n input.customerEmail,\n 'Stripe setup customerEmail',\n ),\n ]);\n }\n }\n\n const params: Record<string, unknown> = {\n mode: 'setup',\n currency,\n // Restrict to cards: SavedPaymentMethod exposes card display fields\n // (brand/last4/expiry), so allowing SEPA/Bacs/etc. would yield saved\n // methods with no usable display detail.\n 'payment_method_types[]': 'card',\n ...Object.fromEntries([\n ['success_url', successUrl],\n ['cancel_url', cancelUrl],\n ...customerParams,\n ]),\n ...flattenStripeMetadata(input.metadata),\n };\n\n const session = await this.stripeRequest<Record<string, unknown>>(\n '/checkout/sessions',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n stripeAccount: this.resolveStripeAccount(input.stripeAccount),\n body: formEncode(params),\n },\n );\n\n const sessionId = normalizeOptionalProviderString(\n readProviderString(session, 'id'),\n );\n const url = normalizeOptionalProviderString(\n readProviderString(session, 'url'),\n );\n\n if (!sessionId || !url) {\n throw new PaymentProviderError(\n 'Stripe setup Checkout Session response did not include id and url.',\n );\n }\n\n return {\n backendId: this.capabilities.id,\n sessionId,\n url,\n providerCustomerId:\n providerCustomerId ??\n normalizeOptionalProviderString(\n readProviderString(session, 'customer'),\n ),\n raw: session,\n };\n }\n\n async getSetupResult(\n input: StripeGetSetupResultInput,\n ): Promise<SavedPaymentMethod> {\n const sessionId = normalizeNonEmptyString(\n input.sessionId,\n 'Stripe setup sessionId',\n );\n\n const query = new URLSearchParams();\n query.append('expand[]', 'setup_intent.payment_method');\n\n const session = await this.stripeRequest<Record<string, unknown>>(\n `/checkout/sessions/${encodeURIComponent(sessionId)}?${query.toString()}`,\n { stripeAccount: this.resolveStripeAccount(input.stripeAccount) },\n );\n\n const setupIntent = readObject(session, 'setup_intent');\n const paymentMethod = readObject(setupIntent, 'payment_method');\n const card = readObject(paymentMethod, 'card');\n\n // `customer` is a bare `cus_` string on the request path (only\n // setup_intent.payment_method is expanded), but read tolerantly of an\n // expanded object so a future `expand[]=customer` can't wrongly downgrade a\n // completed setup to a permanent `pending`.\n const providerCustomerId = normalizeOptionalProviderString(\n readProviderString(session, 'customer') ??\n readProviderString(readObject(session, 'customer'), 'id'),\n );\n const providerPaymentMethodId = normalizeOptionalProviderString(\n readProviderString(paymentMethod, 'id'),\n );\n\n let status = mapStripeSetupStatus(\n readString(session, 'status'),\n readString(setupIntent, 'status'),\n );\n // Never report `complete` without the reusable references a caller needs to\n // charge the method later — a `pm_` with no `cus_` can't be charged\n // off-session, so treat that as not-yet-ready rather than a false success.\n if (\n status === 'complete' &&\n (!providerCustomerId || !providerPaymentMethodId)\n ) {\n status = 'pending';\n }\n\n return {\n backendId: this.capabilities.id,\n status,\n providerCustomerId,\n providerPaymentMethodId,\n type: readString(paymentMethod, 'type'),\n brand: readString(card, 'brand'),\n last4: readString(card, 'last4'),\n expMonth: readSafeInteger(card, 'exp_month'),\n expYear: readSafeInteger(card, 'exp_year'),\n raw: session,\n };\n }\n\n parseWebhookEvent(payload: string, signature?: string): StripeWebhookEvent {\n if (!this.webhookSecret) {\n throw new PaymentConfigurationError(\n 'StripeAdapter parseWebhookEvent requires webhookSecret.',\n );\n }\n\n if (!signature) {\n throw new PaymentProviderError('Missing Stripe webhook signature.');\n }\n\n verifyStripeWebhookSignature(payload, signature, this.webhookSecret);\n\n const event = parseStripeWebhookPayload(payload);\n const id = readRequiredWebhookString(\n event,\n 'id',\n 'Stripe webhook event id',\n );\n const type = readRequiredWebhookString(\n event,\n 'type',\n 'Stripe webhook event type',\n );\n\n const duplicate = this.seenWebhookEventIds.has(id);\n\n if (!duplicate) {\n this.seenWebhookEventIds.add(id);\n while (this.seenWebhookEventIds.size > this.maxStoredWebhookEventIds) {\n const oldest = this.seenWebhookEventIds.values().next().value;\n\n if (oldest === undefined) {\n break;\n }\n\n this.seenWebhookEventIds.delete(oldest);\n }\n }\n\n const data = (\n event.data as { object?: Record<string, unknown> } | undefined\n )?.object;\n\n return {\n id,\n type,\n status: mapStripeWebhookStatus(type, data),\n quoteId: normalizeOptionalWebhookString(\n // `client_reference_id` is a Checkout Session-only field; honor it only\n // for session events so a non-session object (a PaymentIntent / Charge /\n // Transfer, possibly from a malicious Connect account) can't spoof\n // correlation to another quote's id. Non-session events correlate only\n // via our own `metadata.quoteId`.\n (type.startsWith('checkout.session.')\n ? readString(data, 'client_reference_id')\n : undefined) ??\n readString(\n (data?.metadata as Record<string, unknown>) ?? {},\n 'quoteId',\n ),\n ),\n providerPaymentId: normalizeOptionalWebhookString(readString(data, 'id')),\n duplicate,\n raw: event,\n };\n }\n\n private async stripeRequest<T>(\n path: string,\n init: RequestInit & {\n idempotencyKey?: string;\n stripeAccount?: string;\n } = {},\n ): Promise<T> {\n const headers = new Headers(init.headers);\n headers.set('Authorization', `Bearer ${this.secretKey}`);\n headers.set('Content-Type', 'application/x-www-form-urlencoded');\n headers.set('Accept', 'application/json');\n headers.set('Stripe-Version', this.apiVersion);\n\n if (init.stripeAccount !== undefined) {\n headers.set('Stripe-Account', init.stripeAccount);\n }\n\n if (init.idempotencyKey !== undefined) {\n headers.set(\n 'Idempotency-Key',\n normalizeNonEmptyString(init.idempotencyKey, 'Stripe idempotencyKey'),\n );\n }\n\n const {\n idempotencyKey: _idempotencyKey,\n stripeAccount: _stripeAccount,\n ...requestInit\n } = init;\n const response = await this.fetch(`${this.apiBaseUrl}${path}`, {\n ...requestInit,\n method: init.method ?? 'GET',\n headers,\n });\n\n return readJsonResponse<T>(response, `Stripe ${path}`);\n }\n\n private assertSupportedCurrency(currency: string): void {\n if (!this.supportedCurrencies.has(currency)) {\n throw new PaymentConfigurationError(\n `StripeAdapter currency ${currency.toUpperCase()} is not configured as supported.`,\n );\n }\n }\n\n private async resolveStripeRefundReferenceParam(\n paymentReference: string,\n stripeAccount: string | undefined,\n ): Promise<Record<string, string>> {\n if (paymentReference.startsWith('cs_')) {\n const session = await this.stripeRequest<Record<string, unknown>>(\n `/checkout/sessions/${encodeURIComponent(paymentReference)}`,\n { stripeAccount },\n );\n const paymentIntent = normalizeOptionalProviderString(\n readProviderString(session, 'payment_intent'),\n );\n\n if (!paymentIntent) {\n throw new PaymentProviderError(\n 'Stripe Checkout Session did not include payment_intent for refund.',\n );\n }\n\n return Object.fromEntries([['payment_intent', paymentIntent]]);\n }\n\n return stripeRefundReferenceParam(paymentReference);\n }\n\n private resolveStripeAccount(\n override: string | undefined,\n ): string | undefined {\n return (\n normalizeOptionalStripeAccount(override, 'Stripe stripeAccount') ??\n this.stripeAccount\n );\n }\n\n private findStoredOptionBySessionId(\n sessionId: string,\n ): PaymentOption | undefined {\n for (const option of this.optionsByQuote.values()) {\n if (option.providerPaymentId === sessionId) return option;\n }\n return undefined;\n }\n}\n\nfunction readStripeOptionAccount(\n option: PaymentOption | undefined,\n): string | undefined {\n const value = option?.metadata?.stripeAccount;\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction normalizeOptionalStripeAccount(\n value: string | undefined,\n context: string,\n): string | undefined {\n return value === undefined\n ? undefined\n : normalizeNonEmptyString(value, context);\n}\n\nfunction normalizeApplicationFeeAmount(\n value: number | undefined,\n chargeAmount: number,\n context: string,\n): number | undefined {\n if (value === undefined) return undefined;\n\n const fee = normalizePositiveMinorUnitAmount(value, context);\n if (fee > chargeAmount) {\n throw new PaymentConfigurationError(\n `${context} must not exceed the charge amount.`,\n );\n }\n return fee;\n}\n\nfunction stripePaymentOptionKey(\n quoteId: string,\n stripeAccount: string | undefined,\n): string {\n // Platform entries retain their old quote-only keys. Connected-account ids\n // cannot contain NUL in an HTTP header, so it safely separates account scope\n // from the caller's quote id without collapsing tenant-local quote ids.\n return stripeAccount === undefined ? quoteId : `${stripeAccount}\\0${quoteId}`;\n}\n\nfunction stripeRefundReferenceParam(\n paymentReference: string,\n): Record<string, string> {\n if (paymentReference.startsWith('pi_')) {\n return Object.fromEntries([['payment_intent', paymentReference]]);\n }\n\n if (paymentReference.startsWith('ch_')) {\n return { charge: paymentReference };\n }\n\n throw new PaymentConfigurationError(\n 'Stripe refunds require a Checkout Session (cs_), payment_intent (pi_), or charge (ch_) reference.',\n );\n}\n\nfunction normalizeStripeCurrency(value: string): string {\n if (typeof value !== 'string') {\n throw new PaymentConfigurationError(\n `StripeAdapter currency must be a three-letter ISO currency code, received ${String(value)}.`,\n );\n }\n\n const normalized = value.trim().toLowerCase();\n\n if (!/^[a-z]{3}$/.test(normalized)) {\n throw new PaymentConfigurationError(\n `StripeAdapter currency must be a three-letter ISO currency code, received ${String(value)}.`,\n );\n }\n\n return normalized;\n}\n\nfunction normalizeSupportedStripeCurrencies(\n configuredCurrencies: string[] | undefined,\n defaultCurrency: string,\n): Set<string> {\n const normalized = new Set(\n (configuredCurrencies ?? ['usd', 'eur', 'gbp', 'cad']).map(\n normalizeStripeCurrency,\n ),\n );\n normalized.add(defaultCurrency);\n\n return normalized;\n}\n\nfunction normalizeStripeCheckoutExpiresAt(\n expiresAt: Date,\n now = Date.now(),\n): Date {\n if (expiresAt.getTime() <= now) {\n throw new PaymentProviderError('Stripe Checkout expiry is in the past.');\n }\n\n const min = now + STRIPE_CHECKOUT_MIN_EXPIRY_MS;\n const max = now + STRIPE_CHECKOUT_MAX_EXPIRY_MS;\n\n if (expiresAt.getTime() < min || expiresAt.getTime() > max) {\n throw new PaymentConfigurationError(\n 'Stripe Checkout expiry must be at least 30 minutes and no more than 24 hours from now.',\n );\n }\n\n return expiresAt;\n}\n\nexport function verifyStripeWebhookSignature(\n payload: string,\n signatureHeader: string,\n secret: string,\n toleranceSeconds = 300,\n): void {\n if (typeof payload !== 'string') {\n throw new PaymentProviderError('Stripe webhook payload must be a string.');\n }\n\n const normalizedSignatureHeader = normalizeNonEmptyString(\n signatureHeader,\n 'Stripe signature header',\n );\n const normalizedSecret = normalizeNonEmptyString(\n secret,\n 'Stripe webhook secret',\n );\n\n if (!Number.isFinite(toleranceSeconds) || toleranceSeconds < 0) {\n throw new PaymentConfigurationError(\n `Stripe webhook toleranceSeconds must be a non-negative finite number, received ${String(toleranceSeconds)}.`,\n );\n }\n\n const timestampCandidates: string[] = [];\n const signatures: string[] = [];\n\n for (const part of normalizedSignatureHeader.split(',')) {\n const [rawKey, ...rawValue] = part.split('=');\n const key = rawKey?.trim();\n const value = rawValue.join('=').trim();\n\n if (!key || !value) {\n continue;\n }\n\n if (key === 't') {\n timestampCandidates.push(value);\n }\n\n if (key === 'v1') {\n signatures.push(value);\n }\n }\n\n if (timestampCandidates.length !== 1 || signatures.length === 0) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const timestamp = timestampCandidates[0] ?? '';\n\n if (!/^\\d+$/.test(timestamp)) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const timestampSeconds = Number(timestamp);\n\n if (!Number.isSafeInteger(timestampSeconds)) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const nowSeconds = Date.now() / 1_000;\n const ageSeconds = nowSeconds - timestampSeconds;\n\n if (ageSeconds < -5) {\n throw new PaymentProviderError(\n 'Stripe webhook signature timestamp is in the future.',\n );\n }\n\n if (ageSeconds > toleranceSeconds) {\n throw new PaymentProviderError('Stripe webhook signature is too old.');\n }\n\n const expected = createHmac('sha256', normalizedSecret)\n .update(`${timestamp}.${payload}`)\n .digest('hex');\n const expectedBuffer = Buffer.from(expected, 'hex');\n\n for (const signature of signatures) {\n if (!/^[0-9a-f]+$/i.test(signature)) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const actualBuffer = Buffer.from(signature, 'hex');\n\n if (\n expectedBuffer.length === actualBuffer.length &&\n timingSafeEqual(expectedBuffer, actualBuffer)\n ) {\n return;\n }\n }\n\n throw new PaymentProviderError('Invalid Stripe webhook signature.');\n}\n\nfunction parseStripeWebhookPayload(payload: string): Record<string, unknown> {\n try {\n const event = JSON.parse(payload);\n\n if (!event || typeof event !== 'object' || Array.isArray(event)) {\n throw new PaymentProviderError('Invalid Stripe webhook JSON payload.');\n }\n\n return event as Record<string, unknown>;\n } catch (error) {\n if (error instanceof PaymentProviderError) {\n throw error;\n }\n\n throw new PaymentProviderError('Invalid Stripe webhook JSON payload.', {\n cause: error,\n });\n }\n}\n\nfunction normalizeOptionalWebhookString(\n value: string | undefined,\n): string | undefined {\n const normalized = value?.trim();\n\n return normalized ? normalized : undefined;\n}\n\nfunction normalizeOptionalProviderString(\n value: string | undefined,\n): string | undefined {\n const normalized = value?.trim();\n\n return normalized ? normalized : undefined;\n}\n\nfunction readProviderString(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const item = value[key];\n\n return typeof item === 'string' ? item : undefined;\n}\n\nfunction readRequiredWebhookString(\n value: Record<string, unknown>,\n key: string,\n context: string,\n): string {\n const item = value[key];\n\n if (typeof item !== 'string') {\n throw new PaymentProviderError(`${context} must be a string.`);\n }\n\n return normalizeNonEmptyString(item, context);\n}\n\nfunction readStripeSessionQuoteId(\n session: Record<string, unknown>,\n): string | undefined {\n return normalizeOptionalWebhookString(\n readString(session, 'client_reference_id') ??\n readString(\n (session.metadata as Record<string, unknown>) ?? {},\n 'quoteId',\n ),\n );\n}\n\nfunction mapStripeStatus(\n checkoutStatus: string | undefined,\n paymentStatus: string | undefined,\n): PaymentStatus {\n if (paymentStatus === 'paid' || paymentStatus === 'no_payment_required') {\n return 'confirmed';\n }\n\n if (checkoutStatus === 'expired') {\n return 'expired';\n }\n\n if (paymentStatus === 'unpaid' || checkoutStatus === 'open') {\n return 'pending';\n }\n\n if (checkoutStatus === 'complete') {\n return 'processing';\n }\n\n return 'pending';\n}\n\nfunction mapStripeWebhookStatus(\n type: string | undefined,\n object: Record<string, unknown> | undefined,\n): PaymentStatus {\n if (type === 'checkout.session.completed') {\n return mapStripeStatus(\n readString(object, 'status'),\n readString(object, 'payment_status'),\n );\n }\n\n if (type === 'checkout.session.async_payment_succeeded') {\n return 'confirmed';\n }\n\n if (type === 'checkout.session.async_payment_failed') {\n return 'failed';\n }\n\n if (type === 'checkout.session.expired') {\n return 'expired';\n }\n\n // Manual-capture PaymentIntent lifecycle (authorize → capture / void). Only\n // treat these as terminal for intents WE created and can correlate — i.e.\n // ones carrying our `quoteId` in metadata. Checkout Sessions create their own\n // PaymentIntents (which fire these same events with no quoteId on the intent);\n // those are handled via the `checkout.session.*` events above, so here they\n // stay non-terminal (`processing`) rather than emitting a spurious,\n // uncorrelatable terminal event. Handled before the generic `failed` catch\n // below so an un-owned `payment_intent.payment_failed` isn't reclassified.\n if (\n type === 'payment_intent.succeeded' ||\n type === 'payment_intent.canceled' ||\n type === 'payment_intent.payment_failed'\n ) {\n const metadata = (object?.metadata as Record<string, unknown>) ?? {};\n // Match parseWebhookEvent's normalization so an empty/blank quoteId is\n // treated as un-owned by both — gate and reporter must agree on ownership.\n const owned =\n normalizeOptionalWebhookString(readString(metadata, 'quoteId')) !==\n undefined;\n if (owned) {\n if (type === 'payment_intent.succeeded') {\n return 'confirmed';\n }\n // A manual-capture hold Stripe released automatically (it lapsed) is\n // `expired`, distinct from a deliberate void or hard decline (`failed`);\n // the shared PaymentStatus union has no `canceled`.\n if (\n type === 'payment_intent.canceled' &&\n readString(object, 'cancellation_reason') === 'automatic'\n ) {\n return 'expired';\n }\n return 'failed';\n }\n return 'processing';\n }\n\n // Terminal failure/refund only for payment-in objects (Checkout Session,\n // PaymentIntent, Charge). Money-out / unrelated events (transfer.failed,\n // payout.failed, refund.failed, application_fee.refunded, …) also match a\n // naive substring scan — and a failed Transfer even carries our quoteId\n // (sendPayout stamps it), which would miscorrelate a payout failure as a\n // payment failure — so they must not surface as a terminal payment status.\n const isPaymentInEvent =\n type?.startsWith('checkout.session.') === true ||\n type?.startsWith('payment_intent.') === true ||\n type?.startsWith('charge.') === true;\n\n if (isPaymentInEvent && type?.includes('refunded')) {\n return 'refunded';\n }\n\n if (isPaymentInEvent && type?.includes('failed')) {\n return 'failed';\n }\n\n return 'processing';\n}\n\nfunction mapStripeRefundStatus(\n status: string | undefined,\n): RefundResult['status'] {\n switch (status) {\n case 'succeeded':\n return 'succeeded';\n case 'failed':\n case 'canceled':\n return 'failed';\n case 'requires_action':\n return 'requires_action';\n default:\n return 'submitted';\n }\n}\n\nfunction mapStripeAuthorizationStatus(\n status: string | undefined,\n): AuthorizationResult['status'] {\n switch (status) {\n case 'requires_capture':\n return 'requires_capture';\n case 'succeeded':\n return 'succeeded';\n case 'requires_action':\n return 'requires_action';\n case 'processing':\n return 'processing';\n default:\n return 'failed';\n }\n}\n\nfunction mapStripeCaptureStatus(\n status: string | undefined,\n): CaptureResult['status'] {\n switch (status) {\n case 'succeeded':\n return 'succeeded';\n // Capturing an authorized intent shouldn't re-enter authentication; treat\n // any in-flight/action state as still processing rather than a failure.\n case 'processing':\n case 'requires_action':\n return 'processing';\n default:\n return 'failed';\n }\n}\n\nfunction mapStripeVoidStatus(status: string | undefined): VoidResult['status'] {\n return status === 'canceled' ? 'canceled' : 'failed';\n}\n\nfunction readStripeResultCurrency(\n value: Record<string, unknown>,\n): string | undefined {\n const currency = readString(value, 'currency');\n\n return currency === undefined ? undefined : currency.toUpperCase();\n}\n\nfunction mapStripeSetupStatus(\n sessionStatus: string | undefined,\n setupIntentStatus: string | undefined,\n): SavedPaymentMethod['status'] {\n if (sessionStatus === 'expired') {\n return 'expired';\n }\n\n if (sessionStatus === 'complete') {\n // The method is reusable only once the SetupIntent itself has succeeded —\n // the Session can be `complete` while the intent is still `processing`\n // (async setup methods via dynamic payment methods).\n if (setupIntentStatus === 'succeeded') {\n return 'complete';\n }\n // A finished session whose SetupIntent didn't succeed is a terminal\n // failure (card declined → `requires_payment_method`, or `canceled`), so\n // callers can stop polling instead of waiting on a `pending` that will\n // never resolve. Still-in-flight states (`processing`, `requires_action`)\n // remain `pending`.\n if (\n setupIntentStatus === 'canceled' ||\n setupIntentStatus === 'requires_payment_method'\n ) {\n return 'failed';\n }\n }\n\n return 'pending';\n}\n\nfunction readObject(\n value: Record<string, unknown> | undefined,\n key: string,\n): Record<string, unknown> | undefined {\n const item = value?.[key];\n\n return item && typeof item === 'object' && !Array.isArray(item)\n ? (item as Record<string, unknown>)\n : undefined;\n}\n\nfunction extractStripeSessionId(payTo: string): string | undefined {\n if (/^cs_(test_|live_)?[A-Za-z0-9_]+$/.test(payTo)) {\n return payTo;\n }\n\n try {\n const url = new URL(payTo);\n const match = url.pathname.match(/\\/pay\\/([^/?#]+)/);\n\n const sessionId = match?.[1];\n\n return sessionId && /^cs_(test_|live_)?[A-Za-z0-9_]+$/.test(sessionId)\n ? sessionId\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction flattenStripeMetadata(\n metadata:\n | Record<string, string | number | boolean | null | undefined>\n | undefined,\n): Record<string, string | number | boolean> {\n const result: Record<string, string | number | boolean> = {};\n\n for (const [key, value] of Object.entries(metadata ?? {})) {\n if (value !== undefined && value !== null) {\n result[`metadata[${key}]`] = value;\n }\n }\n\n return result;\n}\n\nfunction readString(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const item = value[key];\n\n if (typeof item === 'string') {\n return item;\n }\n\n if (typeof item === 'number') {\n return String(item);\n }\n\n return undefined;\n}\n\nfunction readSafeInteger(\n value: Record<string, unknown> | undefined,\n key: string,\n): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const item = value[key];\n\n return typeof item === 'number' && Number.isSafeInteger(item) && item >= 0\n ? item\n : undefined;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/payments",
3
- "version": "0.105.2",
3
+ "version": "0.105.4",
4
4
  "description": "Payment backend abstraction with adapters for Base USDC, BTCPay Server, and Stripe",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",