CognxSafeTrack
chore: execute Sprint 38 technical debt resolution (Type Safety, Zod validation, Vitest, Mock LLM extracted)
d9879cf | 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(); | |