@flopay/shared

v1.3.0

Published

Shared types, error classes, constants, and validation helpers used across all FloPay packages. This package contains no runtime logic beyond error factories and validation functions -- it is primarily a type/constant library.

Readme

@flopay/shared

Shared types, error classes, constants, and validation helpers used across all FloPay packages. This package contains no runtime logic beyond error factories and validation functions -- it is primarily a type/constant library.

Installation

pnpm add @flopay/shared

Within the monorepo, packages depend on it via workspace:*.

Quick Start

Environment Configuration

import { configureFlopay } from '@flopay/shared';

// Call once at app startup — determines which billing API URL is used
configureFlopay({ environment: 'production' }); // or 'staging'

// Or set NEXT_PUBLIC_FLOPAY_ENV=production in your .env file (no code needed)

Resolve Billing API URL

import { resolveBillingApiUrl } from '@flopay/shared';

// Reads from: explicit param → env var → configureFlopay() → staging fallback
const url = resolveBillingApiUrl();

Other Imports

import {
  FloPayError,
  validationError,
  SDK_VERSION,
  DEFAULT_APPEARANCE,
  NIGHT_APPEARANCE,
  THEMES,
  CURRENCY_MAP,
  getCurrencyByCountry,
  isValidPublishableKey,
} from '@flopay/shared';

// Pick a coherent theme bundle and pass both halves to your checkout
const { appearance, buttonsLayout } = THEMES['glass-dark'];

import type {
  FloPayConfig,
  FloPayEnvironment,
  CheckoutSession,
  PaymentResult,
  PaymentProviderAdapter,
  ElementType,
  FloPayAppearance,
} from '@flopay/shared';

// Validate a key
isValidPublishableKey('pk_test_abc123'); // true

// Look up currency by country
const info = getCurrencyByCountry('DE');
// { currency: 'EUR', symbol: '\u20ac', country: 'Germany', countryCode: 'DE', tax: 1 }

// Create a structured error
throw validationError('Email is required', 'email');

API Reference

Types

| Type | Description | |------|-------------| | FloPayConfig | Top-level config: publishableKey, locale?, appearance?, apiVersion? | | FloPayAppearance | Theme config: theme ('default'/'flat'/'night'/'none'), variables?, rules? | | FloPayThemeVariables | CSS custom property overrides: colorPrimary, colorBackground, colorText, colorDanger, borderRadius, fontFamily, fontSizeBase, spacingUnit | | ButtonsLayoutStyles | Style overrides for the buttons layout: cardButton, cardButtonFontSize, cardFormContainer, cardInputBorder, cardInputColor, cardInputPlaceholderColor, cardInputFontSize, cardInputBackground, nameInput, backButton, backButtonFontSize, backButtonIcon, submitButton, submitButtonFontSize, title, titleFontSize, errorBanner | | ButtonsLayoutTheme | Theme preset name: 'default' / 'minimal' / 'rounded' / 'dark' / 'modern-light' / 'modern-dark' / 'bold-light' / 'bold-dark' / 'glass-light' / 'glass-dark' | | ThemeBundle | A coherent theme bundle: { appearance: FloPayAppearance, buttonsLayout: ButtonsLayoutStyles } | | ThemeBundleId | Bundle id: 'modern-light' / 'modern-dark' / 'bold-light' / 'bold-dark' / 'glass-light' / 'glass-dark' | | ThemeId | Accepted by the React components' theme prop: 'classic'ThemeBundleId | | CheckoutMode | Checkout mode: 'full' / 'auto' / 'confirm' | | CheckoutSession | Session object: id, clientSecret, mode, status, amount, currency, customer?, checkoutMode?, products? (unified CheckoutSessionProduct[]), successUrl?, cancelUrl?, coupons?, subtotalAmount? / discountAmount? / totalAmount? (cart-currency major units; populated by billing API ≥ v1.1.2), gateways? (map keyed by gateway code — stripe, paypal, …), accountData?, tagsData? | | CheckoutSessionProduct | Unified product from session response: uuid, checkoutSessionId, type ('item'/'subscription'), code?, name?, description?, quantity, totalAmount?, overrideAmount?, currency?, metadata? | | CheckoutProductType | 'item' / 'subscription' | | CheckoutProduct | Unified product input for session creation: type, code?, name?, quantity?, totalAmount?, overrideAmount?, currency?, metadata? | | CheckoutGateway | Per-gateway config: publishableKey?, environment? ('sandbox'/'live'), stripeClientSecret? (Stripe-only) | | CheckoutGateways | Map keyed by gateway code (e.g. stripe, paypal). A session can advertise multiple concurrent gateways. | | GatewayEnvironment | 'sandbox' / 'live' — drives the PayPal JS SDK script and any other environment-scoped behavior | | PaymentResult | Payment outcome: status ('succeeded'/'processing'/'requires_action'/'failed'), paymentIntentId?, error? | | ConfirmPaymentParams | clientSecret, returnUrl? | | CreatePaymentMethodResult | paymentMethodId, error? | | ConfirmCardPaymentParams | clientSecret, paymentMethodId | | ConfirmCardPaymentResult | status, paymentIntentId?, paymentMethodId?, error? | | ElementType | 'payment' / 'card' / 'cardNumber' / 'cardExpiry' / 'cardCvc' / 'address' | | ElementOptions | Options for creating elements: appearance?, clientSecret?, amount?, currency?, paymentMethodCreation?, layout?, defaultValues?, readOnly?, mode?, style? | | MountedElement | Runtime element: mount(), unmount(), update(), on(), off(), destroy() | | PaymentProviderAdapter | Provider interface: initialize(), createElement(), getElement(), submitElements(), createPaymentMethod(), confirmCardPayment(), confirmPayment(), confirmPayPalPayment(), resumePayPalPayment(), getRawProvider(), createPayPalElements(), destroy() | | ElementChangeEvent | Change event: elementType, complete, empty, error?, value? | | Customer | id, email, firstName?, lastName?, gender?, city?, state?, country?, zip? | | LineItem | price?, priceData?, quantity | | PriceData | currency, unitAmount, productData, recurring? | | RecurringInterval | interval ('month'/'year'), intervalCount? | | BillingProvider | 'recurly' / 'chargebee' / 'stripe' | | TokenizedBody | id?, type?, threeDSecureActionResultTokenId?, originalPaymentMethodId?, gateway? ('stripe' / 'paypal' / custom), paymentMethodType? (Stripe wire identifier — 'card', 'apple_pay', 'cashapp', 'klarna', … for gateway='stripe'; 'paypal' for gateway='paypal'), isPaypal? (deprecated — replaced by gateway + paymentMethodType; still set for PayPal during the deprecation window so backends gating on isPaypal === 'true' keep working) | | CheckoutGateway | Per-gateway config from the billing API: publishableKey?, environment?, stripeClientSecret?, paypalPublishableKey?, enabledPaymentMethods? (Stripe-only — per-session list of Stripe method type identifiers that the gateway has enabled for this consumer; drives dynamic ExpressCheckoutElement / PaymentElement rendering in @flopay/react) | | NormalizedCheckoutSession | Provider-agnostic session: provider, mode, data, raw? | | CheckoutModeKind | 'tokenize' / 'redirect' | | CreateSessionParams | Full session creation params: billingApiUrl, checkoutBaseUrl, clientId, currency (required — SDK throws FloPayError({ type: 'validation_error', code: 'CurrencyRequired' }) before issuing the request when none can be resolved), products? (unified shape; takes precedence), items?, subscriptions? (legacy — folded into products[] before send), account, successUrl, cancelUrl, checkoutMode?, couponCodes?, tagsData?, redirectParams?, setCookie?, timeoutMs?, utmMetadata? | | CheckoutSessionResult | { status: 201; redirectUrl; nonce } / { status: 204 } / { status: number } (nonce is the session-bound checkout token returned by the billing API — forward it on every continuation call against the same session via x-checkout-session-token) | | CheckoutItem | providerItemId, providerItemName?, quantity?, totalAmount, overrideAmount?, currency? | | CheckoutSubscription | providerPlanId, providerPlanName?, quantity?, totalAmount, overrideAmount?, currency? | | CheckoutAccount | userId, firstName?, lastName?, email, country?, gender?, city?, state?, zip? | | ProcessPaymentParams | sessionId, nonce (required — session-bound checkout token, forwarded as x-checkout-session-token), tokenizedData?, accountData, chv? | | CreateCustomerParams | email, name?, metadata? | | UpdateCustomerParams | email?, name?, metadata? | | WebhookEvent | id, type, data, created | | CurrencyInfo | currency, symbol, country, countryCode, tax | | CountryOption | code, name, flag | | TagsData | googleContainerId?, sessionId?, testEventCode? |

Error Classes

| Export | Description | |--------|-------------| | FloPayError | Custom error class with type, code?, declineCode?, param?, statusCode? | | FloPayErrorType | 'validation_error' / 'api_error' / 'authentication_error' / 'rate_limit_error' / 'network_error' | | validationError(message, param?) | Factory for validation errors | | apiError(message, code?, statusCode?) | Factory for API errors | | authenticationError(message) | Factory for auth errors | | rateLimitError(message) | Factory for rate limit errors | | networkError(message) | Factory for network errors |

Constants

| Export | Description | |--------|-------------| | SDK_VERSION | Current SDK version ('0.1.0') | | DEFAULT_API_BASE_URL | 'https://api.flopay.io' | | DEFAULT_API_VERSION | '2024-01-01' | | DEFAULT_APPEARANCE | Default theme (primary #4A49FF, white background, Poppins font) | | FLAT_APPEARANCE | Flat theme (minimal borders, 4px radius) | | NIGHT_APPEARANCE | Dark theme (dark background #1A1A2E, light text) | | MODERN_LIGHT_APPEARANCE | Clean & airy light — Inter, FloPay-blue primary #1785E0, slate text, 14px radius, soft input shadows | | MODERN_DARK_APPEARANCE | Clean & airy dark — Inter, sky-blue primary #60A5FA, deep-blue surface #0B1220, 14px radius | | BOLD_LIGHT_APPEARANCE | Bold & vibrant light — Inter, saturated FloPay blue #1785E0, 2px borders, 600+ font weight, gradient-ready | | BOLD_DARK_APPEARANCE | Bold & vibrant dark — Inter, sky #60A5FA on deep-blue #0C2B4D, accented borders | | GLASS_LIGHT_APPEARANCE | Glass / elevated light — translucent inputs with backdrop blur, FloPay-blue primary #1785E0, 16px radius | | GLASS_DARK_APPEARANCE | Glass / elevated dark — translucent inputs with backdrop blur, #60A5FA on slate #0F172A | | BUTTONS_LAYOUT_DEFAULT / _MINIMAL / _ROUNDED / _DARK | Original buttons-layout style presets (back-compat) | | BUTTONS_LAYOUT_MODERN_LIGHT / _MODERN_DARK | Wrapper styles paired with the modern appearance bundles | | BUTTONS_LAYOUT_BOLD_LIGHT / _BOLD_DARK | Wrapper styles paired with the bold appearance bundles | | BUTTONS_LAYOUT_GLASS_LIGHT / _GLASS_DARK | Wrapper styles paired with the glass appearance bundles | | THEMES | Record<ThemeBundleId, ThemeBundle> — pick THEMES['glass-dark'] to get { appearance, buttonsLayout } | | resolveTheme(id) | Resolve a ThemeId ('classic'ThemeBundleId) to its ThemeBundle; 'classic' and missing ids return undefined | | resolveButtonsLayoutTheme(name) | Map a ButtonsLayoutTheme name to its ButtonsLayoutStyles preset | | ELEMENT_TYPES | ['payment', 'card', 'cardNumber', 'cardExpiry', 'cardCvc', 'address'] | | SUPPORTED_CARD_BRANDS | ['visa', 'mastercard', 'mastercard_debit', 'amex', 'discover'] | | STRIPE_EXPRESS_METHODS | ['apple_pay', 'google_pay', 'paypal', 'link', 'amazon_pay', 'klarna'] — Stripe method type identifiers supported by ExpressCheckoutElement (everything else returned in gateways.stripe.enabledPaymentMethods falls into the PaymentElement accordion in the React SDK) | | partitionStripeMethods(enabledMethods, { excludePaypal? }) | Split the backend's enabled list into { expressMethods, paymentElementMethods }. Drops card; also drops paypal when excludePaypal: true. | | stripeExpressMethodToOptionKey(method) | Map Stripe wire identifiers (apple_pay, google_pay, amazon_pay) to the camelCase keys (applePay, googlePay, amazonPay) expected by ExpressCheckoutElement's paymentMethods options map. | | CURRENCY_MAP | Country code to CurrencyInfo mapping (EU, GB, US, CA, NZ, AU) | | DEFAULT_CURRENCY | USD fallback |

Validation Helpers

| Export | Description | |--------|-------------| | getCurrencyByCountry(countryCode) | Returns CurrencyInfo for a country code, falls back to USD | | isValidPublishableKey(key) | Returns true if the key matches pk_(test|live)_... | | isValidSecretKey(key) | Returns true if the key matches sk_(test|live)_... |