@flopay/shared 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/index.cjs +21 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -28
- package/dist/index.d.ts +81 -28
- package/dist/index.mjs +20 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,7 +79,10 @@ throw validationError('Email is required', 'email');
|
|
|
79
79
|
| `ButtonsLayoutStyles` | Style overrides for the `buttons` layout: `cardButton`, `cardButtonFontSize`, `cardFormContainer`, `cardInputBorder`, `cardInputColor`, `cardInputPlaceholderColor`, `cardInputFontSize`, `cardInputBackground`, `nameInput`, `backButton`, `backButtonFontSize`, `backButtonIcon`, `submitButton`, `submitButtonFontSize`, `title`, `titleFontSize`, `errorBanner` |
|
|
80
80
|
| `ButtonsLayoutTheme` | Theme preset name: `'default'` / `'minimal'` / `'rounded'` / `'dark'` |
|
|
81
81
|
| `CheckoutMode` | Checkout mode: `'full'` / `'auto'` / `'confirm'` |
|
|
82
|
-
| `CheckoutSession` | Session object: `id`, `clientSecret`, `mode`, `status`, `amount`, `currency`, `customer?`, `checkoutMode?`, `items?`, `subscriptions?`, `successUrl?`, `cancelUrl?`, `coupons?`, `
|
|
82
|
+
| `CheckoutSession` | Session object: `id`, `clientSecret`, `mode`, `status`, `amount`, `currency`, `customer?`, `checkoutMode?`, `items?`, `subscriptions?`, `successUrl?`, `cancelUrl?`, `coupons?`, `gateways?` (map keyed by gateway code — `stripe`, `paypal`, …), `accountData?`, `tagsData?` |
|
|
83
|
+
| `CheckoutGateway` | Per-gateway config: `publishableKey?`, `environment?` (`'sandbox'`/`'live'`), `stripeClientSecret?` (Stripe-only) |
|
|
84
|
+
| `CheckoutGateways` | Map keyed by gateway code (e.g. `stripe`, `paypal`). A session can advertise multiple concurrent gateways. |
|
|
85
|
+
| `GatewayEnvironment` | `'sandbox'` / `'live'` — drives the PayPal JS SDK script and any other environment-scoped behavior |
|
|
83
86
|
| `CheckoutSessionItem` | Session item from billing API: `uuid`, `providerItemId`, `providerItemName`, `quantity`, `totalAmount`, `overrideAmount`, `currency` |
|
|
84
87
|
| `CheckoutSessionSubscription` | Session subscription from billing API: `uuid`, `providerPlanId`, `providerPlanName`, `quantity`, `totalAmount`, `overrideAmount`, `currency` |
|
|
85
88
|
| `PaymentResult` | Payment outcome: `status` (`'succeeded'`/`'processing'`/`'requires_action'`/`'failed'`), `paymentIntentId?`, `error?` |
|
package/dist/index.cjs
CHANGED
|
@@ -60,6 +60,7 @@ __export(index_exports, {
|
|
|
60
60
|
isValidPublishableKey: () => isValidPublishableKey,
|
|
61
61
|
isValidSecretKey: () => isValidSecretKey,
|
|
62
62
|
networkError: () => networkError,
|
|
63
|
+
normalizeGatewayEnvironment: () => normalizeGatewayEnvironment,
|
|
63
64
|
rateLimitError: () => rateLimitError,
|
|
64
65
|
resolveAVSConfig: () => resolveAVSConfig,
|
|
65
66
|
resolveBillingApiUrl: () => resolveBillingApiUrl,
|
|
@@ -69,6 +70,24 @@ __export(index_exports, {
|
|
|
69
70
|
});
|
|
70
71
|
module.exports = __toCommonJS(index_exports);
|
|
71
72
|
|
|
73
|
+
// src/types.ts
|
|
74
|
+
function normalizeGatewayEnvironment(env) {
|
|
75
|
+
if (env == null) return void 0;
|
|
76
|
+
switch (env) {
|
|
77
|
+
case "sandbox":
|
|
78
|
+
case "stage":
|
|
79
|
+
return "sandbox";
|
|
80
|
+
case "live":
|
|
81
|
+
case "production":
|
|
82
|
+
return "live";
|
|
83
|
+
default:
|
|
84
|
+
console.warn(
|
|
85
|
+
`[FloPay] Unrecognized gateway environment "${env}". Expected one of: sandbox, live, stage, production. Falling back to undefined.`
|
|
86
|
+
);
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
72
91
|
// src/errors.ts
|
|
73
92
|
var FloPayError = class extends Error {
|
|
74
93
|
constructor(message, type, options) {
|
|
@@ -116,7 +135,7 @@ function getFloPayEnvironment() {
|
|
|
116
135
|
}
|
|
117
136
|
|
|
118
137
|
// src/constants.ts
|
|
119
|
-
var SDK_VERSION = "1.0
|
|
138
|
+
var SDK_VERSION = "1.1.0";
|
|
120
139
|
var BILLING_API_URL_STAGING = "https://api.stage.flopay.com";
|
|
121
140
|
var BILLING_API_URL_PRODUCTION = "https://api.flopay.com";
|
|
122
141
|
var DEFAULT_API_BASE_URL = BILLING_API_URL_STAGING;
|
|
@@ -940,6 +959,7 @@ function isValidSecretKey(key) {
|
|
|
940
959
|
isValidPublishableKey,
|
|
941
960
|
isValidSecretKey,
|
|
942
961
|
networkError,
|
|
962
|
+
normalizeGatewayEnvironment,
|
|
943
963
|
rateLimitError,
|
|
944
964
|
resolveAVSConfig,
|
|
945
965
|
resolveBillingApiUrl,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/config.ts","../src/constants.ts","../src/postal-code-lookup.ts","../src/checkout-payload.ts","../src/display.ts","../src/validation.ts"],"sourcesContent":["// Types\nexport type {\n FloPayThemeVariables,\n FloPayAppearance,\n Customer,\n RecurringInterval,\n PriceData,\n LineItem,\n CheckoutMode,\n CheckoutSession,\n CheckoutSessionItem,\n CheckoutSessionSubscription,\n PaymentResult,\n ConfirmPaymentParams,\n CreatePaymentMethodResult,\n ConfirmCardPaymentParams,\n ConfirmCardPaymentResult,\n ElementType,\n ElementChangeEvent,\n ElementOptions,\n MountedElement,\n FloPayConfig,\n PaymentProviderAdapter,\n BillingProvider,\n TokenizedBody,\n CheckoutProcessError,\n CheckoutProcessingPending,\n CheckoutModeKind,\n NormalizedCheckoutSession,\n CheckoutItem,\n CheckoutSubscription,\n CheckoutAccount,\n TagsData,\n CreateSessionParams,\n CheckoutSessionResult,\n ProcessPaymentParams,\n CreateCustomerParams,\n UpdateCustomerParams,\n WebhookEvent,\n CurrencyInfo,\n CountryOption,\n ButtonsLayoutStyles,\n ButtonsLayoutTheme,\n AVSFieldConfig,\n InlineSessionParams,\n InlineSessionDraft,\n InlineSessionPatch,\n BeforeButtonClickEvent,\n CheckoutButtonMethod,\n DeclineEvent,\n BillingDetails,\n} from './types.js';\n\n// Errors\nexport {\n FloPayError,\n validationError,\n apiError,\n authenticationError,\n rateLimitError,\n networkError,\n} from './errors.js';\nexport type { FloPayErrorType } from './errors.js';\n\n// Configuration\nexport { configureFlopay, getConfiguredBillingApiUrl, getFloPayEnvironment } from './config.js';\nexport type { FloPayEnvironment } from './config.js';\n\n// Constants\nexport {\n SDK_VERSION,\n DEFAULT_API_BASE_URL,\n DEFAULT_API_VERSION,\n BILLING_API_URL,\n BILLING_API_URL_STAGING,\n BILLING_API_URL_PRODUCTION,\n resolveBillingApiUrl,\n DEFAULT_APPEARANCE,\n FLAT_APPEARANCE,\n NIGHT_APPEARANCE,\n ELEMENT_TYPES,\n SUPPORTED_CARD_BRANDS,\n CURRENCY_MAP,\n DEFAULT_CURRENCY,\n BUTTONS_LAYOUT_DEFAULT,\n BUTTONS_LAYOUT_MINIMAL,\n BUTTONS_LAYOUT_ROUNDED,\n BUTTONS_LAYOUT_DARK,\n resolveButtonsLayoutTheme,\n getPostalCodeLabel,\n COUNTRY_OPTIONS,\n getCountryByCode,\n resolveAVSConfig,\n isAVSFieldVisible,\n isAVSEnabled,\n US_STATES,\n CA_PROVINCES,\n getStateOptions,\n getStateLabel,\n type StateOption,\n} from './constants.js';\n\n// Postal code lookups\nexport { getStateFromPostalCode } from './postal-code-lookup.js';\n\n// Display helpers\nexport { buildCheckoutDisplayData } from './display.js';\nexport type {\n DisplayLineItem,\n CheckoutDisplayData,\n BuildCheckoutDisplayDataOptions,\n} from './display.js';\n\n// Checkout payload helpers\nexport {\n resolveSessionCurrency,\n buildItemPayload,\n buildSubscriptionPayload,\n} from './checkout-payload.js';\n\n// Validation helpers\nexport {\n getCurrencyByCountry,\n isValidPublishableKey,\n isValidSecretKey,\n} from './validation.js';\n","/** Discriminated error types returned by the FloPay SDK. */\nexport type FloPayErrorType =\n | 'validation_error'\n | 'api_error'\n | 'authentication_error'\n | 'rate_limit_error'\n | 'network_error';\n\n/**\n * Custom error class for all FloPay SDK errors.\n *\n * Extends the native `Error` and adds structured fields that mirror\n * Stripe-style error responses for familiarity.\n */\nexport class FloPayError extends Error {\n readonly type: FloPayErrorType;\n readonly code?: string;\n readonly declineCode?: string;\n readonly param?: string;\n readonly statusCode?: number;\n\n constructor(\n message: string,\n type: FloPayErrorType,\n options?: { code?: string; declineCode?: string; param?: string; statusCode?: number },\n ) {\n super(message);\n this.name = 'FloPayError';\n this.type = type;\n this.code = options?.code;\n this.declineCode = options?.declineCode;\n this.param = options?.param;\n this.statusCode = options?.statusCode;\n\n // Restore prototype chain (required when extending built-ins)\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error Factories\n// ---------------------------------------------------------------------------\n\n/** Create a validation error (e.g. missing required field). */\nexport function validationError(\n message: string,\n param?: string,\n): FloPayError {\n return new FloPayError(message, 'validation_error', { param });\n}\n\n/** Create an API error (e.g. upstream provider returned an error). */\nexport function apiError(\n message: string,\n code?: string,\n statusCode?: number,\n): FloPayError {\n return new FloPayError(message, 'api_error', { code, statusCode });\n}\n\n/** Create an authentication error (e.g. invalid publishable key). */\nexport function authenticationError(message: string): FloPayError {\n return new FloPayError(message, 'authentication_error');\n}\n\n/** Create a rate limit error. */\nexport function rateLimitError(message: string): FloPayError {\n return new FloPayError(message, 'rate_limit_error');\n}\n\n/** Create a network error (e.g. fetch failed). */\nexport function networkError(message: string): FloPayError {\n return new FloPayError(message, 'network_error');\n}\n","/** FloPay environment — determines which billing API URL is used. */\nexport type FloPayEnvironment = 'staging' | 'production' | 'local';\n\nconst ENV_URL_MAP: Record<FloPayEnvironment, string> = {\n local: 'https://flo.ngrok.pro',\n staging: 'https://api.stage.flopay.com',\n production: 'https://api.flopay.com',\n};\n\nlet globalEnvironment: FloPayEnvironment = 'staging';\n\n/**\n * Configure the FloPay SDK globally. Call once at app startup.\n *\n * The environment determines which billing API URL is used for all\n * FloPay operations (session creation, payment processing, etc.).\n *\n * @example\n * ```ts\n * import { configureFlopay } from '@flopay/shared';\n *\n * // In production\n * configureFlopay({ environment: 'production' });\n *\n * // In staging/development\n * configureFlopay({ environment: 'staging' });\n * ```\n *\n * Alternatively, set the `NEXT_PUBLIC_FLOPAY_ENV` environment variable\n * to `'staging'` or `'production'` — the SDK reads it automatically.\n */\nexport function configureFlopay(config: { environment: FloPayEnvironment }): void {\n globalEnvironment = config.environment;\n}\n\n/** Get the billing API URL for the currently configured environment. */\nexport function getConfiguredBillingApiUrl(): string {\n return ENV_URL_MAP[globalEnvironment];\n}\n\n/** Get the current configured environment. */\nexport function getFloPayEnvironment(): FloPayEnvironment {\n return globalEnvironment;\n}\n","import type { AVSFieldConfig, ButtonsLayoutStyles, ButtonsLayoutTheme, CountryOption, CurrencyInfo, FloPayAppearance } from './types.js';\n\nimport type { FloPayEnvironment } from './config.js';\nimport { getConfiguredBillingApiUrl } from './config.js';\n\n// ---------------------------------------------------------------------------\n// SDK Version & API\n// ---------------------------------------------------------------------------\n\n/** Current SDK version. */\nexport const SDK_VERSION = '1.0.3';\n\n/** Billing API URL for staging environment. */\nexport const BILLING_API_URL_STAGING = 'https://api.stage.flopay.com';\n\n/** Billing API URL for production environment. */\nexport const BILLING_API_URL_PRODUCTION = 'https://api.flopay.com';\n\n/** Default FloPay API base URL (used by @flopay/node). Alias for staging. */\nexport const DEFAULT_API_BASE_URL = BILLING_API_URL_STAGING;\n\n/** Default billing API base URL. Alias for staging — prefer `resolveBillingApiUrl()`. */\nexport const BILLING_API_URL = BILLING_API_URL_STAGING;\n\n/**\n * Resolve the billing API URL from available configuration.\n *\n * Priority:\n * 1. Explicit `billingApiUrl` (prop/param override)\n * 2. `NEXT_PUBLIC_FLOPAY_ENV` environment variable (`'staging'` | `'production'`)\n * 3. `configureFlopay()` global environment setting\n * 4. Fallback: staging URL\n *\n * @example\n * ```ts\n * import { resolveBillingApiUrl } from '@flopay/shared';\n *\n * // Reads from env var or configureFlopay() — no args needed\n * const url = resolveBillingApiUrl();\n *\n * // Explicit override takes priority\n * const url = resolveBillingApiUrl('https://custom.example.com');\n * ```\n */\nexport function resolveBillingApiUrl(billingApiUrl?: string): string {\n if (billingApiUrl) return billingApiUrl;\n\n // Environment variable (works in Next.js and bundlers that inline process.env)\n if (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_FLOPAY_ENV) {\n const env = process.env.NEXT_PUBLIC_FLOPAY_ENV as FloPayEnvironment;\n if (env === 'production') return BILLING_API_URL_PRODUCTION;\n return BILLING_API_URL_STAGING;\n }\n\n // Global config from configureFlopay()\n return getConfiguredBillingApiUrl();\n}\n\n/** Default API version header value. */\nexport const DEFAULT_API_VERSION = '2024-01-01';\n\n// ---------------------------------------------------------------------------\n// Default Themes\n// ---------------------------------------------------------------------------\n\n/** The default appearance applied when no custom appearance is provided. */\nexport const DEFAULT_APPEARANCE: FloPayAppearance = {\n theme: 'default',\n variables: {\n colorPrimary: '#4A49FF',\n colorBackground: '#FFFFFF',\n colorText: '#262833',\n colorDanger: '#DF1B41',\n borderRadius: '8px',\n fontFamily: 'Poppins, system-ui, sans-serif',\n fontSizeBase: '16px',\n spacingUnit: '4px',\n },\n};\n\n/** Flat theme — minimal borders and shadows. */\nexport const FLAT_APPEARANCE: FloPayAppearance = {\n theme: 'flat',\n variables: {\n ...DEFAULT_APPEARANCE.variables,\n borderRadius: '4px',\n },\n};\n\n/** Night theme — dark background. */\nexport const NIGHT_APPEARANCE: FloPayAppearance = {\n theme: 'night',\n variables: {\n colorPrimary: '#7B7BFF',\n colorBackground: '#1A1A2E',\n colorText: '#E0E0E0',\n colorDanger: '#FF6B6B',\n borderRadius: '8px',\n fontFamily: 'Poppins, system-ui, sans-serif',\n fontSizeBase: '16px',\n spacingUnit: '4px',\n },\n};\n\n// ---------------------------------------------------------------------------\n// Buttons Layout Theme Presets\n// ---------------------------------------------------------------------------\n\n/** Default buttons layout — white card button, neutral borders. */\nexport const BUTTONS_LAYOUT_DEFAULT: ButtonsLayoutStyles = {};\n\n/** Minimal buttons layout — borderless, subtle hover. */\nexport const BUTTONS_LAYOUT_MINIMAL: ButtonsLayoutStyles = {\n cardButton: {\n border: 'none',\n backgroundColor: '#f9fafb',\n boxShadow: 'none',\n },\n cardFormContainer: {\n backgroundColor: '#f9fafb',\n border: 'none',\n },\n cardInputBorder: '#e5e7eb',\n backButtonIcon: {\n backgroundColor: '#e5e7eb',\n },\n submitButton: {\n borderRadius: '6px',\n },\n};\n\n/** Rounded buttons layout — large border radius, soft shadows. */\nexport const BUTTONS_LAYOUT_ROUNDED: ButtonsLayoutStyles = {\n cardButton: {\n borderRadius: '9999px',\n border: '1px solid #e5e7eb',\n boxShadow: '0 1px 3px rgba(0,0,0,0.06)',\n },\n cardFormContainer: {\n borderRadius: '16px',\n border: '1px solid #e5e7eb',\n boxShadow: '0 2px 8px rgba(0,0,0,0.06)',\n },\n cardInputBorder: '#d1d5db',\n submitButton: {\n borderRadius: '9999px',\n },\n backButtonIcon: {\n backgroundColor: '#f3f4f6',\n },\n};\n\n/** Dark buttons layout — dark backgrounds, light text. */\nexport const BUTTONS_LAYOUT_DARK: ButtonsLayoutStyles = {\n cardButton: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n border: '1px solid #374151',\n boxShadow: 'none',\n },\n cardFormContainer: {\n backgroundColor: '#111827',\n border: '1px solid #374151',\n },\n cardInputBorder: '#4b5563',\n cardInputColor: '#f9fafb',\n cardInputPlaceholderColor: '#6b7280',\n cardInputBackground: '#1f2937',\n nameInput: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n backButton: {\n color: '#9ca3af',\n },\n backButtonIcon: {\n backgroundColor: '#374151',\n },\n submitButton: {\n backgroundColor: '#6366f1',\n },\n title: {\n color: '#f9fafb',\n },\n countrySelect: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n zipInput: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n};\n\n/** Resolve a buttons layout theme name to its style preset. */\nexport function resolveButtonsLayoutTheme(theme?: ButtonsLayoutTheme): ButtonsLayoutStyles {\n switch (theme) {\n case 'minimal': return BUTTONS_LAYOUT_MINIMAL;\n case 'rounded': return BUTTONS_LAYOUT_ROUNDED;\n case 'dark': return BUTTONS_LAYOUT_DARK;\n default: return BUTTONS_LAYOUT_DEFAULT;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Supported Element Types\n// ---------------------------------------------------------------------------\n\n/** All supported element type identifiers. */\nexport const ELEMENT_TYPES = [\n 'payment',\n 'card',\n 'cardNumber',\n 'cardExpiry',\n 'cardCvc',\n 'address',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Supported Card Brands\n// ---------------------------------------------------------------------------\n\nexport const SUPPORTED_CARD_BRANDS = [\n 'visa',\n 'mastercard',\n 'mastercard_debit',\n 'amex',\n 'discover',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Currency Mapping (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Country code to currency information mapping. */\nexport const CURRENCY_MAP: Record<string, CurrencyInfo> = {\n // EUR (VAT applies)\n AT: { currency: 'EUR', symbol: '\\u20AC', country: 'Austria', countryCode: 'AT', tax: 1 },\n BE: { currency: 'EUR', symbol: '\\u20AC', country: 'Belgium', countryCode: 'BE', tax: 1 },\n CY: { currency: 'EUR', symbol: '\\u20AC', country: 'Cyprus', countryCode: 'CY', tax: 1 },\n DE: { currency: 'EUR', symbol: '\\u20AC', country: 'Germany', countryCode: 'DE', tax: 1 },\n EE: { currency: 'EUR', symbol: '\\u20AC', country: 'Estonia', countryCode: 'EE', tax: 1 },\n ES: { currency: 'EUR', symbol: '\\u20AC', country: 'Spain', countryCode: 'ES', tax: 1 },\n FI: { currency: 'EUR', symbol: '\\u20AC', country: 'Finland', countryCode: 'FI', tax: 1 },\n FR: { currency: 'EUR', symbol: '\\u20AC', country: 'France', countryCode: 'FR', tax: 1 },\n GR: { currency: 'EUR', symbol: '\\u20AC', country: 'Greece', countryCode: 'GR', tax: 1 },\n HR: { currency: 'EUR', symbol: '\\u20AC', country: 'Croatia', countryCode: 'HR', tax: 1 },\n IE: { currency: 'EUR', symbol: '\\u20AC', country: 'Ireland', countryCode: 'IE', tax: 1 },\n IT: { currency: 'EUR', symbol: '\\u20AC', country: 'Italy', countryCode: 'IT', tax: 1 },\n LT: { currency: 'EUR', symbol: '\\u20AC', country: 'Lithuania', countryCode: 'LT', tax: 1 },\n LU: { currency: 'EUR', symbol: '\\u20AC', country: 'Luxembourg', countryCode: 'LU', tax: 1 },\n LV: { currency: 'EUR', symbol: '\\u20AC', country: 'Latvia', countryCode: 'LV', tax: 1 },\n MT: { currency: 'EUR', symbol: '\\u20AC', country: 'Malta', countryCode: 'MT', tax: 1 },\n NL: { currency: 'EUR', symbol: '\\u20AC', country: 'Netherlands', countryCode: 'NL', tax: 1 },\n PT: { currency: 'EUR', symbol: '\\u20AC', country: 'Portugal', countryCode: 'PT', tax: 1 },\n SI: { currency: 'EUR', symbol: '\\u20AC', country: 'Slovenia', countryCode: 'SI', tax: 1 },\n SK: { currency: 'EUR', symbol: '\\u20AC', country: 'Slovakia', countryCode: 'SK', tax: 1 },\n BG: { currency: 'EUR', symbol: '\\u20AC', country: 'Bulgaria', countryCode: 'BG', tax: 1 },\n RO: { currency: 'EUR', symbol: '\\u20AC', country: 'Romania', countryCode: 'RO', tax: 1 },\n CZ: { currency: 'EUR', symbol: '\\u20AC', country: 'Czech Republic', countryCode: 'CZ', tax: 1 },\n SE: { currency: 'EUR', symbol: '\\u20AC', country: 'Sweden', countryCode: 'SE', tax: 1 },\n DK: { currency: 'EUR', symbol: '\\u20AC', country: 'Denmark', countryCode: 'DK', tax: 1 },\n PL: { currency: 'EUR', symbol: '\\u20AC', country: 'Poland', countryCode: 'PL', tax: 1 },\n HU: { currency: 'EUR', symbol: '\\u20AC', country: 'Hungary', countryCode: 'HU', tax: 1 },\n // GBP (VAT applies)\n GB: { currency: 'GBP', symbol: '\\u00A3', country: 'United Kingdom', countryCode: 'GB', tax: 1 },\n // USD (no VAT)\n US: { currency: 'USD', symbol: '$', country: 'United States', countryCode: 'US', tax: 0 },\n // CAD (no VAT)\n CA: { currency: 'CAD', symbol: 'CA$', country: 'Canada', countryCode: 'CA', tax: 0 },\n // NZD (no VAT)\n NZ: { currency: 'NZD', symbol: 'NZ$', country: 'New Zealand', countryCode: 'NZ', tax: 0 },\n // AUD (no VAT)\n AU: { currency: 'AUD', symbol: 'AU$', country: 'Australia', countryCode: 'AU', tax: 0 },\n};\n\n/** Default currency info when country is unknown. */\nexport const DEFAULT_CURRENCY: CurrencyInfo = {\n currency: 'USD',\n symbol: '$',\n country: 'United States',\n countryCode: 'US',\n tax: 0,\n};\n\n// ---------------------------------------------------------------------------\n// Postal Code Labels\n// ---------------------------------------------------------------------------\n\n/** Returns the correct postal code label for a country code (ISO 3166-1 alpha-2). */\nexport function getPostalCodeLabel(countryCode: string): string {\n switch (countryCode.toUpperCase()) {\n case 'US': return 'ZIP Code';\n case 'GB': return 'Postcode';\n case 'CA': return 'Postal Code';\n case 'AU':\n case 'NZ': return 'Postcode';\n case 'IE': return 'Eircode';\n default: return 'Postal Code';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Country List (ISO 3166-1 alpha-2)\n// ---------------------------------------------------------------------------\n\nconst regionNames = new Intl.DisplayNames(['en'], { type: 'region' });\n\nfunction codeToFlag(code: string): string {\n return [...code.toUpperCase()]\n .map((c) => String.fromCodePoint(0x1f1e6 - 65 + c.charCodeAt(0)))\n .join('');\n}\n\n/** Priority countries shown first in dropdowns. */\nconst PRIORITY_CODES = ['US', 'GB', 'CA', 'AU', 'NZ', 'IE', 'DE', 'FR'];\n\nconst ALL_CODES = [\n 'AD', 'AE', 'AF', 'AG', 'AL', 'AM', 'AO', 'AR', 'AT', 'AU',\n 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ',\n 'BN', 'BO', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CD',\n 'CF', 'CG', 'CH', 'CI', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU',\n 'CV', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC',\n 'EE', 'EG', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FM', 'FR', 'GA',\n 'GB', 'GD', 'GE', 'GH', 'GM', 'GN', 'GQ', 'GR', 'GT', 'GW',\n 'GY', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IN', 'IQ',\n 'IR', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI',\n 'KM', 'KN', 'KR', 'KW', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK',\n 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME',\n 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MR', 'MT', 'MU', 'MV',\n 'MW', 'MX', 'MY', 'MZ', 'NA', 'NE', 'NG', 'NI', 'NL', 'NO',\n 'NP', 'NR', 'NZ', 'OM', 'PA', 'PE', 'PG', 'PH', 'PK', 'PL',\n 'PT', 'PW', 'PY', 'QA', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB',\n 'SC', 'SD', 'SE', 'SG', 'SI', 'SK', 'SL', 'SM', 'SN', 'SO',\n 'SR', 'SS', 'ST', 'SV', 'SY', 'SZ', 'TD', 'TG', 'TH', 'TJ',\n 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA',\n 'UG', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VN', 'VU', 'WS',\n 'XK', 'YE', 'ZA', 'ZM', 'ZW',\n] as const;\n\nfunction buildCountryOption(code: string): CountryOption {\n return { code, name: regionNames.of(code) ?? code, flag: codeToFlag(code) };\n}\n\nconst prioritySet = new Set(PRIORITY_CODES);\nconst rest = ALL_CODES.filter((c) => !prioritySet.has(c));\n\n/** All countries for dropdown select, priority countries first. */\nexport const COUNTRY_OPTIONS: CountryOption[] = [\n ...PRIORITY_CODES.map(buildCountryOption),\n ...rest.map(buildCountryOption),\n];\n\n/** Look up a country option by ISO 3166-1 alpha-2 code. */\nexport function getCountryByCode(code: string): CountryOption | undefined {\n return COUNTRY_OPTIONS.find((c) => c.code === code);\n}\n\n// ---------------------------------------------------------------------------\n// AVS Configuration Helpers\n// ---------------------------------------------------------------------------\n\n/** Default AVS config when `enableAVS: true` (backward compatible — country + postal code). */\nconst DEFAULT_AVS_CONFIG: AVSFieldConfig = {\n country: true,\n postal_code: true,\n};\n\n/**\n * Normalize `enableAVS` to a resolved config object.\n * - `false` / `undefined` → `null` (AVS disabled)\n * - `true` → default config (country + postal_code)\n * - `AVSFieldConfig` → returned as-is\n */\nexport function resolveAVSConfig(enableAVS?: boolean | AVSFieldConfig): AVSFieldConfig | null {\n if (!enableAVS) return null;\n if (enableAVS === true) return DEFAULT_AVS_CONFIG;\n return enableAVS;\n}\n\n/**\n * Check if an AVS field should be visible for the given country.\n * - `undefined` / `false` → hidden\n * - `true` → visible for all countries\n * - `string[]` → visible only for listed country codes\n */\nexport function isAVSFieldVisible(\n field: boolean | string[] | undefined,\n country: string,\n): boolean {\n if (field === undefined || field === false) return false;\n if (field === true) return true;\n const normalizedCountry = country.trim().toUpperCase();\n return field.some((code) => code.trim().toUpperCase() === normalizedCountry);\n}\n\n/** Returns true if any AVS field is meaningfully configured (at least one field is truthy). */\nexport function isAVSEnabled(enableAVS?: boolean | AVSFieldConfig): boolean {\n const config = resolveAVSConfig(enableAVS);\n if (!config) return false;\n return Object.values(config).some(\n (v) => v === true || (Array.isArray(v) && v.length > 0),\n );\n}\n\n// ---------------------------------------------------------------------------\n// US States & CA Provinces\n// ---------------------------------------------------------------------------\n\nexport interface StateOption {\n code: string;\n name: string;\n}\n\nexport const US_STATES: StateOption[] = [\n { code: 'AL', name: 'Alabama' },\n { code: 'AK', name: 'Alaska' },\n { code: 'AZ', name: 'Arizona' },\n { code: 'AR', name: 'Arkansas' },\n { code: 'CA', name: 'California' },\n { code: 'CO', name: 'Colorado' },\n { code: 'CT', name: 'Connecticut' },\n { code: 'DE', name: 'Delaware' },\n { code: 'DC', name: 'District of Columbia' },\n { code: 'FL', name: 'Florida' },\n { code: 'GA', name: 'Georgia' },\n { code: 'HI', name: 'Hawaii' },\n { code: 'ID', name: 'Idaho' },\n { code: 'IL', name: 'Illinois' },\n { code: 'IN', name: 'Indiana' },\n { code: 'IA', name: 'Iowa' },\n { code: 'KS', name: 'Kansas' },\n { code: 'KY', name: 'Kentucky' },\n { code: 'LA', name: 'Louisiana' },\n { code: 'ME', name: 'Maine' },\n { code: 'MD', name: 'Maryland' },\n { code: 'MA', name: 'Massachusetts' },\n { code: 'MI', name: 'Michigan' },\n { code: 'MN', name: 'Minnesota' },\n { code: 'MS', name: 'Mississippi' },\n { code: 'MO', name: 'Missouri' },\n { code: 'MT', name: 'Montana' },\n { code: 'NE', name: 'Nebraska' },\n { code: 'NV', name: 'Nevada' },\n { code: 'NH', name: 'New Hampshire' },\n { code: 'NJ', name: 'New Jersey' },\n { code: 'NM', name: 'New Mexico' },\n { code: 'NY', name: 'New York' },\n { code: 'NC', name: 'North Carolina' },\n { code: 'ND', name: 'North Dakota' },\n { code: 'OH', name: 'Ohio' },\n { code: 'OK', name: 'Oklahoma' },\n { code: 'OR', name: 'Oregon' },\n { code: 'PA', name: 'Pennsylvania' },\n { code: 'RI', name: 'Rhode Island' },\n { code: 'SC', name: 'South Carolina' },\n { code: 'SD', name: 'South Dakota' },\n { code: 'TN', name: 'Tennessee' },\n { code: 'TX', name: 'Texas' },\n { code: 'UT', name: 'Utah' },\n { code: 'VT', name: 'Vermont' },\n { code: 'VA', name: 'Virginia' },\n { code: 'WA', name: 'Washington' },\n { code: 'WV', name: 'West Virginia' },\n { code: 'WI', name: 'Wisconsin' },\n { code: 'WY', name: 'Wyoming' },\n];\n\nexport const CA_PROVINCES: StateOption[] = [\n { code: 'AB', name: 'Alberta' },\n { code: 'BC', name: 'British Columbia' },\n { code: 'MB', name: 'Manitoba' },\n { code: 'NB', name: 'New Brunswick' },\n { code: 'NL', name: 'Newfoundland and Labrador' },\n { code: 'NS', name: 'Nova Scotia' },\n { code: 'NT', name: 'Northwest Territories' },\n { code: 'NU', name: 'Nunavut' },\n { code: 'ON', name: 'Ontario' },\n { code: 'PE', name: 'Prince Edward Island' },\n { code: 'QC', name: 'Quebec' },\n { code: 'SK', name: 'Saskatchewan' },\n { code: 'YT', name: 'Yukon' },\n];\n\n/**\n * Get state/province options for a country.\n * Returns a list for US and CA, or `null` for countries where a free-text input is appropriate.\n */\nexport function getStateOptions(country: string): StateOption[] | null {\n switch (country.toUpperCase()) {\n case 'US': return US_STATES;\n case 'CA': return CA_PROVINCES;\n default: return null;\n }\n}\n\n/** Returns the appropriate label for the state/province field based on country. */\nexport function getStateLabel(countryCode: string): string {\n switch (countryCode.toUpperCase()) {\n case 'US': return 'State';\n case 'CA': return 'Province';\n case 'GB': return 'County';\n case 'AU': return 'State / Territory';\n default: return 'State / Province / Region';\n }\n}\n","/**\n * Postal-code → state derivation for AVS.\n *\n * Used when the form configuration shows `address_line_1` but hides the\n * `state` input — we still want to populate `billing_details.address.state`\n * so Stripe Radar gets a richer address signal. Currently supports US and CA;\n * other countries return `null` (caller should fall back to omitting state).\n */\n\n/**\n * US 3-digit ZIP-prefix ranges → state code (USPS Sectional Center Facility).\n * Sourced from the public USPS SCF table. Each entry is `[startPrefix, endPrefix, stateCode]`,\n * inclusive on both ends. Coverage is contiguous within a state; gaps in the table\n * (e.g. unused 3-digit prefixes) are intentional and resolve to `null`.\n */\nconst US_ZIP_PREFIX_RANGES: ReadonlyArray<readonly [number, number, string]> = [\n [5, 5, 'NY'],\n [10, 27, 'MA'],\n [28, 29, 'RI'],\n [30, 38, 'NH'],\n [39, 49, 'ME'],\n [50, 59, 'VT'],\n [60, 69, 'CT'],\n [70, 89, 'NJ'],\n [100, 149, 'NY'],\n [150, 196, 'PA'],\n [197, 199, 'DE'],\n [200, 205, 'DC'],\n [206, 219, 'MD'],\n [220, 246, 'VA'],\n [247, 268, 'WV'],\n [270, 289, 'NC'],\n [290, 299, 'SC'],\n [300, 319, 'GA'],\n [320, 349, 'FL'],\n [350, 369, 'AL'],\n [370, 385, 'TN'],\n [386, 397, 'MS'],\n [398, 399, 'GA'],\n [400, 427, 'KY'],\n [430, 459, 'OH'],\n [460, 479, 'IN'],\n [480, 499, 'MI'],\n [500, 528, 'IA'],\n [530, 549, 'WI'],\n [550, 567, 'MN'],\n [570, 577, 'SD'],\n [580, 588, 'ND'],\n [590, 599, 'MT'],\n [600, 629, 'IL'],\n [630, 658, 'MO'],\n [660, 679, 'KS'],\n [680, 693, 'NE'],\n [700, 714, 'LA'],\n [716, 729, 'AR'],\n [730, 749, 'OK'],\n [750, 799, 'TX'],\n [800, 816, 'CO'],\n [820, 831, 'WY'],\n [832, 838, 'ID'],\n [840, 847, 'UT'],\n [850, 865, 'AZ'],\n [870, 884, 'NM'],\n [889, 898, 'NV'],\n [900, 961, 'CA'],\n [967, 968, 'HI'],\n [970, 979, 'OR'],\n [980, 994, 'WA'],\n [995, 999, 'AK'],\n];\n\n/**\n * CA postal-code first letter → province code (Forward Sortation Area).\n * The first letter of every Canadian postal code identifies the province\n * uniquely, except `X` which is shared by Northwest Territories and Nunavut\n * — we resolve it to `NT` because the volume strongly favours NT.\n */\nconst CA_FSA_FIRST_LETTER_TO_PROVINCE: Readonly<Record<string, string>> = {\n A: 'NL',\n B: 'NS',\n C: 'PE',\n E: 'NB',\n G: 'QC',\n H: 'QC',\n J: 'QC',\n K: 'ON',\n L: 'ON',\n M: 'ON',\n N: 'ON',\n P: 'ON',\n R: 'MB',\n S: 'SK',\n T: 'AB',\n V: 'BC',\n X: 'NT',\n Y: 'YT',\n};\n\nfunction deriveUsState(zip: string): string | null {\n const digits = zip.replace(/\\D/g, '');\n if (digits.length < 5) return null;\n const prefix = Number.parseInt(digits.slice(0, 3), 10);\n if (!Number.isFinite(prefix)) return null;\n\n for (const [start, end, code] of US_ZIP_PREFIX_RANGES) {\n if (prefix >= start && prefix <= end) return code;\n }\n return null;\n}\n\nfunction deriveCaProvince(postalCode: string): string | null {\n const compact = postalCode.replace(/\\s+/g, '').toUpperCase();\n if (!/^[A-Z]\\d[A-Z]\\d[A-Z]\\d$/.test(compact)) return null;\n const firstLetter = compact[0] ?? '';\n return CA_FSA_FIRST_LETTER_TO_PROVINCE[firstLetter] ?? null;\n}\n\n/**\n * Resolve a state / province code from a postal code for the given country.\n *\n * - US: 5-digit ZIP → 2-letter USPS state code (uses 3-digit prefix table).\n * - CA: A1A 1A1 → 2-letter ISO 3166-2:CA province code (first-letter mapping).\n * - All other countries: `null`.\n *\n * Returns `null` when the postal code is malformed or falls in an unmapped\n * range. Callers should treat `null` as \"skip — don't derive\".\n */\nexport function getStateFromPostalCode(\n country: string,\n postalCode: string,\n): string | null {\n if (!country || !postalCode) return null;\n const normalizedCountry = country.trim().toUpperCase();\n const normalizedZip = postalCode.trim();\n if (!normalizedZip) return null;\n\n switch (normalizedCountry) {\n case 'US':\n return deriveUsState(normalizedZip);\n case 'CA':\n return deriveCaProvince(normalizedZip);\n default:\n return null;\n }\n}\n","import type { CheckoutItem, CheckoutSubscription } from './types.js';\n\n/**\n * Return the trimmed string when it has at least one non-whitespace character,\n * otherwise undefined. Used so that empty and whitespace-only inputs flow\n * through the same fallback chain as `undefined`.\n */\nfunction nonBlank(value: string | null | undefined): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Resolve the session-level currency, honoring the documented fallback:\n * `session.currency ?? items[*].currency ?? subscriptions[*].currency`.\n *\n * Returns the first non-blank currency found, or 'USD' when nothing is set.\n * Empty and whitespace-only strings are treated as unset so they do not\n * bypass the fallback chain.\n */\nexport function resolveSessionCurrency(\n sessionCurrency: string | undefined,\n items: ReadonlyArray<{ currency?: string }> | undefined,\n subscriptions: ReadonlyArray<{ currency?: string }> | undefined,\n): string {\n const session = nonBlank(sessionCurrency);\n if (session) return session;\n for (const item of items ?? []) {\n const c = nonBlank(item.currency);\n if (c) return c;\n }\n for (const sub of subscriptions ?? []) {\n const c = nonBlank(sub.currency);\n if (c) return c;\n }\n return 'USD';\n}\n\n/**\n * Build the request payload for a single item.\n *\n * Sends the new `code` field alongside the deprecated `providerItemId`,\n * `providerItemName`, `totalAmount`, and `overrideAmount` fields so that\n * both new and old backend versions accept the same request body.\n */\nexport function buildItemPayload(\n item: CheckoutItem,\n sessionCurrency: string,\n): Record<string, unknown> {\n const code = nonBlank(item.code) ?? nonBlank(item.providerItemId);\n if (!code) {\n throw new Error('CheckoutItem requires either `code` or the deprecated `providerItemId`.');\n }\n const itemName = nonBlank(item.itemName) ?? nonBlank(item.providerItemName) ?? null;\n\n const payload: Record<string, unknown> = {\n code,\n providerItemId: nonBlank(item.providerItemId) ?? code,\n itemName,\n providerItemName: nonBlank(item.providerItemName) ?? itemName,\n quantity: item.quantity ?? 1,\n totalAmount: item.totalAmount,\n overrideAmount: item.overrideAmount ?? null,\n currency: nonBlank(item.currency) ?? sessionCurrency,\n };\n\n if (item.metadata) {\n payload['metadata'] = item.metadata;\n }\n\n return payload;\n}\n\n/**\n * Build the request payload for a single subscription.\n *\n * Sends the new `code` field alongside the deprecated `providerPlanId`,\n * `providerPlanName`, `totalAmount`, and `overrideAmount` fields for\n * backward compatibility.\n */\nexport function buildSubscriptionPayload(\n subscription: CheckoutSubscription,\n sessionCurrency: string,\n): Record<string, unknown> {\n const code = nonBlank(subscription.code) ?? nonBlank(subscription.providerPlanId);\n if (!code) {\n throw new Error(\n 'CheckoutSubscription requires either `code` or the deprecated `providerPlanId`.',\n );\n }\n const subscriptionName =\n nonBlank(subscription.subscriptionName) ?? nonBlank(subscription.providerPlanName) ?? null;\n\n const payload: Record<string, unknown> = {\n code,\n providerPlanId: nonBlank(subscription.providerPlanId) ?? code,\n subscriptionName,\n providerPlanName: nonBlank(subscription.providerPlanName) ?? subscriptionName,\n quantity: subscription.quantity ?? 1,\n totalAmount: subscription.totalAmount,\n overrideAmount: subscription.overrideAmount ?? null,\n currency: nonBlank(subscription.currency) ?? sessionCurrency,\n };\n\n if (subscription.metadata) {\n payload['metadata'] = subscription.metadata;\n }\n\n return payload;\n}\n","import { resolveSessionCurrency } from './checkout-payload.js';\nimport type { CheckoutSession } from './types.js';\n\n/** A single line item formatted for display in the checkout UI. */\nexport interface DisplayLineItem {\n name: string;\n quantity: number;\n /** Price per unit in the session's currency (major units, e.g. 24.95). */\n price: number;\n /** Original price per unit before any discount (major units). */\n originalPrice: number;\n}\n\n/** Computed display data for rendering an order summary. */\nexport interface CheckoutDisplayData {\n /** Individual items/subscriptions with names, prices, and quantities. */\n items: DisplayLineItem[];\n /** ISO 4217 currency code (uppercase). */\n currency: string;\n /** Total amount due after discounts (major units, e.g. 24.95). */\n total: number;\n /** Sum of original prices before discounts (major units). */\n originalTotal: number;\n /** Total savings (originalTotal - total), clamped to >= 0. */\n totalSave: number;\n /** Discount percentage (0–100). */\n discountPercent: number;\n}\n\n/** Options for {@link buildCheckoutDisplayData}. */\nexport interface BuildCheckoutDisplayDataOptions {\n /**\n * When `true`, items are hidden from the order summary if the session also\n * contains subscriptions (matches the legacy checkout/CheckoutModal\n * behavior). Defaults to `false` — items are always shown.\n */\n hideBundledItems?: boolean;\n}\n\n/**\n * Builds display data from a `CheckoutSession` for rendering an order summary.\n *\n * - Subscriptions are always shown\n * - Items are shown by default; pass `{ hideBundledItems: true }` to suppress\n * them when the session also contains subscriptions (legacy behavior)\n * - `overrideAmount` (when not null/undefined) is the discounted price\n * - Plan name \"4-WEEK PLAN\" with price <= 1 is renamed to \"7-DAY TRIAL: FULL ACCESS\"\n * - Discount percentage and savings are computed from the difference\n *\n * All amounts are in **major currency units** (dollars, not cents).\n *\n * @example\n * ```ts\n * import { buildCheckoutDisplayData } from '@flopay/shared';\n *\n * const display = buildCheckoutDisplayData(session);\n * // display.items → [{ name: 'Starter', price: 24.95, originalPrice: 24.95, quantity: 1 }]\n * // display.total → 24.95\n * // display.currency → 'EUR'\n * ```\n */\nexport function buildCheckoutDisplayData(\n session: CheckoutSession,\n options: BuildCheckoutDisplayDataOptions = {},\n): CheckoutDisplayData {\n const itemsList: DisplayLineItem[] = [];\n\n const subscriptions = session.subscriptions ?? [];\n const items = session.items ?? [];\n\n // Resolve currency once: session > first item > first subscription > USD.\n const currency = resolveSessionCurrency(session.currency, items, subscriptions).toUpperCase();\n\n // Subscriptions\n for (const sub of subscriptions) {\n const originalPrice = sub.totalAmount ?? 0;\n const discountedPrice = sub.overrideAmount ?? originalPrice;\n\n // Match checkout/CheckoutModal: rename \"4-WEEK PLAN\" to \"7-DAY TRIAL: FULL ACCESS\"\n // when the discounted price is $1 or less\n let name = sub.subscriptionName || sub.providerPlanName || sub.code || 'Subscription';\n if (name === '4-WEEK PLAN' && discountedPrice <= 1) {\n name = '7-DAY TRIAL: FULL ACCESS';\n }\n\n itemsList.push({\n name,\n quantity: sub.quantity,\n price: discountedPrice,\n originalPrice,\n });\n }\n\n // Items are shown by default. Opt-in `hideBundledItems` hides them when\n // the session also contains subscriptions (legacy checkout/CheckoutModal\n // behavior).\n const hideItems =\n options.hideBundledItems === true\n && subscriptions.length > 0\n && items.length > 0;\n\n if (!hideItems) {\n for (const item of items) {\n const originalPrice = item.totalAmount ?? 0;\n const discountedPrice = item.overrideAmount ?? originalPrice;\n\n itemsList.push({\n name: item.itemName || item.providerItemName || item.code || 'Item',\n quantity: item.quantity,\n price: discountedPrice,\n originalPrice,\n });\n }\n }\n\n // Fallback if session has no items/subscriptions\n if (itemsList.length === 0) {\n itemsList.push({\n name: 'Purchase',\n quantity: 1,\n price: session.amount / 100,\n originalPrice: session.amount / 100,\n });\n }\n\n const originalTotal = itemsList.reduce((sum, i) => sum + i.originalPrice * i.quantity, 0);\n const total = itemsList.reduce((sum, i) => sum + i.price * i.quantity, 0);\n const totalSave = Math.max(0, originalTotal - total);\n const discountPercent = originalTotal > 0\n ? Math.round((totalSave / originalTotal) * 100)\n : 0;\n\n return {\n items: itemsList,\n currency,\n total,\n originalTotal,\n totalSave,\n discountPercent,\n };\n}\n","import type { CurrencyInfo } from './types.js';\nimport { CURRENCY_MAP, DEFAULT_CURRENCY } from './constants.js';\n\n/**\n * Look up currency information by ISO 3166-1 alpha-2 country code.\n * Falls back to USD when the country is not in the map.\n */\nexport function getCurrencyByCountry(countryCode: string): CurrencyInfo {\n return CURRENCY_MAP[countryCode.toUpperCase()] ?? DEFAULT_CURRENCY;\n}\n\n/** Returns `true` if the string looks like a Stripe publishable key. */\nexport function isValidPublishableKey(key: string): boolean {\n return /^pk_(test|live)_[A-Za-z0-9]+$/.test(key);\n}\n\n/** Returns `true` if the string looks like a Stripe secret key. */\nexport function isValidSecretKey(key: string): boolean {\n return /^sk_(test|live)_[A-Za-z0-9]+$/.test(key);\n}\n"],"mappings":"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AAI,IAAI;AAAA,EACb,CAAC,IAAI,IAAI,IAAI;AAAA,EACb,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,K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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/errors.ts","../src/config.ts","../src/constants.ts","../src/postal-code-lookup.ts","../src/checkout-payload.ts","../src/display.ts","../src/validation.ts"],"sourcesContent":["// Types\nexport type {\n FloPayThemeVariables,\n FloPayAppearance,\n Customer,\n RecurringInterval,\n PriceData,\n LineItem,\n CheckoutMode,\n CheckoutSession,\n CheckoutSessionItem,\n CheckoutSessionSubscription,\n PaymentResult,\n ConfirmPaymentParams,\n CreatePaymentMethodResult,\n ConfirmCardPaymentParams,\n ConfirmCardPaymentResult,\n ElementType,\n ElementChangeEvent,\n ElementOptions,\n MountedElement,\n FloPayConfig,\n PaymentProviderAdapter,\n BillingProvider,\n GatewayEnvironment,\n NormalizedGatewayEnvironment,\n CheckoutGateway,\n CheckoutGateways,\n TokenizedBody,\n CheckoutProcessError,\n CheckoutProcessingPending,\n CheckoutModeKind,\n NormalizedCheckoutSession,\n CheckoutItem,\n CheckoutSubscription,\n CheckoutAccount,\n TagsData,\n CreateSessionParams,\n CheckoutSessionResult,\n ProcessPaymentParams,\n CreateCustomerParams,\n UpdateCustomerParams,\n WebhookEvent,\n CurrencyInfo,\n CountryOption,\n ButtonsLayoutStyles,\n ButtonsLayoutTheme,\n AVSFieldConfig,\n InlineSessionParams,\n InlineSessionDraft,\n InlineSessionPatch,\n BeforeButtonClickEvent,\n CheckoutButtonMethod,\n DeclineEvent,\n BillingDetails,\n} from './types.js';\nexport { normalizeGatewayEnvironment } from './types.js';\n\n// Errors\nexport {\n FloPayError,\n validationError,\n apiError,\n authenticationError,\n rateLimitError,\n networkError,\n} from './errors.js';\nexport type { FloPayErrorType } from './errors.js';\n\n// Configuration\nexport { configureFlopay, getConfiguredBillingApiUrl, getFloPayEnvironment } from './config.js';\nexport type { FloPayEnvironment } from './config.js';\n\n// Constants\nexport {\n SDK_VERSION,\n DEFAULT_API_BASE_URL,\n DEFAULT_API_VERSION,\n BILLING_API_URL,\n BILLING_API_URL_STAGING,\n BILLING_API_URL_PRODUCTION,\n resolveBillingApiUrl,\n DEFAULT_APPEARANCE,\n FLAT_APPEARANCE,\n NIGHT_APPEARANCE,\n ELEMENT_TYPES,\n SUPPORTED_CARD_BRANDS,\n CURRENCY_MAP,\n DEFAULT_CURRENCY,\n BUTTONS_LAYOUT_DEFAULT,\n BUTTONS_LAYOUT_MINIMAL,\n BUTTONS_LAYOUT_ROUNDED,\n BUTTONS_LAYOUT_DARK,\n resolveButtonsLayoutTheme,\n getPostalCodeLabel,\n COUNTRY_OPTIONS,\n getCountryByCode,\n resolveAVSConfig,\n isAVSFieldVisible,\n isAVSEnabled,\n US_STATES,\n CA_PROVINCES,\n getStateOptions,\n getStateLabel,\n type StateOption,\n} from './constants.js';\n\n// Postal code lookups\nexport { getStateFromPostalCode } from './postal-code-lookup.js';\n\n// Display helpers\nexport { buildCheckoutDisplayData } from './display.js';\nexport type {\n DisplayLineItem,\n CheckoutDisplayData,\n BuildCheckoutDisplayDataOptions,\n} from './display.js';\n\n// Checkout payload helpers\nexport {\n resolveSessionCurrency,\n buildItemPayload,\n buildSubscriptionPayload,\n} from './checkout-payload.js';\n\n// Validation helpers\nexport {\n getCurrencyByCountry,\n isValidPublishableKey,\n isValidSecretKey,\n} from './validation.js';\n","// ---------------------------------------------------------------------------\n// Appearance / Theming\n// ---------------------------------------------------------------------------\n\n/** Theme variables that map to CSS custom properties on FloPay elements. */\nexport interface FloPayThemeVariables {\n colorPrimary?: string;\n colorBackground?: string;\n colorText?: string;\n colorDanger?: string;\n borderRadius?: string;\n fontFamily?: string;\n fontSizeBase?: string;\n spacingUnit?: string;\n}\n\n/** Controls the visual appearance of all FloPay elements. */\nexport interface FloPayAppearance {\n theme?: 'default' | 'flat' | 'night' | 'none';\n variables?: FloPayThemeVariables;\n /** CSS-like rules keyed by selector (e.g. `\".Input\"`, `\".Label\"`). */\n rules?: Record<string, Record<string, string>>;\n}\n\n/** Style overrides for the `buttons` layout mode. */\nexport interface ButtonsLayoutStyles {\n /** Style for the \"Credit / Debit Card\" button. */\n cardButton?: Record<string, string | number>;\n /** Font size for the \"Credit / Debit Card\" button label. */\n cardButtonFontSize?: string;\n /** Style for the card form container when expanded. */\n cardFormContainer?: Record<string, string | number>;\n /** Border color for card input fields. */\n cardInputBorder?: string;\n /** Text color inside Stripe card input fields (number, expiry, CVC). */\n cardInputColor?: string;\n /** Placeholder text color for Stripe card input fields. */\n cardInputPlaceholderColor?: string;\n /** Font size for Stripe card input fields. */\n cardInputFontSize?: string;\n /** Background color for card input fields. */\n cardInputBackground?: string;\n /** Style for the full-name text input. */\n nameInput?: Record<string, string | number>;\n /** Style for the \"Go back\" button text/container. */\n backButton?: Record<string, string | number>;\n /** Font size for the \"Go back\" button label. */\n backButtonFontSize?: string;\n /** Style for the back button circle icon. */\n backButtonIcon?: Record<string, string | number>;\n /** Style for the submit/confirm button. */\n submitButton?: Record<string, string | number>;\n /** Font size for the submit button label. */\n submitButtonFontSize?: string;\n /** Style for the \"Secure card checkout\" title. */\n title?: Record<string, string | number>;\n /** Font size for the \"Secure card checkout\" title. */\n titleFontSize?: string;\n /** Style for the error banner. */\n errorBanner?: Record<string, string | number>;\n /** Style for the country select dropdown container (AVS). */\n countrySelect?: Record<string, string | number>;\n /** Style for the ZIP/postcode input container (AVS). */\n zipInput?: Record<string, string | number>;\n /** Style for the street address input (AVS address_line_1). */\n addressLine1Input?: Record<string, string | number>;\n /** Style for the apt/suite input (AVS address_line_2). */\n addressLine2Input?: Record<string, string | number>;\n /** Style for the city input (AVS). */\n cityInput?: Record<string, string | number>;\n /** Style for the state/province input or dropdown (AVS). */\n stateInput?: Record<string, string | number>;\n}\n\n/** Predefined theme for the `buttons` layout. */\nexport type ButtonsLayoutTheme = 'default' | 'minimal' | 'rounded' | 'dark';\n\n// ---------------------------------------------------------------------------\n// AVS Field Configuration\n// ---------------------------------------------------------------------------\n\n/**\n * Per-field AVS configuration.\n * - `true` = show for all countries\n * - `string[]` = show only for listed country codes (ISO 3166-1 alpha-2)\n * - `false` or omitted = hidden\n */\nexport interface AVSFieldConfig {\n /** Street address (line 1). */\n address_line_1?: boolean | string[];\n /** Apt, suite, unit, etc. (line 2). */\n address_line_2?: boolean | string[];\n /** City / Town. */\n city?: boolean | string[];\n /** State / Province / Region. Renders as dropdown for US and CA. */\n state?: boolean | string[];\n /** ZIP / Postal code. */\n postal_code?: boolean | string[];\n /** Country dropdown. */\n country?: boolean | string[];\n}\n\n// ---------------------------------------------------------------------------\n// Checkout Session (mirrors checkout project's CheckoutSession)\n// ---------------------------------------------------------------------------\n\n/** A customer attached to a checkout session. */\nexport interface Customer {\n id: string;\n email: string;\n firstName?: string;\n lastName?: string;\n gender?: string;\n city?: string;\n state?: string;\n country?: string;\n zip?: string;\n /** Street address (line 1). */\n line1?: string;\n /** Apt, suite, unit (line 2). */\n line2?: string;\n}\n\n/** Recurring interval configuration for subscription line items. */\nexport interface RecurringInterval {\n interval: 'month' | 'year';\n intervalCount?: number;\n}\n\n/** Inline product data when no pre-created price is referenced. */\nexport interface PriceData {\n currency: string;\n unitAmount: number;\n productData: { name: string; description?: string };\n recurring?: RecurringInterval;\n}\n\n/** A single line item within a checkout session. */\nexport interface LineItem {\n /** Reference to a pre-created price object on the provider. */\n price?: string;\n /** Inline price data (used when no `price` reference exists). */\n priceData?: PriceData;\n quantity: number;\n}\n\n/** Checkout mode controlling the payment UI behavior. */\nexport type CheckoutMode = 'full' | 'auto' | 'confirm';\n\n/** A one-time item from a checkout session response. */\nexport interface CheckoutSessionItem {\n uuid: string;\n checkoutSessionId: string;\n /** Preferred catalog code for the item. */\n code?: string;\n /** @deprecated Use {@link CheckoutSessionItem.code}. Backend may stop returning this in a future major. */\n providerItemId?: string;\n /**\n * Display-only name for the item. Preferred over `providerItemName`.\n * The backend no longer persists names; the SDK populates this from the\n * client-side display cache when the server response omits it.\n */\n itemName?: string | null;\n /** @deprecated Use {@link CheckoutSessionItem.itemName}. Mirrored from `itemName` for backward compatibility. */\n providerItemName?: string | null;\n /** Display-only. Resolved from the catalog server-side; not part of the persisted session. */\n providerItemDescription?: string | null;\n quantity: number;\n /** 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. */\n totalAmount?: number;\n /** 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. */\n overrideAmount?: number | null;\n /** @deprecated Prefer the session-level `currency` on {@link CheckoutSession}. Kept for backward compatibility and populated from cache when the server omits it. */\n currency?: string;\n metadata?: Record<string, unknown> | null;\n}\n\n/** A subscription plan from a checkout session response. */\nexport interface CheckoutSessionSubscription {\n uuid: string;\n checkoutSessionId: string;\n /** Preferred catalog code for the subscription plan. */\n code?: string;\n /** @deprecated Use {@link CheckoutSessionSubscription.code}. Backend may stop returning this in a future major. */\n providerPlanId?: string;\n /**\n * Display-only name for the subscription plan. Preferred over\n * `providerPlanName`. The backend no longer persists names; the SDK\n * populates this from the client-side display cache when the server\n * response omits it.\n */\n subscriptionName?: string | null;\n /** @deprecated Use {@link CheckoutSessionSubscription.subscriptionName}. Mirrored from `subscriptionName` for backward compatibility. */\n providerPlanName?: string | null;\n /** Display-only. Resolved from the catalog server-side; not part of the persisted session. */\n providerPlanDescription?: string | null;\n quantity: number;\n /** 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. */\n totalAmount?: number;\n /** 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. */\n overrideAmount?: number | null;\n /** @deprecated Prefer the session-level `currency` on {@link CheckoutSession}. Kept for backward compatibility and populated from cache when the server omits it. */\n currency?: string;\n /** @deprecated Removed from backend. Checkouts only create new subscriptions. */\n isUpdate?: boolean;\n metadata?: Record<string, unknown> | null;\n}\n\n/**\n * Environment for an upstream gateway. Accepts both the gateway-native values\n * (`'sandbox'` | `'live'`) and FloPay's internal aliases (`'stage'` |\n * `'production'`) so the same string can flow from the billing API straight\n * to gateway SDKs without translation at every call site. Use\n * {@link normalizeGatewayEnvironment} to collapse to the canonical pair\n * before handing the value to a gateway SDK.\n */\nexport type GatewayEnvironment = 'sandbox' | 'live' | 'stage' | 'production';\n\n/** Canonical gateway-native form returned by {@link normalizeGatewayEnvironment}. */\nexport type NormalizedGatewayEnvironment = 'sandbox' | 'live';\n\n/**\n * Map FloPay's environment aliases to the gateway-native `'sandbox'`/`'live'`\n * pair. `'stage'` → `'sandbox'`, `'production'` → `'live'`. Returns `undefined`\n * for `undefined` input and logs a console warning for unrecognized strings\n * (so misconfiguration surfaces immediately instead of hanging later — most\n * gateway SDKs silently fall back to live endpoints on an unknown env, which\n * then fails opaquely against sandbox credentials).\n */\nexport function normalizeGatewayEnvironment(\n env: GatewayEnvironment | string | undefined | null,\n): NormalizedGatewayEnvironment | undefined {\n if (env == null) return undefined;\n switch (env) {\n case 'sandbox':\n case 'stage':\n return 'sandbox';\n case 'live':\n case 'production':\n return 'live';\n default:\n // eslint-disable-next-line no-console\n console.warn(\n `[FloPay] Unrecognized gateway environment \"${env}\". Expected one of: sandbox, live, stage, production. Falling back to undefined.`,\n );\n return undefined;\n }\n}\n\n/** Per-gateway configuration returned by the billing API. */\nexport interface CheckoutGateway {\n /** Public client identifier (e.g. Stripe publishable key, PayPal client id). */\n publishableKey?: string | null;\n /** Sandbox or live mode for the gateway credentials. */\n environment?: GatewayEnvironment;\n /**\n * Optional Stripe PaymentIntent client secret exposed by the billing API\n * when additional authentication is required for a saved payment method.\n * Stripe-specific.\n */\n stripeClientSecret?: string | null;\n /**\n * Optional publishable key for a dedicated Stripe sub-account that renders\n * PayPal via Stripe Elements. Stripe-specific. Distinct from\n * `gateways.paypal.publishableKey`, which is a PayPal client id used by the\n * direct PayPal SDK.\n */\n paypalPublishableKey?: string | null;\n}\n\n/**\n * Map of gateways attached to a session, keyed by gateway code. A session can\n * advertise multiple gateways concurrently — e.g. `gateways.stripe` for card\n * + wallets and `gateways.paypal` for direct PayPal rendering.\n */\nexport interface CheckoutGateways {\n stripe?: CheckoutGateway;\n paypal?: CheckoutGateway;\n [key: string]: CheckoutGateway | undefined;\n}\n\n/** Represents a FloPay checkout session. */\nexport interface CheckoutSession {\n // ── Core fields ──\n id: string;\n clientSecret: string;\n mode: 'payment' | 'subscription' | 'setup';\n status: 'open' | 'complete' | 'expired';\n amount: number;\n currency: string;\n lineItems?: LineItem[];\n customer?: Customer;\n metadata?: Record<string, string>;\n\n // ── Session data from billing API ──\n checkoutMode?: CheckoutMode;\n items?: CheckoutSessionItem[];\n subscriptions?: CheckoutSessionSubscription[];\n successUrl?: string;\n cancelUrl?: string;\n coupons?: string[];\n createdAt?: string;\n /**\n * Per-gateway configuration. A session can advertise multiple concurrent\n * gateways — read `gateways.stripe` for card/wallets, `gateways.paypal` for\n * direct PayPal, and so on.\n */\n gateways?: CheckoutGateways;\n accountData?: {\n userId: string;\n email: string;\n firstName: string;\n lastName: string;\n gender?: string | null;\n city?: string | null;\n state?: string | null;\n country?: string | null;\n zip?: string | null;\n };\n tagsData?: TagsData;\n}\n\n// ---------------------------------------------------------------------------\n// Payment Results\n// ---------------------------------------------------------------------------\n\n/** The result of a payment confirmation attempt. */\nexport interface PaymentResult {\n status: 'succeeded' | 'processing' | 'requires_action' | 'failed';\n paymentIntentId?: string;\n paymentMethodId?: string;\n checkoutMethod?: CheckoutButtonMethod;\n error?: import('./errors.js').FloPayError;\n}\n\n/** Parameters for confirming a payment. */\nexport interface ConfirmPaymentParams {\n clientSecret: string;\n /** Optional redirect URL after 3-D Secure or wallet authentication. */\n returnUrl?: string;\n /**\n * Optional billing details appended to `payment_method_data` on the confirm call.\n * Ensures `billing_details.email` (and name/address) lands on the PaymentMethod\n * Stripe mints from Elements during 3DS confirmation — otherwise the new PM\n * inherits none of the info we attached at `createPaymentMethod` time.\n */\n billingDetails?: BillingDetails;\n}\n\n/** Billing details passed to Stripe for AVS (Address Verification). */\nexport interface BillingDetails {\n email?: string;\n name?: string;\n address?: {\n country?: string;\n postal_code?: string;\n city?: string;\n line1?: string;\n line2?: string;\n state?: string;\n };\n}\n\n/** Result from creating a payment method (tokenizing card fields). */\nexport interface CreatePaymentMethodResult {\n paymentMethodId: string | null;\n error?: import('./errors.js').FloPayError;\n}\n\n/** Parameters for confirming a card payment with a known client secret. */\nexport interface ConfirmCardPaymentParams {\n clientSecret: string;\n paymentMethodId: string;\n}\n\n/** Result from confirming a card payment. */\nexport interface ConfirmCardPaymentResult {\n status: 'succeeded' | 'processing' | 'requires_action' | 'requires_capture' | 'failed';\n paymentIntentId?: string;\n paymentMethodId?: string;\n error?: import('./errors.js').FloPayError;\n}\n\n// ---------------------------------------------------------------------------\n// Elements\n// ---------------------------------------------------------------------------\n\n/** The type of payment element to render. */\nexport type ElementType =\n | 'payment'\n | 'card'\n | 'cardNumber'\n | 'cardExpiry'\n | 'cardCvc'\n | 'address';\n\n/** Emitted when an element's internal state changes. */\nexport interface ElementChangeEvent {\n elementType: ElementType;\n complete: boolean;\n empty: boolean;\n error?: { message: string; type: string };\n /** Only populated for non-sensitive fields (e.g. address). */\n value?: Record<string, unknown>;\n}\n\n/** Configuration options when creating an element. */\nexport interface ElementOptions {\n appearance?: FloPayAppearance;\n /** Client secret for the PaymentIntent or SetupIntent. When present, Stripe uses it directly. */\n clientSecret?: string;\n /**\n * Total amount in the smallest currency unit (e.g. cents).\n * Used when no `clientSecret` is available — Stripe Elements needs\n * `mode` + `amount` + `currency` to render without a server-side intent.\n */\n amount?: number;\n /** ISO 4217 currency code (lowercase). Used with `amount` when no `clientSecret`. */\n currency?: string;\n /** How payment methods are created. 'manual' = tokenize only, 'auto' = Stripe handles it. */\n paymentMethodCreation?: 'manual' | 'auto';\n /**\n * Requests reusable payment credentials for future payments when Stripe\n * creates or validates a deferred PaymentIntent for this Elements group.\n */\n setupFutureUsage?: 'off_session' | 'on_session';\n layout?: 'tabs' | 'accordion' | 'auto';\n defaultValues?: Record<string, unknown>;\n readOnly?: boolean;\n /** Address element mode: 'billing' or 'shipping'. */\n mode?: 'billing' | 'shipping';\n /**\n * Style object for individual card elements (cardNumber, cardExpiry, cardCvc).\n * Passed directly to the underlying provider element.\n *\n * @example\n * ```ts\n * style: {\n * base: { color: '#f9fafb', fontSize: '16px', '::placeholder': { color: '#6b7280' } },\n * invalid: { color: '#ef4444' },\n * }\n * ```\n */\n style?: Record<string, Record<string, unknown>>;\n}\n\n// ---------------------------------------------------------------------------\n// Mounted Element (runtime instance)\n// ---------------------------------------------------------------------------\n\n/**\n * A payment element that has been created and can be mounted into the DOM.\n *\n * TODO: In a future phase, each MountedElement will render inside an iframe\n * for PCI DSS SAQ-A compliance. For now, it wraps the underlying provider\n * element directly.\n */\nexport interface MountedElement {\n mount(container: HTMLElement): void;\n unmount(): void;\n update(options: Partial<ElementOptions>): void;\n on(event: string, handler: (...args: unknown[]) => void): void;\n off(event: string, handler: (...args: unknown[]) => void): void;\n destroy(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Provider Configuration\n// ---------------------------------------------------------------------------\n\n/** Top-level configuration for initializing FloPay. */\nexport interface FloPayConfig {\n publishableKey: string;\n /** Billing API base URL (e.g. https://api.stage.flopay.com). */\n billingApiUrl?: string;\n locale?: string;\n appearance?: FloPayAppearance;\n apiVersion?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Provider Adapter Interface\n// ---------------------------------------------------------------------------\n\n/**\n * Abstraction layer for payment providers.\n *\n * Currently only Stripe is implemented (`StripeAdapter`). The interface\n * ensures that adding new providers (Chargebee, Recurly, etc.) will not\n * require changes in consumer code.\n */\nexport interface PaymentProviderAdapter {\n readonly name: string;\n initialize(config: FloPayConfig): Promise<void>;\n createElement(\n type: ElementType,\n options: ElementOptions,\n ): Promise<MountedElement>;\n /** Retrieve an existing element by type, or `null` if not yet created. */\n getElement(type: ElementType): MountedElement | null;\n /** Submit elements for validation (Stripe `elements.submit()`). */\n submitElements(): Promise<{ error?: import('./errors.js').FloPayError }>;\n /** Create a payment method from the current elements (tokenize card). */\n createPaymentMethod(billingDetails?: BillingDetails): Promise<CreatePaymentMethodResult>;\n /** Confirm a card payment with a known client secret and payment method. */\n confirmCardPayment(params: ConfirmCardPaymentParams): Promise<ConfirmCardPaymentResult>;\n confirmPayment(params: ConfirmPaymentParams): Promise<PaymentResult>;\n /**\n * Create a PayPal payment: create PM → create intent → confirm with redirect.\n * Returns the confirmed PaymentIntent ID if completed inline, or redirects to PayPal.\n */\n confirmPayPalPayment(params: {\n billingApiUrl: string;\n sessionId: string;\n email: string;\n returnUrl: string;\n }): Promise<ConfirmCardPaymentResult>;\n /**\n * Resume a PayPal payment after redirect return.\n * Checks URL params for payment_intent + redirect_status.\n */\n resumePayPalPayment(): Promise<ConfirmCardPaymentResult | null>;\n /**\n * Get the raw underlying provider instance (e.g. Stripe object).\n * Used internally for creating secondary Elements groups (e.g. PayPal).\n */\n getRawProvider(): unknown;\n /**\n * Create a secondary Elements group for PayPal.\n * PayPal can't share Elements with card fields that use paymentMethodCreation: 'manual'.\n */\n createPayPalElements(options: ElementOptions): unknown;\n destroy(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Billing Provider (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Supported upstream gateway codes. */\nexport type BillingProvider = 'stripe' | 'paypal';\n\n// ---------------------------------------------------------------------------\n// Tokenized Body (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Token payload produced by client-side tokenization. */\nexport interface TokenizedBody {\n id?: string;\n type?: string;\n threeDSecureActionResultTokenId?: string;\n originalPaymentMethodId?: string;\n isPaypal?: boolean;\n}\n\n/** Structured checkout-processing error returned by the billing API. */\nexport interface CheckoutProcessError {\n type: string;\n message?: string;\n transactionId?: string;\n threeDSecureToken?: string;\n paymentMethodId?: string;\n checkoutMethod?: CheckoutButtonMethod;\n advice?: string;\n gatewayErrorCode?: string;\n fields?: Array<{ field: string; message: string }>;\n}\n\n/** Recoverable checkout-processing state returned when fulfillment is still in progress. */\nexport interface CheckoutProcessingPending {\n type: 'checkout_processing';\n sessionId: string;\n retryAfterMs: number;\n statusUrl?: string;\n sessionUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Normalized Checkout Session (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Checkout mode: tokenize client-side or redirect to hosted page. */\nexport type CheckoutModeKind = 'tokenize' | 'redirect';\n\n/**\n * Provider-agnostic normalized checkout session. Backend may attach multiple\n * gateways per session — read each from `data.<gatewayCode>`.\n */\nexport interface NormalizedCheckoutSession {\n /** Gateway codes advertised by the backend for this session, for diagnostics. */\n providers: BillingProvider[];\n mode: CheckoutModeKind;\n autoProcessingError?: CheckoutProcessError;\n autoProcessingAttempted?: boolean;\n autoProcessingPending?: CheckoutProcessingPending;\n data: {\n hostedUrl?: string;\n clientToken?: string;\n session?: CheckoutSession;\n stripe?: {\n clientSecret?: string;\n publishableKey?: string;\n /**\n * Optional dedicated Stripe sub-account publishable key for rendering\n * PayPal via Stripe Elements. When present and distinct, the saved-PM\n * resume flow loads a separate FloPay instance for the PayPal PI.\n */\n paypalPublishableKey?: string;\n environment?: GatewayEnvironment;\n };\n /**\n * Direct PayPal gateway configuration. Present only when the backend has\n * configured a dedicated PayPal gateway for the consumer; absent means the\n * Stripe-rendered PayPal fallback should be used (if Stripe is configured).\n */\n paypal?: {\n publishableKey?: string;\n environment?: GatewayEnvironment;\n };\n };\n raw?: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Server-side SDK types (mirrors clicktech-core-ui/createCheckoutSession)\n// ---------------------------------------------------------------------------\n\n/** A one-time purchase item for checkout session creation. */\nexport interface CheckoutItem {\n /**\n * Catalog code for the item — the preferred identifier. When omitted, the\n * deprecated `providerItemId` is used as a fallback.\n */\n code?: string;\n /**\n * @deprecated Use {@link CheckoutItem.code}. Still accepted as a fallback\n * when `code` is not provided.\n */\n providerItemId?: string;\n /**\n * Display-only name for the item. Takes priority over the deprecated\n * `providerItemName`. Backend resolves names from the catalog; pass this\n * to seed the client-side display cache for the post-redirect fetch.\n */\n itemName?: string | null;\n /** @deprecated Use {@link CheckoutItem.itemName}. Still accepted as a fallback when `itemName` is not provided. */\n providerItemName?: string | null;\n /** Defaults to 1. */\n quantity?: number;\n /** Display-only. Backend resolves prices from the catalog; pass this to seed the client-side display cache so the UI can render the regular price after redirect. */\n totalAmount?: number;\n /** Display-only. Backend ignores this entirely; pass this to seed the client-side display cache so the UI can render the discounted price after redirect. */\n overrideAmount?: number | null;\n /** @deprecated Prefer the session-level `currency` on {@link CreateSessionParams}/{@link InlineSessionParams}. */\n currency?: string;\n /** Arbitrary key/value metadata forwarded to the backend. */\n metadata?: Record<string, unknown> | null;\n}\n\n/** A recurring subscription plan for checkout session creation. */\nexport interface CheckoutSubscription {\n /**\n * Catalog code for the plan — the preferred identifier. When omitted, the\n * deprecated `providerPlanId` is used as a fallback.\n */\n code?: string;\n /**\n * @deprecated Use {@link CheckoutSubscription.code}. Still accepted as a\n * fallback when `code` is not provided.\n */\n providerPlanId?: string;\n /**\n * Display-only name for the subscription plan. Takes priority over the\n * deprecated `providerPlanName`. Backend resolves names from the catalog;\n * pass this to seed the client-side display cache for the post-redirect fetch.\n */\n subscriptionName?: string | null;\n /** @deprecated Use {@link CheckoutSubscription.subscriptionName}. Still accepted as a fallback when `subscriptionName` is not provided. */\n providerPlanName?: string | null;\n /** Defaults to 1. */\n quantity?: number;\n /** Display-only. Backend resolves prices from the catalog; pass this to seed the client-side display cache so the UI can render the regular price after redirect. */\n totalAmount?: number;\n /** Display-only. Backend ignores this entirely; pass this to seed the client-side display cache so the UI can render the discounted price after redirect. */\n overrideAmount?: number | null;\n /** @deprecated Prefer the session-level `currency` on {@link CreateSessionParams}/{@link InlineSessionParams}. */\n currency?: string;\n /** Arbitrary key/value metadata forwarded to the backend. */\n metadata?: Record<string, unknown> | null;\n}\n\n/** Buyer's account information for session creation. */\nexport interface CheckoutAccount {\n userId: string;\n firstName?: string;\n lastName?: string;\n email: string;\n country?: string | null;\n gender?: string | null;\n city?: string | null;\n state?: string | null;\n zip?: string | null;\n /** Street address (line 1). */\n addressLine1?: string | null;\n /** Apt, suite, unit (line 2). */\n addressLine2?: string | null;\n}\n\n/** Analytics / pixel tags forwarded to the checkout page. */\nexport interface TagsData {\n googleContainerId?: string | null;\n sessionId?: string | null;\n testEventCode?: string | null;\n}\n\n/**\n * Parameters for creating a checkout session via the billing API.\n * Mirrors the `CreateCheckoutSessionOptions` from clicktech-core-ui.\n */\nexport interface CreateSessionParams {\n /** Base URL of the billing API, e.g. https://billing.clicktech.com */\n billingApiUrl: string;\n /** Base URL of the checkout frontend, e.g. https://checkout.clicktech.com */\n checkoutBaseUrl: string;\n /** The client ID for the checkout session. */\n clientId: string;\n /**\n * Session-level ISO 4217 currency code. Takes precedence over any\n * per-item/per-subscription `currency` field. When omitted, the SDK\n * falls back to `items[0].currency ?? subscriptions[0].currency`.\n */\n currency?: string;\n /** One-time purchase items. */\n items?: CheckoutItem[];\n /** Recurring subscription plans. */\n subscriptions?: CheckoutSubscription[];\n /** Buyer's account information. */\n account: CheckoutAccount;\n /** URL to redirect to after successful payment. */\n successUrl: string;\n /** URL to redirect to if the user cancels. */\n cancelUrl: string;\n /**\n * Checkout mode sent to the billing API.\n * - 'confirm' – show a payment confirmation page (default)\n * - 'auto' – skip confirmation when a payment method is already on file\n * - 'full' – full checkout flow\n */\n checkoutMode?: 'confirm' | 'auto' | 'full';\n /** Coupon codes to apply. */\n couponCodes?: string[];\n /** Pixel / analytics tags forwarded to the checkout page. */\n tagsData?: TagsData;\n /** Extra query params appended to the checkout redirect URL. */\n redirectParams?: Record<string, string>;\n /** Whether to set the checkout_data cookie. Defaults to true. */\n setCookie?: boolean;\n /** Request timeout in milliseconds. Defaults to 12000. */\n timeoutMs?: number;\n /** UTM and funnel tracking metadata. */\n utmMetadata?: Record<string, string | null | undefined>[];\n}\n\n/**\n * Parameters for inline session creation via `FloPayCheckout.createSession`.\n * Subset of `CreateSessionParams` — no redirect fields needed since the\n * component handles the checkout flow inline.\n */\nexport interface InlineSessionParams {\n /** The client ID for the checkout session. */\n clientId: string;\n /**\n * Session-level ISO 4217 currency code. Takes precedence over any\n * per-item/per-subscription `currency` field. When omitted, the SDK\n * falls back to `items[0].currency ?? subscriptions[0].currency`.\n */\n currency?: string;\n /** One-time purchase items. */\n items?: CheckoutItem[];\n /** Recurring subscription plans. */\n subscriptions?: CheckoutSubscription[];\n /** Buyer's account information. */\n account: CheckoutAccount;\n /** URL to redirect to after successful payment. */\n successUrl: string;\n /** URL to redirect to if the user cancels. */\n cancelUrl: string;\n /** Checkout mode: 'full' (default), 'auto', or 'confirm'. */\n checkoutMode?: 'full' | 'auto' | 'confirm';\n /** Optional saved/tokenized payment method for inline auto or confirm checkout. */\n tokenizedData?: TokenizedBody;\n /** Coupon codes to apply. */\n couponCodes?: string[];\n /** Pixel / analytics tags. */\n tagsData?: TagsData;\n /** UTM and funnel tracking metadata. */\n utmMetadata?: Record<string, string | null | undefined>[];\n // ── Checkout analytics metadata (set by SDK automatically) ──\n /** Whether AVS is enabled for this checkout. */\n avsCheck?: boolean;\n /** Checkout type: 'standard_checkout' or 'embedded_checkout'. */\n checkoutType?: string;\n /** Checkout layout: 'default_layout', 'buttons_layout', or 'custom_layout'. */\n checkoutLayout?: string;\n /** AVS field configuration for analytics. */\n avsConfig?: AVSFieldConfig;\n}\n\n/** Payment methods exposed by the React buttons layout callbacks. */\nexport type CheckoutButtonMethod = 'card' | 'paypal' | 'apple_pay' | 'google_pay';\n\n/**\n * Draft inline-session params used by `FloPayCheckout` before a real\n * checkout session has been created. Buttons-layout checkout can seed\n * placeholder account data up front; `onBeforeButtonClick` can still\n * update it before the selected payment button continues.\n */\nexport interface InlineSessionDraft extends Omit<InlineSessionParams, 'account'> {\n account: Omit<CheckoutAccount, 'email'> & { email?: string };\n}\n\n/**\n * Partial inline-session fields that can be returned from\n * `onBeforeButtonClick` and merged into the draft session params.\n */\nexport interface InlineSessionPatch {\n account?: Partial<CheckoutAccount>;\n couponCodes?: string[];\n tagsData?: TagsData;\n utmMetadata?: Record<string, string | null | undefined>[];\n}\n\n/** Context passed to the `onBeforeButtonClick` callback for buttons-layout payment methods. */\nexport interface BeforeButtonClickEvent {\n method: CheckoutButtonMethod;\n sessionId?: string;\n createSession?: InlineSessionDraft;\n}\n\n/** Structured decline event emitted by the React checkout components. */\nexport interface DeclineEvent {\n method: CheckoutButtonMethod;\n message: string;\n code?: string;\n declineCode?: string;\n}\n\n/** Result from creating a checkout session. */\nexport type CheckoutSessionResult =\n | { status: 201; redirectUrl: string }\n | { status: 204 }\n | { status: number };\n\n/**\n * Data submitted when processing a payment (tokenized card/wallet data).\n * Mirrors checkout project's ProcessCheckoutBodyDto.\n */\nexport interface ProcessPaymentParams {\n sessionId: string;\n tokenizedData?: TokenizedBody;\n accountData: {\n userId: string;\n email: string;\n firstName: string;\n lastName: string;\n zip?: string;\n country?: string;\n city?: string;\n state?: string;\n addressLine1?: string;\n addressLine2?: string;\n };\n chv?: string;\n /** Current page URL for redirect-capable auth flows such as 3DS and PayPal. */\n returnUrl?: string;\n // ── Checkout analytics metadata ──\n /** Whether AVS (Address Verification) was enabled for this checkout. */\n avsCheck?: boolean;\n /** Checkout type: 'standard_checkout' or 'embedded_checkout'. */\n checkoutType?: string;\n /** Checkout layout: 'default_layout', 'buttons_layout', or 'custom_layout'. */\n checkoutLayout?: string;\n /** AVS field configuration for analytics — which fields were shown. */\n avsConfig?: AVSFieldConfig;\n}\n\n/** Parameters for creating a customer. */\nexport interface CreateCustomerParams {\n email: string;\n name?: string;\n metadata?: Record<string, string>;\n}\n\n/** Parameters for updating a customer. */\nexport interface UpdateCustomerParams {\n email?: string;\n name?: string;\n metadata?: Record<string, string>;\n}\n\n/** A webhook event from FloPay. */\nexport interface WebhookEvent {\n id: string;\n type: string;\n data: Record<string, unknown>;\n created: number;\n}\n\n// ---------------------------------------------------------------------------\n// Currency (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Currency information mapped to a country. */\nexport interface CurrencyInfo {\n currency: string;\n symbol: string;\n country: string;\n countryCode: string;\n /** 0 = no tax, 1 = tax (VAT) applies. */\n tax: number;\n}\n\n/** A country option for UI select elements. */\nexport interface CountryOption {\n code: string;\n name: string;\n flag: string;\n}\n","/** Discriminated error types returned by the FloPay SDK. */\nexport type FloPayErrorType =\n | 'validation_error'\n | 'api_error'\n | 'authentication_error'\n | 'rate_limit_error'\n | 'network_error';\n\n/**\n * Custom error class for all FloPay SDK errors.\n *\n * Extends the native `Error` and adds structured fields that mirror\n * Stripe-style error responses for familiarity.\n */\nexport class FloPayError extends Error {\n readonly type: FloPayErrorType;\n readonly code?: string;\n readonly declineCode?: string;\n readonly param?: string;\n readonly statusCode?: number;\n\n constructor(\n message: string,\n type: FloPayErrorType,\n options?: { code?: string; declineCode?: string; param?: string; statusCode?: number },\n ) {\n super(message);\n this.name = 'FloPayError';\n this.type = type;\n this.code = options?.code;\n this.declineCode = options?.declineCode;\n this.param = options?.param;\n this.statusCode = options?.statusCode;\n\n // Restore prototype chain (required when extending built-ins)\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error Factories\n// ---------------------------------------------------------------------------\n\n/** Create a validation error (e.g. missing required field). */\nexport function validationError(\n message: string,\n param?: string,\n): FloPayError {\n return new FloPayError(message, 'validation_error', { param });\n}\n\n/** Create an API error (e.g. upstream provider returned an error). */\nexport function apiError(\n message: string,\n code?: string,\n statusCode?: number,\n): FloPayError {\n return new FloPayError(message, 'api_error', { code, statusCode });\n}\n\n/** Create an authentication error (e.g. invalid publishable key). */\nexport function authenticationError(message: string): FloPayError {\n return new FloPayError(message, 'authentication_error');\n}\n\n/** Create a rate limit error. */\nexport function rateLimitError(message: string): FloPayError {\n return new FloPayError(message, 'rate_limit_error');\n}\n\n/** Create a network error (e.g. fetch failed). */\nexport function networkError(message: string): FloPayError {\n return new FloPayError(message, 'network_error');\n}\n","/** FloPay environment — determines which billing API URL is used. */\nexport type FloPayEnvironment = 'staging' | 'production' | 'local';\n\nconst ENV_URL_MAP: Record<FloPayEnvironment, string> = {\n local: 'https://flo.ngrok.pro',\n staging: 'https://api.stage.flopay.com',\n production: 'https://api.flopay.com',\n};\n\nlet globalEnvironment: FloPayEnvironment = 'staging';\n\n/**\n * Configure the FloPay SDK globally. Call once at app startup.\n *\n * The environment determines which billing API URL is used for all\n * FloPay operations (session creation, payment processing, etc.).\n *\n * @example\n * ```ts\n * import { configureFlopay } from '@flopay/shared';\n *\n * // In production\n * configureFlopay({ environment: 'production' });\n *\n * // In staging/development\n * configureFlopay({ environment: 'staging' });\n * ```\n *\n * Alternatively, set the `NEXT_PUBLIC_FLOPAY_ENV` environment variable\n * to `'staging'` or `'production'` — the SDK reads it automatically.\n */\nexport function configureFlopay(config: { environment: FloPayEnvironment }): void {\n globalEnvironment = config.environment;\n}\n\n/** Get the billing API URL for the currently configured environment. */\nexport function getConfiguredBillingApiUrl(): string {\n return ENV_URL_MAP[globalEnvironment];\n}\n\n/** Get the current configured environment. */\nexport function getFloPayEnvironment(): FloPayEnvironment {\n return globalEnvironment;\n}\n","import type { AVSFieldConfig, ButtonsLayoutStyles, ButtonsLayoutTheme, CountryOption, CurrencyInfo, FloPayAppearance } from './types.js';\n\nimport type { FloPayEnvironment } from './config.js';\nimport { getConfiguredBillingApiUrl } from './config.js';\n\n// ---------------------------------------------------------------------------\n// SDK Version & API\n// ---------------------------------------------------------------------------\n\n/** Current SDK version. */\nexport const SDK_VERSION = '1.1.0';\n\n/** Billing API URL for staging environment. */\nexport const BILLING_API_URL_STAGING = 'https://api.stage.flopay.com';\n\n/** Billing API URL for production environment. */\nexport const BILLING_API_URL_PRODUCTION = 'https://api.flopay.com';\n\n/** Default FloPay API base URL (used by @flopay/node). Alias for staging. */\nexport const DEFAULT_API_BASE_URL = BILLING_API_URL_STAGING;\n\n/** Default billing API base URL. Alias for staging — prefer `resolveBillingApiUrl()`. */\nexport const BILLING_API_URL = BILLING_API_URL_STAGING;\n\n/**\n * Resolve the billing API URL from available configuration.\n *\n * Priority:\n * 1. Explicit `billingApiUrl` (prop/param override)\n * 2. `NEXT_PUBLIC_FLOPAY_ENV` environment variable (`'staging'` | `'production'`)\n * 3. `configureFlopay()` global environment setting\n * 4. Fallback: staging URL\n *\n * @example\n * ```ts\n * import { resolveBillingApiUrl } from '@flopay/shared';\n *\n * // Reads from env var or configureFlopay() — no args needed\n * const url = resolveBillingApiUrl();\n *\n * // Explicit override takes priority\n * const url = resolveBillingApiUrl('https://custom.example.com');\n * ```\n */\nexport function resolveBillingApiUrl(billingApiUrl?: string): string {\n if (billingApiUrl) return billingApiUrl;\n\n // Environment variable (works in Next.js and bundlers that inline process.env)\n if (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_FLOPAY_ENV) {\n const env = process.env.NEXT_PUBLIC_FLOPAY_ENV as FloPayEnvironment;\n if (env === 'production') return BILLING_API_URL_PRODUCTION;\n return BILLING_API_URL_STAGING;\n }\n\n // Global config from configureFlopay()\n return getConfiguredBillingApiUrl();\n}\n\n/** Default API version header value. */\nexport const DEFAULT_API_VERSION = '2024-01-01';\n\n// ---------------------------------------------------------------------------\n// Default Themes\n// ---------------------------------------------------------------------------\n\n/** The default appearance applied when no custom appearance is provided. */\nexport const DEFAULT_APPEARANCE: FloPayAppearance = {\n theme: 'default',\n variables: {\n colorPrimary: '#4A49FF',\n colorBackground: '#FFFFFF',\n colorText: '#262833',\n colorDanger: '#DF1B41',\n borderRadius: '8px',\n fontFamily: 'Poppins, system-ui, sans-serif',\n fontSizeBase: '16px',\n spacingUnit: '4px',\n },\n};\n\n/** Flat theme — minimal borders and shadows. */\nexport const FLAT_APPEARANCE: FloPayAppearance = {\n theme: 'flat',\n variables: {\n ...DEFAULT_APPEARANCE.variables,\n borderRadius: '4px',\n },\n};\n\n/** Night theme — dark background. */\nexport const NIGHT_APPEARANCE: FloPayAppearance = {\n theme: 'night',\n variables: {\n colorPrimary: '#7B7BFF',\n colorBackground: '#1A1A2E',\n colorText: '#E0E0E0',\n colorDanger: '#FF6B6B',\n borderRadius: '8px',\n fontFamily: 'Poppins, system-ui, sans-serif',\n fontSizeBase: '16px',\n spacingUnit: '4px',\n },\n};\n\n// ---------------------------------------------------------------------------\n// Buttons Layout Theme Presets\n// ---------------------------------------------------------------------------\n\n/** Default buttons layout — white card button, neutral borders. */\nexport const BUTTONS_LAYOUT_DEFAULT: ButtonsLayoutStyles = {};\n\n/** Minimal buttons layout — borderless, subtle hover. */\nexport const BUTTONS_LAYOUT_MINIMAL: ButtonsLayoutStyles = {\n cardButton: {\n border: 'none',\n backgroundColor: '#f9fafb',\n boxShadow: 'none',\n },\n cardFormContainer: {\n backgroundColor: '#f9fafb',\n border: 'none',\n },\n cardInputBorder: '#e5e7eb',\n backButtonIcon: {\n backgroundColor: '#e5e7eb',\n },\n submitButton: {\n borderRadius: '6px',\n },\n};\n\n/** Rounded buttons layout — large border radius, soft shadows. */\nexport const BUTTONS_LAYOUT_ROUNDED: ButtonsLayoutStyles = {\n cardButton: {\n borderRadius: '9999px',\n border: '1px solid #e5e7eb',\n boxShadow: '0 1px 3px rgba(0,0,0,0.06)',\n },\n cardFormContainer: {\n borderRadius: '16px',\n border: '1px solid #e5e7eb',\n boxShadow: '0 2px 8px rgba(0,0,0,0.06)',\n },\n cardInputBorder: '#d1d5db',\n submitButton: {\n borderRadius: '9999px',\n },\n backButtonIcon: {\n backgroundColor: '#f3f4f6',\n },\n};\n\n/** Dark buttons layout — dark backgrounds, light text. */\nexport const BUTTONS_LAYOUT_DARK: ButtonsLayoutStyles = {\n cardButton: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n border: '1px solid #374151',\n boxShadow: 'none',\n },\n cardFormContainer: {\n backgroundColor: '#111827',\n border: '1px solid #374151',\n },\n cardInputBorder: '#4b5563',\n cardInputColor: '#f9fafb',\n cardInputPlaceholderColor: '#6b7280',\n cardInputBackground: '#1f2937',\n nameInput: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n backButton: {\n color: '#9ca3af',\n },\n backButtonIcon: {\n backgroundColor: '#374151',\n },\n submitButton: {\n backgroundColor: '#6366f1',\n },\n title: {\n color: '#f9fafb',\n },\n countrySelect: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n zipInput: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n};\n\n/** Resolve a buttons layout theme name to its style preset. */\nexport function resolveButtonsLayoutTheme(theme?: ButtonsLayoutTheme): ButtonsLayoutStyles {\n switch (theme) {\n case 'minimal': return BUTTONS_LAYOUT_MINIMAL;\n case 'rounded': return BUTTONS_LAYOUT_ROUNDED;\n case 'dark': return BUTTONS_LAYOUT_DARK;\n default: return BUTTONS_LAYOUT_DEFAULT;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Supported Element Types\n// ---------------------------------------------------------------------------\n\n/** All supported element type identifiers. */\nexport const ELEMENT_TYPES = [\n 'payment',\n 'card',\n 'cardNumber',\n 'cardExpiry',\n 'cardCvc',\n 'address',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Supported Card Brands\n// ---------------------------------------------------------------------------\n\nexport const SUPPORTED_CARD_BRANDS = [\n 'visa',\n 'mastercard',\n 'mastercard_debit',\n 'amex',\n 'discover',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Currency Mapping (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Country code to currency information mapping. */\nexport const CURRENCY_MAP: Record<string, CurrencyInfo> = {\n // EUR (VAT applies)\n AT: { currency: 'EUR', symbol: '\\u20AC', country: 'Austria', countryCode: 'AT', tax: 1 },\n BE: { currency: 'EUR', symbol: '\\u20AC', country: 'Belgium', countryCode: 'BE', tax: 1 },\n CY: { currency: 'EUR', symbol: '\\u20AC', country: 'Cyprus', countryCode: 'CY', tax: 1 },\n DE: { currency: 'EUR', symbol: '\\u20AC', country: 'Germany', countryCode: 'DE', tax: 1 },\n EE: { currency: 'EUR', symbol: '\\u20AC', country: 'Estonia', countryCode: 'EE', tax: 1 },\n ES: { currency: 'EUR', symbol: '\\u20AC', country: 'Spain', countryCode: 'ES', tax: 1 },\n FI: { currency: 'EUR', symbol: '\\u20AC', country: 'Finland', countryCode: 'FI', tax: 1 },\n FR: { currency: 'EUR', symbol: '\\u20AC', country: 'France', countryCode: 'FR', tax: 1 },\n GR: { currency: 'EUR', symbol: '\\u20AC', country: 'Greece', countryCode: 'GR', tax: 1 },\n HR: { currency: 'EUR', symbol: '\\u20AC', country: 'Croatia', countryCode: 'HR', tax: 1 },\n IE: { currency: 'EUR', symbol: '\\u20AC', country: 'Ireland', countryCode: 'IE', tax: 1 },\n IT: { currency: 'EUR', symbol: '\\u20AC', country: 'Italy', countryCode: 'IT', tax: 1 },\n LT: { currency: 'EUR', symbol: '\\u20AC', country: 'Lithuania', countryCode: 'LT', tax: 1 },\n LU: { currency: 'EUR', symbol: '\\u20AC', country: 'Luxembourg', countryCode: 'LU', tax: 1 },\n LV: { currency: 'EUR', symbol: '\\u20AC', country: 'Latvia', countryCode: 'LV', tax: 1 },\n MT: { currency: 'EUR', symbol: '\\u20AC', country: 'Malta', countryCode: 'MT', tax: 1 },\n NL: { currency: 'EUR', symbol: '\\u20AC', country: 'Netherlands', countryCode: 'NL', tax: 1 },\n PT: { currency: 'EUR', symbol: '\\u20AC', country: 'Portugal', countryCode: 'PT', tax: 1 },\n SI: { currency: 'EUR', symbol: '\\u20AC', country: 'Slovenia', countryCode: 'SI', tax: 1 },\n SK: { currency: 'EUR', symbol: '\\u20AC', country: 'Slovakia', countryCode: 'SK', tax: 1 },\n BG: { currency: 'EUR', symbol: '\\u20AC', country: 'Bulgaria', countryCode: 'BG', tax: 1 },\n RO: { currency: 'EUR', symbol: '\\u20AC', country: 'Romania', countryCode: 'RO', tax: 1 },\n CZ: { currency: 'EUR', symbol: '\\u20AC', country: 'Czech Republic', countryCode: 'CZ', tax: 1 },\n SE: { currency: 'EUR', symbol: '\\u20AC', country: 'Sweden', countryCode: 'SE', tax: 1 },\n DK: { currency: 'EUR', symbol: '\\u20AC', country: 'Denmark', countryCode: 'DK', tax: 1 },\n PL: { currency: 'EUR', symbol: '\\u20AC', country: 'Poland', countryCode: 'PL', tax: 1 },\n HU: { currency: 'EUR', symbol: '\\u20AC', country: 'Hungary', countryCode: 'HU', tax: 1 },\n // GBP (VAT applies)\n GB: { currency: 'GBP', symbol: '\\u00A3', country: 'United Kingdom', countryCode: 'GB', tax: 1 },\n // USD (no VAT)\n US: { currency: 'USD', symbol: '$', country: 'United States', countryCode: 'US', tax: 0 },\n // CAD (no VAT)\n CA: { currency: 'CAD', symbol: 'CA$', country: 'Canada', countryCode: 'CA', tax: 0 },\n // NZD (no VAT)\n NZ: { currency: 'NZD', symbol: 'NZ$', country: 'New Zealand', countryCode: 'NZ', tax: 0 },\n // AUD (no VAT)\n AU: { currency: 'AUD', symbol: 'AU$', country: 'Australia', countryCode: 'AU', tax: 0 },\n};\n\n/** Default currency info when country is unknown. */\nexport const DEFAULT_CURRENCY: CurrencyInfo = {\n currency: 'USD',\n symbol: '$',\n country: 'United States',\n countryCode: 'US',\n tax: 0,\n};\n\n// ---------------------------------------------------------------------------\n// Postal Code Labels\n// ---------------------------------------------------------------------------\n\n/** Returns the correct postal code label for a country code (ISO 3166-1 alpha-2). */\nexport function getPostalCodeLabel(countryCode: string): string {\n switch (countryCode.toUpperCase()) {\n case 'US': return 'ZIP Code';\n case 'GB': return 'Postcode';\n case 'CA': return 'Postal Code';\n case 'AU':\n case 'NZ': return 'Postcode';\n case 'IE': return 'Eircode';\n default: return 'Postal Code';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Country List (ISO 3166-1 alpha-2)\n// ---------------------------------------------------------------------------\n\nconst regionNames = new Intl.DisplayNames(['en'], { type: 'region' });\n\nfunction codeToFlag(code: string): string {\n return [...code.toUpperCase()]\n .map((c) => String.fromCodePoint(0x1f1e6 - 65 + c.charCodeAt(0)))\n .join('');\n}\n\n/** Priority countries shown first in dropdowns. */\nconst PRIORITY_CODES = ['US', 'GB', 'CA', 'AU', 'NZ', 'IE', 'DE', 'FR'];\n\nconst ALL_CODES = [\n 'AD', 'AE', 'AF', 'AG', 'AL', 'AM', 'AO', 'AR', 'AT', 'AU',\n 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ',\n 'BN', 'BO', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CD',\n 'CF', 'CG', 'CH', 'CI', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU',\n 'CV', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC',\n 'EE', 'EG', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FM', 'FR', 'GA',\n 'GB', 'GD', 'GE', 'GH', 'GM', 'GN', 'GQ', 'GR', 'GT', 'GW',\n 'GY', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IN', 'IQ',\n 'IR', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI',\n 'KM', 'KN', 'KR', 'KW', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK',\n 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME',\n 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MR', 'MT', 'MU', 'MV',\n 'MW', 'MX', 'MY', 'MZ', 'NA', 'NE', 'NG', 'NI', 'NL', 'NO',\n 'NP', 'NR', 'NZ', 'OM', 'PA', 'PE', 'PG', 'PH', 'PK', 'PL',\n 'PT', 'PW', 'PY', 'QA', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB',\n 'SC', 'SD', 'SE', 'SG', 'SI', 'SK', 'SL', 'SM', 'SN', 'SO',\n 'SR', 'SS', 'ST', 'SV', 'SY', 'SZ', 'TD', 'TG', 'TH', 'TJ',\n 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA',\n 'UG', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VN', 'VU', 'WS',\n 'XK', 'YE', 'ZA', 'ZM', 'ZW',\n] as const;\n\nfunction buildCountryOption(code: string): CountryOption {\n return { code, name: regionNames.of(code) ?? code, flag: codeToFlag(code) };\n}\n\nconst prioritySet = new Set(PRIORITY_CODES);\nconst rest = ALL_CODES.filter((c) => !prioritySet.has(c));\n\n/** All countries for dropdown select, priority countries first. */\nexport const COUNTRY_OPTIONS: CountryOption[] = [\n ...PRIORITY_CODES.map(buildCountryOption),\n ...rest.map(buildCountryOption),\n];\n\n/** Look up a country option by ISO 3166-1 alpha-2 code. */\nexport function getCountryByCode(code: string): CountryOption | undefined {\n return COUNTRY_OPTIONS.find((c) => c.code === code);\n}\n\n// ---------------------------------------------------------------------------\n// AVS Configuration Helpers\n// ---------------------------------------------------------------------------\n\n/** Default AVS config when `enableAVS: true` (backward compatible — country + postal code). */\nconst DEFAULT_AVS_CONFIG: AVSFieldConfig = {\n country: true,\n postal_code: true,\n};\n\n/**\n * Normalize `enableAVS` to a resolved config object.\n * - `false` / `undefined` → `null` (AVS disabled)\n * - `true` → default config (country + postal_code)\n * - `AVSFieldConfig` → returned as-is\n */\nexport function resolveAVSConfig(enableAVS?: boolean | AVSFieldConfig): AVSFieldConfig | null {\n if (!enableAVS) return null;\n if (enableAVS === true) return DEFAULT_AVS_CONFIG;\n return enableAVS;\n}\n\n/**\n * Check if an AVS field should be visible for the given country.\n * - `undefined` / `false` → hidden\n * - `true` → visible for all countries\n * - `string[]` → visible only for listed country codes\n */\nexport function isAVSFieldVisible(\n field: boolean | string[] | undefined,\n country: string,\n): boolean {\n if (field === undefined || field === false) return false;\n if (field === true) return true;\n const normalizedCountry = country.trim().toUpperCase();\n return field.some((code) => code.trim().toUpperCase() === normalizedCountry);\n}\n\n/** Returns true if any AVS field is meaningfully configured (at least one field is truthy). */\nexport function isAVSEnabled(enableAVS?: boolean | AVSFieldConfig): boolean {\n const config = resolveAVSConfig(enableAVS);\n if (!config) return false;\n return Object.values(config).some(\n (v) => v === true || (Array.isArray(v) && v.length > 0),\n );\n}\n\n// ---------------------------------------------------------------------------\n// US States & CA Provinces\n// ---------------------------------------------------------------------------\n\nexport interface StateOption {\n code: string;\n name: string;\n}\n\nexport const US_STATES: StateOption[] = [\n { code: 'AL', name: 'Alabama' },\n { code: 'AK', name: 'Alaska' },\n { code: 'AZ', name: 'Arizona' },\n { code: 'AR', name: 'Arkansas' },\n { code: 'CA', name: 'California' },\n { code: 'CO', name: 'Colorado' },\n { code: 'CT', name: 'Connecticut' },\n { code: 'DE', name: 'Delaware' },\n { code: 'DC', name: 'District of Columbia' },\n { code: 'FL', name: 'Florida' },\n { code: 'GA', name: 'Georgia' },\n { code: 'HI', name: 'Hawaii' },\n { code: 'ID', name: 'Idaho' },\n { code: 'IL', name: 'Illinois' },\n { code: 'IN', name: 'Indiana' },\n { code: 'IA', name: 'Iowa' },\n { code: 'KS', name: 'Kansas' },\n { code: 'KY', name: 'Kentucky' },\n { code: 'LA', name: 'Louisiana' },\n { code: 'ME', name: 'Maine' },\n { code: 'MD', name: 'Maryland' },\n { code: 'MA', name: 'Massachusetts' },\n { code: 'MI', name: 'Michigan' },\n { code: 'MN', name: 'Minnesota' },\n { code: 'MS', name: 'Mississippi' },\n { code: 'MO', name: 'Missouri' },\n { code: 'MT', name: 'Montana' },\n { code: 'NE', name: 'Nebraska' },\n { code: 'NV', name: 'Nevada' },\n { code: 'NH', name: 'New Hampshire' },\n { code: 'NJ', name: 'New Jersey' },\n { code: 'NM', name: 'New Mexico' },\n { code: 'NY', name: 'New York' },\n { code: 'NC', name: 'North Carolina' },\n { code: 'ND', name: 'North Dakota' },\n { code: 'OH', name: 'Ohio' },\n { code: 'OK', name: 'Oklahoma' },\n { code: 'OR', name: 'Oregon' },\n { code: 'PA', name: 'Pennsylvania' },\n { code: 'RI', name: 'Rhode Island' },\n { code: 'SC', name: 'South Carolina' },\n { code: 'SD', name: 'South Dakota' },\n { code: 'TN', name: 'Tennessee' },\n { code: 'TX', name: 'Texas' },\n { code: 'UT', name: 'Utah' },\n { code: 'VT', name: 'Vermont' },\n { code: 'VA', name: 'Virginia' },\n { code: 'WA', name: 'Washington' },\n { code: 'WV', name: 'West Virginia' },\n { code: 'WI', name: 'Wisconsin' },\n { code: 'WY', name: 'Wyoming' },\n];\n\nexport const CA_PROVINCES: StateOption[] = [\n { code: 'AB', name: 'Alberta' },\n { code: 'BC', name: 'British Columbia' },\n { code: 'MB', name: 'Manitoba' },\n { code: 'NB', name: 'New Brunswick' },\n { code: 'NL', name: 'Newfoundland and Labrador' },\n { code: 'NS', name: 'Nova Scotia' },\n { code: 'NT', name: 'Northwest Territories' },\n { code: 'NU', name: 'Nunavut' },\n { code: 'ON', name: 'Ontario' },\n { code: 'PE', name: 'Prince Edward Island' },\n { code: 'QC', name: 'Quebec' },\n { code: 'SK', name: 'Saskatchewan' },\n { code: 'YT', name: 'Yukon' },\n];\n\n/**\n * Get state/province options for a country.\n * Returns a list for US and CA, or `null` for countries where a free-text input is appropriate.\n */\nexport function getStateOptions(country: string): StateOption[] | null {\n switch (country.toUpperCase()) {\n case 'US': return US_STATES;\n case 'CA': return CA_PROVINCES;\n default: return null;\n }\n}\n\n/** Returns the appropriate label for the state/province field based on country. */\nexport function getStateLabel(countryCode: string): string {\n switch (countryCode.toUpperCase()) {\n case 'US': return 'State';\n case 'CA': return 'Province';\n case 'GB': return 'County';\n case 'AU': return 'State / Territory';\n default: return 'State / Province / Region';\n }\n}\n","/**\n * Postal-code → state derivation for AVS.\n *\n * Used when the form configuration shows `address_line_1` but hides the\n * `state` input — we still want to populate `billing_details.address.state`\n * so Stripe Radar gets a richer address signal. Currently supports US and CA;\n * other countries return `null` (caller should fall back to omitting state).\n */\n\n/**\n * US 3-digit ZIP-prefix ranges → state code (USPS Sectional Center Facility).\n * Sourced from the public USPS SCF table. Each entry is `[startPrefix, endPrefix, stateCode]`,\n * inclusive on both ends. Coverage is contiguous within a state; gaps in the table\n * (e.g. unused 3-digit prefixes) are intentional and resolve to `null`.\n */\nconst US_ZIP_PREFIX_RANGES: ReadonlyArray<readonly [number, number, string]> = [\n [5, 5, 'NY'],\n [10, 27, 'MA'],\n [28, 29, 'RI'],\n [30, 38, 'NH'],\n [39, 49, 'ME'],\n [50, 59, 'VT'],\n [60, 69, 'CT'],\n [70, 89, 'NJ'],\n [100, 149, 'NY'],\n [150, 196, 'PA'],\n [197, 199, 'DE'],\n [200, 205, 'DC'],\n [206, 219, 'MD'],\n [220, 246, 'VA'],\n [247, 268, 'WV'],\n [270, 289, 'NC'],\n [290, 299, 'SC'],\n [300, 319, 'GA'],\n [320, 349, 'FL'],\n [350, 369, 'AL'],\n [370, 385, 'TN'],\n [386, 397, 'MS'],\n [398, 399, 'GA'],\n [400, 427, 'KY'],\n [430, 459, 'OH'],\n [460, 479, 'IN'],\n [480, 499, 'MI'],\n [500, 528, 'IA'],\n [530, 549, 'WI'],\n [550, 567, 'MN'],\n [570, 577, 'SD'],\n [580, 588, 'ND'],\n [590, 599, 'MT'],\n [600, 629, 'IL'],\n [630, 658, 'MO'],\n [660, 679, 'KS'],\n [680, 693, 'NE'],\n [700, 714, 'LA'],\n [716, 729, 'AR'],\n [730, 749, 'OK'],\n [750, 799, 'TX'],\n [800, 816, 'CO'],\n [820, 831, 'WY'],\n [832, 838, 'ID'],\n [840, 847, 'UT'],\n [850, 865, 'AZ'],\n [870, 884, 'NM'],\n [889, 898, 'NV'],\n [900, 961, 'CA'],\n [967, 968, 'HI'],\n [970, 979, 'OR'],\n [980, 994, 'WA'],\n [995, 999, 'AK'],\n];\n\n/**\n * CA postal-code first letter → province code (Forward Sortation Area).\n * The first letter of every Canadian postal code identifies the province\n * uniquely, except `X` which is shared by Northwest Territories and Nunavut\n * — we resolve it to `NT` because the volume strongly favours NT.\n */\nconst CA_FSA_FIRST_LETTER_TO_PROVINCE: Readonly<Record<string, string>> = {\n A: 'NL',\n B: 'NS',\n C: 'PE',\n E: 'NB',\n G: 'QC',\n H: 'QC',\n J: 'QC',\n K: 'ON',\n L: 'ON',\n M: 'ON',\n N: 'ON',\n P: 'ON',\n R: 'MB',\n S: 'SK',\n T: 'AB',\n V: 'BC',\n X: 'NT',\n Y: 'YT',\n};\n\nfunction deriveUsState(zip: string): string | null {\n const digits = zip.replace(/\\D/g, '');\n if (digits.length < 5) return null;\n const prefix = Number.parseInt(digits.slice(0, 3), 10);\n if (!Number.isFinite(prefix)) return null;\n\n for (const [start, end, code] of US_ZIP_PREFIX_RANGES) {\n if (prefix >= start && prefix <= end) return code;\n }\n return null;\n}\n\nfunction deriveCaProvince(postalCode: string): string | null {\n const compact = postalCode.replace(/\\s+/g, '').toUpperCase();\n if (!/^[A-Z]\\d[A-Z]\\d[A-Z]\\d$/.test(compact)) return null;\n const firstLetter = compact[0] ?? '';\n return CA_FSA_FIRST_LETTER_TO_PROVINCE[firstLetter] ?? null;\n}\n\n/**\n * Resolve a state / province code from a postal code for the given country.\n *\n * - US: 5-digit ZIP → 2-letter USPS state code (uses 3-digit prefix table).\n * - CA: A1A 1A1 → 2-letter ISO 3166-2:CA province code (first-letter mapping).\n * - All other countries: `null`.\n *\n * Returns `null` when the postal code is malformed or falls in an unmapped\n * range. Callers should treat `null` as \"skip — don't derive\".\n */\nexport function getStateFromPostalCode(\n country: string,\n postalCode: string,\n): string | null {\n if (!country || !postalCode) return null;\n const normalizedCountry = country.trim().toUpperCase();\n const normalizedZip = postalCode.trim();\n if (!normalizedZip) return null;\n\n switch (normalizedCountry) {\n case 'US':\n return deriveUsState(normalizedZip);\n case 'CA':\n return deriveCaProvince(normalizedZip);\n default:\n return null;\n }\n}\n","import type { CheckoutItem, CheckoutSubscription } from './types.js';\n\n/**\n * Return the trimmed string when it has at least one non-whitespace character,\n * otherwise undefined. Used so that empty and whitespace-only inputs flow\n * through the same fallback chain as `undefined`.\n */\nfunction nonBlank(value: string | null | undefined): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Resolve the session-level currency, honoring the documented fallback:\n * `session.currency ?? items[*].currency ?? subscriptions[*].currency`.\n *\n * Returns the first non-blank currency found, or 'USD' when nothing is set.\n * Empty and whitespace-only strings are treated as unset so they do not\n * bypass the fallback chain.\n */\nexport function resolveSessionCurrency(\n sessionCurrency: string | undefined,\n items: ReadonlyArray<{ currency?: string }> | undefined,\n subscriptions: ReadonlyArray<{ currency?: string }> | undefined,\n): string {\n const session = nonBlank(sessionCurrency);\n if (session) return session;\n for (const item of items ?? []) {\n const c = nonBlank(item.currency);\n if (c) return c;\n }\n for (const sub of subscriptions ?? []) {\n const c = nonBlank(sub.currency);\n if (c) return c;\n }\n return 'USD';\n}\n\n/**\n * Build the request payload for a single item.\n *\n * Sends the new `code` field alongside the deprecated `providerItemId`,\n * `providerItemName`, `totalAmount`, and `overrideAmount` fields so that\n * both new and old backend versions accept the same request body.\n */\nexport function buildItemPayload(\n item: CheckoutItem,\n sessionCurrency: string,\n): Record<string, unknown> {\n const code = nonBlank(item.code) ?? nonBlank(item.providerItemId);\n if (!code) {\n throw new Error('CheckoutItem requires either `code` or the deprecated `providerItemId`.');\n }\n const itemName = nonBlank(item.itemName) ?? nonBlank(item.providerItemName) ?? null;\n\n const payload: Record<string, unknown> = {\n code,\n providerItemId: nonBlank(item.providerItemId) ?? code,\n itemName,\n providerItemName: nonBlank(item.providerItemName) ?? itemName,\n quantity: item.quantity ?? 1,\n totalAmount: item.totalAmount,\n overrideAmount: item.overrideAmount ?? null,\n currency: nonBlank(item.currency) ?? sessionCurrency,\n };\n\n if (item.metadata) {\n payload['metadata'] = item.metadata;\n }\n\n return payload;\n}\n\n/**\n * Build the request payload for a single subscription.\n *\n * Sends the new `code` field alongside the deprecated `providerPlanId`,\n * `providerPlanName`, `totalAmount`, and `overrideAmount` fields for\n * backward compatibility.\n */\nexport function buildSubscriptionPayload(\n subscription: CheckoutSubscription,\n sessionCurrency: string,\n): Record<string, unknown> {\n const code = nonBlank(subscription.code) ?? nonBlank(subscription.providerPlanId);\n if (!code) {\n throw new Error(\n 'CheckoutSubscription requires either `code` or the deprecated `providerPlanId`.',\n );\n }\n const subscriptionName =\n nonBlank(subscription.subscriptionName) ?? nonBlank(subscription.providerPlanName) ?? null;\n\n const payload: Record<string, unknown> = {\n code,\n providerPlanId: nonBlank(subscription.providerPlanId) ?? code,\n subscriptionName,\n providerPlanName: nonBlank(subscription.providerPlanName) ?? subscriptionName,\n quantity: subscription.quantity ?? 1,\n totalAmount: subscription.totalAmount,\n overrideAmount: subscription.overrideAmount ?? null,\n currency: nonBlank(subscription.currency) ?? sessionCurrency,\n };\n\n if (subscription.metadata) {\n payload['metadata'] = subscription.metadata;\n }\n\n return payload;\n}\n","import { resolveSessionCurrency } from './checkout-payload.js';\nimport type { CheckoutSession } from './types.js';\n\n/** A single line item formatted for display in the checkout UI. */\nexport interface DisplayLineItem {\n name: string;\n quantity: number;\n /** Price per unit in the session's currency (major units, e.g. 24.95). */\n price: number;\n /** Original price per unit before any discount (major units). */\n originalPrice: number;\n}\n\n/** Computed display data for rendering an order summary. */\nexport interface CheckoutDisplayData {\n /** Individual items/subscriptions with names, prices, and quantities. */\n items: DisplayLineItem[];\n /** ISO 4217 currency code (uppercase). */\n currency: string;\n /** Total amount due after discounts (major units, e.g. 24.95). */\n total: number;\n /** Sum of original prices before discounts (major units). */\n originalTotal: number;\n /** Total savings (originalTotal - total), clamped to >= 0. */\n totalSave: number;\n /** Discount percentage (0–100). */\n discountPercent: number;\n}\n\n/** Options for {@link buildCheckoutDisplayData}. */\nexport interface BuildCheckoutDisplayDataOptions {\n /**\n * When `true`, items are hidden from the order summary if the session also\n * contains subscriptions (matches the legacy checkout/CheckoutModal\n * behavior). Defaults to `false` — items are always shown.\n */\n hideBundledItems?: boolean;\n}\n\n/**\n * Builds display data from a `CheckoutSession` for rendering an order summary.\n *\n * - Subscriptions are always shown\n * - Items are shown by default; pass `{ hideBundledItems: true }` to suppress\n * them when the session also contains subscriptions (legacy behavior)\n * - `overrideAmount` (when not null/undefined) is the discounted price\n * - Plan name \"4-WEEK PLAN\" with price <= 1 is renamed to \"7-DAY TRIAL: FULL ACCESS\"\n * - Discount percentage and savings are computed from the difference\n *\n * All amounts are in **major currency units** (dollars, not cents).\n *\n * @example\n * ```ts\n * import { buildCheckoutDisplayData } from '@flopay/shared';\n *\n * const display = buildCheckoutDisplayData(session);\n * // display.items → [{ name: 'Starter', price: 24.95, originalPrice: 24.95, quantity: 1 }]\n * // display.total → 24.95\n * // display.currency → 'EUR'\n * ```\n */\nexport function buildCheckoutDisplayData(\n session: CheckoutSession,\n options: BuildCheckoutDisplayDataOptions = {},\n): CheckoutDisplayData {\n const itemsList: DisplayLineItem[] = [];\n\n const subscriptions = session.subscriptions ?? [];\n const items = session.items ?? [];\n\n // Resolve currency once: session > first item > first subscription > USD.\n const currency = resolveSessionCurrency(session.currency, items, subscriptions).toUpperCase();\n\n // Subscriptions\n for (const sub of subscriptions) {\n const originalPrice = sub.totalAmount ?? 0;\n const discountedPrice = sub.overrideAmount ?? originalPrice;\n\n // Match checkout/CheckoutModal: rename \"4-WEEK PLAN\" to \"7-DAY TRIAL: FULL ACCESS\"\n // when the discounted price is $1 or less\n let name = sub.subscriptionName || sub.providerPlanName || sub.code || 'Subscription';\n if (name === '4-WEEK PLAN' && discountedPrice <= 1) {\n name = '7-DAY TRIAL: FULL ACCESS';\n }\n\n itemsList.push({\n name,\n quantity: sub.quantity,\n price: discountedPrice,\n originalPrice,\n });\n }\n\n // Items are shown by default. Opt-in `hideBundledItems` hides them when\n // the session also contains subscriptions (legacy checkout/CheckoutModal\n // behavior).\n const hideItems =\n options.hideBundledItems === true\n && subscriptions.length > 0\n && items.length > 0;\n\n if (!hideItems) {\n for (const item of items) {\n const originalPrice = item.totalAmount ?? 0;\n const discountedPrice = item.overrideAmount ?? originalPrice;\n\n itemsList.push({\n name: item.itemName || item.providerItemName || item.code || 'Item',\n quantity: item.quantity,\n price: discountedPrice,\n originalPrice,\n });\n }\n }\n\n // Fallback if session has no items/subscriptions\n if (itemsList.length === 0) {\n itemsList.push({\n name: 'Purchase',\n quantity: 1,\n price: session.amount / 100,\n originalPrice: session.amount / 100,\n });\n }\n\n const originalTotal = itemsList.reduce((sum, i) => sum + i.originalPrice * i.quantity, 0);\n const total = itemsList.reduce((sum, i) => sum + i.price * i.quantity, 0);\n const totalSave = Math.max(0, originalTotal - total);\n const discountPercent = originalTotal > 0\n ? Math.round((totalSave / originalTotal) * 100)\n : 0;\n\n return {\n items: itemsList,\n currency,\n total,\n originalTotal,\n totalSave,\n discountPercent,\n };\n}\n","import type { CurrencyInfo } from './types.js';\nimport { CURRENCY_MAP, DEFAULT_CURRENCY } from './constants.js';\n\n/**\n * Look up currency information by ISO 3166-1 alpha-2 country code.\n * Falls back to USD when the country is not in the map.\n */\nexport function getCurrencyByCountry(countryCode: string): CurrencyInfo {\n return CURRENCY_MAP[countryCode.toUpperCase()] ?? DEFAULT_CURRENCY;\n}\n\n/** Returns `true` if the string looks like a Stripe publishable key. */\nexport function isValidPublishableKey(key: string): boolean {\n return /^pk_(test|live)_[A-Za-z0-9]+$/.test(key);\n}\n\n/** Returns `true` if the string looks like a Stripe secret key. */\nexport function isValidSecretKey(key: string): boolean {\n return /^sk_(test|live)_[A-Za-z0-9]+$/.test(key);\n}\n"],"mappings":"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,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AA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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -217,6 +217,56 @@ interface CheckoutSessionSubscription {
|
|
|
217
217
|
isUpdate?: boolean;
|
|
218
218
|
metadata?: Record<string, unknown> | null;
|
|
219
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Environment for an upstream gateway. Accepts both the gateway-native values
|
|
222
|
+
* (`'sandbox'` | `'live'`) and FloPay's internal aliases (`'stage'` |
|
|
223
|
+
* `'production'`) so the same string can flow from the billing API straight
|
|
224
|
+
* to gateway SDKs without translation at every call site. Use
|
|
225
|
+
* {@link normalizeGatewayEnvironment} to collapse to the canonical pair
|
|
226
|
+
* before handing the value to a gateway SDK.
|
|
227
|
+
*/
|
|
228
|
+
type GatewayEnvironment = 'sandbox' | 'live' | 'stage' | 'production';
|
|
229
|
+
/** Canonical gateway-native form returned by {@link normalizeGatewayEnvironment}. */
|
|
230
|
+
type NormalizedGatewayEnvironment = 'sandbox' | 'live';
|
|
231
|
+
/**
|
|
232
|
+
* Map FloPay's environment aliases to the gateway-native `'sandbox'`/`'live'`
|
|
233
|
+
* pair. `'stage'` → `'sandbox'`, `'production'` → `'live'`. Returns `undefined`
|
|
234
|
+
* for `undefined` input and logs a console warning for unrecognized strings
|
|
235
|
+
* (so misconfiguration surfaces immediately instead of hanging later — most
|
|
236
|
+
* gateway SDKs silently fall back to live endpoints on an unknown env, which
|
|
237
|
+
* then fails opaquely against sandbox credentials).
|
|
238
|
+
*/
|
|
239
|
+
declare function normalizeGatewayEnvironment(env: GatewayEnvironment | string | undefined | null): NormalizedGatewayEnvironment | undefined;
|
|
240
|
+
/** Per-gateway configuration returned by the billing API. */
|
|
241
|
+
interface CheckoutGateway {
|
|
242
|
+
/** Public client identifier (e.g. Stripe publishable key, PayPal client id). */
|
|
243
|
+
publishableKey?: string | null;
|
|
244
|
+
/** Sandbox or live mode for the gateway credentials. */
|
|
245
|
+
environment?: GatewayEnvironment;
|
|
246
|
+
/**
|
|
247
|
+
* Optional Stripe PaymentIntent client secret exposed by the billing API
|
|
248
|
+
* when additional authentication is required for a saved payment method.
|
|
249
|
+
* Stripe-specific.
|
|
250
|
+
*/
|
|
251
|
+
stripeClientSecret?: string | null;
|
|
252
|
+
/**
|
|
253
|
+
* Optional publishable key for a dedicated Stripe sub-account that renders
|
|
254
|
+
* PayPal via Stripe Elements. Stripe-specific. Distinct from
|
|
255
|
+
* `gateways.paypal.publishableKey`, which is a PayPal client id used by the
|
|
256
|
+
* direct PayPal SDK.
|
|
257
|
+
*/
|
|
258
|
+
paypalPublishableKey?: string | null;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Map of gateways attached to a session, keyed by gateway code. A session can
|
|
262
|
+
* advertise multiple gateways concurrently — e.g. `gateways.stripe` for card
|
|
263
|
+
* + wallets and `gateways.paypal` for direct PayPal rendering.
|
|
264
|
+
*/
|
|
265
|
+
interface CheckoutGateways {
|
|
266
|
+
stripe?: CheckoutGateway;
|
|
267
|
+
paypal?: CheckoutGateway;
|
|
268
|
+
[key: string]: CheckoutGateway | undefined;
|
|
269
|
+
}
|
|
220
270
|
/** Represents a FloPay checkout session. */
|
|
221
271
|
interface CheckoutSession {
|
|
222
272
|
id: string;
|
|
@@ -235,21 +285,12 @@ interface CheckoutSession {
|
|
|
235
285
|
cancelUrl?: string;
|
|
236
286
|
coupons?: string[];
|
|
237
287
|
createdAt?: string;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
};
|
|
288
|
+
/**
|
|
289
|
+
* Per-gateway configuration. A session can advertise multiple concurrent
|
|
290
|
+
* gateways — read `gateways.stripe` for card/wallets, `gateways.paypal` for
|
|
291
|
+
* direct PayPal, and so on.
|
|
292
|
+
*/
|
|
293
|
+
gateways?: CheckoutGateways;
|
|
253
294
|
accountData?: {
|
|
254
295
|
userId: string;
|
|
255
296
|
email: string;
|
|
@@ -440,8 +481,8 @@ interface PaymentProviderAdapter {
|
|
|
440
481
|
createPayPalElements(options: ElementOptions): unknown;
|
|
441
482
|
destroy(): void;
|
|
442
483
|
}
|
|
443
|
-
/** Supported upstream
|
|
444
|
-
type BillingProvider = '
|
|
484
|
+
/** Supported upstream gateway codes. */
|
|
485
|
+
type BillingProvider = 'stripe' | 'paypal';
|
|
445
486
|
/** Token payload produced by client-side tokenization. */
|
|
446
487
|
interface TokenizedBody {
|
|
447
488
|
id?: string;
|
|
@@ -475,9 +516,13 @@ interface CheckoutProcessingPending {
|
|
|
475
516
|
}
|
|
476
517
|
/** Checkout mode: tokenize client-side or redirect to hosted page. */
|
|
477
518
|
type CheckoutModeKind = 'tokenize' | 'redirect';
|
|
478
|
-
/**
|
|
519
|
+
/**
|
|
520
|
+
* Provider-agnostic normalized checkout session. Backend may attach multiple
|
|
521
|
+
* gateways per session — read each from `data.<gatewayCode>`.
|
|
522
|
+
*/
|
|
479
523
|
interface NormalizedCheckoutSession {
|
|
480
|
-
|
|
524
|
+
/** Gateway codes advertised by the backend for this session, for diagnostics. */
|
|
525
|
+
providers: BillingProvider[];
|
|
481
526
|
mode: CheckoutModeKind;
|
|
482
527
|
autoProcessingError?: CheckoutProcessError;
|
|
483
528
|
autoProcessingAttempted?: boolean;
|
|
@@ -486,17 +531,25 @@ interface NormalizedCheckoutSession {
|
|
|
486
531
|
hostedUrl?: string;
|
|
487
532
|
clientToken?: string;
|
|
488
533
|
session?: CheckoutSession;
|
|
489
|
-
chargebee?: {
|
|
490
|
-
site?: string;
|
|
491
|
-
publishableKey?: string;
|
|
492
|
-
dropInToken?: string;
|
|
493
|
-
sessionId?: string;
|
|
494
|
-
};
|
|
495
534
|
stripe?: {
|
|
496
535
|
clientSecret?: string;
|
|
497
536
|
publishableKey?: string;
|
|
498
|
-
/**
|
|
537
|
+
/**
|
|
538
|
+
* Optional dedicated Stripe sub-account publishable key for rendering
|
|
539
|
+
* PayPal via Stripe Elements. When present and distinct, the saved-PM
|
|
540
|
+
* resume flow loads a separate FloPay instance for the PayPal PI.
|
|
541
|
+
*/
|
|
499
542
|
paypalPublishableKey?: string;
|
|
543
|
+
environment?: GatewayEnvironment;
|
|
544
|
+
};
|
|
545
|
+
/**
|
|
546
|
+
* Direct PayPal gateway configuration. Present only when the backend has
|
|
547
|
+
* configured a dedicated PayPal gateway for the consumer; absent means the
|
|
548
|
+
* Stripe-rendered PayPal fallback should be used (if Stripe is configured).
|
|
549
|
+
*/
|
|
550
|
+
paypal?: {
|
|
551
|
+
publishableKey?: string;
|
|
552
|
+
environment?: GatewayEnvironment;
|
|
500
553
|
};
|
|
501
554
|
};
|
|
502
555
|
raw?: unknown;
|
|
@@ -817,7 +870,7 @@ declare function getConfiguredBillingApiUrl(): string;
|
|
|
817
870
|
declare function getFloPayEnvironment(): FloPayEnvironment;
|
|
818
871
|
|
|
819
872
|
/** Current SDK version. */
|
|
820
|
-
declare const SDK_VERSION = "1.0
|
|
873
|
+
declare const SDK_VERSION = "1.1.0";
|
|
821
874
|
/** Billing API URL for staging environment. */
|
|
822
875
|
declare const BILLING_API_URL_STAGING = "https://api.stage.flopay.com";
|
|
823
876
|
/** Billing API URL for production environment. */
|
|
@@ -1025,4 +1078,4 @@ declare function isValidPublishableKey(key: string): boolean;
|
|
|
1025
1078
|
/** Returns `true` if the string looks like a Stripe secret key. */
|
|
1026
1079
|
declare function isValidSecretKey(key: string): boolean;
|
|
1027
1080
|
|
|
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 };
|
|
1081
|
+
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 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 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, buildSubscriptionPayload, configureFlopay, getConfiguredBillingApiUrl, getCountryByCode, getCurrencyByCountry, getFloPayEnvironment, getPostalCodeLabel, getStateFromPostalCode, getStateLabel, getStateOptions, isAVSEnabled, isAVSFieldVisible, isValidPublishableKey, isValidSecretKey, networkError, normalizeGatewayEnvironment, rateLimitError, resolveAVSConfig, resolveBillingApiUrl, resolveButtonsLayoutTheme, resolveSessionCurrency, validationError };
|
package/dist/index.d.ts
CHANGED
|
@@ -217,6 +217,56 @@ interface CheckoutSessionSubscription {
|
|
|
217
217
|
isUpdate?: boolean;
|
|
218
218
|
metadata?: Record<string, unknown> | null;
|
|
219
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Environment for an upstream gateway. Accepts both the gateway-native values
|
|
222
|
+
* (`'sandbox'` | `'live'`) and FloPay's internal aliases (`'stage'` |
|
|
223
|
+
* `'production'`) so the same string can flow from the billing API straight
|
|
224
|
+
* to gateway SDKs without translation at every call site. Use
|
|
225
|
+
* {@link normalizeGatewayEnvironment} to collapse to the canonical pair
|
|
226
|
+
* before handing the value to a gateway SDK.
|
|
227
|
+
*/
|
|
228
|
+
type GatewayEnvironment = 'sandbox' | 'live' | 'stage' | 'production';
|
|
229
|
+
/** Canonical gateway-native form returned by {@link normalizeGatewayEnvironment}. */
|
|
230
|
+
type NormalizedGatewayEnvironment = 'sandbox' | 'live';
|
|
231
|
+
/**
|
|
232
|
+
* Map FloPay's environment aliases to the gateway-native `'sandbox'`/`'live'`
|
|
233
|
+
* pair. `'stage'` → `'sandbox'`, `'production'` → `'live'`. Returns `undefined`
|
|
234
|
+
* for `undefined` input and logs a console warning for unrecognized strings
|
|
235
|
+
* (so misconfiguration surfaces immediately instead of hanging later — most
|
|
236
|
+
* gateway SDKs silently fall back to live endpoints on an unknown env, which
|
|
237
|
+
* then fails opaquely against sandbox credentials).
|
|
238
|
+
*/
|
|
239
|
+
declare function normalizeGatewayEnvironment(env: GatewayEnvironment | string | undefined | null): NormalizedGatewayEnvironment | undefined;
|
|
240
|
+
/** Per-gateway configuration returned by the billing API. */
|
|
241
|
+
interface CheckoutGateway {
|
|
242
|
+
/** Public client identifier (e.g. Stripe publishable key, PayPal client id). */
|
|
243
|
+
publishableKey?: string | null;
|
|
244
|
+
/** Sandbox or live mode for the gateway credentials. */
|
|
245
|
+
environment?: GatewayEnvironment;
|
|
246
|
+
/**
|
|
247
|
+
* Optional Stripe PaymentIntent client secret exposed by the billing API
|
|
248
|
+
* when additional authentication is required for a saved payment method.
|
|
249
|
+
* Stripe-specific.
|
|
250
|
+
*/
|
|
251
|
+
stripeClientSecret?: string | null;
|
|
252
|
+
/**
|
|
253
|
+
* Optional publishable key for a dedicated Stripe sub-account that renders
|
|
254
|
+
* PayPal via Stripe Elements. Stripe-specific. Distinct from
|
|
255
|
+
* `gateways.paypal.publishableKey`, which is a PayPal client id used by the
|
|
256
|
+
* direct PayPal SDK.
|
|
257
|
+
*/
|
|
258
|
+
paypalPublishableKey?: string | null;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Map of gateways attached to a session, keyed by gateway code. A session can
|
|
262
|
+
* advertise multiple gateways concurrently — e.g. `gateways.stripe` for card
|
|
263
|
+
* + wallets and `gateways.paypal` for direct PayPal rendering.
|
|
264
|
+
*/
|
|
265
|
+
interface CheckoutGateways {
|
|
266
|
+
stripe?: CheckoutGateway;
|
|
267
|
+
paypal?: CheckoutGateway;
|
|
268
|
+
[key: string]: CheckoutGateway | undefined;
|
|
269
|
+
}
|
|
220
270
|
/** Represents a FloPay checkout session. */
|
|
221
271
|
interface CheckoutSession {
|
|
222
272
|
id: string;
|
|
@@ -235,21 +285,12 @@ interface CheckoutSession {
|
|
|
235
285
|
cancelUrl?: string;
|
|
236
286
|
coupons?: string[];
|
|
237
287
|
createdAt?: string;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
};
|
|
288
|
+
/**
|
|
289
|
+
* Per-gateway configuration. A session can advertise multiple concurrent
|
|
290
|
+
* gateways — read `gateways.stripe` for card/wallets, `gateways.paypal` for
|
|
291
|
+
* direct PayPal, and so on.
|
|
292
|
+
*/
|
|
293
|
+
gateways?: CheckoutGateways;
|
|
253
294
|
accountData?: {
|
|
254
295
|
userId: string;
|
|
255
296
|
email: string;
|
|
@@ -440,8 +481,8 @@ interface PaymentProviderAdapter {
|
|
|
440
481
|
createPayPalElements(options: ElementOptions): unknown;
|
|
441
482
|
destroy(): void;
|
|
442
483
|
}
|
|
443
|
-
/** Supported upstream
|
|
444
|
-
type BillingProvider = '
|
|
484
|
+
/** Supported upstream gateway codes. */
|
|
485
|
+
type BillingProvider = 'stripe' | 'paypal';
|
|
445
486
|
/** Token payload produced by client-side tokenization. */
|
|
446
487
|
interface TokenizedBody {
|
|
447
488
|
id?: string;
|
|
@@ -475,9 +516,13 @@ interface CheckoutProcessingPending {
|
|
|
475
516
|
}
|
|
476
517
|
/** Checkout mode: tokenize client-side or redirect to hosted page. */
|
|
477
518
|
type CheckoutModeKind = 'tokenize' | 'redirect';
|
|
478
|
-
/**
|
|
519
|
+
/**
|
|
520
|
+
* Provider-agnostic normalized checkout session. Backend may attach multiple
|
|
521
|
+
* gateways per session — read each from `data.<gatewayCode>`.
|
|
522
|
+
*/
|
|
479
523
|
interface NormalizedCheckoutSession {
|
|
480
|
-
|
|
524
|
+
/** Gateway codes advertised by the backend for this session, for diagnostics. */
|
|
525
|
+
providers: BillingProvider[];
|
|
481
526
|
mode: CheckoutModeKind;
|
|
482
527
|
autoProcessingError?: CheckoutProcessError;
|
|
483
528
|
autoProcessingAttempted?: boolean;
|
|
@@ -486,17 +531,25 @@ interface NormalizedCheckoutSession {
|
|
|
486
531
|
hostedUrl?: string;
|
|
487
532
|
clientToken?: string;
|
|
488
533
|
session?: CheckoutSession;
|
|
489
|
-
chargebee?: {
|
|
490
|
-
site?: string;
|
|
491
|
-
publishableKey?: string;
|
|
492
|
-
dropInToken?: string;
|
|
493
|
-
sessionId?: string;
|
|
494
|
-
};
|
|
495
534
|
stripe?: {
|
|
496
535
|
clientSecret?: string;
|
|
497
536
|
publishableKey?: string;
|
|
498
|
-
/**
|
|
537
|
+
/**
|
|
538
|
+
* Optional dedicated Stripe sub-account publishable key for rendering
|
|
539
|
+
* PayPal via Stripe Elements. When present and distinct, the saved-PM
|
|
540
|
+
* resume flow loads a separate FloPay instance for the PayPal PI.
|
|
541
|
+
*/
|
|
499
542
|
paypalPublishableKey?: string;
|
|
543
|
+
environment?: GatewayEnvironment;
|
|
544
|
+
};
|
|
545
|
+
/**
|
|
546
|
+
* Direct PayPal gateway configuration. Present only when the backend has
|
|
547
|
+
* configured a dedicated PayPal gateway for the consumer; absent means the
|
|
548
|
+
* Stripe-rendered PayPal fallback should be used (if Stripe is configured).
|
|
549
|
+
*/
|
|
550
|
+
paypal?: {
|
|
551
|
+
publishableKey?: string;
|
|
552
|
+
environment?: GatewayEnvironment;
|
|
500
553
|
};
|
|
501
554
|
};
|
|
502
555
|
raw?: unknown;
|
|
@@ -817,7 +870,7 @@ declare function getConfiguredBillingApiUrl(): string;
|
|
|
817
870
|
declare function getFloPayEnvironment(): FloPayEnvironment;
|
|
818
871
|
|
|
819
872
|
/** Current SDK version. */
|
|
820
|
-
declare const SDK_VERSION = "1.0
|
|
873
|
+
declare const SDK_VERSION = "1.1.0";
|
|
821
874
|
/** Billing API URL for staging environment. */
|
|
822
875
|
declare const BILLING_API_URL_STAGING = "https://api.stage.flopay.com";
|
|
823
876
|
/** Billing API URL for production environment. */
|
|
@@ -1025,4 +1078,4 @@ declare function isValidPublishableKey(key: string): boolean;
|
|
|
1025
1078
|
/** Returns `true` if the string looks like a Stripe secret key. */
|
|
1026
1079
|
declare function isValidSecretKey(key: string): boolean;
|
|
1027
1080
|
|
|
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 };
|
|
1081
|
+
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 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 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, buildSubscriptionPayload, configureFlopay, 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
|
|
66
|
+
var SDK_VERSION = "1.1.0";
|
|
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;
|
|
@@ -868,6 +886,7 @@ export {
|
|
|
868
886
|
isValidPublishableKey,
|
|
869
887
|
isValidSecretKey,
|
|
870
888
|
networkError,
|
|
889
|
+
normalizeGatewayEnvironment,
|
|
871
890
|
rateLimitError,
|
|
872
891
|
resolveAVSConfig,
|
|
873
892
|
resolveBillingApiUrl,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/config.ts","../src/constants.ts","../src/postal-code-lookup.ts","../src/checkout-payload.ts","../src/display.ts","../src/validation.ts"],"sourcesContent":["/** Discriminated error types returned by the FloPay SDK. */\nexport type FloPayErrorType =\n | 'validation_error'\n | 'api_error'\n | 'authentication_error'\n | 'rate_limit_error'\n | 'network_error';\n\n/**\n * Custom error class for all FloPay SDK errors.\n *\n * Extends the native `Error` and adds structured fields that mirror\n * Stripe-style error responses for familiarity.\n */\nexport class FloPayError extends Error {\n readonly type: FloPayErrorType;\n readonly code?: string;\n readonly declineCode?: string;\n readonly param?: string;\n readonly statusCode?: number;\n\n constructor(\n message: string,\n type: FloPayErrorType,\n options?: { code?: string; declineCode?: string; param?: string; statusCode?: number },\n ) {\n super(message);\n this.name = 'FloPayError';\n this.type = type;\n this.code = options?.code;\n this.declineCode = options?.declineCode;\n this.param = options?.param;\n this.statusCode = options?.statusCode;\n\n // Restore prototype chain (required when extending built-ins)\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error Factories\n// ---------------------------------------------------------------------------\n\n/** Create a validation error (e.g. missing required field). */\nexport function validationError(\n message: string,\n param?: string,\n): FloPayError {\n return new FloPayError(message, 'validation_error', { param });\n}\n\n/** Create an API error (e.g. upstream provider returned an error). */\nexport function apiError(\n message: string,\n code?: string,\n statusCode?: number,\n): FloPayError {\n return new FloPayError(message, 'api_error', { code, statusCode });\n}\n\n/** Create an authentication error (e.g. invalid publishable key). */\nexport function authenticationError(message: string): FloPayError {\n return new FloPayError(message, 'authentication_error');\n}\n\n/** Create a rate limit error. */\nexport function rateLimitError(message: string): FloPayError {\n return new FloPayError(message, 'rate_limit_error');\n}\n\n/** Create a network error (e.g. fetch failed). */\nexport function networkError(message: string): FloPayError {\n return new FloPayError(message, 'network_error');\n}\n","/** FloPay environment — determines which billing API URL is used. */\nexport type FloPayEnvironment = 'staging' | 'production' | 'local';\n\nconst ENV_URL_MAP: Record<FloPayEnvironment, string> = {\n local: 'https://flo.ngrok.pro',\n staging: 'https://api.stage.flopay.com',\n production: 'https://api.flopay.com',\n};\n\nlet globalEnvironment: FloPayEnvironment = 'staging';\n\n/**\n * Configure the FloPay SDK globally. Call once at app startup.\n *\n * The environment determines which billing API URL is used for all\n * FloPay operations (session creation, payment processing, etc.).\n *\n * @example\n * ```ts\n * import { configureFlopay } from '@flopay/shared';\n *\n * // In production\n * configureFlopay({ environment: 'production' });\n *\n * // In staging/development\n * configureFlopay({ environment: 'staging' });\n * ```\n *\n * Alternatively, set the `NEXT_PUBLIC_FLOPAY_ENV` environment variable\n * to `'staging'` or `'production'` — the SDK reads it automatically.\n */\nexport function configureFlopay(config: { environment: FloPayEnvironment }): void {\n globalEnvironment = config.environment;\n}\n\n/** Get the billing API URL for the currently configured environment. */\nexport function getConfiguredBillingApiUrl(): string {\n return ENV_URL_MAP[globalEnvironment];\n}\n\n/** Get the current configured environment. */\nexport function getFloPayEnvironment(): FloPayEnvironment {\n return globalEnvironment;\n}\n","import type { AVSFieldConfig, ButtonsLayoutStyles, ButtonsLayoutTheme, CountryOption, CurrencyInfo, FloPayAppearance } from './types.js';\n\nimport type { FloPayEnvironment } from './config.js';\nimport { getConfiguredBillingApiUrl } from './config.js';\n\n// ---------------------------------------------------------------------------\n// SDK Version & API\n// ---------------------------------------------------------------------------\n\n/** Current SDK version. */\nexport const SDK_VERSION = '1.0.3';\n\n/** Billing API URL for staging environment. */\nexport const BILLING_API_URL_STAGING = 'https://api.stage.flopay.com';\n\n/** Billing API URL for production environment. */\nexport const BILLING_API_URL_PRODUCTION = 'https://api.flopay.com';\n\n/** Default FloPay API base URL (used by @flopay/node). Alias for staging. */\nexport const DEFAULT_API_BASE_URL = BILLING_API_URL_STAGING;\n\n/** Default billing API base URL. Alias for staging — prefer `resolveBillingApiUrl()`. */\nexport const BILLING_API_URL = BILLING_API_URL_STAGING;\n\n/**\n * Resolve the billing API URL from available configuration.\n *\n * Priority:\n * 1. Explicit `billingApiUrl` (prop/param override)\n * 2. `NEXT_PUBLIC_FLOPAY_ENV` environment variable (`'staging'` | `'production'`)\n * 3. `configureFlopay()` global environment setting\n * 4. Fallback: staging URL\n *\n * @example\n * ```ts\n * import { resolveBillingApiUrl } from '@flopay/shared';\n *\n * // Reads from env var or configureFlopay() — no args needed\n * const url = resolveBillingApiUrl();\n *\n * // Explicit override takes priority\n * const url = resolveBillingApiUrl('https://custom.example.com');\n * ```\n */\nexport function resolveBillingApiUrl(billingApiUrl?: string): string {\n if (billingApiUrl) return billingApiUrl;\n\n // Environment variable (works in Next.js and bundlers that inline process.env)\n if (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_FLOPAY_ENV) {\n const env = process.env.NEXT_PUBLIC_FLOPAY_ENV as FloPayEnvironment;\n if (env === 'production') return BILLING_API_URL_PRODUCTION;\n return BILLING_API_URL_STAGING;\n }\n\n // Global config from configureFlopay()\n return getConfiguredBillingApiUrl();\n}\n\n/** Default API version header value. */\nexport const DEFAULT_API_VERSION = '2024-01-01';\n\n// ---------------------------------------------------------------------------\n// Default Themes\n// ---------------------------------------------------------------------------\n\n/** The default appearance applied when no custom appearance is provided. */\nexport const DEFAULT_APPEARANCE: FloPayAppearance = {\n theme: 'default',\n variables: {\n colorPrimary: '#4A49FF',\n colorBackground: '#FFFFFF',\n colorText: '#262833',\n colorDanger: '#DF1B41',\n borderRadius: '8px',\n fontFamily: 'Poppins, system-ui, sans-serif',\n fontSizeBase: '16px',\n spacingUnit: '4px',\n },\n};\n\n/** Flat theme — minimal borders and shadows. */\nexport const FLAT_APPEARANCE: FloPayAppearance = {\n theme: 'flat',\n variables: {\n ...DEFAULT_APPEARANCE.variables,\n borderRadius: '4px',\n },\n};\n\n/** Night theme — dark background. */\nexport const NIGHT_APPEARANCE: FloPayAppearance = {\n theme: 'night',\n variables: {\n colorPrimary: '#7B7BFF',\n colorBackground: '#1A1A2E',\n colorText: '#E0E0E0',\n colorDanger: '#FF6B6B',\n borderRadius: '8px',\n fontFamily: 'Poppins, system-ui, sans-serif',\n fontSizeBase: '16px',\n spacingUnit: '4px',\n },\n};\n\n// ---------------------------------------------------------------------------\n// Buttons Layout Theme Presets\n// ---------------------------------------------------------------------------\n\n/** Default buttons layout — white card button, neutral borders. */\nexport const BUTTONS_LAYOUT_DEFAULT: ButtonsLayoutStyles = {};\n\n/** Minimal buttons layout — borderless, subtle hover. */\nexport const BUTTONS_LAYOUT_MINIMAL: ButtonsLayoutStyles = {\n cardButton: {\n border: 'none',\n backgroundColor: '#f9fafb',\n boxShadow: 'none',\n },\n cardFormContainer: {\n backgroundColor: '#f9fafb',\n border: 'none',\n },\n cardInputBorder: '#e5e7eb',\n backButtonIcon: {\n backgroundColor: '#e5e7eb',\n },\n submitButton: {\n borderRadius: '6px',\n },\n};\n\n/** Rounded buttons layout — large border radius, soft shadows. */\nexport const BUTTONS_LAYOUT_ROUNDED: ButtonsLayoutStyles = {\n cardButton: {\n borderRadius: '9999px',\n border: '1px solid #e5e7eb',\n boxShadow: '0 1px 3px rgba(0,0,0,0.06)',\n },\n cardFormContainer: {\n borderRadius: '16px',\n border: '1px solid #e5e7eb',\n boxShadow: '0 2px 8px rgba(0,0,0,0.06)',\n },\n cardInputBorder: '#d1d5db',\n submitButton: {\n borderRadius: '9999px',\n },\n backButtonIcon: {\n backgroundColor: '#f3f4f6',\n },\n};\n\n/** Dark buttons layout — dark backgrounds, light text. */\nexport const BUTTONS_LAYOUT_DARK: ButtonsLayoutStyles = {\n cardButton: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n border: '1px solid #374151',\n boxShadow: 'none',\n },\n cardFormContainer: {\n backgroundColor: '#111827',\n border: '1px solid #374151',\n },\n cardInputBorder: '#4b5563',\n cardInputColor: '#f9fafb',\n cardInputPlaceholderColor: '#6b7280',\n cardInputBackground: '#1f2937',\n nameInput: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n backButton: {\n color: '#9ca3af',\n },\n backButtonIcon: {\n backgroundColor: '#374151',\n },\n submitButton: {\n backgroundColor: '#6366f1',\n },\n title: {\n color: '#f9fafb',\n },\n countrySelect: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n zipInput: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n};\n\n/** Resolve a buttons layout theme name to its style preset. */\nexport function resolveButtonsLayoutTheme(theme?: ButtonsLayoutTheme): ButtonsLayoutStyles {\n switch (theme) {\n case 'minimal': return BUTTONS_LAYOUT_MINIMAL;\n case 'rounded': return BUTTONS_LAYOUT_ROUNDED;\n case 'dark': return BUTTONS_LAYOUT_DARK;\n default: return BUTTONS_LAYOUT_DEFAULT;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Supported Element Types\n// ---------------------------------------------------------------------------\n\n/** All supported element type identifiers. */\nexport const ELEMENT_TYPES = [\n 'payment',\n 'card',\n 'cardNumber',\n 'cardExpiry',\n 'cardCvc',\n 'address',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Supported Card Brands\n// ---------------------------------------------------------------------------\n\nexport const SUPPORTED_CARD_BRANDS = [\n 'visa',\n 'mastercard',\n 'mastercard_debit',\n 'amex',\n 'discover',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Currency Mapping (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Country code to currency information mapping. */\nexport const CURRENCY_MAP: Record<string, CurrencyInfo> = {\n // EUR (VAT applies)\n AT: { currency: 'EUR', symbol: '\\u20AC', country: 'Austria', countryCode: 'AT', tax: 1 },\n BE: { currency: 'EUR', symbol: '\\u20AC', country: 'Belgium', countryCode: 'BE', tax: 1 },\n CY: { currency: 'EUR', symbol: '\\u20AC', country: 'Cyprus', countryCode: 'CY', tax: 1 },\n DE: { currency: 'EUR', symbol: '\\u20AC', country: 'Germany', countryCode: 'DE', tax: 1 },\n EE: { currency: 'EUR', symbol: '\\u20AC', country: 'Estonia', countryCode: 'EE', tax: 1 },\n ES: { currency: 'EUR', symbol: '\\u20AC', country: 'Spain', countryCode: 'ES', tax: 1 },\n FI: { currency: 'EUR', symbol: '\\u20AC', country: 'Finland', countryCode: 'FI', tax: 1 },\n FR: { currency: 'EUR', symbol: '\\u20AC', country: 'France', countryCode: 'FR', tax: 1 },\n GR: { currency: 'EUR', symbol: '\\u20AC', country: 'Greece', countryCode: 'GR', tax: 1 },\n HR: { currency: 'EUR', symbol: '\\u20AC', country: 'Croatia', countryCode: 'HR', tax: 1 },\n IE: { currency: 'EUR', symbol: '\\u20AC', country: 'Ireland', countryCode: 'IE', tax: 1 },\n IT: { currency: 'EUR', symbol: '\\u20AC', country: 'Italy', countryCode: 'IT', tax: 1 },\n LT: { currency: 'EUR', symbol: '\\u20AC', country: 'Lithuania', countryCode: 'LT', tax: 1 },\n LU: { currency: 'EUR', symbol: '\\u20AC', country: 'Luxembourg', countryCode: 'LU', tax: 1 },\n LV: { currency: 'EUR', symbol: '\\u20AC', country: 'Latvia', countryCode: 'LV', tax: 1 },\n MT: { currency: 'EUR', symbol: '\\u20AC', country: 'Malta', countryCode: 'MT', tax: 1 },\n NL: { currency: 'EUR', symbol: '\\u20AC', country: 'Netherlands', countryCode: 'NL', tax: 1 },\n PT: { currency: 'EUR', symbol: '\\u20AC', country: 'Portugal', countryCode: 'PT', tax: 1 },\n SI: { currency: 'EUR', symbol: '\\u20AC', country: 'Slovenia', countryCode: 'SI', tax: 1 },\n SK: { currency: 'EUR', symbol: '\\u20AC', country: 'Slovakia', countryCode: 'SK', tax: 1 },\n BG: { currency: 'EUR', symbol: '\\u20AC', country: 'Bulgaria', countryCode: 'BG', tax: 1 },\n RO: { currency: 'EUR', symbol: '\\u20AC', country: 'Romania', countryCode: 'RO', tax: 1 },\n CZ: { currency: 'EUR', symbol: '\\u20AC', country: 'Czech Republic', countryCode: 'CZ', tax: 1 },\n SE: { currency: 'EUR', symbol: '\\u20AC', country: 'Sweden', countryCode: 'SE', tax: 1 },\n DK: { currency: 'EUR', symbol: '\\u20AC', country: 'Denmark', countryCode: 'DK', tax: 1 },\n PL: { currency: 'EUR', symbol: '\\u20AC', country: 'Poland', countryCode: 'PL', tax: 1 },\n HU: { currency: 'EUR', symbol: '\\u20AC', country: 'Hungary', countryCode: 'HU', tax: 1 },\n // GBP (VAT applies)\n GB: { currency: 'GBP', symbol: '\\u00A3', country: 'United Kingdom', countryCode: 'GB', tax: 1 },\n // USD (no VAT)\n US: { currency: 'USD', symbol: '$', country: 'United States', countryCode: 'US', tax: 0 },\n // CAD (no VAT)\n CA: { currency: 'CAD', symbol: 'CA$', country: 'Canada', countryCode: 'CA', tax: 0 },\n // NZD (no VAT)\n NZ: { currency: 'NZD', symbol: 'NZ$', country: 'New Zealand', countryCode: 'NZ', tax: 0 },\n // AUD (no VAT)\n AU: { currency: 'AUD', symbol: 'AU$', country: 'Australia', countryCode: 'AU', tax: 0 },\n};\n\n/** Default currency info when country is unknown. */\nexport const DEFAULT_CURRENCY: CurrencyInfo = {\n currency: 'USD',\n symbol: '$',\n country: 'United States',\n countryCode: 'US',\n tax: 0,\n};\n\n// ---------------------------------------------------------------------------\n// Postal Code Labels\n// ---------------------------------------------------------------------------\n\n/** Returns the correct postal code label for a country code (ISO 3166-1 alpha-2). */\nexport function getPostalCodeLabel(countryCode: string): string {\n switch (countryCode.toUpperCase()) {\n case 'US': return 'ZIP Code';\n case 'GB': return 'Postcode';\n case 'CA': return 'Postal Code';\n case 'AU':\n case 'NZ': return 'Postcode';\n case 'IE': return 'Eircode';\n default: return 'Postal Code';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Country List (ISO 3166-1 alpha-2)\n// ---------------------------------------------------------------------------\n\nconst regionNames = new Intl.DisplayNames(['en'], { type: 'region' });\n\nfunction codeToFlag(code: string): string {\n return [...code.toUpperCase()]\n .map((c) => String.fromCodePoint(0x1f1e6 - 65 + c.charCodeAt(0)))\n .join('');\n}\n\n/** Priority countries shown first in dropdowns. */\nconst PRIORITY_CODES = ['US', 'GB', 'CA', 'AU', 'NZ', 'IE', 'DE', 'FR'];\n\nconst ALL_CODES = [\n 'AD', 'AE', 'AF', 'AG', 'AL', 'AM', 'AO', 'AR', 'AT', 'AU',\n 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ',\n 'BN', 'BO', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CD',\n 'CF', 'CG', 'CH', 'CI', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU',\n 'CV', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC',\n 'EE', 'EG', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FM', 'FR', 'GA',\n 'GB', 'GD', 'GE', 'GH', 'GM', 'GN', 'GQ', 'GR', 'GT', 'GW',\n 'GY', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IN', 'IQ',\n 'IR', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI',\n 'KM', 'KN', 'KR', 'KW', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK',\n 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME',\n 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MR', 'MT', 'MU', 'MV',\n 'MW', 'MX', 'MY', 'MZ', 'NA', 'NE', 'NG', 'NI', 'NL', 'NO',\n 'NP', 'NR', 'NZ', 'OM', 'PA', 'PE', 'PG', 'PH', 'PK', 'PL',\n 'PT', 'PW', 'PY', 'QA', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB',\n 'SC', 'SD', 'SE', 'SG', 'SI', 'SK', 'SL', 'SM', 'SN', 'SO',\n 'SR', 'SS', 'ST', 'SV', 'SY', 'SZ', 'TD', 'TG', 'TH', 'TJ',\n 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA',\n 'UG', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VN', 'VU', 'WS',\n 'XK', 'YE', 'ZA', 'ZM', 'ZW',\n] as const;\n\nfunction buildCountryOption(code: string): CountryOption {\n return { code, name: regionNames.of(code) ?? code, flag: codeToFlag(code) };\n}\n\nconst prioritySet = new Set(PRIORITY_CODES);\nconst rest = ALL_CODES.filter((c) => !prioritySet.has(c));\n\n/** All countries for dropdown select, priority countries first. */\nexport const COUNTRY_OPTIONS: CountryOption[] = [\n ...PRIORITY_CODES.map(buildCountryOption),\n ...rest.map(buildCountryOption),\n];\n\n/** Look up a country option by ISO 3166-1 alpha-2 code. */\nexport function getCountryByCode(code: string): CountryOption | undefined {\n return COUNTRY_OPTIONS.find((c) => c.code === code);\n}\n\n// ---------------------------------------------------------------------------\n// AVS Configuration Helpers\n// ---------------------------------------------------------------------------\n\n/** Default AVS config when `enableAVS: true` (backward compatible — country + postal code). */\nconst DEFAULT_AVS_CONFIG: AVSFieldConfig = {\n country: true,\n postal_code: true,\n};\n\n/**\n * Normalize `enableAVS` to a resolved config object.\n * - `false` / `undefined` → `null` (AVS disabled)\n * - `true` → default config (country + postal_code)\n * - `AVSFieldConfig` → returned as-is\n */\nexport function resolveAVSConfig(enableAVS?: boolean | AVSFieldConfig): AVSFieldConfig | null {\n if (!enableAVS) return null;\n if (enableAVS === true) return DEFAULT_AVS_CONFIG;\n return enableAVS;\n}\n\n/**\n * Check if an AVS field should be visible for the given country.\n * - `undefined` / `false` → hidden\n * - `true` → visible for all countries\n * - `string[]` → visible only for listed country codes\n */\nexport function isAVSFieldVisible(\n field: boolean | string[] | undefined,\n country: string,\n): boolean {\n if (field === undefined || field === false) return false;\n if (field === true) return true;\n const normalizedCountry = country.trim().toUpperCase();\n return field.some((code) => code.trim().toUpperCase() === normalizedCountry);\n}\n\n/** Returns true if any AVS field is meaningfully configured (at least one field is truthy). */\nexport function isAVSEnabled(enableAVS?: boolean | AVSFieldConfig): boolean {\n const config = resolveAVSConfig(enableAVS);\n if (!config) return false;\n return Object.values(config).some(\n (v) => v === true || (Array.isArray(v) && v.length > 0),\n );\n}\n\n// ---------------------------------------------------------------------------\n// US States & CA Provinces\n// ---------------------------------------------------------------------------\n\nexport interface StateOption {\n code: string;\n name: string;\n}\n\nexport const US_STATES: StateOption[] = [\n { code: 'AL', name: 'Alabama' },\n { code: 'AK', name: 'Alaska' },\n { code: 'AZ', name: 'Arizona' },\n { code: 'AR', name: 'Arkansas' },\n { code: 'CA', name: 'California' },\n { code: 'CO', name: 'Colorado' },\n { code: 'CT', name: 'Connecticut' },\n { code: 'DE', name: 'Delaware' },\n { code: 'DC', name: 'District of Columbia' },\n { code: 'FL', name: 'Florida' },\n { code: 'GA', name: 'Georgia' },\n { code: 'HI', name: 'Hawaii' },\n { code: 'ID', name: 'Idaho' },\n { code: 'IL', name: 'Illinois' },\n { code: 'IN', name: 'Indiana' },\n { code: 'IA', name: 'Iowa' },\n { code: 'KS', name: 'Kansas' },\n { code: 'KY', name: 'Kentucky' },\n { code: 'LA', name: 'Louisiana' },\n { code: 'ME', name: 'Maine' },\n { code: 'MD', name: 'Maryland' },\n { code: 'MA', name: 'Massachusetts' },\n { code: 'MI', name: 'Michigan' },\n { code: 'MN', name: 'Minnesota' },\n { code: 'MS', name: 'Mississippi' },\n { code: 'MO', name: 'Missouri' },\n { code: 'MT', name: 'Montana' },\n { code: 'NE', name: 'Nebraska' },\n { code: 'NV', name: 'Nevada' },\n { code: 'NH', name: 'New Hampshire' },\n { code: 'NJ', name: 'New Jersey' },\n { code: 'NM', name: 'New Mexico' },\n { code: 'NY', name: 'New York' },\n { code: 'NC', name: 'North Carolina' },\n { code: 'ND', name: 'North Dakota' },\n { code: 'OH', name: 'Ohio' },\n { code: 'OK', name: 'Oklahoma' },\n { code: 'OR', name: 'Oregon' },\n { code: 'PA', name: 'Pennsylvania' },\n { code: 'RI', name: 'Rhode Island' },\n { code: 'SC', name: 'South Carolina' },\n { code: 'SD', name: 'South Dakota' },\n { code: 'TN', name: 'Tennessee' },\n { code: 'TX', name: 'Texas' },\n { code: 'UT', name: 'Utah' },\n { code: 'VT', name: 'Vermont' },\n { code: 'VA', name: 'Virginia' },\n { code: 'WA', name: 'Washington' },\n { code: 'WV', name: 'West Virginia' },\n { code: 'WI', name: 'Wisconsin' },\n { code: 'WY', name: 'Wyoming' },\n];\n\nexport const CA_PROVINCES: StateOption[] = [\n { code: 'AB', name: 'Alberta' },\n { code: 'BC', name: 'British Columbia' },\n { code: 'MB', name: 'Manitoba' },\n { code: 'NB', name: 'New Brunswick' },\n { code: 'NL', name: 'Newfoundland and Labrador' },\n { code: 'NS', name: 'Nova Scotia' },\n { code: 'NT', name: 'Northwest Territories' },\n { code: 'NU', name: 'Nunavut' },\n { code: 'ON', name: 'Ontario' },\n { code: 'PE', name: 'Prince Edward Island' },\n { code: 'QC', name: 'Quebec' },\n { code: 'SK', name: 'Saskatchewan' },\n { code: 'YT', name: 'Yukon' },\n];\n\n/**\n * Get state/province options for a country.\n * Returns a list for US and CA, or `null` for countries where a free-text input is appropriate.\n */\nexport function getStateOptions(country: string): StateOption[] | null {\n switch (country.toUpperCase()) {\n case 'US': return US_STATES;\n case 'CA': return CA_PROVINCES;\n default: return null;\n }\n}\n\n/** Returns the appropriate label for the state/province field based on country. */\nexport function getStateLabel(countryCode: string): string {\n switch (countryCode.toUpperCase()) {\n case 'US': return 'State';\n case 'CA': return 'Province';\n case 'GB': return 'County';\n case 'AU': return 'State / Territory';\n default: return 'State / Province / Region';\n }\n}\n","/**\n * Postal-code → state derivation for AVS.\n *\n * Used when the form configuration shows `address_line_1` but hides the\n * `state` input — we still want to populate `billing_details.address.state`\n * so Stripe Radar gets a richer address signal. Currently supports US and CA;\n * other countries return `null` (caller should fall back to omitting state).\n */\n\n/**\n * US 3-digit ZIP-prefix ranges → state code (USPS Sectional Center Facility).\n * Sourced from the public USPS SCF table. Each entry is `[startPrefix, endPrefix, stateCode]`,\n * inclusive on both ends. Coverage is contiguous within a state; gaps in the table\n * (e.g. unused 3-digit prefixes) are intentional and resolve to `null`.\n */\nconst US_ZIP_PREFIX_RANGES: ReadonlyArray<readonly [number, number, string]> = [\n [5, 5, 'NY'],\n [10, 27, 'MA'],\n [28, 29, 'RI'],\n [30, 38, 'NH'],\n [39, 49, 'ME'],\n [50, 59, 'VT'],\n [60, 69, 'CT'],\n [70, 89, 'NJ'],\n [100, 149, 'NY'],\n [150, 196, 'PA'],\n [197, 199, 'DE'],\n [200, 205, 'DC'],\n [206, 219, 'MD'],\n [220, 246, 'VA'],\n [247, 268, 'WV'],\n [270, 289, 'NC'],\n [290, 299, 'SC'],\n [300, 319, 'GA'],\n [320, 349, 'FL'],\n [350, 369, 'AL'],\n [370, 385, 'TN'],\n [386, 397, 'MS'],\n [398, 399, 'GA'],\n [400, 427, 'KY'],\n [430, 459, 'OH'],\n [460, 479, 'IN'],\n [480, 499, 'MI'],\n [500, 528, 'IA'],\n [530, 549, 'WI'],\n [550, 567, 'MN'],\n [570, 577, 'SD'],\n [580, 588, 'ND'],\n [590, 599, 'MT'],\n [600, 629, 'IL'],\n [630, 658, 'MO'],\n [660, 679, 'KS'],\n [680, 693, 'NE'],\n [700, 714, 'LA'],\n [716, 729, 'AR'],\n [730, 749, 'OK'],\n [750, 799, 'TX'],\n [800, 816, 'CO'],\n [820, 831, 'WY'],\n [832, 838, 'ID'],\n [840, 847, 'UT'],\n [850, 865, 'AZ'],\n [870, 884, 'NM'],\n [889, 898, 'NV'],\n [900, 961, 'CA'],\n [967, 968, 'HI'],\n [970, 979, 'OR'],\n [980, 994, 'WA'],\n [995, 999, 'AK'],\n];\n\n/**\n * CA postal-code first letter → province code (Forward Sortation Area).\n * The first letter of every Canadian postal code identifies the province\n * uniquely, except `X` which is shared by Northwest Territories and Nunavut\n * — we resolve it to `NT` because the volume strongly favours NT.\n */\nconst CA_FSA_FIRST_LETTER_TO_PROVINCE: Readonly<Record<string, string>> = {\n A: 'NL',\n B: 'NS',\n C: 'PE',\n E: 'NB',\n G: 'QC',\n H: 'QC',\n J: 'QC',\n K: 'ON',\n L: 'ON',\n M: 'ON',\n N: 'ON',\n P: 'ON',\n R: 'MB',\n S: 'SK',\n T: 'AB',\n V: 'BC',\n X: 'NT',\n Y: 'YT',\n};\n\nfunction deriveUsState(zip: string): string | null {\n const digits = zip.replace(/\\D/g, '');\n if (digits.length < 5) return null;\n const prefix = Number.parseInt(digits.slice(0, 3), 10);\n if (!Number.isFinite(prefix)) return null;\n\n for (const [start, end, code] of US_ZIP_PREFIX_RANGES) {\n if (prefix >= start && prefix <= end) return code;\n }\n return null;\n}\n\nfunction deriveCaProvince(postalCode: string): string | null {\n const compact = postalCode.replace(/\\s+/g, '').toUpperCase();\n if (!/^[A-Z]\\d[A-Z]\\d[A-Z]\\d$/.test(compact)) return null;\n const firstLetter = compact[0] ?? '';\n return CA_FSA_FIRST_LETTER_TO_PROVINCE[firstLetter] ?? null;\n}\n\n/**\n * Resolve a state / province code from a postal code for the given country.\n *\n * - US: 5-digit ZIP → 2-letter USPS state code (uses 3-digit prefix table).\n * - CA: A1A 1A1 → 2-letter ISO 3166-2:CA province code (first-letter mapping).\n * - All other countries: `null`.\n *\n * Returns `null` when the postal code is malformed or falls in an unmapped\n * range. Callers should treat `null` as \"skip — don't derive\".\n */\nexport function getStateFromPostalCode(\n country: string,\n postalCode: string,\n): string | null {\n if (!country || !postalCode) return null;\n const normalizedCountry = country.trim().toUpperCase();\n const normalizedZip = postalCode.trim();\n if (!normalizedZip) return null;\n\n switch (normalizedCountry) {\n case 'US':\n return deriveUsState(normalizedZip);\n case 'CA':\n return deriveCaProvince(normalizedZip);\n default:\n return null;\n }\n}\n","import type { CheckoutItem, CheckoutSubscription } from './types.js';\n\n/**\n * Return the trimmed string when it has at least one non-whitespace character,\n * otherwise undefined. Used so that empty and whitespace-only inputs flow\n * through the same fallback chain as `undefined`.\n */\nfunction nonBlank(value: string | null | undefined): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Resolve the session-level currency, honoring the documented fallback:\n * `session.currency ?? items[*].currency ?? subscriptions[*].currency`.\n *\n * Returns the first non-blank currency found, or 'USD' when nothing is set.\n * Empty and whitespace-only strings are treated as unset so they do not\n * bypass the fallback chain.\n */\nexport function resolveSessionCurrency(\n sessionCurrency: string | undefined,\n items: ReadonlyArray<{ currency?: string }> | undefined,\n subscriptions: ReadonlyArray<{ currency?: string }> | undefined,\n): string {\n const session = nonBlank(sessionCurrency);\n if (session) return session;\n for (const item of items ?? []) {\n const c = nonBlank(item.currency);\n if (c) return c;\n }\n for (const sub of subscriptions ?? []) {\n const c = nonBlank(sub.currency);\n if (c) return c;\n }\n return 'USD';\n}\n\n/**\n * Build the request payload for a single item.\n *\n * Sends the new `code` field alongside the deprecated `providerItemId`,\n * `providerItemName`, `totalAmount`, and `overrideAmount` fields so that\n * both new and old backend versions accept the same request body.\n */\nexport function buildItemPayload(\n item: CheckoutItem,\n sessionCurrency: string,\n): Record<string, unknown> {\n const code = nonBlank(item.code) ?? nonBlank(item.providerItemId);\n if (!code) {\n throw new Error('CheckoutItem requires either `code` or the deprecated `providerItemId`.');\n }\n const itemName = nonBlank(item.itemName) ?? nonBlank(item.providerItemName) ?? null;\n\n const payload: Record<string, unknown> = {\n code,\n providerItemId: nonBlank(item.providerItemId) ?? code,\n itemName,\n providerItemName: nonBlank(item.providerItemName) ?? itemName,\n quantity: item.quantity ?? 1,\n totalAmount: item.totalAmount,\n overrideAmount: item.overrideAmount ?? null,\n currency: nonBlank(item.currency) ?? sessionCurrency,\n };\n\n if (item.metadata) {\n payload['metadata'] = item.metadata;\n }\n\n return payload;\n}\n\n/**\n * Build the request payload for a single subscription.\n *\n * Sends the new `code` field alongside the deprecated `providerPlanId`,\n * `providerPlanName`, `totalAmount`, and `overrideAmount` fields for\n * backward compatibility.\n */\nexport function buildSubscriptionPayload(\n subscription: CheckoutSubscription,\n sessionCurrency: string,\n): Record<string, unknown> {\n const code = nonBlank(subscription.code) ?? nonBlank(subscription.providerPlanId);\n if (!code) {\n throw new Error(\n 'CheckoutSubscription requires either `code` or the deprecated `providerPlanId`.',\n );\n }\n const subscriptionName =\n nonBlank(subscription.subscriptionName) ?? nonBlank(subscription.providerPlanName) ?? null;\n\n const payload: Record<string, unknown> = {\n code,\n providerPlanId: nonBlank(subscription.providerPlanId) ?? code,\n subscriptionName,\n providerPlanName: nonBlank(subscription.providerPlanName) ?? subscriptionName,\n quantity: subscription.quantity ?? 1,\n totalAmount: subscription.totalAmount,\n overrideAmount: subscription.overrideAmount ?? null,\n currency: nonBlank(subscription.currency) ?? sessionCurrency,\n };\n\n if (subscription.metadata) {\n payload['metadata'] = subscription.metadata;\n }\n\n return payload;\n}\n","import { resolveSessionCurrency } from './checkout-payload.js';\nimport type { CheckoutSession } from './types.js';\n\n/** A single line item formatted for display in the checkout UI. */\nexport interface DisplayLineItem {\n name: string;\n quantity: number;\n /** Price per unit in the session's currency (major units, e.g. 24.95). */\n price: number;\n /** Original price per unit before any discount (major units). */\n originalPrice: number;\n}\n\n/** Computed display data for rendering an order summary. */\nexport interface CheckoutDisplayData {\n /** Individual items/subscriptions with names, prices, and quantities. */\n items: DisplayLineItem[];\n /** ISO 4217 currency code (uppercase). */\n currency: string;\n /** Total amount due after discounts (major units, e.g. 24.95). */\n total: number;\n /** Sum of original prices before discounts (major units). */\n originalTotal: number;\n /** Total savings (originalTotal - total), clamped to >= 0. */\n totalSave: number;\n /** Discount percentage (0–100). */\n discountPercent: number;\n}\n\n/** Options for {@link buildCheckoutDisplayData}. */\nexport interface BuildCheckoutDisplayDataOptions {\n /**\n * When `true`, items are hidden from the order summary if the session also\n * contains subscriptions (matches the legacy checkout/CheckoutModal\n * behavior). Defaults to `false` — items are always shown.\n */\n hideBundledItems?: boolean;\n}\n\n/**\n * Builds display data from a `CheckoutSession` for rendering an order summary.\n *\n * - Subscriptions are always shown\n * - Items are shown by default; pass `{ hideBundledItems: true }` to suppress\n * them when the session also contains subscriptions (legacy behavior)\n * - `overrideAmount` (when not null/undefined) is the discounted price\n * - Plan name \"4-WEEK PLAN\" with price <= 1 is renamed to \"7-DAY TRIAL: FULL ACCESS\"\n * - Discount percentage and savings are computed from the difference\n *\n * All amounts are in **major currency units** (dollars, not cents).\n *\n * @example\n * ```ts\n * import { buildCheckoutDisplayData } from '@flopay/shared';\n *\n * const display = buildCheckoutDisplayData(session);\n * // display.items → [{ name: 'Starter', price: 24.95, originalPrice: 24.95, quantity: 1 }]\n * // display.total → 24.95\n * // display.currency → 'EUR'\n * ```\n */\nexport function buildCheckoutDisplayData(\n session: CheckoutSession,\n options: BuildCheckoutDisplayDataOptions = {},\n): CheckoutDisplayData {\n const itemsList: DisplayLineItem[] = [];\n\n const subscriptions = session.subscriptions ?? [];\n const items = session.items ?? [];\n\n // Resolve currency once: session > first item > first subscription > USD.\n const currency = resolveSessionCurrency(session.currency, items, subscriptions).toUpperCase();\n\n // Subscriptions\n for (const sub of subscriptions) {\n const originalPrice = sub.totalAmount ?? 0;\n const discountedPrice = sub.overrideAmount ?? originalPrice;\n\n // Match checkout/CheckoutModal: rename \"4-WEEK PLAN\" to \"7-DAY TRIAL: FULL ACCESS\"\n // when the discounted price is $1 or less\n let name = sub.subscriptionName || sub.providerPlanName || sub.code || 'Subscription';\n if (name === '4-WEEK PLAN' && discountedPrice <= 1) {\n name = '7-DAY TRIAL: FULL ACCESS';\n }\n\n itemsList.push({\n name,\n quantity: sub.quantity,\n price: discountedPrice,\n originalPrice,\n });\n }\n\n // Items are shown by default. Opt-in `hideBundledItems` hides them when\n // the session also contains subscriptions (legacy checkout/CheckoutModal\n // behavior).\n const hideItems =\n options.hideBundledItems === true\n && subscriptions.length > 0\n && items.length > 0;\n\n if (!hideItems) {\n for (const item of items) {\n const originalPrice = item.totalAmount ?? 0;\n const discountedPrice = item.overrideAmount ?? originalPrice;\n\n itemsList.push({\n name: item.itemName || item.providerItemName || item.code || 'Item',\n quantity: item.quantity,\n price: discountedPrice,\n originalPrice,\n });\n }\n }\n\n // Fallback if session has no items/subscriptions\n if (itemsList.length === 0) {\n itemsList.push({\n name: 'Purchase',\n quantity: 1,\n price: session.amount / 100,\n originalPrice: session.amount / 100,\n });\n }\n\n const originalTotal = itemsList.reduce((sum, i) => sum + i.originalPrice * i.quantity, 0);\n const total = itemsList.reduce((sum, i) => sum + i.price * i.quantity, 0);\n const totalSave = Math.max(0, originalTotal - total);\n const discountPercent = originalTotal > 0\n ? Math.round((totalSave / originalTotal) * 100)\n : 0;\n\n return {\n items: itemsList,\n currency,\n total,\n originalTotal,\n totalSave,\n discountPercent,\n };\n}\n","import type { CurrencyInfo } from './types.js';\nimport { CURRENCY_MAP, DEFAULT_CURRENCY } from './constants.js';\n\n/**\n * Look up currency information by ISO 3166-1 alpha-2 country code.\n * Falls back to USD when the country is not in the map.\n */\nexport function getCurrencyByCountry(countryCode: string): CurrencyInfo {\n return CURRENCY_MAP[countryCode.toUpperCase()] ?? DEFAULT_CURRENCY;\n}\n\n/** Returns `true` if the string looks like a Stripe publishable key. */\nexport function isValidPublishableKey(key: string): boolean {\n return /^pk_(test|live)_[A-Za-z0-9]+$/.test(key);\n}\n\n/** Returns `true` if the string looks like a Stripe secret key. */\nexport function isValidSecretKey(key: string): boolean {\n return /^sk_(test|live)_[A-Za-z0-9]+$/.test(key);\n}\n"],"mappings":"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A,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAC1B;AAEA,SAAS,mBAAmB,MAA6B;AACvD,SAAO,EAAE,MAAM,MAAM,YAAY,GAAG,IAAI,KAAK,MAAM,MAAM,WAAW,IAAI,EAAE;AAC5E;AAEA,IAAM,cAAc,IAAI,IAAI,cAAc;AAC1C,IAAM,OAAO,UAAU,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC;AAGjD,IAAM,kBAAmC;AAAA,EAC9C,GAAG,eAAe,IAAI,kBAAkB;AAAA,EACxC,GAAG,KAAK,IAAI,kBAAkB;AAChC;AAGO,SAAS,iBAAiB,MAAyC;AACxE,SAAO,gBAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AACpD;AAOA,IAAM,qBAAqC;AAAA,EACzC,SAAS;AAAA,EACT,aAAa;AACf;AAQO,SAAS,iBAAiB,WAA6D;AAC5F,MAAI,CAAC,UAAW,QAAO;AACvB,MAAI,cAAc,KAAM,QAAO;AAC/B,SAAO;AACT;AAQO,SAAS,kBACd,OACA,SACS;AACT,MAAI,UAAU,UAAa,UAAU,MAAO,QAAO;AACnD,MAAI,UAAU,KAAM,QAAO;AAC3B,QAAM,oBAAoB,QAAQ,KAAK,EAAE,YAAY;AACrD,SAAO,MAAM,KAAK,CAAC,SAAS,KAAK,KAAK,EAAE,YAAY,MAAM,iBAAiB;AAC7E;AAGO,SAAS,aAAa,WAA+C;AAC1E,QAAM,SAAS,iBAAiB,SAAS;AACzC,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,OAAO,OAAO,MAAM,EAAE;AAAA,IAC3B,CAAC,MAAM,MAAM,QAAS,MAAM,QAAQ,CAAC,KAAK,EAAE,SAAS;AAAA,EACvD;AACF;AAWO,IAAM,YAA2B;AAAA,EACtC,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,SAAS;AAAA,EAC7B,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,aAAa;AAAA,EACjC,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,cAAc;AAAA,EAClC,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,uBAAuB;AAAA,EAC3C,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,SAAS;AAAA,EAC7B,EAAE,MAAM,MAAM,MAAM,QAAQ;AAAA,EAC5B,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,OAAO;AAAA,EAC3B,EAAE,MAAM,MAAM,MAAM,SAAS;AAAA,EAC7B,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,YAAY;AAAA,EAChC,EAAE,MAAM,MAAM,MAAM,QAAQ;AAAA,EAC5B,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,gBAAgB;AAAA,EACpC,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,YAAY;AAAA,EAChC,EAAE,MAAM,MAAM,MAAM,cAAc;AAAA,EAClC,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,SAAS;AAAA,EAC7B,EAAE,MAAM,MAAM,MAAM,gBAAgB;AAAA,EACpC,EAAE,MAAM,MAAM,MAAM,aAAa;AAAA,EACjC,EAAE,MAAM,MAAM,MAAM,aAAa;AAAA,EACjC,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,iBAAiB;AAAA,EACrC,EAAE,MAAM,MAAM,MAAM,eAAe;AAAA,EACnC,EAAE,MAAM,MAAM,MAAM,OAAO;AAAA,EAC3B,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,SAAS;AAAA,EAC7B,EAAE,MAAM,MAAM,MAAM,eAAe;AAAA,EACnC,EAAE,MAAM,MAAM,MAAM,eAAe;AAAA,EACnC,EAAE,MAAM,MAAM,MAAM,iBAAiB;AAAA,EACrC,EAAE,MAAM,MAAM,MAAM,eAAe;AAAA,EACnC,EAAE,MAAM,MAAM,MAAM,YAAY;AAAA,EAChC,EAAE,MAAM,MAAM,MAAM,QAAQ;AAAA,EAC5B,EAAE,MAAM,MAAM,MAAM,OAAO;AAAA,EAC3B,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,aAAa;AAAA,EACjC,EAAE,MAAM,MAAM,MAAM,gBAAgB;AAAA,EACpC,EAAE,MAAM,MAAM,MAAM,YAAY;AAAA,EAChC,EAAE,MAAM,MAAM,MAAM,UAAU;AAChC;AAEO,IAAM,eAA8B;AAAA,EACzC,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,mBAAmB;AAAA,EACvC,EAAE,MAAM,MAAM,MAAM,WAAW;AAAA,EAC/B,EAAE,MAAM,MAAM,MAAM,gBAAgB;AAAA,EACpC,EAAE,MAAM,MAAM,MAAM,4BAA4B;AAAA,EAChD,EAAE,MAAM,MAAM,MAAM,cAAc;AAAA,EAClC,EAAE,MAAM,MAAM,MAAM,wBAAwB;AAAA,EAC5C,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,EAC9B,EAAE,MAAM,MAAM,MAAM,uBAAuB;AAAA,EAC3C,EAAE,MAAM,MAAM,MAAM,SAAS;AAAA,EAC7B,EAAE,MAAM,MAAM,MAAM,eAAe;AAAA,EACnC,EAAE,MAAM,MAAM,MAAM,QAAQ;AAC9B;AAMO,SAAS,gBAAgB,SAAuC;AACrE,UAAQ,QAAQ,YAAY,GAAG;AAAA,IAC7B,KAAK;AAAM,aAAO;AAAA,IAClB,KAAK;AAAM,aAAO;AAAA,IAClB;AAAS,aAAO;AAAA,EAClB;AACF;AAGO,SAAS,cAAc,aAA6B;AACzD,UAAQ,YAAY,YAAY,GAAG;AAAA,IACjC,KAAK;AAAM,aAAO;AAAA,IAClB,KAAK;AAAM,aAAO;AAAA,IAClB,KAAK;AAAM,aAAO;AAAA,IAClB,KAAK;AAAM,aAAO;AAAA,IAClB;AAAS,aAAO;AAAA,EAClB;AACF;;;AC1eA,IAAM,uBAAyE;AAAA,EAC7E,CAAC,GAAG,GAAG,IAAI;AAAA,EACX,CAAC,IAAI,IAAI,IAAI;AAAA,EACb,CAAC,IAAI,IAAI,IAAI;AAAA,EACb,CAAC,IAAI,IAAI,IAAI;AAAA,EACb,CAAC,IAAI,IAAI,IAAI;AAAA,EACb,CAAC,IAAI,IAAI,IAAI;AAAA,EACb,CAAC,IAAI,IAAI,IAAI;AAAA,EACb,CAAC,IAAI,IAAI,IAAI;AAAA,EACb,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AACjB;AAQA,IAAM,kCAAoE;AAAA,EACxE,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEA,SAAS,cAAc,KAA4B;AACjD,QAAM,SAAS,IAAI,QAAQ,OAAO,EAAE;AACpC,MAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,QAAM,SAAS,OAAO,SAAS,OAAO,MAAM,GAAG,CAAC,GAAG,EAAE;AACrD,MAAI,CAAC,OAAO,SAAS,MAAM,EAAG,QAAO;AAErC,aAAW,CAAC,OAAO,KAAK,IAAI,KAAK,sBAAsB;AACrD,QAAI,UAAU,SAAS,UAAU,IAAK,QAAO;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,YAAmC;AAC3D,QAAM,UAAU,WAAW,QAAQ,QAAQ,EAAE,EAAE,YAAY;AAC3D,MAAI,CAAC,0BAA0B,KAAK,OAAO,EAAG,QAAO;AACrD,QAAM,cAAc,QAAQ,CAAC,KAAK;AAClC,SAAO,gCAAgC,WAAW,KAAK;AACzD;AAYO,SAAS,uBACd,SACA,YACe;AACf,MAAI,CAAC,WAAW,CAAC,WAAY,QAAO;AACpC,QAAM,oBAAoB,QAAQ,KAAK,EAAE,YAAY;AACrD,QAAM,gBAAgB,WAAW,KAAK;AACtC,MAAI,CAAC,cAAe,QAAO;AAE3B,UAAQ,mBAAmB;AAAA,IACzB,KAAK;AACH,aAAO,cAAc,aAAa;AAAA,IACpC,KAAK;AACH,aAAO,iBAAiB,aAAa;AAAA,IACvC;AACE,aAAO;AAAA,EACX;AACF;;;ACzIA,SAAS,SAAS,OAAsD;AACtE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;AAUO,SAAS,uBACd,iBACA,OACA,eACQ;AACR,QAAM,UAAU,SAAS,eAAe;AACxC,MAAI,QAAS,QAAO;AACpB,aAAW,QAAQ,SAAS,CAAC,GAAG;AAC9B,UAAM,IAAI,SAAS,KAAK,QAAQ;AAChC,QAAI,EAAG,QAAO;AAAA,EAChB;AACA,aAAW,OAAO,iBAAiB,CAAC,GAAG;AACrC,UAAM,IAAI,SAAS,IAAI,QAAQ;AAC/B,QAAI,EAAG,QAAO;AAAA,EAChB;AACA,SAAO;AACT;AASO,SAAS,iBACd,MACA,iBACyB;AACzB,QAAM,OAAO,SAAS,KAAK,IAAI,KAAK,SAAS,KAAK,cAAc;AAChE,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,yEAAyE;AAAA,EAC3F;AACA,QAAM,WAAW,SAAS,KAAK,QAAQ,KAAK,SAAS,KAAK,gBAAgB,KAAK;AAE/E,QAAM,UAAmC;AAAA,IACvC;AAAA,IACA,gBAAgB,SAAS,KAAK,cAAc,KAAK;AAAA,IACjD;AAAA,IACA,kBAAkB,SAAS,KAAK,gBAAgB,KAAK;AAAA,IACrD,UAAU,KAAK,YAAY;AAAA,IAC3B,aAAa,KAAK;AAAA,IAClB,gBAAgB,KAAK,kBAAkB;AAAA,IACvC,UAAU,SAAS,KAAK,QAAQ,KAAK;AAAA,EACvC;AAEA,MAAI,KAAK,UAAU;AACjB,YAAQ,UAAU,IAAI,KAAK;AAAA,EAC7B;AAEA,SAAO;AACT;AASO,SAAS,yBACd,cACA,iBACyB;AACzB,QAAM,OAAO,SAAS,aAAa,IAAI,KAAK,SAAS,aAAa,cAAc;AAChF,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,mBACJ,SAAS,aAAa,gBAAgB,KAAK,SAAS,aAAa,gBAAgB,KAAK;AAExF,QAAM,UAAmC;AAAA,IACvC;AAAA,IACA,gBAAgB,SAAS,aAAa,cAAc,KAAK;AAAA,IACzD;AAAA,IACA,kBAAkB,SAAS,aAAa,gBAAgB,KAAK;AAAA,IAC7D,UAAU,aAAa,YAAY;AAAA,IACnC,aAAa,aAAa;AAAA,IAC1B,gBAAgB,aAAa,kBAAkB;AAAA,IAC/C,UAAU,SAAS,aAAa,QAAQ,KAAK;AAAA,EAC/C;AAEA,MAAI,aAAa,UAAU;AACzB,YAAQ,UAAU,IAAI,aAAa;AAAA,EACrC;AAEA,SAAO;AACT;;;ACjDO,SAAS,yBACd,SACA,UAA2C,CAAC,GACvB;AACrB,QAAM,YAA+B,CAAC;AAEtC,QAAM,gBAAgB,QAAQ,iBAAiB,CAAC;AAChD,QAAM,QAAQ,QAAQ,SAAS,CAAC;AAGhC,QAAM,WAAW,uBAAuB,QAAQ,UAAU,OAAO,aAAa,EAAE,YAAY;AAG5F,aAAW,OAAO,eAAe;AAC/B,UAAM,gBAAgB,IAAI,eAAe;AACzC,UAAM,kBAAkB,IAAI,kBAAkB;AAI9C,QAAI,OAAO,IAAI,oBAAoB,IAAI,oBAAoB,IAAI,QAAQ;AACvE,QAAI,SAAS,iBAAiB,mBAAmB,GAAG;AAClD,aAAO;AAAA,IACT;AAEA,cAAU,KAAK;AAAA,MACb;AAAA,MACA,UAAU,IAAI;AAAA,MACd,OAAO;AAAA,MACP;AAAA,IACF,CAAC;AAAA,EACH;AAKA,QAAM,YACJ,QAAQ,qBAAqB,QAC1B,cAAc,SAAS,KACvB,MAAM,SAAS;AAEpB,MAAI,CAAC,WAAW;AACd,eAAW,QAAQ,OAAO;AACxB,YAAM,gBAAgB,KAAK,eAAe;AAC1C,YAAM,kBAAkB,KAAK,kBAAkB;AAE/C,gBAAU,KAAK;AAAA,QACb,MAAM,KAAK,YAAY,KAAK,oBAAoB,KAAK,QAAQ;AAAA,QAC7D,UAAU,KAAK;AAAA,QACf,OAAO;AAAA,QACP;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,UAAU,WAAW,GAAG;AAC1B,cAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,UAAU;AAAA,MACV,OAAO,QAAQ,SAAS;AAAA,MACxB,eAAe,QAAQ,SAAS;AAAA,IAClC,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,gBAAgB,EAAE,UAAU,CAAC;AACxF,QAAM,QAAQ,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC;AACxE,QAAM,YAAY,KAAK,IAAI,GAAG,gBAAgB,KAAK;AACnD,QAAM,kBAAkB,gBAAgB,IACpC,KAAK,MAAO,YAAY,gBAAiB,GAAG,IAC5C;AAEJ,SAAO;AAAA,IACL,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACrIO,SAAS,qBAAqB,aAAmC;AACtE,SAAO,aAAa,YAAY,YAAY,CAAC,KAAK;AACpD;AAGO,SAAS,sBAAsB,KAAsB;AAC1D,SAAO,gCAAgC,KAAK,GAAG;AACjD;AAGO,SAAS,iBAAiB,KAAsB;AACrD,SAAO,gCAAgC,KAAK,GAAG;AACjD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/errors.ts","../src/config.ts","../src/constants.ts","../src/postal-code-lookup.ts","../src/checkout-payload.ts","../src/display.ts","../src/validation.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Appearance / Theming\n// ---------------------------------------------------------------------------\n\n/** Theme variables that map to CSS custom properties on FloPay elements. */\nexport interface FloPayThemeVariables {\n colorPrimary?: string;\n colorBackground?: string;\n colorText?: string;\n colorDanger?: string;\n borderRadius?: string;\n fontFamily?: string;\n fontSizeBase?: string;\n spacingUnit?: string;\n}\n\n/** Controls the visual appearance of all FloPay elements. */\nexport interface FloPayAppearance {\n theme?: 'default' | 'flat' | 'night' | 'none';\n variables?: FloPayThemeVariables;\n /** CSS-like rules keyed by selector (e.g. `\".Input\"`, `\".Label\"`). */\n rules?: Record<string, Record<string, string>>;\n}\n\n/** Style overrides for the `buttons` layout mode. */\nexport interface ButtonsLayoutStyles {\n /** Style for the \"Credit / Debit Card\" button. */\n cardButton?: Record<string, string | number>;\n /** Font size for the \"Credit / Debit Card\" button label. */\n cardButtonFontSize?: string;\n /** Style for the card form container when expanded. */\n cardFormContainer?: Record<string, string | number>;\n /** Border color for card input fields. */\n cardInputBorder?: string;\n /** Text color inside Stripe card input fields (number, expiry, CVC). */\n cardInputColor?: string;\n /** Placeholder text color for Stripe card input fields. */\n cardInputPlaceholderColor?: string;\n /** Font size for Stripe card input fields. */\n cardInputFontSize?: string;\n /** Background color for card input fields. */\n cardInputBackground?: string;\n /** Style for the full-name text input. */\n nameInput?: Record<string, string | number>;\n /** Style for the \"Go back\" button text/container. */\n backButton?: Record<string, string | number>;\n /** Font size for the \"Go back\" button label. */\n backButtonFontSize?: string;\n /** Style for the back button circle icon. */\n backButtonIcon?: Record<string, string | number>;\n /** Style for the submit/confirm button. */\n submitButton?: Record<string, string | number>;\n /** Font size for the submit button label. */\n submitButtonFontSize?: string;\n /** Style for the \"Secure card checkout\" title. */\n title?: Record<string, string | number>;\n /** Font size for the \"Secure card checkout\" title. */\n titleFontSize?: string;\n /** Style for the error banner. */\n errorBanner?: Record<string, string | number>;\n /** Style for the country select dropdown container (AVS). */\n countrySelect?: Record<string, string | number>;\n /** Style for the ZIP/postcode input container (AVS). */\n zipInput?: Record<string, string | number>;\n /** Style for the street address input (AVS address_line_1). */\n addressLine1Input?: Record<string, string | number>;\n /** Style for the apt/suite input (AVS address_line_2). */\n addressLine2Input?: Record<string, string | number>;\n /** Style for the city input (AVS). */\n cityInput?: Record<string, string | number>;\n /** Style for the state/province input or dropdown (AVS). */\n stateInput?: Record<string, string | number>;\n}\n\n/** Predefined theme for the `buttons` layout. */\nexport type ButtonsLayoutTheme = 'default' | 'minimal' | 'rounded' | 'dark';\n\n// ---------------------------------------------------------------------------\n// AVS Field Configuration\n// ---------------------------------------------------------------------------\n\n/**\n * Per-field AVS configuration.\n * - `true` = show for all countries\n * - `string[]` = show only for listed country codes (ISO 3166-1 alpha-2)\n * - `false` or omitted = hidden\n */\nexport interface AVSFieldConfig {\n /** Street address (line 1). */\n address_line_1?: boolean | string[];\n /** Apt, suite, unit, etc. (line 2). */\n address_line_2?: boolean | string[];\n /** City / Town. */\n city?: boolean | string[];\n /** State / Province / Region. Renders as dropdown for US and CA. */\n state?: boolean | string[];\n /** ZIP / Postal code. */\n postal_code?: boolean | string[];\n /** Country dropdown. */\n country?: boolean | string[];\n}\n\n// ---------------------------------------------------------------------------\n// Checkout Session (mirrors checkout project's CheckoutSession)\n// ---------------------------------------------------------------------------\n\n/** A customer attached to a checkout session. */\nexport interface Customer {\n id: string;\n email: string;\n firstName?: string;\n lastName?: string;\n gender?: string;\n city?: string;\n state?: string;\n country?: string;\n zip?: string;\n /** Street address (line 1). */\n line1?: string;\n /** Apt, suite, unit (line 2). */\n line2?: string;\n}\n\n/** Recurring interval configuration for subscription line items. */\nexport interface RecurringInterval {\n interval: 'month' | 'year';\n intervalCount?: number;\n}\n\n/** Inline product data when no pre-created price is referenced. */\nexport interface PriceData {\n currency: string;\n unitAmount: number;\n productData: { name: string; description?: string };\n recurring?: RecurringInterval;\n}\n\n/** A single line item within a checkout session. */\nexport interface LineItem {\n /** Reference to a pre-created price object on the provider. */\n price?: string;\n /** Inline price data (used when no `price` reference exists). */\n priceData?: PriceData;\n quantity: number;\n}\n\n/** Checkout mode controlling the payment UI behavior. */\nexport type CheckoutMode = 'full' | 'auto' | 'confirm';\n\n/** A one-time item from a checkout session response. */\nexport interface CheckoutSessionItem {\n uuid: string;\n checkoutSessionId: string;\n /** Preferred catalog code for the item. */\n code?: string;\n /** @deprecated Use {@link CheckoutSessionItem.code}. Backend may stop returning this in a future major. */\n providerItemId?: string;\n /**\n * Display-only name for the item. Preferred over `providerItemName`.\n * The backend no longer persists names; the SDK populates this from the\n * client-side display cache when the server response omits it.\n */\n itemName?: string | null;\n /** @deprecated Use {@link CheckoutSessionItem.itemName}. Mirrored from `itemName` for backward compatibility. */\n providerItemName?: string | null;\n /** Display-only. Resolved from the catalog server-side; not part of the persisted session. */\n providerItemDescription?: string | null;\n quantity: number;\n /** 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. */\n totalAmount?: number;\n /** 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. */\n overrideAmount?: number | null;\n /** @deprecated Prefer the session-level `currency` on {@link CheckoutSession}. Kept for backward compatibility and populated from cache when the server omits it. */\n currency?: string;\n metadata?: Record<string, unknown> | null;\n}\n\n/** A subscription plan from a checkout session response. */\nexport interface CheckoutSessionSubscription {\n uuid: string;\n checkoutSessionId: string;\n /** Preferred catalog code for the subscription plan. */\n code?: string;\n /** @deprecated Use {@link CheckoutSessionSubscription.code}. Backend may stop returning this in a future major. */\n providerPlanId?: string;\n /**\n * Display-only name for the subscription plan. Preferred over\n * `providerPlanName`. The backend no longer persists names; the SDK\n * populates this from the client-side display cache when the server\n * response omits it.\n */\n subscriptionName?: string | null;\n /** @deprecated Use {@link CheckoutSessionSubscription.subscriptionName}. Mirrored from `subscriptionName` for backward compatibility. */\n providerPlanName?: string | null;\n /** Display-only. Resolved from the catalog server-side; not part of the persisted session. */\n providerPlanDescription?: string | null;\n quantity: number;\n /** 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. */\n totalAmount?: number;\n /** 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. */\n overrideAmount?: number | null;\n /** @deprecated Prefer the session-level `currency` on {@link CheckoutSession}. Kept for backward compatibility and populated from cache when the server omits it. */\n currency?: string;\n /** @deprecated Removed from backend. Checkouts only create new subscriptions. */\n isUpdate?: boolean;\n metadata?: Record<string, unknown> | null;\n}\n\n/**\n * Environment for an upstream gateway. Accepts both the gateway-native values\n * (`'sandbox'` | `'live'`) and FloPay's internal aliases (`'stage'` |\n * `'production'`) so the same string can flow from the billing API straight\n * to gateway SDKs without translation at every call site. Use\n * {@link normalizeGatewayEnvironment} to collapse to the canonical pair\n * before handing the value to a gateway SDK.\n */\nexport type GatewayEnvironment = 'sandbox' | 'live' | 'stage' | 'production';\n\n/** Canonical gateway-native form returned by {@link normalizeGatewayEnvironment}. */\nexport type NormalizedGatewayEnvironment = 'sandbox' | 'live';\n\n/**\n * Map FloPay's environment aliases to the gateway-native `'sandbox'`/`'live'`\n * pair. `'stage'` → `'sandbox'`, `'production'` → `'live'`. Returns `undefined`\n * for `undefined` input and logs a console warning for unrecognized strings\n * (so misconfiguration surfaces immediately instead of hanging later — most\n * gateway SDKs silently fall back to live endpoints on an unknown env, which\n * then fails opaquely against sandbox credentials).\n */\nexport function normalizeGatewayEnvironment(\n env: GatewayEnvironment | string | undefined | null,\n): NormalizedGatewayEnvironment | undefined {\n if (env == null) return undefined;\n switch (env) {\n case 'sandbox':\n case 'stage':\n return 'sandbox';\n case 'live':\n case 'production':\n return 'live';\n default:\n // eslint-disable-next-line no-console\n console.warn(\n `[FloPay] Unrecognized gateway environment \"${env}\". Expected one of: sandbox, live, stage, production. Falling back to undefined.`,\n );\n return undefined;\n }\n}\n\n/** Per-gateway configuration returned by the billing API. */\nexport interface CheckoutGateway {\n /** Public client identifier (e.g. Stripe publishable key, PayPal client id). */\n publishableKey?: string | null;\n /** Sandbox or live mode for the gateway credentials. */\n environment?: GatewayEnvironment;\n /**\n * Optional Stripe PaymentIntent client secret exposed by the billing API\n * when additional authentication is required for a saved payment method.\n * Stripe-specific.\n */\n stripeClientSecret?: string | null;\n /**\n * Optional publishable key for a dedicated Stripe sub-account that renders\n * PayPal via Stripe Elements. Stripe-specific. Distinct from\n * `gateways.paypal.publishableKey`, which is a PayPal client id used by the\n * direct PayPal SDK.\n */\n paypalPublishableKey?: string | null;\n}\n\n/**\n * Map of gateways attached to a session, keyed by gateway code. A session can\n * advertise multiple gateways concurrently — e.g. `gateways.stripe` for card\n * + wallets and `gateways.paypal` for direct PayPal rendering.\n */\nexport interface CheckoutGateways {\n stripe?: CheckoutGateway;\n paypal?: CheckoutGateway;\n [key: string]: CheckoutGateway | undefined;\n}\n\n/** Represents a FloPay checkout session. */\nexport interface CheckoutSession {\n // ── Core fields ──\n id: string;\n clientSecret: string;\n mode: 'payment' | 'subscription' | 'setup';\n status: 'open' | 'complete' | 'expired';\n amount: number;\n currency: string;\n lineItems?: LineItem[];\n customer?: Customer;\n metadata?: Record<string, string>;\n\n // ── Session data from billing API ──\n checkoutMode?: CheckoutMode;\n items?: CheckoutSessionItem[];\n subscriptions?: CheckoutSessionSubscription[];\n successUrl?: string;\n cancelUrl?: string;\n coupons?: string[];\n createdAt?: string;\n /**\n * Per-gateway configuration. A session can advertise multiple concurrent\n * gateways — read `gateways.stripe` for card/wallets, `gateways.paypal` for\n * direct PayPal, and so on.\n */\n gateways?: CheckoutGateways;\n accountData?: {\n userId: string;\n email: string;\n firstName: string;\n lastName: string;\n gender?: string | null;\n city?: string | null;\n state?: string | null;\n country?: string | null;\n zip?: string | null;\n };\n tagsData?: TagsData;\n}\n\n// ---------------------------------------------------------------------------\n// Payment Results\n// ---------------------------------------------------------------------------\n\n/** The result of a payment confirmation attempt. */\nexport interface PaymentResult {\n status: 'succeeded' | 'processing' | 'requires_action' | 'failed';\n paymentIntentId?: string;\n paymentMethodId?: string;\n checkoutMethod?: CheckoutButtonMethod;\n error?: import('./errors.js').FloPayError;\n}\n\n/** Parameters for confirming a payment. */\nexport interface ConfirmPaymentParams {\n clientSecret: string;\n /** Optional redirect URL after 3-D Secure or wallet authentication. */\n returnUrl?: string;\n /**\n * Optional billing details appended to `payment_method_data` on the confirm call.\n * Ensures `billing_details.email` (and name/address) lands on the PaymentMethod\n * Stripe mints from Elements during 3DS confirmation — otherwise the new PM\n * inherits none of the info we attached at `createPaymentMethod` time.\n */\n billingDetails?: BillingDetails;\n}\n\n/** Billing details passed to Stripe for AVS (Address Verification). */\nexport interface BillingDetails {\n email?: string;\n name?: string;\n address?: {\n country?: string;\n postal_code?: string;\n city?: string;\n line1?: string;\n line2?: string;\n state?: string;\n };\n}\n\n/** Result from creating a payment method (tokenizing card fields). */\nexport interface CreatePaymentMethodResult {\n paymentMethodId: string | null;\n error?: import('./errors.js').FloPayError;\n}\n\n/** Parameters for confirming a card payment with a known client secret. */\nexport interface ConfirmCardPaymentParams {\n clientSecret: string;\n paymentMethodId: string;\n}\n\n/** Result from confirming a card payment. */\nexport interface ConfirmCardPaymentResult {\n status: 'succeeded' | 'processing' | 'requires_action' | 'requires_capture' | 'failed';\n paymentIntentId?: string;\n paymentMethodId?: string;\n error?: import('./errors.js').FloPayError;\n}\n\n// ---------------------------------------------------------------------------\n// Elements\n// ---------------------------------------------------------------------------\n\n/** The type of payment element to render. */\nexport type ElementType =\n | 'payment'\n | 'card'\n | 'cardNumber'\n | 'cardExpiry'\n | 'cardCvc'\n | 'address';\n\n/** Emitted when an element's internal state changes. */\nexport interface ElementChangeEvent {\n elementType: ElementType;\n complete: boolean;\n empty: boolean;\n error?: { message: string; type: string };\n /** Only populated for non-sensitive fields (e.g. address). */\n value?: Record<string, unknown>;\n}\n\n/** Configuration options when creating an element. */\nexport interface ElementOptions {\n appearance?: FloPayAppearance;\n /** Client secret for the PaymentIntent or SetupIntent. When present, Stripe uses it directly. */\n clientSecret?: string;\n /**\n * Total amount in the smallest currency unit (e.g. cents).\n * Used when no `clientSecret` is available — Stripe Elements needs\n * `mode` + `amount` + `currency` to render without a server-side intent.\n */\n amount?: number;\n /** ISO 4217 currency code (lowercase). Used with `amount` when no `clientSecret`. */\n currency?: string;\n /** How payment methods are created. 'manual' = tokenize only, 'auto' = Stripe handles it. */\n paymentMethodCreation?: 'manual' | 'auto';\n /**\n * Requests reusable payment credentials for future payments when Stripe\n * creates or validates a deferred PaymentIntent for this Elements group.\n */\n setupFutureUsage?: 'off_session' | 'on_session';\n layout?: 'tabs' | 'accordion' | 'auto';\n defaultValues?: Record<string, unknown>;\n readOnly?: boolean;\n /** Address element mode: 'billing' or 'shipping'. */\n mode?: 'billing' | 'shipping';\n /**\n * Style object for individual card elements (cardNumber, cardExpiry, cardCvc).\n * Passed directly to the underlying provider element.\n *\n * @example\n * ```ts\n * style: {\n * base: { color: '#f9fafb', fontSize: '16px', '::placeholder': { color: '#6b7280' } },\n * invalid: { color: '#ef4444' },\n * }\n * ```\n */\n style?: Record<string, Record<string, unknown>>;\n}\n\n// ---------------------------------------------------------------------------\n// Mounted Element (runtime instance)\n// ---------------------------------------------------------------------------\n\n/**\n * A payment element that has been created and can be mounted into the DOM.\n *\n * TODO: In a future phase, each MountedElement will render inside an iframe\n * for PCI DSS SAQ-A compliance. For now, it wraps the underlying provider\n * element directly.\n */\nexport interface MountedElement {\n mount(container: HTMLElement): void;\n unmount(): void;\n update(options: Partial<ElementOptions>): void;\n on(event: string, handler: (...args: unknown[]) => void): void;\n off(event: string, handler: (...args: unknown[]) => void): void;\n destroy(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Provider Configuration\n// ---------------------------------------------------------------------------\n\n/** Top-level configuration for initializing FloPay. */\nexport interface FloPayConfig {\n publishableKey: string;\n /** Billing API base URL (e.g. https://api.stage.flopay.com). */\n billingApiUrl?: string;\n locale?: string;\n appearance?: FloPayAppearance;\n apiVersion?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Provider Adapter Interface\n// ---------------------------------------------------------------------------\n\n/**\n * Abstraction layer for payment providers.\n *\n * Currently only Stripe is implemented (`StripeAdapter`). The interface\n * ensures that adding new providers (Chargebee, Recurly, etc.) will not\n * require changes in consumer code.\n */\nexport interface PaymentProviderAdapter {\n readonly name: string;\n initialize(config: FloPayConfig): Promise<void>;\n createElement(\n type: ElementType,\n options: ElementOptions,\n ): Promise<MountedElement>;\n /** Retrieve an existing element by type, or `null` if not yet created. */\n getElement(type: ElementType): MountedElement | null;\n /** Submit elements for validation (Stripe `elements.submit()`). */\n submitElements(): Promise<{ error?: import('./errors.js').FloPayError }>;\n /** Create a payment method from the current elements (tokenize card). */\n createPaymentMethod(billingDetails?: BillingDetails): Promise<CreatePaymentMethodResult>;\n /** Confirm a card payment with a known client secret and payment method. */\n confirmCardPayment(params: ConfirmCardPaymentParams): Promise<ConfirmCardPaymentResult>;\n confirmPayment(params: ConfirmPaymentParams): Promise<PaymentResult>;\n /**\n * Create a PayPal payment: create PM → create intent → confirm with redirect.\n * Returns the confirmed PaymentIntent ID if completed inline, or redirects to PayPal.\n */\n confirmPayPalPayment(params: {\n billingApiUrl: string;\n sessionId: string;\n email: string;\n returnUrl: string;\n }): Promise<ConfirmCardPaymentResult>;\n /**\n * Resume a PayPal payment after redirect return.\n * Checks URL params for payment_intent + redirect_status.\n */\n resumePayPalPayment(): Promise<ConfirmCardPaymentResult | null>;\n /**\n * Get the raw underlying provider instance (e.g. Stripe object).\n * Used internally for creating secondary Elements groups (e.g. PayPal).\n */\n getRawProvider(): unknown;\n /**\n * Create a secondary Elements group for PayPal.\n * PayPal can't share Elements with card fields that use paymentMethodCreation: 'manual'.\n */\n createPayPalElements(options: ElementOptions): unknown;\n destroy(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Billing Provider (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Supported upstream gateway codes. */\nexport type BillingProvider = 'stripe' | 'paypal';\n\n// ---------------------------------------------------------------------------\n// Tokenized Body (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Token payload produced by client-side tokenization. */\nexport interface TokenizedBody {\n id?: string;\n type?: string;\n threeDSecureActionResultTokenId?: string;\n originalPaymentMethodId?: string;\n isPaypal?: boolean;\n}\n\n/** Structured checkout-processing error returned by the billing API. */\nexport interface CheckoutProcessError {\n type: string;\n message?: string;\n transactionId?: string;\n threeDSecureToken?: string;\n paymentMethodId?: string;\n checkoutMethod?: CheckoutButtonMethod;\n advice?: string;\n gatewayErrorCode?: string;\n fields?: Array<{ field: string; message: string }>;\n}\n\n/** Recoverable checkout-processing state returned when fulfillment is still in progress. */\nexport interface CheckoutProcessingPending {\n type: 'checkout_processing';\n sessionId: string;\n retryAfterMs: number;\n statusUrl?: string;\n sessionUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Normalized Checkout Session (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Checkout mode: tokenize client-side or redirect to hosted page. */\nexport type CheckoutModeKind = 'tokenize' | 'redirect';\n\n/**\n * Provider-agnostic normalized checkout session. Backend may attach multiple\n * gateways per session — read each from `data.<gatewayCode>`.\n */\nexport interface NormalizedCheckoutSession {\n /** Gateway codes advertised by the backend for this session, for diagnostics. */\n providers: BillingProvider[];\n mode: CheckoutModeKind;\n autoProcessingError?: CheckoutProcessError;\n autoProcessingAttempted?: boolean;\n autoProcessingPending?: CheckoutProcessingPending;\n data: {\n hostedUrl?: string;\n clientToken?: string;\n session?: CheckoutSession;\n stripe?: {\n clientSecret?: string;\n publishableKey?: string;\n /**\n * Optional dedicated Stripe sub-account publishable key for rendering\n * PayPal via Stripe Elements. When present and distinct, the saved-PM\n * resume flow loads a separate FloPay instance for the PayPal PI.\n */\n paypalPublishableKey?: string;\n environment?: GatewayEnvironment;\n };\n /**\n * Direct PayPal gateway configuration. Present only when the backend has\n * configured a dedicated PayPal gateway for the consumer; absent means the\n * Stripe-rendered PayPal fallback should be used (if Stripe is configured).\n */\n paypal?: {\n publishableKey?: string;\n environment?: GatewayEnvironment;\n };\n };\n raw?: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Server-side SDK types (mirrors clicktech-core-ui/createCheckoutSession)\n// ---------------------------------------------------------------------------\n\n/** A one-time purchase item for checkout session creation. */\nexport interface CheckoutItem {\n /**\n * Catalog code for the item — the preferred identifier. When omitted, the\n * deprecated `providerItemId` is used as a fallback.\n */\n code?: string;\n /**\n * @deprecated Use {@link CheckoutItem.code}. Still accepted as a fallback\n * when `code` is not provided.\n */\n providerItemId?: string;\n /**\n * Display-only name for the item. Takes priority over the deprecated\n * `providerItemName`. Backend resolves names from the catalog; pass this\n * to seed the client-side display cache for the post-redirect fetch.\n */\n itemName?: string | null;\n /** @deprecated Use {@link CheckoutItem.itemName}. Still accepted as a fallback when `itemName` is not provided. */\n providerItemName?: string | null;\n /** Defaults to 1. */\n quantity?: number;\n /** Display-only. Backend resolves prices from the catalog; pass this to seed the client-side display cache so the UI can render the regular price after redirect. */\n totalAmount?: number;\n /** Display-only. Backend ignores this entirely; pass this to seed the client-side display cache so the UI can render the discounted price after redirect. */\n overrideAmount?: number | null;\n /** @deprecated Prefer the session-level `currency` on {@link CreateSessionParams}/{@link InlineSessionParams}. */\n currency?: string;\n /** Arbitrary key/value metadata forwarded to the backend. */\n metadata?: Record<string, unknown> | null;\n}\n\n/** A recurring subscription plan for checkout session creation. */\nexport interface CheckoutSubscription {\n /**\n * Catalog code for the plan — the preferred identifier. When omitted, the\n * deprecated `providerPlanId` is used as a fallback.\n */\n code?: string;\n /**\n * @deprecated Use {@link CheckoutSubscription.code}. Still accepted as a\n * fallback when `code` is not provided.\n */\n providerPlanId?: string;\n /**\n * Display-only name for the subscription plan. Takes priority over the\n * deprecated `providerPlanName`. Backend resolves names from the catalog;\n * pass this to seed the client-side display cache for the post-redirect fetch.\n */\n subscriptionName?: string | null;\n /** @deprecated Use {@link CheckoutSubscription.subscriptionName}. Still accepted as a fallback when `subscriptionName` is not provided. */\n providerPlanName?: string | null;\n /** Defaults to 1. */\n quantity?: number;\n /** Display-only. Backend resolves prices from the catalog; pass this to seed the client-side display cache so the UI can render the regular price after redirect. */\n totalAmount?: number;\n /** Display-only. Backend ignores this entirely; pass this to seed the client-side display cache so the UI can render the discounted price after redirect. */\n overrideAmount?: number | null;\n /** @deprecated Prefer the session-level `currency` on {@link CreateSessionParams}/{@link InlineSessionParams}. */\n currency?: string;\n /** Arbitrary key/value metadata forwarded to the backend. */\n metadata?: Record<string, unknown> | null;\n}\n\n/** Buyer's account information for session creation. */\nexport interface CheckoutAccount {\n userId: string;\n firstName?: string;\n lastName?: string;\n email: string;\n country?: string | null;\n gender?: string | null;\n city?: string | null;\n state?: string | null;\n zip?: string | null;\n /** Street address (line 1). */\n addressLine1?: string | null;\n /** Apt, suite, unit (line 2). */\n addressLine2?: string | null;\n}\n\n/** Analytics / pixel tags forwarded to the checkout page. */\nexport interface TagsData {\n googleContainerId?: string | null;\n sessionId?: string | null;\n testEventCode?: string | null;\n}\n\n/**\n * Parameters for creating a checkout session via the billing API.\n * Mirrors the `CreateCheckoutSessionOptions` from clicktech-core-ui.\n */\nexport interface CreateSessionParams {\n /** Base URL of the billing API, e.g. https://billing.clicktech.com */\n billingApiUrl: string;\n /** Base URL of the checkout frontend, e.g. https://checkout.clicktech.com */\n checkoutBaseUrl: string;\n /** The client ID for the checkout session. */\n clientId: string;\n /**\n * Session-level ISO 4217 currency code. Takes precedence over any\n * per-item/per-subscription `currency` field. When omitted, the SDK\n * falls back to `items[0].currency ?? subscriptions[0].currency`.\n */\n currency?: string;\n /** One-time purchase items. */\n items?: CheckoutItem[];\n /** Recurring subscription plans. */\n subscriptions?: CheckoutSubscription[];\n /** Buyer's account information. */\n account: CheckoutAccount;\n /** URL to redirect to after successful payment. */\n successUrl: string;\n /** URL to redirect to if the user cancels. */\n cancelUrl: string;\n /**\n * Checkout mode sent to the billing API.\n * - 'confirm' – show a payment confirmation page (default)\n * - 'auto' – skip confirmation when a payment method is already on file\n * - 'full' – full checkout flow\n */\n checkoutMode?: 'confirm' | 'auto' | 'full';\n /** Coupon codes to apply. */\n couponCodes?: string[];\n /** Pixel / analytics tags forwarded to the checkout page. */\n tagsData?: TagsData;\n /** Extra query params appended to the checkout redirect URL. */\n redirectParams?: Record<string, string>;\n /** Whether to set the checkout_data cookie. Defaults to true. */\n setCookie?: boolean;\n /** Request timeout in milliseconds. Defaults to 12000. */\n timeoutMs?: number;\n /** UTM and funnel tracking metadata. */\n utmMetadata?: Record<string, string | null | undefined>[];\n}\n\n/**\n * Parameters for inline session creation via `FloPayCheckout.createSession`.\n * Subset of `CreateSessionParams` — no redirect fields needed since the\n * component handles the checkout flow inline.\n */\nexport interface InlineSessionParams {\n /** The client ID for the checkout session. */\n clientId: string;\n /**\n * Session-level ISO 4217 currency code. Takes precedence over any\n * per-item/per-subscription `currency` field. When omitted, the SDK\n * falls back to `items[0].currency ?? subscriptions[0].currency`.\n */\n currency?: string;\n /** One-time purchase items. */\n items?: CheckoutItem[];\n /** Recurring subscription plans. */\n subscriptions?: CheckoutSubscription[];\n /** Buyer's account information. */\n account: CheckoutAccount;\n /** URL to redirect to after successful payment. */\n successUrl: string;\n /** URL to redirect to if the user cancels. */\n cancelUrl: string;\n /** Checkout mode: 'full' (default), 'auto', or 'confirm'. */\n checkoutMode?: 'full' | 'auto' | 'confirm';\n /** Optional saved/tokenized payment method for inline auto or confirm checkout. */\n tokenizedData?: TokenizedBody;\n /** Coupon codes to apply. */\n couponCodes?: string[];\n /** Pixel / analytics tags. */\n tagsData?: TagsData;\n /** UTM and funnel tracking metadata. */\n utmMetadata?: Record<string, string | null | undefined>[];\n // ── Checkout analytics metadata (set by SDK automatically) ──\n /** Whether AVS is enabled for this checkout. */\n avsCheck?: boolean;\n /** Checkout type: 'standard_checkout' or 'embedded_checkout'. */\n checkoutType?: string;\n /** Checkout layout: 'default_layout', 'buttons_layout', or 'custom_layout'. */\n checkoutLayout?: string;\n /** AVS field configuration for analytics. */\n avsConfig?: AVSFieldConfig;\n}\n\n/** Payment methods exposed by the React buttons layout callbacks. */\nexport type CheckoutButtonMethod = 'card' | 'paypal' | 'apple_pay' | 'google_pay';\n\n/**\n * Draft inline-session params used by `FloPayCheckout` before a real\n * checkout session has been created. Buttons-layout checkout can seed\n * placeholder account data up front; `onBeforeButtonClick` can still\n * update it before the selected payment button continues.\n */\nexport interface InlineSessionDraft extends Omit<InlineSessionParams, 'account'> {\n account: Omit<CheckoutAccount, 'email'> & { email?: string };\n}\n\n/**\n * Partial inline-session fields that can be returned from\n * `onBeforeButtonClick` and merged into the draft session params.\n */\nexport interface InlineSessionPatch {\n account?: Partial<CheckoutAccount>;\n couponCodes?: string[];\n tagsData?: TagsData;\n utmMetadata?: Record<string, string | null | undefined>[];\n}\n\n/** Context passed to the `onBeforeButtonClick` callback for buttons-layout payment methods. */\nexport interface BeforeButtonClickEvent {\n method: CheckoutButtonMethod;\n sessionId?: string;\n createSession?: InlineSessionDraft;\n}\n\n/** Structured decline event emitted by the React checkout components. */\nexport interface DeclineEvent {\n method: CheckoutButtonMethod;\n message: string;\n code?: string;\n declineCode?: string;\n}\n\n/** Result from creating a checkout session. */\nexport type CheckoutSessionResult =\n | { status: 201; redirectUrl: string }\n | { status: 204 }\n | { status: number };\n\n/**\n * Data submitted when processing a payment (tokenized card/wallet data).\n * Mirrors checkout project's ProcessCheckoutBodyDto.\n */\nexport interface ProcessPaymentParams {\n sessionId: string;\n tokenizedData?: TokenizedBody;\n accountData: {\n userId: string;\n email: string;\n firstName: string;\n lastName: string;\n zip?: string;\n country?: string;\n city?: string;\n state?: string;\n addressLine1?: string;\n addressLine2?: string;\n };\n chv?: string;\n /** Current page URL for redirect-capable auth flows such as 3DS and PayPal. */\n returnUrl?: string;\n // ── Checkout analytics metadata ──\n /** Whether AVS (Address Verification) was enabled for this checkout. */\n avsCheck?: boolean;\n /** Checkout type: 'standard_checkout' or 'embedded_checkout'. */\n checkoutType?: string;\n /** Checkout layout: 'default_layout', 'buttons_layout', or 'custom_layout'. */\n checkoutLayout?: string;\n /** AVS field configuration for analytics — which fields were shown. */\n avsConfig?: AVSFieldConfig;\n}\n\n/** Parameters for creating a customer. */\nexport interface CreateCustomerParams {\n email: string;\n name?: string;\n metadata?: Record<string, string>;\n}\n\n/** Parameters for updating a customer. */\nexport interface UpdateCustomerParams {\n email?: string;\n name?: string;\n metadata?: Record<string, string>;\n}\n\n/** A webhook event from FloPay. */\nexport interface WebhookEvent {\n id: string;\n type: string;\n data: Record<string, unknown>;\n created: number;\n}\n\n// ---------------------------------------------------------------------------\n// Currency (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Currency information mapped to a country. */\nexport interface CurrencyInfo {\n currency: string;\n symbol: string;\n country: string;\n countryCode: string;\n /** 0 = no tax, 1 = tax (VAT) applies. */\n tax: number;\n}\n\n/** A country option for UI select elements. */\nexport interface CountryOption {\n code: string;\n name: string;\n flag: string;\n}\n","/** Discriminated error types returned by the FloPay SDK. */\nexport type FloPayErrorType =\n | 'validation_error'\n | 'api_error'\n | 'authentication_error'\n | 'rate_limit_error'\n | 'network_error';\n\n/**\n * Custom error class for all FloPay SDK errors.\n *\n * Extends the native `Error` and adds structured fields that mirror\n * Stripe-style error responses for familiarity.\n */\nexport class FloPayError extends Error {\n readonly type: FloPayErrorType;\n readonly code?: string;\n readonly declineCode?: string;\n readonly param?: string;\n readonly statusCode?: number;\n\n constructor(\n message: string,\n type: FloPayErrorType,\n options?: { code?: string; declineCode?: string; param?: string; statusCode?: number },\n ) {\n super(message);\n this.name = 'FloPayError';\n this.type = type;\n this.code = options?.code;\n this.declineCode = options?.declineCode;\n this.param = options?.param;\n this.statusCode = options?.statusCode;\n\n // Restore prototype chain (required when extending built-ins)\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error Factories\n// ---------------------------------------------------------------------------\n\n/** Create a validation error (e.g. missing required field). */\nexport function validationError(\n message: string,\n param?: string,\n): FloPayError {\n return new FloPayError(message, 'validation_error', { param });\n}\n\n/** Create an API error (e.g. upstream provider returned an error). */\nexport function apiError(\n message: string,\n code?: string,\n statusCode?: number,\n): FloPayError {\n return new FloPayError(message, 'api_error', { code, statusCode });\n}\n\n/** Create an authentication error (e.g. invalid publishable key). */\nexport function authenticationError(message: string): FloPayError {\n return new FloPayError(message, 'authentication_error');\n}\n\n/** Create a rate limit error. */\nexport function rateLimitError(message: string): FloPayError {\n return new FloPayError(message, 'rate_limit_error');\n}\n\n/** Create a network error (e.g. fetch failed). */\nexport function networkError(message: string): FloPayError {\n return new FloPayError(message, 'network_error');\n}\n","/** FloPay environment — determines which billing API URL is used. */\nexport type FloPayEnvironment = 'staging' | 'production' | 'local';\n\nconst ENV_URL_MAP: Record<FloPayEnvironment, string> = {\n local: 'https://flo.ngrok.pro',\n staging: 'https://api.stage.flopay.com',\n production: 'https://api.flopay.com',\n};\n\nlet globalEnvironment: FloPayEnvironment = 'staging';\n\n/**\n * Configure the FloPay SDK globally. Call once at app startup.\n *\n * The environment determines which billing API URL is used for all\n * FloPay operations (session creation, payment processing, etc.).\n *\n * @example\n * ```ts\n * import { configureFlopay } from '@flopay/shared';\n *\n * // In production\n * configureFlopay({ environment: 'production' });\n *\n * // In staging/development\n * configureFlopay({ environment: 'staging' });\n * ```\n *\n * Alternatively, set the `NEXT_PUBLIC_FLOPAY_ENV` environment variable\n * to `'staging'` or `'production'` — the SDK reads it automatically.\n */\nexport function configureFlopay(config: { environment: FloPayEnvironment }): void {\n globalEnvironment = config.environment;\n}\n\n/** Get the billing API URL for the currently configured environment. */\nexport function getConfiguredBillingApiUrl(): string {\n return ENV_URL_MAP[globalEnvironment];\n}\n\n/** Get the current configured environment. */\nexport function getFloPayEnvironment(): FloPayEnvironment {\n return globalEnvironment;\n}\n","import type { AVSFieldConfig, ButtonsLayoutStyles, ButtonsLayoutTheme, CountryOption, CurrencyInfo, FloPayAppearance } from './types.js';\n\nimport type { FloPayEnvironment } from './config.js';\nimport { getConfiguredBillingApiUrl } from './config.js';\n\n// ---------------------------------------------------------------------------\n// SDK Version & API\n// ---------------------------------------------------------------------------\n\n/** Current SDK version. */\nexport const SDK_VERSION = '1.1.0';\n\n/** Billing API URL for staging environment. */\nexport const BILLING_API_URL_STAGING = 'https://api.stage.flopay.com';\n\n/** Billing API URL for production environment. */\nexport const BILLING_API_URL_PRODUCTION = 'https://api.flopay.com';\n\n/** Default FloPay API base URL (used by @flopay/node). Alias for staging. */\nexport const DEFAULT_API_BASE_URL = BILLING_API_URL_STAGING;\n\n/** Default billing API base URL. Alias for staging — prefer `resolveBillingApiUrl()`. */\nexport const BILLING_API_URL = BILLING_API_URL_STAGING;\n\n/**\n * Resolve the billing API URL from available configuration.\n *\n * Priority:\n * 1. Explicit `billingApiUrl` (prop/param override)\n * 2. `NEXT_PUBLIC_FLOPAY_ENV` environment variable (`'staging'` | `'production'`)\n * 3. `configureFlopay()` global environment setting\n * 4. Fallback: staging URL\n *\n * @example\n * ```ts\n * import { resolveBillingApiUrl } from '@flopay/shared';\n *\n * // Reads from env var or configureFlopay() — no args needed\n * const url = resolveBillingApiUrl();\n *\n * // Explicit override takes priority\n * const url = resolveBillingApiUrl('https://custom.example.com');\n * ```\n */\nexport function resolveBillingApiUrl(billingApiUrl?: string): string {\n if (billingApiUrl) return billingApiUrl;\n\n // Environment variable (works in Next.js and bundlers that inline process.env)\n if (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_FLOPAY_ENV) {\n const env = process.env.NEXT_PUBLIC_FLOPAY_ENV as FloPayEnvironment;\n if (env === 'production') return BILLING_API_URL_PRODUCTION;\n return BILLING_API_URL_STAGING;\n }\n\n // Global config from configureFlopay()\n return getConfiguredBillingApiUrl();\n}\n\n/** Default API version header value. */\nexport const DEFAULT_API_VERSION = '2024-01-01';\n\n// ---------------------------------------------------------------------------\n// Default Themes\n// ---------------------------------------------------------------------------\n\n/** The default appearance applied when no custom appearance is provided. */\nexport const DEFAULT_APPEARANCE: FloPayAppearance = {\n theme: 'default',\n variables: {\n colorPrimary: '#4A49FF',\n colorBackground: '#FFFFFF',\n colorText: '#262833',\n colorDanger: '#DF1B41',\n borderRadius: '8px',\n fontFamily: 'Poppins, system-ui, sans-serif',\n fontSizeBase: '16px',\n spacingUnit: '4px',\n },\n};\n\n/** Flat theme — minimal borders and shadows. */\nexport const FLAT_APPEARANCE: FloPayAppearance = {\n theme: 'flat',\n variables: {\n ...DEFAULT_APPEARANCE.variables,\n borderRadius: '4px',\n },\n};\n\n/** Night theme — dark background. */\nexport const NIGHT_APPEARANCE: FloPayAppearance = {\n theme: 'night',\n variables: {\n colorPrimary: '#7B7BFF',\n colorBackground: '#1A1A2E',\n colorText: '#E0E0E0',\n colorDanger: '#FF6B6B',\n borderRadius: '8px',\n fontFamily: 'Poppins, system-ui, sans-serif',\n fontSizeBase: '16px',\n spacingUnit: '4px',\n },\n};\n\n// ---------------------------------------------------------------------------\n// Buttons Layout Theme Presets\n// ---------------------------------------------------------------------------\n\n/** Default buttons layout — white card button, neutral borders. */\nexport const BUTTONS_LAYOUT_DEFAULT: ButtonsLayoutStyles = {};\n\n/** Minimal buttons layout — borderless, subtle hover. */\nexport const BUTTONS_LAYOUT_MINIMAL: ButtonsLayoutStyles = {\n cardButton: {\n border: 'none',\n backgroundColor: '#f9fafb',\n boxShadow: 'none',\n },\n cardFormContainer: {\n backgroundColor: '#f9fafb',\n border: 'none',\n },\n cardInputBorder: '#e5e7eb',\n backButtonIcon: {\n backgroundColor: '#e5e7eb',\n },\n submitButton: {\n borderRadius: '6px',\n },\n};\n\n/** Rounded buttons layout — large border radius, soft shadows. */\nexport const BUTTONS_LAYOUT_ROUNDED: ButtonsLayoutStyles = {\n cardButton: {\n borderRadius: '9999px',\n border: '1px solid #e5e7eb',\n boxShadow: '0 1px 3px rgba(0,0,0,0.06)',\n },\n cardFormContainer: {\n borderRadius: '16px',\n border: '1px solid #e5e7eb',\n boxShadow: '0 2px 8px rgba(0,0,0,0.06)',\n },\n cardInputBorder: '#d1d5db',\n submitButton: {\n borderRadius: '9999px',\n },\n backButtonIcon: {\n backgroundColor: '#f3f4f6',\n },\n};\n\n/** Dark buttons layout — dark backgrounds, light text. */\nexport const BUTTONS_LAYOUT_DARK: ButtonsLayoutStyles = {\n cardButton: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n border: '1px solid #374151',\n boxShadow: 'none',\n },\n cardFormContainer: {\n backgroundColor: '#111827',\n border: '1px solid #374151',\n },\n cardInputBorder: '#4b5563',\n cardInputColor: '#f9fafb',\n cardInputPlaceholderColor: '#6b7280',\n cardInputBackground: '#1f2937',\n nameInput: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n backButton: {\n color: '#9ca3af',\n },\n backButtonIcon: {\n backgroundColor: '#374151',\n },\n submitButton: {\n backgroundColor: '#6366f1',\n },\n title: {\n color: '#f9fafb',\n },\n countrySelect: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n zipInput: {\n backgroundColor: '#1f2937',\n color: '#f9fafb',\n },\n};\n\n/** Resolve a buttons layout theme name to its style preset. */\nexport function resolveButtonsLayoutTheme(theme?: ButtonsLayoutTheme): ButtonsLayoutStyles {\n switch (theme) {\n case 'minimal': return BUTTONS_LAYOUT_MINIMAL;\n case 'rounded': return BUTTONS_LAYOUT_ROUNDED;\n case 'dark': return BUTTONS_LAYOUT_DARK;\n default: return BUTTONS_LAYOUT_DEFAULT;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Supported Element Types\n// ---------------------------------------------------------------------------\n\n/** All supported element type identifiers. */\nexport const ELEMENT_TYPES = [\n 'payment',\n 'card',\n 'cardNumber',\n 'cardExpiry',\n 'cardCvc',\n 'address',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Supported Card Brands\n// ---------------------------------------------------------------------------\n\nexport const SUPPORTED_CARD_BRANDS = [\n 'visa',\n 'mastercard',\n 'mastercard_debit',\n 'amex',\n 'discover',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Currency Mapping (from checkout project)\n// ---------------------------------------------------------------------------\n\n/** Country code to currency information mapping. */\nexport const CURRENCY_MAP: Record<string, CurrencyInfo> = {\n // EUR (VAT applies)\n AT: { currency: 'EUR', symbol: '\\u20AC', country: 'Austria', countryCode: 'AT', tax: 1 },\n BE: { currency: 'EUR', symbol: '\\u20AC', country: 'Belgium', countryCode: 'BE', tax: 1 },\n CY: { currency: 'EUR', symbol: '\\u20AC', country: 'Cyprus', countryCode: 'CY', tax: 1 },\n DE: { currency: 'EUR', symbol: '\\u20AC', country: 'Germany', countryCode: 'DE', tax: 1 },\n EE: { currency: 'EUR', symbol: '\\u20AC', country: 'Estonia', countryCode: 'EE', tax: 1 },\n ES: { currency: 'EUR', symbol: '\\u20AC', country: 'Spain', countryCode: 'ES', tax: 1 },\n FI: { currency: 'EUR', symbol: '\\u20AC', country: 'Finland', countryCode: 'FI', tax: 1 },\n FR: { currency: 'EUR', symbol: '\\u20AC', country: 'France', countryCode: 'FR', tax: 1 },\n GR: { currency: 'EUR', symbol: '\\u20AC', country: 'Greece', countryCode: 'GR', tax: 1 },\n HR: { currency: 'EUR', symbol: '\\u20AC', country: 'Croatia', countryCode: 'HR', tax: 1 },\n IE: { currency: 'EUR', symbol: '\\u20AC', country: 'Ireland', countryCode: 'IE', tax: 1 },\n IT: { currency: 'EUR', symbol: '\\u20AC', country: 'Italy', countryCode: 'IT', tax: 1 },\n LT: { currency: 'EUR', symbol: '\\u20AC', country: 'Lithuania', countryCode: 'LT', tax: 1 },\n LU: { currency: 'EUR', symbol: '\\u20AC', country: 'Luxembourg', countryCode: 'LU', tax: 1 },\n LV: { currency: 'EUR', symbol: '\\u20AC', country: 'Latvia', countryCode: 'LV', tax: 1 },\n MT: { currency: 'EUR', symbol: '\\u20AC', country: 'Malta', countryCode: 'MT', tax: 1 },\n NL: { currency: 'EUR', symbol: '\\u20AC', country: 'Netherlands', countryCode: 'NL', tax: 1 },\n PT: { currency: 'EUR', symbol: '\\u20AC', country: 'Portugal', countryCode: 'PT', tax: 1 },\n SI: { currency: 'EUR', symbol: '\\u20AC', country: 'Slovenia', countryCode: 'SI', tax: 1 },\n SK: { currency: 'EUR', symbol: '\\u20AC', country: 'Slovakia', countryCode: 'SK', tax: 1 },\n BG: { currency: 'EUR', symbol: '\\u20AC', country: 'Bulgaria', countryCode: 'BG', tax: 1 },\n RO: { currency: 'EUR', symbol: '\\u20AC', country: 'Romania', countryCode: 'RO', tax: 1 },\n CZ: { currency: 'EUR', symbol: '\\u20AC', country: 'Czech Republic', countryCode: 'CZ', tax: 1 },\n SE: { currency: 'EUR', symbol: '\\u20AC', country: 'Sweden', countryCode: 'SE', tax: 1 },\n DK: { currency: 'EUR', symbol: '\\u20AC', country: 'Denmark', countryCode: 'DK', tax: 1 },\n PL: { currency: 'EUR', symbol: '\\u20AC', country: 'Poland', countryCode: 'PL', tax: 1 },\n HU: { currency: 'EUR', symbol: '\\u20AC', country: 'Hungary', countryCode: 'HU', tax: 1 },\n // GBP (VAT applies)\n GB: { currency: 'GBP', symbol: '\\u00A3', country: 'United Kingdom', countryCode: 'GB', tax: 1 },\n // USD (no VAT)\n US: { currency: 'USD', symbol: '$', country: 'United States', countryCode: 'US', tax: 0 },\n // CAD (no VAT)\n CA: { currency: 'CAD', symbol: 'CA$', country: 'Canada', countryCode: 'CA', tax: 0 },\n // NZD (no VAT)\n NZ: { currency: 'NZD', symbol: 'NZ$', country: 'New Zealand', countryCode: 'NZ', tax: 0 },\n // AUD (no VAT)\n AU: { currency: 'AUD', symbol: 'AU$', country: 'Australia', countryCode: 'AU', tax: 0 },\n};\n\n/** Default currency info when country is unknown. */\nexport const DEFAULT_CURRENCY: CurrencyInfo = {\n currency: 'USD',\n symbol: '$',\n country: 'United States',\n countryCode: 'US',\n tax: 0,\n};\n\n// ---------------------------------------------------------------------------\n// Postal Code Labels\n// ---------------------------------------------------------------------------\n\n/** Returns the correct postal code label for a country code (ISO 3166-1 alpha-2). */\nexport function getPostalCodeLabel(countryCode: string): string {\n switch (countryCode.toUpperCase()) {\n case 'US': return 'ZIP Code';\n case 'GB': return 'Postcode';\n case 'CA': return 'Postal Code';\n case 'AU':\n case 'NZ': return 'Postcode';\n case 'IE': return 'Eircode';\n default: return 'Postal Code';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Country List (ISO 3166-1 alpha-2)\n// ---------------------------------------------------------------------------\n\nconst regionNames = new Intl.DisplayNames(['en'], { type: 'region' });\n\nfunction codeToFlag(code: string): string {\n return [...code.toUpperCase()]\n .map((c) => String.fromCodePoint(0x1f1e6 - 65 + c.charCodeAt(0)))\n .join('');\n}\n\n/** Priority countries shown first in dropdowns. */\nconst PRIORITY_CODES = ['US', 'GB', 'CA', 'AU', 'NZ', 'IE', 'DE', 'FR'];\n\nconst ALL_CODES = [\n 'AD', 'AE', 'AF', 'AG', 'AL', 'AM', 'AO', 'AR', 'AT', 'AU',\n 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ',\n 'BN', 'BO', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CD',\n 'CF', 'CG', 'CH', 'CI', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU',\n 'CV', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC',\n 'EE', 'EG', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FM', 'FR', 'GA',\n 'GB', 'GD', 'GE', 'GH', 'GM', 'GN', 'GQ', 'GR', 'GT', 'GW',\n 'GY', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IN', 'IQ',\n 'IR', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI',\n 'KM', 'KN', 'KR', 'KW', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK',\n 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME',\n 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MR', 'MT', 'MU', 'MV',\n 'MW', 'MX', 'MY', 'MZ', 'NA', 'NE', 'NG', 'NI', 'NL', 'NO',\n 'NP', 'NR', 'NZ', 'OM', 'PA', 'PE', 'PG', 'PH', 'PK', 'PL',\n 'PT', 'PW', 'PY', 'QA', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB',\n 'SC', 'SD', 'SE', 'SG', 'SI', 'SK', 'SL', 'SM', 'SN', 'SO',\n 'SR', 'SS', 'ST', 'SV', 'SY', 'SZ', 'TD', 'TG', 'TH', 'TJ',\n 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA',\n 'UG', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VN', 'VU', 'WS',\n 'XK', 'YE', 'ZA', 'ZM', 'ZW',\n] as const;\n\nfunction buildCountryOption(code: string): CountryOption {\n return { code, name: regionNames.of(code) ?? code, flag: codeToFlag(code) };\n}\n\nconst prioritySet = new Set(PRIORITY_CODES);\nconst rest = ALL_CODES.filter((c) => !prioritySet.has(c));\n\n/** All countries for dropdown select, priority countries first. */\nexport const COUNTRY_OPTIONS: CountryOption[] = [\n ...PRIORITY_CODES.map(buildCountryOption),\n ...rest.map(buildCountryOption),\n];\n\n/** Look up a country option by ISO 3166-1 alpha-2 code. */\nexport function getCountryByCode(code: string): CountryOption | undefined {\n return COUNTRY_OPTIONS.find((c) => c.code === code);\n}\n\n// ---------------------------------------------------------------------------\n// AVS Configuration Helpers\n// ---------------------------------------------------------------------------\n\n/** Default AVS config when `enableAVS: true` (backward compatible — country + postal code). */\nconst DEFAULT_AVS_CONFIG: AVSFieldConfig = {\n country: true,\n postal_code: true,\n};\n\n/**\n * Normalize `enableAVS` to a resolved config object.\n * - `false` / `undefined` → `null` (AVS disabled)\n * - `true` → default config (country + postal_code)\n * - `AVSFieldConfig` → returned as-is\n */\nexport function resolveAVSConfig(enableAVS?: boolean | AVSFieldConfig): AVSFieldConfig | null {\n if (!enableAVS) return null;\n if (enableAVS === true) return DEFAULT_AVS_CONFIG;\n return enableAVS;\n}\n\n/**\n * Check if an AVS field should be visible for the given country.\n * - `undefined` / `false` → hidden\n * - `true` → visible for all countries\n * - `string[]` → visible only for listed country codes\n */\nexport function isAVSFieldVisible(\n field: boolean | string[] | undefined,\n country: string,\n): boolean {\n if (field === undefined || field === false) return false;\n if (field === true) return true;\n const normalizedCountry = country.trim().toUpperCase();\n return field.some((code) => code.trim().toUpperCase() === normalizedCountry);\n}\n\n/** Returns true if any AVS field is meaningfully configured (at least one field is truthy). */\nexport function isAVSEnabled(enableAVS?: boolean | AVSFieldConfig): boolean {\n const config = resolveAVSConfig(enableAVS);\n if (!config) return false;\n return Object.values(config).some(\n (v) => v === true || (Array.isArray(v) && v.length > 0),\n );\n}\n\n// ---------------------------------------------------------------------------\n// US States & CA Provinces\n// ---------------------------------------------------------------------------\n\nexport interface StateOption {\n code: string;\n name: string;\n}\n\nexport const US_STATES: StateOption[] = [\n { code: 'AL', name: 'Alabama' },\n { code: 'AK', name: 'Alaska' },\n { code: 'AZ', name: 'Arizona' },\n { code: 'AR', name: 'Arkansas' },\n { code: 'CA', name: 'California' },\n { code: 'CO', name: 'Colorado' },\n { code: 'CT', name: 'Connecticut' },\n { code: 'DE', name: 'Delaware' },\n { code: 'DC', name: 'District of Columbia' },\n { code: 'FL', name: 'Florida' },\n { code: 'GA', name: 'Georgia' },\n { code: 'HI', name: 'Hawaii' },\n { code: 'ID', name: 'Idaho' },\n { code: 'IL', name: 'Illinois' },\n { code: 'IN', name: 'Indiana' },\n { code: 'IA', name: 'Iowa' },\n { code: 'KS', name: 'Kansas' },\n { code: 'KY', name: 'Kentucky' },\n { code: 'LA', name: 'Louisiana' },\n { code: 'ME', name: 'Maine' },\n { code: 'MD', name: 'Maryland' },\n { code: 'MA', name: 'Massachusetts' },\n { code: 'MI', name: 'Michigan' },\n { code: 'MN', name: 'Minnesota' },\n { code: 'MS', name: 'Mississippi' },\n { code: 'MO', name: 'Missouri' },\n { code: 'MT', name: 'Montana' },\n { code: 'NE', name: 'Nebraska' },\n { code: 'NV', name: 'Nevada' },\n { code: 'NH', name: 'New Hampshire' },\n { code: 'NJ', name: 'New Jersey' },\n { code: 'NM', name: 'New Mexico' },\n { code: 'NY', name: 'New York' },\n { code: 'NC', name: 'North Carolina' },\n { code: 'ND', name: 'North Dakota' },\n { code: 'OH', name: 'Ohio' },\n { code: 'OK', name: 'Oklahoma' },\n { code: 'OR', name: 'Oregon' },\n { code: 'PA', name: 'Pennsylvania' },\n { code: 'RI', name: 'Rhode Island' },\n { code: 'SC', name: 'South Carolina' },\n { code: 'SD', name: 'South Dakota' },\n { code: 'TN', name: 'Tennessee' },\n { code: 'TX', name: 'Texas' },\n { code: 'UT', name: 'Utah' },\n { code: 'VT', name: 'Vermont' },\n { code: 'VA', name: 'Virginia' },\n { code: 'WA', name: 'Washington' },\n { code: 'WV', name: 'West Virginia' },\n { code: 'WI', name: 'Wisconsin' },\n { code: 'WY', name: 'Wyoming' },\n];\n\nexport const CA_PROVINCES: StateOption[] = [\n { code: 'AB', name: 'Alberta' },\n { code: 'BC', name: 'British Columbia' },\n { code: 'MB', name: 'Manitoba' },\n { code: 'NB', name: 'New Brunswick' },\n { code: 'NL', name: 'Newfoundland and Labrador' },\n { code: 'NS', name: 'Nova Scotia' },\n { code: 'NT', name: 'Northwest Territories' },\n { code: 'NU', name: 'Nunavut' },\n { code: 'ON', name: 'Ontario' },\n { code: 'PE', name: 'Prince Edward Island' },\n { code: 'QC', name: 'Quebec' },\n { code: 'SK', name: 'Saskatchewan' },\n { code: 'YT', name: 'Yukon' },\n];\n\n/**\n * Get state/province options for a country.\n * Returns a list for US and CA, or `null` for countries where a free-text input is appropriate.\n */\nexport function getStateOptions(country: string): StateOption[] | null {\n switch (country.toUpperCase()) {\n case 'US': return US_STATES;\n case 'CA': return CA_PROVINCES;\n default: return null;\n }\n}\n\n/** Returns the appropriate label for the state/province field based on country. */\nexport function getStateLabel(countryCode: string): string {\n switch (countryCode.toUpperCase()) {\n case 'US': return 'State';\n case 'CA': return 'Province';\n case 'GB': return 'County';\n case 'AU': return 'State / Territory';\n default: return 'State / Province / Region';\n }\n}\n","/**\n * Postal-code → state derivation for AVS.\n *\n * Used when the form configuration shows `address_line_1` but hides the\n * `state` input — we still want to populate `billing_details.address.state`\n * so Stripe Radar gets a richer address signal. Currently supports US and CA;\n * other countries return `null` (caller should fall back to omitting state).\n */\n\n/**\n * US 3-digit ZIP-prefix ranges → state code (USPS Sectional Center Facility).\n * Sourced from the public USPS SCF table. Each entry is `[startPrefix, endPrefix, stateCode]`,\n * inclusive on both ends. Coverage is contiguous within a state; gaps in the table\n * (e.g. unused 3-digit prefixes) are intentional and resolve to `null`.\n */\nconst US_ZIP_PREFIX_RANGES: ReadonlyArray<readonly [number, number, string]> = [\n [5, 5, 'NY'],\n [10, 27, 'MA'],\n [28, 29, 'RI'],\n [30, 38, 'NH'],\n [39, 49, 'ME'],\n [50, 59, 'VT'],\n [60, 69, 'CT'],\n [70, 89, 'NJ'],\n [100, 149, 'NY'],\n [150, 196, 'PA'],\n [197, 199, 'DE'],\n [200, 205, 'DC'],\n [206, 219, 'MD'],\n [220, 246, 'VA'],\n [247, 268, 'WV'],\n [270, 289, 'NC'],\n [290, 299, 'SC'],\n [300, 319, 'GA'],\n [320, 349, 'FL'],\n [350, 369, 'AL'],\n [370, 385, 'TN'],\n [386, 397, 'MS'],\n [398, 399, 'GA'],\n [400, 427, 'KY'],\n [430, 459, 'OH'],\n [460, 479, 'IN'],\n [480, 499, 'MI'],\n [500, 528, 'IA'],\n [530, 549, 'WI'],\n [550, 567, 'MN'],\n [570, 577, 'SD'],\n [580, 588, 'ND'],\n [590, 599, 'MT'],\n [600, 629, 'IL'],\n [630, 658, 'MO'],\n [660, 679, 'KS'],\n [680, 693, 'NE'],\n [700, 714, 'LA'],\n [716, 729, 'AR'],\n [730, 749, 'OK'],\n [750, 799, 'TX'],\n [800, 816, 'CO'],\n [820, 831, 'WY'],\n [832, 838, 'ID'],\n [840, 847, 'UT'],\n [850, 865, 'AZ'],\n [870, 884, 'NM'],\n [889, 898, 'NV'],\n [900, 961, 'CA'],\n [967, 968, 'HI'],\n [970, 979, 'OR'],\n [980, 994, 'WA'],\n [995, 999, 'AK'],\n];\n\n/**\n * CA postal-code first letter → province code (Forward Sortation Area).\n * The first letter of every Canadian postal code identifies the province\n * uniquely, except `X` which is shared by Northwest Territories and Nunavut\n * — we resolve it to `NT` because the volume strongly favours NT.\n */\nconst CA_FSA_FIRST_LETTER_TO_PROVINCE: Readonly<Record<string, string>> = {\n A: 'NL',\n B: 'NS',\n C: 'PE',\n E: 'NB',\n G: 'QC',\n H: 'QC',\n J: 'QC',\n K: 'ON',\n L: 'ON',\n M: 'ON',\n N: 'ON',\n P: 'ON',\n R: 'MB',\n S: 'SK',\n T: 'AB',\n V: 'BC',\n X: 'NT',\n Y: 'YT',\n};\n\nfunction deriveUsState(zip: string): string | null {\n const digits = zip.replace(/\\D/g, '');\n if (digits.length < 5) return null;\n const prefix = Number.parseInt(digits.slice(0, 3), 10);\n if (!Number.isFinite(prefix)) return null;\n\n for (const [start, end, code] of US_ZIP_PREFIX_RANGES) {\n if (prefix >= start && prefix <= end) return code;\n }\n return null;\n}\n\nfunction deriveCaProvince(postalCode: string): string | null {\n const compact = postalCode.replace(/\\s+/g, '').toUpperCase();\n if (!/^[A-Z]\\d[A-Z]\\d[A-Z]\\d$/.test(compact)) return null;\n const firstLetter = compact[0] ?? '';\n return CA_FSA_FIRST_LETTER_TO_PROVINCE[firstLetter] ?? null;\n}\n\n/**\n * Resolve a state / province code from a postal code for the given country.\n *\n * - US: 5-digit ZIP → 2-letter USPS state code (uses 3-digit prefix table).\n * - CA: A1A 1A1 → 2-letter ISO 3166-2:CA province code (first-letter mapping).\n * - All other countries: `null`.\n *\n * Returns `null` when the postal code is malformed or falls in an unmapped\n * range. Callers should treat `null` as \"skip — don't derive\".\n */\nexport function getStateFromPostalCode(\n country: string,\n postalCode: string,\n): string | null {\n if (!country || !postalCode) return null;\n const normalizedCountry = country.trim().toUpperCase();\n const normalizedZip = postalCode.trim();\n if (!normalizedZip) return null;\n\n switch (normalizedCountry) {\n case 'US':\n return deriveUsState(normalizedZip);\n case 'CA':\n return deriveCaProvince(normalizedZip);\n default:\n return null;\n }\n}\n","import type { CheckoutItem, CheckoutSubscription } from './types.js';\n\n/**\n * Return the trimmed string when it has at least one non-whitespace character,\n * otherwise undefined. Used so that empty and whitespace-only inputs flow\n * through the same fallback chain as `undefined`.\n */\nfunction nonBlank(value: string | null | undefined): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Resolve the session-level currency, honoring the documented fallback:\n * `session.currency ?? items[*].currency ?? subscriptions[*].currency`.\n *\n * Returns the first non-blank currency found, or 'USD' when nothing is set.\n * Empty and whitespace-only strings are treated as unset so they do not\n * bypass the fallback chain.\n */\nexport function resolveSessionCurrency(\n sessionCurrency: string | undefined,\n items: ReadonlyArray<{ currency?: string }> | undefined,\n subscriptions: ReadonlyArray<{ currency?: string }> | undefined,\n): string {\n const session = nonBlank(sessionCurrency);\n if (session) return session;\n for (const item of items ?? []) {\n const c = nonBlank(item.currency);\n if (c) return c;\n }\n for (const sub of subscriptions ?? []) {\n const c = nonBlank(sub.currency);\n if (c) return c;\n }\n return 'USD';\n}\n\n/**\n * Build the request payload for a single item.\n *\n * Sends the new `code` field alongside the deprecated `providerItemId`,\n * `providerItemName`, `totalAmount`, and `overrideAmount` fields so that\n * both new and old backend versions accept the same request body.\n */\nexport function buildItemPayload(\n item: CheckoutItem,\n sessionCurrency: string,\n): Record<string, unknown> {\n const code = nonBlank(item.code) ?? nonBlank(item.providerItemId);\n if (!code) {\n throw new Error('CheckoutItem requires either `code` or the deprecated `providerItemId`.');\n }\n const itemName = nonBlank(item.itemName) ?? nonBlank(item.providerItemName) ?? null;\n\n const payload: Record<string, unknown> = {\n code,\n providerItemId: nonBlank(item.providerItemId) ?? code,\n itemName,\n providerItemName: nonBlank(item.providerItemName) ?? itemName,\n quantity: item.quantity ?? 1,\n totalAmount: item.totalAmount,\n overrideAmount: item.overrideAmount ?? null,\n currency: nonBlank(item.currency) ?? sessionCurrency,\n };\n\n if (item.metadata) {\n payload['metadata'] = item.metadata;\n }\n\n return payload;\n}\n\n/**\n * Build the request payload for a single subscription.\n *\n * Sends the new `code` field alongside the deprecated `providerPlanId`,\n * `providerPlanName`, `totalAmount`, and `overrideAmount` fields for\n * backward compatibility.\n */\nexport function buildSubscriptionPayload(\n subscription: CheckoutSubscription,\n sessionCurrency: string,\n): Record<string, unknown> {\n const code = nonBlank(subscription.code) ?? nonBlank(subscription.providerPlanId);\n if (!code) {\n throw new Error(\n 'CheckoutSubscription requires either `code` or the deprecated `providerPlanId`.',\n );\n }\n const subscriptionName =\n nonBlank(subscription.subscriptionName) ?? nonBlank(subscription.providerPlanName) ?? null;\n\n const payload: Record<string, unknown> = {\n code,\n providerPlanId: nonBlank(subscription.providerPlanId) ?? code,\n subscriptionName,\n providerPlanName: nonBlank(subscription.providerPlanName) ?? subscriptionName,\n quantity: subscription.quantity ?? 1,\n totalAmount: subscription.totalAmount,\n overrideAmount: subscription.overrideAmount ?? null,\n currency: nonBlank(subscription.currency) ?? sessionCurrency,\n };\n\n if (subscription.metadata) {\n payload['metadata'] = subscription.metadata;\n }\n\n return payload;\n}\n","import { resolveSessionCurrency } from './checkout-payload.js';\nimport type { CheckoutSession } from './types.js';\n\n/** A single line item formatted for display in the checkout UI. */\nexport interface DisplayLineItem {\n name: string;\n quantity: number;\n /** Price per unit in the session's currency (major units, e.g. 24.95). */\n price: number;\n /** Original price per unit before any discount (major units). */\n originalPrice: number;\n}\n\n/** Computed display data for rendering an order summary. */\nexport interface CheckoutDisplayData {\n /** Individual items/subscriptions with names, prices, and quantities. */\n items: DisplayLineItem[];\n /** ISO 4217 currency code (uppercase). */\n currency: string;\n /** Total amount due after discounts (major units, e.g. 24.95). */\n total: number;\n /** Sum of original prices before discounts (major units). */\n originalTotal: number;\n /** Total savings (originalTotal - total), clamped to >= 0. */\n totalSave: number;\n /** Discount percentage (0–100). */\n discountPercent: number;\n}\n\n/** Options for {@link buildCheckoutDisplayData}. */\nexport interface BuildCheckoutDisplayDataOptions {\n /**\n * When `true`, items are hidden from the order summary if the session also\n * contains subscriptions (matches the legacy checkout/CheckoutModal\n * behavior). Defaults to `false` — items are always shown.\n */\n hideBundledItems?: boolean;\n}\n\n/**\n * Builds display data from a `CheckoutSession` for rendering an order summary.\n *\n * - Subscriptions are always shown\n * - Items are shown by default; pass `{ hideBundledItems: true }` to suppress\n * them when the session also contains subscriptions (legacy behavior)\n * - `overrideAmount` (when not null/undefined) is the discounted price\n * - Plan name \"4-WEEK PLAN\" with price <= 1 is renamed to \"7-DAY TRIAL: FULL ACCESS\"\n * - Discount percentage and savings are computed from the difference\n *\n * All amounts are in **major currency units** (dollars, not cents).\n *\n * @example\n * ```ts\n * import { buildCheckoutDisplayData } from '@flopay/shared';\n *\n * const display = buildCheckoutDisplayData(session);\n * // display.items → [{ name: 'Starter', price: 24.95, originalPrice: 24.95, quantity: 1 }]\n * // display.total → 24.95\n * // display.currency → 'EUR'\n * ```\n */\nexport function buildCheckoutDisplayData(\n session: CheckoutSession,\n options: BuildCheckoutDisplayDataOptions = {},\n): CheckoutDisplayData {\n const itemsList: DisplayLineItem[] = [];\n\n const subscriptions = session.subscriptions ?? [];\n const items = session.items ?? [];\n\n // Resolve currency once: session > first item > first subscription > USD.\n const currency = resolveSessionCurrency(session.currency, items, subscriptions).toUpperCase();\n\n // Subscriptions\n for (const sub of subscriptions) {\n const originalPrice = sub.totalAmount ?? 0;\n const discountedPrice = sub.overrideAmount ?? originalPrice;\n\n // Match checkout/CheckoutModal: rename \"4-WEEK PLAN\" to \"7-DAY TRIAL: FULL ACCESS\"\n // when the discounted price is $1 or less\n let name = sub.subscriptionName || sub.providerPlanName || sub.code || 'Subscription';\n if (name === '4-WEEK PLAN' && discountedPrice <= 1) {\n name = '7-DAY TRIAL: FULL ACCESS';\n }\n\n itemsList.push({\n name,\n quantity: sub.quantity,\n price: discountedPrice,\n originalPrice,\n });\n }\n\n // Items are shown by default. Opt-in `hideBundledItems` hides them when\n // the session also contains subscriptions (legacy checkout/CheckoutModal\n // behavior).\n const hideItems =\n options.hideBundledItems === true\n && subscriptions.length > 0\n && items.length > 0;\n\n if (!hideItems) {\n for (const item of items) {\n const originalPrice = item.totalAmount ?? 0;\n const discountedPrice = item.overrideAmount ?? originalPrice;\n\n itemsList.push({\n name: item.itemName || item.providerItemName || item.code || 'Item',\n quantity: item.quantity,\n price: discountedPrice,\n originalPrice,\n });\n }\n }\n\n // Fallback if session has no items/subscriptions\n if (itemsList.length === 0) {\n itemsList.push({\n name: 'Purchase',\n quantity: 1,\n price: session.amount / 100,\n originalPrice: session.amount / 100,\n });\n }\n\n const originalTotal = itemsList.reduce((sum, i) => sum + i.originalPrice * i.quantity, 0);\n const total = itemsList.reduce((sum, i) => sum + i.price * i.quantity, 0);\n const totalSave = Math.max(0, originalTotal - total);\n const discountPercent = originalTotal > 0\n ? Math.round((totalSave / originalTotal) * 100)\n : 0;\n\n return {\n items: itemsList,\n currency,\n total,\n originalTotal,\n totalSave,\n discountPercent,\n };\n}\n","import type { CurrencyInfo } from './types.js';\nimport { CURRENCY_MAP, DEFAULT_CURRENCY } from './constants.js';\n\n/**\n * Look up currency information by ISO 3166-1 alpha-2 country code.\n * Falls back to USD when the country is not in the map.\n */\nexport function getCurrencyByCountry(countryCode: string): CurrencyInfo {\n return CURRENCY_MAP[countryCode.toUpperCase()] ?? DEFAULT_CURRENCY;\n}\n\n/** Returns `true` if the string looks like a Stripe publishable key. */\nexport function isValidPublishableKey(key: string): boolean {\n return /^pk_(test|live)_[A-Za-z0-9]+$/.test(key);\n}\n\n/** Returns `true` if the string looks like a Stripe secret key. */\nexport function isValidSecretKey(key: string): boolean {\n return /^sk_(test|live)_[A-Za-z0-9]+$/.test(key);\n}\n"],"mappings":"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ACb,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,EACf,CAAC,KAAK,KAAK,IAAI;AAAA,E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","names":[]}
|