import { createLogger } from '@sim/logger' import Stripe from 'stripe' import { env } from '@/lib/core/config/env' const logger = createLogger('StripeClient') /** * Check if Stripe credentials are valid */ export function hasValidStripeCredentials(): boolean { return !!env.STRIPE_SECRET_KEY } /** * Secure Stripe client singleton with initialization guard */ const createStripeClientSingleton = () => { let stripeClient: Stripe | null = null let isInitializing = false return { getInstance(): Stripe | null { // If already initialized, return immediately if (stripeClient) return stripeClient // Prevent concurrent initialization attempts if (isInitializing) { logger.debug('Stripe client initialization already in progress') return null } if (!hasValidStripeCredentials()) { logger.warn('Stripe credentials not available - Stripe operations will be disabled') return null } try { isInitializing = true stripeClient = new Stripe(env.STRIPE_SECRET_KEY || '', { apiVersion: '2025-08-27.basil', }) logger.info('Stripe client initialized successfully') return stripeClient } catch (error) { logger.error('Failed to initialize Stripe client', { error }) stripeClient = null // Ensure cleanup on failure return null } finally { isInitializing = false } }, // For testing purposes only - allows resetting the singleton reset(): void { stripeClient = null isInitializing = false }, } } const stripeClientSingleton = createStripeClientSingleton() /** * Get the Stripe client instance * @returns Stripe client or null if credentials are not available */ export function getStripeClient(): Stripe | null { return stripeClientSingleton.getInstance() } /** * Get the Stripe client instance, throwing an error if not available * Use this when Stripe operations are required */ export function requireStripeClient(): Stripe { const client = getStripeClient() if (!client) { throw new Error( 'Stripe client is not available. Set STRIPE_SECRET_KEY in your environment variables.' ) } return client }