codeflash-internal/js/cf-api/endpoints/subscription-management.ts
Kevin Turcios d7a8b8f227
perf: fix CI build + lazy-load heavy libs + parallelize DB queries (#2601)
## Summary
- **Fix CI build failure**: Auth0Client crashes during Next.js
prerendering when env vars aren't set. Returns a no-op stub (`getSession
→ null`) when domain is missing — semantically correct for static
generation
- **Lazy-load markdown libs (~260kb)**: ReactMarkdown, remarkGfm, and
react-syntax-highlighter were eagerly imported in monaco-diff-viewer but
only rendered when user expands "Generated Tests". Extracted into a
dynamic component
- **Parallelize repo detail query**: `getRepositoryById` ran the
activity count sequentially after the repo lookup. Since `repoId` is
already available, all three queries now run in parallel

## Test plan
- [ ] CI `build` check passes (was failing since #2598)
- [ ] Trace page still renders generated tests correctly when expanded
- [ ] Repository detail page loads correctly with activity status
2026-04-13 11:03:05 -05:00

132 lines
3.9 KiB
TypeScript

import { Request, Response, NextFunction } from "express"
import {
prisma,
createCheckoutSession,
getSubscription as fetchSubscription,
cancelSubscription as cancelStripeSubscription,
} from "@codeflash-ai/common"
import * as Sentry from "@sentry/node"
import { logger } from "../utils/logger.js"
import { missingRequiredFields, subscriptionNotFound } from "../exceptions/index.js"
// Dependencies interface for easier testing
export interface SubscriptionDependencies {
prisma: {
subscriptions: {
findUnique: (params: any) => Promise<any>
}
}
createCheckoutSession: typeof createCheckoutSession
fetchSubscription: typeof fetchSubscription // Add this
cancelStripeSubscription: typeof cancelStripeSubscription
Sentry: {
captureException: (error: any) => void
}
}
// Default dependencies
let dependencies: SubscriptionDependencies = {
prisma,
createCheckoutSession,
fetchSubscription,
cancelStripeSubscription,
Sentry,
}
// For testing - allow dependency injection
export function setSubscriptionDependencies(deps: Partial<SubscriptionDependencies>) {
dependencies = { ...dependencies, ...deps }
}
export function resetSubscriptionDependencies() {
dependencies = {
prisma,
createCheckoutSession,
fetchSubscription,
cancelStripeSubscription,
Sentry,
}
}
// Get a user's subscription details
export async function getSubscription(req: Request, res: Response, next: NextFunction) {
const userId = req.query.userId as string
if (!userId) {
next(missingRequiredFields("userId"))
return
}
try {
// Get subscription with usage data (includes lazy reset)
const subscription = await dependencies.fetchSubscription(userId)
if (!subscription) {
next(subscriptionNotFound(userId))
return
}
return res.json({
plan: subscription.plan_type,
status: subscription.subscription_status,
usageCount: subscription.optimizations_used,
usageLimit: subscription.optimizations_limit,
renewalDate: subscription.current_period_end,
totalLifetimeOptimizations: subscription.total_lifetime_optimizations,
})
} catch (error) {
logger.errorWithSentry("Error getting subscription", req, {}, error as Error)
dependencies.Sentry.captureException(error)
next(error) // Pass errors to the error handler
}
}
// Create a checkout session for upgrading subscription
export async function createCheckout(req: Request, res: Response, next: NextFunction) {
const { userId, priceId, successUrl, cancelUrl, period } = req.body
if (!userId || !priceId) {
next(missingRequiredFields("userId, priceId"))
return
}
try {
// Use the common function with options object
const checkoutUrl = await dependencies.createCheckoutSession(userId, priceId, {
successUrl: successUrl || `${process.env.WEBAPP_URL}/app/billing?success=true`,
cancelUrl: cancelUrl || `${process.env.WEBAPP_URL}/app/billing?canceled=true`,
period: period || (priceId === process.env.STRIPE_PRO_PRICE_YEARLY_ID ? "yearly" : "monthly"),
})
return res.json({ url: checkoutUrl })
} catch (error) {
logger.errorWithSentry(
"Error creating checkout session",
req,
{ successUrl, cancelUrl, period },
error as Error,
)
dependencies.Sentry.captureException(error)
next(error) // Pass errors to the error handler
}
}
// Cancel a subscription
export async function cancelSubscription(req: Request, res: Response, next: NextFunction) {
const { userId } = req.body
if (!userId) {
next(missingRequiredFields("userId"))
return
}
try {
// Use the common function for cancellation
await dependencies.cancelStripeSubscription(userId)
return res.json({ status: "canceled" })
} catch (error) {
logger.errorWithSentry("Error canceling subscription", req, {}, error as Error)
dependencies.Sentry.captureException(error)
next(error) // Pass errors to the error handler
}
}