@flopay/shared 1.0.3 → 1.1.3

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/dist/index.d.ts CHANGED
@@ -160,62 +160,84 @@ interface LineItem {
160
160
  }
161
161
  /** Checkout mode controlling the payment UI behavior. */
162
162
  type CheckoutMode = 'full' | 'auto' | 'confirm';
163
- /** A one-time item from a checkout session response. */
164
- interface CheckoutSessionItem {
163
+ /**
164
+ * Discriminator describing whether a checkout product is a one-time item or a
165
+ * recurring subscription. Mirrors the backend's `ProductTypeEnum`.
166
+ */
167
+ type CheckoutProductType = 'item' | 'subscription';
168
+ /** Unified checkout product from a session response. */
169
+ interface CheckoutSessionProduct {
165
170
  uuid: string;
166
171
  checkoutSessionId: string;
167
- /** Preferred catalog code for the item. */
172
+ /** Whether this product is a one-time item or a recurring subscription. */
173
+ type: CheckoutProductType;
174
+ /** Preferred catalog code for the product. */
168
175
  code?: string;
169
- /** @deprecated Use {@link CheckoutSessionItem.code}. Backend may stop returning this in a future major. */
170
- providerItemId?: string;
171
176
  /**
172
- * Display-only name for the item. Preferred over `providerItemName`.
173
- * The backend no longer persists names; the SDK populates this from the
174
- * client-side display cache when the server response omits it.
177
+ * Display-only name. Resolved from the catalog server-side; the SDK
178
+ * populates this from the client-side display cache when missing.
175
179
  */
176
- itemName?: string | null;
177
- /** @deprecated Use {@link CheckoutSessionItem.itemName}. Mirrored from `itemName` for backward compatibility. */
178
- providerItemName?: string | null;
179
- /** Display-only. Resolved from the catalog server-side; not part of the persisted session. */
180
- providerItemDescription?: string | null;
180
+ name?: string | null;
181
+ /** Display-only description from the catalog. */
182
+ description?: string | null;
181
183
  quantity: number;
182
- /** Display-only. Backend no longer persists this; the SDK populates it from the client-side cache (set via `paymentAPI.cacheSessionDisplayData`) when missing from the server response. */
184
+ /** Display-only. Populated from cache when the server omits it. */
183
185
  totalAmount?: number;
184
- /** Display-only. Backend no longer persists this; the SDK populates it from the client-side cache (set via `paymentAPI.cacheSessionDisplayData`) when missing from the server response. */
186
+ /** Display-only. Populated from cache when the server omits it. */
185
187
  overrideAmount?: number | null;
186
- /** @deprecated Prefer the session-level `currency` on {@link CheckoutSession}. Kept for backward compatibility and populated from cache when the server omits it. */
188
+ /** @deprecated Prefer the session-level `currency` on {@link CheckoutSession}. */
187
189
  currency?: string;
188
190
  metadata?: Record<string, unknown> | null;
189
191
  }
190
- /** A subscription plan from a checkout session response. */
191
- interface CheckoutSessionSubscription {
192
- uuid: string;
193
- checkoutSessionId: string;
194
- /** Preferred catalog code for the subscription plan. */
195
- code?: string;
196
- /** @deprecated Use {@link CheckoutSessionSubscription.code}. Backend may stop returning this in a future major. */
197
- providerPlanId?: string;
192
+ /**
193
+ * Environment for an upstream gateway. Accepts both the gateway-native values
194
+ * (`'sandbox'` | `'live'`) and FloPay's internal aliases (`'stage'` |
195
+ * `'production'`) so the same string can flow from the billing API straight
196
+ * to gateway SDKs without translation at every call site. Use
197
+ * {@link normalizeGatewayEnvironment} to collapse to the canonical pair
198
+ * before handing the value to a gateway SDK.
199
+ */
200
+ type GatewayEnvironment = 'sandbox' | 'live' | 'stage' | 'production';
201
+ /** Canonical gateway-native form returned by {@link normalizeGatewayEnvironment}. */
202
+ type NormalizedGatewayEnvironment = 'sandbox' | 'live';
203
+ /**
204
+ * Map FloPay's environment aliases to the gateway-native `'sandbox'`/`'live'`
205
+ * pair. `'stage'` → `'sandbox'`, `'production'` → `'live'`. Returns `undefined`
206
+ * for `undefined` input and logs a console warning for unrecognized strings
207
+ * (so misconfiguration surfaces immediately instead of hanging later — most
208
+ * gateway SDKs silently fall back to live endpoints on an unknown env, which
209
+ * then fails opaquely against sandbox credentials).
210
+ */
211
+ declare function normalizeGatewayEnvironment(env: GatewayEnvironment | string | undefined | null): NormalizedGatewayEnvironment | undefined;
212
+ /** Per-gateway configuration returned by the billing API. */
213
+ interface CheckoutGateway {
214
+ /** Public client identifier (e.g. Stripe publishable key, PayPal client id). */
215
+ publishableKey?: string | null;
216
+ /** Sandbox or live mode for the gateway credentials. */
217
+ environment?: GatewayEnvironment;
198
218
  /**
199
- * Display-only name for the subscription plan. Preferred over
200
- * `providerPlanName`. The backend no longer persists names; the SDK
201
- * populates this from the client-side display cache when the server
202
- * response omits it.
219
+ * Optional Stripe PaymentIntent client secret exposed by the billing API
220
+ * when additional authentication is required for a saved payment method.
221
+ * Stripe-specific.
203
222
  */
204
- subscriptionName?: string | null;
205
- /** @deprecated Use {@link CheckoutSessionSubscription.subscriptionName}. Mirrored from `subscriptionName` for backward compatibility. */
206
- providerPlanName?: string | null;
207
- /** Display-only. Resolved from the catalog server-side; not part of the persisted session. */
208
- providerPlanDescription?: string | null;
209
- quantity: number;
210
- /** Display-only. Backend no longer persists this; the SDK populates it from the client-side cache (set via `paymentAPI.cacheSessionDisplayData`) when missing from the server response. */
211
- totalAmount?: number;
212
- /** Display-only. Backend no longer persists this; the SDK populates it from the client-side cache (set via `paymentAPI.cacheSessionDisplayData`) when missing from the server response. */
213
- overrideAmount?: number | null;
214
- /** @deprecated Prefer the session-level `currency` on {@link CheckoutSession}. Kept for backward compatibility and populated from cache when the server omits it. */
215
- currency?: string;
216
- /** @deprecated Removed from backend. Checkouts only create new subscriptions. */
217
- isUpdate?: boolean;
218
- metadata?: Record<string, unknown> | null;
223
+ stripeClientSecret?: string | null;
224
+ /**
225
+ * Optional publishable key for a dedicated Stripe sub-account that renders
226
+ * PayPal via Stripe Elements. Stripe-specific. Distinct from
227
+ * `gateways.paypal.publishableKey`, which is a PayPal client id used by the
228
+ * direct PayPal SDK.
229
+ */
230
+ paypalPublishableKey?: string | null;
231
+ }
232
+ /**
233
+ * Map of gateways attached to a session, keyed by gateway code. A session can
234
+ * advertise multiple gateways concurrently — e.g. `gateways.stripe` for card
235
+ * + wallets and `gateways.paypal` for direct PayPal rendering.
236
+ */
237
+ interface CheckoutGateways {
238
+ stripe?: CheckoutGateway;
239
+ paypal?: CheckoutGateway;
240
+ [key: string]: CheckoutGateway | undefined;
219
241
  }
220
242
  /** Represents a FloPay checkout session. */
221
243
  interface CheckoutSession {
@@ -229,27 +251,35 @@ interface CheckoutSession {
229
251
  customer?: Customer;
230
252
  metadata?: Record<string, string>;
231
253
  checkoutMode?: CheckoutMode;
232
- items?: CheckoutSessionItem[];
233
- subscriptions?: CheckoutSessionSubscription[];
254
+ /** Unified products array as returned by post-#760 backends. */
255
+ products?: CheckoutSessionProduct[];
234
256
  successUrl?: string;
235
257
  cancelUrl?: string;
236
258
  coupons?: string[];
259
+ /**
260
+ * Pre-discount total in cart-currency major units (e.g. 24.95). Populated by
261
+ * billing API ≥ v1.1.2; `undefined` on older backends — readers must fall
262
+ * back to summing per-line `totalAmount`.
263
+ */
264
+ subtotalAmount?: number;
265
+ /**
266
+ * Total reduction from applied coupons in cart-currency major units.
267
+ * Populated by billing API ≥ v1.1.2; `undefined` on older backends.
268
+ */
269
+ discountAmount?: number;
270
+ /**
271
+ * Final charge amount in cart-currency major units (subtotal − discount,
272
+ * clamped ≥ 0). Populated by billing API ≥ v1.1.2; `undefined` on older
273
+ * backends — readers must fall back to summing per-line `overrideAmount`.
274
+ */
275
+ totalAmount?: number;
237
276
  createdAt?: string;
238
- gateway?: BillingProvider;
239
- gatewayData?: {
240
- publishableKey?: string | null;
241
- /**
242
- * Optional Stripe PaymentIntent client secret exposed by the billing API
243
- * when additional authentication is required for a saved payment method.
244
- */
245
- stripeClientSecret?: string | null;
246
- /**
247
- * Dedicated Stripe publishable key for PayPal. When set, PayPal uses a
248
- * separate Stripe account from the primary `publishableKey`. When `null`
249
- * or missing, PayPal is disabled — there is no fallback to `publishableKey`.
250
- */
251
- paypalPublishableKey?: string | null;
252
- };
277
+ /**
278
+ * Per-gateway configuration. A session can advertise multiple concurrent
279
+ * gateways read `gateways.stripe` for card/wallets, `gateways.paypal` for
280
+ * direct PayPal, and so on.
281
+ */
282
+ gateways?: CheckoutGateways;
253
283
  accountData?: {
254
284
  userId: string;
255
285
  email: string;
@@ -440,8 +470,8 @@ interface PaymentProviderAdapter {
440
470
  createPayPalElements(options: ElementOptions): unknown;
441
471
  destroy(): void;
442
472
  }
443
- /** Supported upstream billing providers. */
444
- type BillingProvider = 'recurly' | 'chargebee' | 'stripe';
473
+ /** Supported upstream gateway codes. */
474
+ type BillingProvider = 'stripe' | 'paypal';
445
475
  /** Token payload produced by client-side tokenization. */
446
476
  interface TokenizedBody {
447
477
  id?: string;
@@ -475,9 +505,13 @@ interface CheckoutProcessingPending {
475
505
  }
476
506
  /** Checkout mode: tokenize client-side or redirect to hosted page. */
477
507
  type CheckoutModeKind = 'tokenize' | 'redirect';
478
- /** Provider-agnostic normalized checkout session. */
508
+ /**
509
+ * Provider-agnostic normalized checkout session. Backend may attach multiple
510
+ * gateways per session — read each from `data.<gatewayCode>`.
511
+ */
479
512
  interface NormalizedCheckoutSession {
480
- provider: BillingProvider;
513
+ /** Gateway codes advertised by the backend for this session, for diagnostics. */
514
+ providers: BillingProvider[];
481
515
  mode: CheckoutModeKind;
482
516
  autoProcessingError?: CheckoutProcessError;
483
517
  autoProcessingAttempted?: boolean;
@@ -486,17 +520,25 @@ interface NormalizedCheckoutSession {
486
520
  hostedUrl?: string;
487
521
  clientToken?: string;
488
522
  session?: CheckoutSession;
489
- chargebee?: {
490
- site?: string;
491
- publishableKey?: string;
492
- dropInToken?: string;
493
- sessionId?: string;
494
- };
495
523
  stripe?: {
496
524
  clientSecret?: string;
497
525
  publishableKey?: string;
498
- /** Dedicated PayPal publishable key. `undefined` means PayPal is disabled. */
526
+ /**
527
+ * Optional dedicated Stripe sub-account publishable key for rendering
528
+ * PayPal via Stripe Elements. When present and distinct, the saved-PM
529
+ * resume flow loads a separate FloPay instance for the PayPal PI.
530
+ */
499
531
  paypalPublishableKey?: string;
532
+ environment?: GatewayEnvironment;
533
+ };
534
+ /**
535
+ * Direct PayPal gateway configuration. Present only when the backend has
536
+ * configured a dedicated PayPal gateway for the consumer; absent means the
537
+ * Stripe-rendered PayPal fallback should be used (if Stripe is configured).
538
+ */
539
+ paypal?: {
540
+ publishableKey?: string;
541
+ environment?: GatewayEnvironment;
500
542
  };
501
543
  };
502
544
  raw?: unknown;
@@ -532,6 +574,42 @@ interface CheckoutItem {
532
574
  /** Arbitrary key/value metadata forwarded to the backend. */
533
575
  metadata?: Record<string, unknown> | null;
534
576
  }
577
+ /**
578
+ * Unified product input for checkout session creation. Mirrors the backend's
579
+ * `CreateCheckoutProductBodyDto` introduced in #760 — the SDK accepts this
580
+ * shape on `CreateSessionParams.products`. Callers using the legacy
581
+ * {@link CheckoutItem} / {@link CheckoutSubscription} shapes do not need to
582
+ * migrate; the SDK folds them into this shape internally.
583
+ */
584
+ interface CheckoutProduct {
585
+ /** Whether this product is a one-time item or a recurring subscription. */
586
+ type: CheckoutProductType;
587
+ /** Catalog code — preferred identifier. */
588
+ code?: string;
589
+ /** @deprecated Falls back to {@link CheckoutProduct.code} for back-compat. */
590
+ providerItemId?: string;
591
+ /** @deprecated Falls back to {@link CheckoutProduct.code} for back-compat. */
592
+ providerPlanId?: string;
593
+ /** Display-only name for the product. */
594
+ name?: string | null;
595
+ /** @deprecated Use {@link CheckoutProduct.name}. */
596
+ itemName?: string | null;
597
+ /** @deprecated Use {@link CheckoutProduct.name}. */
598
+ providerItemName?: string | null;
599
+ /** @deprecated Use {@link CheckoutProduct.name}. */
600
+ subscriptionName?: string | null;
601
+ /** @deprecated Use {@link CheckoutProduct.name}. */
602
+ providerPlanName?: string | null;
603
+ /** Defaults to 1. */
604
+ quantity?: number;
605
+ /** Display-only. Backend resolves prices from the catalog. */
606
+ totalAmount?: number;
607
+ /** Display-only discount override. Backend ignores this entirely. */
608
+ overrideAmount?: number | null;
609
+ /** @deprecated Prefer the session-level `currency`. */
610
+ currency?: string;
611
+ metadata?: Record<string, unknown> | null;
612
+ }
535
613
  /** A recurring subscription plan for checkout session creation. */
536
614
  interface CheckoutSubscription {
537
615
  /**
@@ -597,14 +675,23 @@ interface CreateSessionParams {
597
675
  /** The client ID for the checkout session. */
598
676
  clientId: string;
599
677
  /**
600
- * Session-level ISO 4217 currency code. Takes precedence over any
601
- * per-item/per-subscription `currency` field. When omitted, the SDK
602
- * falls back to `items[0].currency ?? subscriptions[0].currency`.
678
+ * Session-level ISO 4217 currency code. **Required** by post-#760
679
+ * backends (`@IsNotEmpty`). The SDK resolves it from this field first,
680
+ * then `items[0].currency`, then `subscriptions[0].currency`, then
681
+ * `products[0].currency`. When none resolve, the SDK throws
682
+ * `FloPayError('validation_error')` before issuing the HTTP request.
603
683
  */
604
684
  currency?: string;
605
- /** One-time purchase items. */
685
+ /**
686
+ * Unified products array. When supplied, it is sent verbatim and
687
+ * {@link CreateSessionParams.items} / {@link CreateSessionParams.subscriptions}
688
+ * are ignored. Otherwise the SDK folds the legacy fields into this shape
689
+ * before POSTing to the backend.
690
+ */
691
+ products?: CheckoutProduct[];
692
+ /** One-time purchase items. Folded into `products[]` before send. */
606
693
  items?: CheckoutItem[];
607
- /** Recurring subscription plans. */
694
+ /** Recurring subscription plans. Folded into `products[]` before send. */
608
695
  subscriptions?: CheckoutSubscription[];
609
696
  /** Buyer's account information. */
610
697
  account: CheckoutAccount;
@@ -641,14 +728,23 @@ interface InlineSessionParams {
641
728
  /** The client ID for the checkout session. */
642
729
  clientId: string;
643
730
  /**
644
- * Session-level ISO 4217 currency code. Takes precedence over any
645
- * per-item/per-subscription `currency` field. When omitted, the SDK
646
- * falls back to `items[0].currency ?? subscriptions[0].currency`.
731
+ * Session-level ISO 4217 currency code. **Required** by post-#760
732
+ * backends (`@IsNotEmpty`). The SDK resolves it from this field first,
733
+ * then `items[0].currency`, then `subscriptions[0].currency`, then
734
+ * `products[0].currency`. When none resolve, the SDK throws
735
+ * `FloPayError('validation_error')` before issuing the HTTP request.
647
736
  */
648
737
  currency?: string;
649
- /** One-time purchase items. */
738
+ /**
739
+ * Unified products array. When supplied, it is sent verbatim and
740
+ * {@link InlineSessionParams.items} / {@link InlineSessionParams.subscriptions}
741
+ * are ignored. Otherwise the SDK folds the legacy fields into this shape
742
+ * before POSTing to the backend.
743
+ */
744
+ products?: CheckoutProduct[];
745
+ /** One-time purchase items. Folded into `products[]` before send. */
650
746
  items?: CheckoutItem[];
651
- /** Recurring subscription plans. */
747
+ /** Recurring subscription plans. Folded into `products[]` before send. */
652
748
  subscriptions?: CheckoutSubscription[];
653
749
  /** Buyer's account information. */
654
750
  account: CheckoutAccount;
@@ -817,7 +913,7 @@ declare function getConfiguredBillingApiUrl(): string;
817
913
  declare function getFloPayEnvironment(): FloPayEnvironment;
818
914
 
819
915
  /** Current SDK version. */
820
- declare const SDK_VERSION = "1.0.3";
916
+ declare const SDK_VERSION = "1.1.3";
821
917
  /** Billing API URL for staging environment. */
822
918
  declare const BILLING_API_URL_STAGING = "https://api.stage.flopay.com";
823
919
  /** Billing API URL for production environment. */
@@ -951,6 +1047,13 @@ interface CheckoutDisplayData {
951
1047
  totalSave: number;
952
1048
  /** Discount percentage (0–100). */
953
1049
  discountPercent: number;
1050
+ /**
1051
+ * Coupon discount reported by the backend (cart-currency major units),
1052
+ * when available. Populated from `session.discountAmount` (billing
1053
+ * API ≥ v1.1.2); `undefined` on older backends. Use this to render an
1054
+ * explicit "coupon" line without recomputing per-item math.
1055
+ */
1056
+ couponDiscount?: number;
954
1057
  }
955
1058
  /** Options for {@link buildCheckoutDisplayData}. */
956
1059
  interface BuildCheckoutDisplayDataOptions {
@@ -987,31 +1090,51 @@ declare function buildCheckoutDisplayData(session: CheckoutSession, options?: Bu
987
1090
 
988
1091
  /**
989
1092
  * Resolve the session-level currency, honoring the documented fallback:
990
- * `session.currency ?? items[*].currency ?? subscriptions[*].currency`.
1093
+ * `session.currency ?? items[*].currency ?? subscriptions[*].currency ?? products[*].currency`.
991
1094
  *
992
- * Returns the first non-blank currency found, or 'USD' when nothing is set.
1095
+ * Returns the first non-blank currency found, or `null` when nothing is set.
993
1096
  * Empty and whitespace-only strings are treated as unset so they do not
994
1097
  * bypass the fallback chain.
1098
+ *
1099
+ * Post-#760 backends reject session-create requests without a session-level
1100
+ * currency (`@IsNotEmpty`); callers should throw a validation error when
1101
+ * this returns `null` rather than silently defaulting.
995
1102
  */
996
- declare function resolveSessionCurrency(sessionCurrency: string | undefined, items: ReadonlyArray<{
1103
+ declare function resolveSessionCurrency(sessionCurrency: string | undefined, items?: ReadonlyArray<{
1104
+ currency?: string;
1105
+ }> | undefined, subscriptions?: ReadonlyArray<{
997
1106
  currency?: string;
998
- }> | undefined, subscriptions: ReadonlyArray<{
1107
+ }> | undefined, products?: ReadonlyArray<{
999
1108
  currency?: string;
1000
- }> | undefined): string;
1109
+ }> | undefined): string | null;
1110
+ /**
1111
+ * Fold legacy `items` + `subscriptions` arrays into the unified `products[]`
1112
+ * shape introduced by backend #760. Items become `type: 'item'`,
1113
+ * subscriptions become `type: 'subscription'`. The relative order is
1114
+ * subscriptions-first then items, matching the order the previous payload
1115
+ * builders emitted on the wire.
1116
+ */
1117
+ declare function foldIntoProducts(items: readonly CheckoutItem[] | undefined, subscriptions: readonly CheckoutSubscription[] | undefined): CheckoutProduct[];
1118
+ /**
1119
+ * Build the request payload for a single product in the unified shape
1120
+ * introduced by backend #760. Emits `type`, `code`, `name`, `quantity`,
1121
+ * `totalAmount`, `overrideAmount`, `currency`, and optional `metadata`.
1122
+ */
1123
+ declare function buildProductPayload(product: CheckoutProduct, sessionCurrency: string): Record<string, unknown>;
1001
1124
  /**
1002
1125
  * Build the request payload for a single item.
1003
1126
  *
1004
- * Sends the new `code` field alongside the deprecated `providerItemId`,
1005
- * `providerItemName`, `totalAmount`, and `overrideAmount` fields so that
1006
- * both new and old backend versions accept the same request body.
1127
+ * @deprecated Use {@link buildProductPayload} with {@link foldIntoProducts}.
1128
+ * Retained until the next major so external callers building the legacy
1129
+ * `items[]` payload manually keep working.
1007
1130
  */
1008
1131
  declare function buildItemPayload(item: CheckoutItem, sessionCurrency: string): Record<string, unknown>;
1009
1132
  /**
1010
1133
  * Build the request payload for a single subscription.
1011
1134
  *
1012
- * Sends the new `code` field alongside the deprecated `providerPlanId`,
1013
- * `providerPlanName`, `totalAmount`, and `overrideAmount` fields for
1014
- * backward compatibility.
1135
+ * @deprecated Use {@link buildProductPayload} with {@link foldIntoProducts}.
1136
+ * Retained until the next major so external callers building the legacy
1137
+ * `subscriptions[]` payload manually keep working.
1015
1138
  */
1016
1139
  declare function buildSubscriptionPayload(subscription: CheckoutSubscription, sessionCurrency: string): Record<string, unknown>;
1017
1140
 
@@ -1025,4 +1148,4 @@ declare function isValidPublishableKey(key: string): boolean;
1025
1148
  /** Returns `true` if the string looks like a Stripe secret key. */
1026
1149
  declare function isValidSecretKey(key: string): boolean;
1027
1150
 
1028
- export { type AVSFieldConfig, BILLING_API_URL, BILLING_API_URL_PRODUCTION, BILLING_API_URL_STAGING, BUTTONS_LAYOUT_DARK, BUTTONS_LAYOUT_DEFAULT, BUTTONS_LAYOUT_MINIMAL, BUTTONS_LAYOUT_ROUNDED, type BeforeButtonClickEvent, type BillingDetails, type BillingProvider, type BuildCheckoutDisplayDataOptions, type ButtonsLayoutStyles, type ButtonsLayoutTheme, CA_PROVINCES, COUNTRY_OPTIONS, CURRENCY_MAP, type CheckoutAccount, type CheckoutButtonMethod, type CheckoutDisplayData, type CheckoutItem, type CheckoutMode, type CheckoutModeKind, type CheckoutProcessError, type CheckoutProcessingPending, type CheckoutSession, type CheckoutSessionItem, type CheckoutSessionResult, type CheckoutSessionSubscription, type CheckoutSubscription, type ConfirmCardPaymentParams, type ConfirmCardPaymentResult, type ConfirmPaymentParams, type CountryOption, type CreateCustomerParams, type CreatePaymentMethodResult, type CreateSessionParams, type CurrencyInfo, type Customer, DEFAULT_API_BASE_URL, DEFAULT_API_VERSION, DEFAULT_APPEARANCE, DEFAULT_CURRENCY, type DeclineEvent, type DisplayLineItem, ELEMENT_TYPES, type ElementChangeEvent, type ElementOptions, type ElementType, FLAT_APPEARANCE, type FloPayAppearance, type FloPayConfig, type FloPayEnvironment, FloPayError, type FloPayErrorType, type FloPayThemeVariables, type InlineSessionDraft, type InlineSessionParams, type InlineSessionPatch, type LineItem, type MountedElement, NIGHT_APPEARANCE, type NormalizedCheckoutSession, type PaymentProviderAdapter, type PaymentResult, type PriceData, type ProcessPaymentParams, type RecurringInterval, SDK_VERSION, SUPPORTED_CARD_BRANDS, type StateOption, type TagsData, type TokenizedBody, US_STATES, type UpdateCustomerParams, type WebhookEvent, apiError, authenticationError, buildCheckoutDisplayData, buildItemPayload, buildSubscriptionPayload, configureFlopay, getConfiguredBillingApiUrl, getCountryByCode, getCurrencyByCountry, getFloPayEnvironment, getPostalCodeLabel, getStateFromPostalCode, getStateLabel, getStateOptions, isAVSEnabled, isAVSFieldVisible, isValidPublishableKey, isValidSecretKey, networkError, rateLimitError, resolveAVSConfig, resolveBillingApiUrl, resolveButtonsLayoutTheme, resolveSessionCurrency, validationError };
1151
+ export { type AVSFieldConfig, BILLING_API_URL, BILLING_API_URL_PRODUCTION, BILLING_API_URL_STAGING, BUTTONS_LAYOUT_DARK, BUTTONS_LAYOUT_DEFAULT, BUTTONS_LAYOUT_MINIMAL, BUTTONS_LAYOUT_ROUNDED, type BeforeButtonClickEvent, type BillingDetails, type BillingProvider, type BuildCheckoutDisplayDataOptions, type ButtonsLayoutStyles, type ButtonsLayoutTheme, CA_PROVINCES, COUNTRY_OPTIONS, CURRENCY_MAP, type CheckoutAccount, type CheckoutButtonMethod, type CheckoutDisplayData, type CheckoutGateway, type CheckoutGateways, type CheckoutItem, type CheckoutMode, type CheckoutModeKind, type CheckoutProcessError, type CheckoutProcessingPending, type CheckoutProduct, type CheckoutProductType, type CheckoutSession, type CheckoutSessionProduct, type CheckoutSessionResult, type CheckoutSubscription, type ConfirmCardPaymentParams, type ConfirmCardPaymentResult, type ConfirmPaymentParams, type CountryOption, type CreateCustomerParams, type CreatePaymentMethodResult, type CreateSessionParams, type CurrencyInfo, type Customer, DEFAULT_API_BASE_URL, DEFAULT_API_VERSION, DEFAULT_APPEARANCE, DEFAULT_CURRENCY, type DeclineEvent, type DisplayLineItem, ELEMENT_TYPES, type ElementChangeEvent, type ElementOptions, type ElementType, FLAT_APPEARANCE, type FloPayAppearance, type FloPayConfig, type FloPayEnvironment, FloPayError, type FloPayErrorType, type FloPayThemeVariables, type GatewayEnvironment, type InlineSessionDraft, type InlineSessionParams, type InlineSessionPatch, type LineItem, type MountedElement, NIGHT_APPEARANCE, type NormalizedCheckoutSession, type NormalizedGatewayEnvironment, type PaymentProviderAdapter, type PaymentResult, type PriceData, type ProcessPaymentParams, type RecurringInterval, SDK_VERSION, SUPPORTED_CARD_BRANDS, type StateOption, type TagsData, type TokenizedBody, US_STATES, type UpdateCustomerParams, type WebhookEvent, apiError, authenticationError, buildCheckoutDisplayData, buildItemPayload, buildProductPayload, buildSubscriptionPayload, configureFlopay, foldIntoProducts, getConfiguredBillingApiUrl, getCountryByCode, getCurrencyByCountry, getFloPayEnvironment, getPostalCodeLabel, getStateFromPostalCode, getStateLabel, getStateOptions, isAVSEnabled, isAVSFieldVisible, isValidPublishableKey, isValidSecretKey, networkError, normalizeGatewayEnvironment, rateLimitError, resolveAVSConfig, resolveBillingApiUrl, resolveButtonsLayoutTheme, resolveSessionCurrency, validationError };
package/dist/index.mjs CHANGED
@@ -1,3 +1,21 @@
1
+ // src/types.ts
2
+ function normalizeGatewayEnvironment(env) {
3
+ if (env == null) return void 0;
4
+ switch (env) {
5
+ case "sandbox":
6
+ case "stage":
7
+ return "sandbox";
8
+ case "live":
9
+ case "production":
10
+ return "live";
11
+ default:
12
+ console.warn(
13
+ `[FloPay] Unrecognized gateway environment "${env}". Expected one of: sandbox, live, stage, production. Falling back to undefined.`
14
+ );
15
+ return void 0;
16
+ }
17
+ }
18
+
1
19
  // src/errors.ts
2
20
  var FloPayError = class extends Error {
3
21
  constructor(message, type, options) {
@@ -45,7 +63,7 @@ function getFloPayEnvironment() {
45
63
  }
46
64
 
47
65
  // src/constants.ts
48
- var SDK_VERSION = "1.0.3";
66
+ var SDK_VERSION = "1.1.3";
49
67
  var BILLING_API_URL_STAGING = "https://api.stage.flopay.com";
50
68
  var BILLING_API_URL_PRODUCTION = "https://api.flopay.com";
51
69
  var DEFAULT_API_BASE_URL = BILLING_API_URL_STAGING;
@@ -704,7 +722,7 @@ function nonBlank(value) {
704
722
  const trimmed = value.trim();
705
723
  return trimmed.length > 0 ? trimmed : void 0;
706
724
  }
707
- function resolveSessionCurrency(sessionCurrency, items, subscriptions) {
725
+ function resolveSessionCurrency(sessionCurrency, items, subscriptions, products) {
708
726
  const session = nonBlank(sessionCurrency);
709
727
  if (session) return session;
710
728
  for (const item of items ?? []) {
@@ -715,7 +733,67 @@ function resolveSessionCurrency(sessionCurrency, items, subscriptions) {
715
733
  const c = nonBlank(sub.currency);
716
734
  if (c) return c;
717
735
  }
718
- return "USD";
736
+ for (const product of products ?? []) {
737
+ const c = nonBlank(product.currency);
738
+ if (c) return c;
739
+ }
740
+ return null;
741
+ }
742
+ function foldIntoProducts(items, subscriptions) {
743
+ const products = [];
744
+ for (const sub of subscriptions ?? []) {
745
+ products.push({
746
+ type: "subscription",
747
+ code: nonBlank(sub.code) ?? nonBlank(sub.providerPlanId),
748
+ providerPlanId: sub.providerPlanId,
749
+ name: nonBlank(sub.subscriptionName) ?? nonBlank(sub.providerPlanName) ?? null,
750
+ subscriptionName: sub.subscriptionName ?? null,
751
+ providerPlanName: sub.providerPlanName ?? null,
752
+ quantity: sub.quantity,
753
+ totalAmount: sub.totalAmount,
754
+ overrideAmount: sub.overrideAmount,
755
+ currency: sub.currency,
756
+ metadata: sub.metadata
757
+ });
758
+ }
759
+ for (const item of items ?? []) {
760
+ products.push({
761
+ type: "item",
762
+ code: nonBlank(item.code) ?? nonBlank(item.providerItemId),
763
+ providerItemId: item.providerItemId,
764
+ name: nonBlank(item.itemName) ?? nonBlank(item.providerItemName) ?? null,
765
+ itemName: item.itemName ?? null,
766
+ providerItemName: item.providerItemName ?? null,
767
+ quantity: item.quantity,
768
+ totalAmount: item.totalAmount,
769
+ overrideAmount: item.overrideAmount,
770
+ currency: item.currency,
771
+ metadata: item.metadata
772
+ });
773
+ }
774
+ return products;
775
+ }
776
+ function buildProductPayload(product, sessionCurrency) {
777
+ const code = nonBlank(product.code) ?? nonBlank(product.providerItemId) ?? nonBlank(product.providerPlanId);
778
+ if (!code) {
779
+ throw new Error(
780
+ "CheckoutProduct requires `code` (or the deprecated `providerItemId` / `providerPlanId`)."
781
+ );
782
+ }
783
+ const name = nonBlank(product.name) ?? nonBlank(product.itemName) ?? nonBlank(product.providerItemName) ?? nonBlank(product.subscriptionName) ?? nonBlank(product.providerPlanName) ?? null;
784
+ const payload = {
785
+ type: product.type,
786
+ code,
787
+ name,
788
+ quantity: product.quantity ?? 1,
789
+ totalAmount: product.totalAmount,
790
+ overrideAmount: product.overrideAmount ?? null,
791
+ currency: nonBlank(product.currency) ?? sessionCurrency
792
+ };
793
+ if (product.metadata) {
794
+ payload["metadata"] = product.metadata;
795
+ }
796
+ return payload;
719
797
  }
720
798
  function buildItemPayload(item, sessionCurrency) {
721
799
  const code = nonBlank(item.code) ?? nonBlank(item.providerItemId);
@@ -765,13 +843,15 @@ function buildSubscriptionPayload(subscription, sessionCurrency) {
765
843
  // src/display.ts
766
844
  function buildCheckoutDisplayData(session, options = {}) {
767
845
  const itemsList = [];
768
- const subscriptions = session.subscriptions ?? [];
769
- const items = session.items ?? [];
770
- const currency = resolveSessionCurrency(session.currency, items, subscriptions).toUpperCase();
846
+ const products = session.products ?? [];
847
+ const subscriptions = products.filter((p) => p.type === "subscription");
848
+ const items = products.filter((p) => p.type === "item");
849
+ const resolvedCurrency = resolveSessionCurrency(session.currency, void 0, void 0, products);
850
+ const currency = (resolvedCurrency ?? "USD").toUpperCase();
771
851
  for (const sub of subscriptions) {
772
852
  const originalPrice = sub.totalAmount ?? 0;
773
853
  const discountedPrice = sub.overrideAmount ?? originalPrice;
774
- let name = sub.subscriptionName || sub.providerPlanName || sub.code || "Subscription";
854
+ let name = sub.name || sub.code || "Subscription";
775
855
  if (name === "4-WEEK PLAN" && discountedPrice <= 1) {
776
856
  name = "7-DAY TRIAL: FULL ACCESS";
777
857
  }
@@ -788,7 +868,7 @@ function buildCheckoutDisplayData(session, options = {}) {
788
868
  const originalPrice = item.totalAmount ?? 0;
789
869
  const discountedPrice = item.overrideAmount ?? originalPrice;
790
870
  itemsList.push({
791
- name: item.itemName || item.providerItemName || item.code || "Item",
871
+ name: item.name || item.code || "Item",
792
872
  quantity: item.quantity,
793
873
  price: discountedPrice,
794
874
  originalPrice
@@ -803,8 +883,13 @@ function buildCheckoutDisplayData(session, options = {}) {
803
883
  originalPrice: session.amount / 100
804
884
  });
805
885
  }
806
- const originalTotal = itemsList.reduce((sum, i) => sum + i.originalPrice * i.quantity, 0);
807
- const total = itemsList.reduce((sum, i) => sum + i.price * i.quantity, 0);
886
+ const lineOriginalTotal = itemsList.reduce((sum, i) => sum + i.originalPrice * i.quantity, 0);
887
+ const lineTotal = itemsList.reduce((sum, i) => sum + i.price * i.quantity, 0);
888
+ const hasBackendTotals = typeof session.totalAmount === "number" && Number.isFinite(session.totalAmount);
889
+ const hasBackendSubtotal = typeof session.subtotalAmount === "number" && Number.isFinite(session.subtotalAmount);
890
+ const hasBackendDiscount = typeof session.discountAmount === "number" && Number.isFinite(session.discountAmount);
891
+ const total = hasBackendTotals ? session.totalAmount : lineTotal;
892
+ const originalTotal = hasBackendSubtotal ? session.subtotalAmount : lineOriginalTotal;
808
893
  const totalSave = Math.max(0, originalTotal - total);
809
894
  const discountPercent = originalTotal > 0 ? Math.round(totalSave / originalTotal * 100) : 0;
810
895
  return {
@@ -813,7 +898,8 @@ function buildCheckoutDisplayData(session, options = {}) {
813
898
  total,
814
899
  originalTotal,
815
900
  totalSave,
816
- discountPercent
901
+ discountPercent,
902
+ ...hasBackendDiscount ? { couponDiscount: session.discountAmount } : {}
817
903
  };
818
904
  }
819
905
 
@@ -853,8 +939,10 @@ export {
853
939
  authenticationError,
854
940
  buildCheckoutDisplayData,
855
941
  buildItemPayload,
942
+ buildProductPayload,
856
943
  buildSubscriptionPayload,
857
944
  configureFlopay,
945
+ foldIntoProducts,
858
946
  getConfiguredBillingApiUrl,
859
947
  getCountryByCode,
860
948
  getCurrencyByCountry,
@@ -868,6 +956,7 @@ export {
868
956
  isValidPublishableKey,
869
957
  isValidSecretKey,
870
958
  networkError,
959
+ normalizeGatewayEnvironment,
871
960
  rateLimitError,
872
961
  resolveAVSConfig,
873
962
  resolveBillingApiUrl,