import Stripe from 'stripe'; export class StripeService { private stripe: Stripe | null = null; private webhookSecret: string | null = null; private clientUrl: string; constructor() { const secretKey = process.env.STRIPE_SECRET_KEY; const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET; this.webhookSecret = webhookSecret || null; this.clientUrl = process.env.VITE_CLIENT_URL || 'http://localhost:5174'; if (secretKey) { this.stripe = new Stripe(secretKey, { apiVersion: '2025-01-27.acacia' as any, }); } } /** * Creates a Stripe Checkout Session for a specific track and user. */ async createCheckoutSession(userId: string, trackId: string, priceId: string, userPhone: string) { if (!this.stripe) throw new Error('[StripeService] STRIPE_SECRET_KEY is not configured'); try { const session = await this.stripe.checkout.sessions.create({ payment_method_types: ['card'], line_items: [ { price: priceId, quantity: 1, }, ], mode: 'payment', success_url: `${this.clientUrl}/payment/success?session_id={CHECKOUT_SESSION_ID}&track=${trackId}`, cancel_url: `${this.clientUrl}/student?cancel=true`, metadata: { userId, trackId, userPhone } }); return session.url; } catch (error) { console.error('[StripeService] Failed to create checkout session:', error); throw error; } } /** * Verifies the signature of an incoming Stripe webhook. */ verifyWebhookSignature(payload: Buffer, signature: string | undefined): Stripe.Event { if (!this.stripe || !this.webhookSecret) { throw new Error('[StripeService] Stripe is not configured (missing keys)'); } if (!signature) { throw new Error('Missing stripe-signature header'); } try { return this.stripe.webhooks.constructEvent( payload, signature, this.webhookSecret ); } catch (err: unknown) { throw new Error(`Webhook Error: ${(err instanceof Error ? (err instanceof Error ? err.message : String(err)) : String(err))}`); } } } export const stripeService = new StripeService();