From 8799ce522f7746956cf0cf343d258f381882527f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 6 May 2026 11:04:38 +0000 Subject: [PATCH] fix: bind credit APIs to authenticated user Co-authored-by: Cole Collins --- app/api/analyses/[id]/analyze/route.ts | 14 +++---- app/api/credits/summary/route.ts | 18 ++++---- app/api/generate-scaffold/route.ts | 57 ++++++++++++-------------- components/credits-display.tsx | 2 +- 4 files changed, 44 insertions(+), 47 deletions(-) diff --git a/app/api/analyses/[id]/analyze/route.ts b/app/api/analyses/[id]/analyze/route.ts index f48138d..7c54a93 100644 --- a/app/api/analyses/[id]/analyze/route.ts +++ b/app/api/analyses/[id]/analyze/route.ts @@ -1,5 +1,6 @@ import { NextRequest, NextResponse } from 'next/server' import { generateText } from 'ai' +import { getCurrentUser } from '@/lib/auth' import { getCreditBalance, deductCredits, CREDITS } from '@/lib/credits' import { getAnalysisById } from '@/lib/queries' @@ -22,18 +23,17 @@ interface AppSuggestion { export async function POST(request: NextRequest) { try { - const { analysisId, selectedRepos, userId } = (await request.json()) as { + const { analysisId, selectedRepos } = (await request.json()) as { analysisId: string selectedRepos: SelectedRepository[] - userId: string } - // Check credit balance before proceeding - if (!userId) { - return NextResponse.json({ error: 'User ID required' }, { status: 401 }) + const user = await getCurrentUser() + if (!user?.id) { + return NextResponse.json({ error: 'Sign in with GitHub before running an analysis.' }, { status: 401 }) } - const currentBalance = await getCreditBalance(userId) + const currentBalance = await getCreditBalance(user.id) if (currentBalance < CREDITS.ANALYSIS_COST) { return NextResponse.json( { @@ -96,7 +96,7 @@ Return as JSON array of app suggestions. Focus on practical, buildable applicati } // Deduct credits for successful analysis - const deductResult = await deductCredits(userId, CREDITS.ANALYSIS_COST, 'analysis', { + const deductResult = await deductCredits(user.id, CREDITS.ANALYSIS_COST, 'analysis', { analysisId, selectedRepos: selectedRepos.map((r) => r.name), }) diff --git a/app/api/credits/summary/route.ts b/app/api/credits/summary/route.ts index 6445841..111e2f4 100644 --- a/app/api/credits/summary/route.ts +++ b/app/api/credits/summary/route.ts @@ -1,21 +1,21 @@ -import { NextRequest, NextResponse } from 'next/server' +import { NextResponse } from 'next/server' +import { getCurrentUser } from '@/lib/auth' import { getOrCreateUserCredits, getCreditUsageSummary } from '@/lib/credits' -export async function GET(request: NextRequest) { +export async function GET() { try { - const userId = request.nextUrl.searchParams.get('userId') - - if (!userId) { + const user = await getCurrentUser() + if (!user?.id) { return NextResponse.json( - { error: 'User ID is required' }, - { status: 400 } + { error: 'Sign in with GitHub to view credits.' }, + { status: 401 } ) } // Get credits and usage summary const [credits, summary] = await Promise.all([ - getOrCreateUserCredits(userId), - getCreditUsageSummary(userId), + getOrCreateUserCredits(user.id), + getCreditUsageSummary(user.id), ]) return NextResponse.json({ diff --git a/app/api/generate-scaffold/route.ts b/app/api/generate-scaffold/route.ts index 8ad1b70..b647f77 100644 --- a/app/api/generate-scaffold/route.ts +++ b/app/api/generate-scaffold/route.ts @@ -1,12 +1,8 @@ import { NextRequest, NextResponse } from 'next/server' import Anthropic from '@anthropic-ai/sdk' import { getAnthropicModel } from '@/lib/anthropic-model' -import { getCreditBalance, deductCredits, CREDITS } from '@/lib/credits' - -const client = new Anthropic({ - apiKey: process.env.ANTHROPIC_API_KEY, -}) import { getCurrentUser } from '@/lib/auth' +import { getCreditBalance, deductCredits, CREDITS } from '@/lib/credits' import { getSubscriptionByGithubId, upsertSubscription } from '@/lib/queries' export async function POST(request: NextRequest) { @@ -18,9 +14,9 @@ export async function POST(request: NextRequest) { ) } - const { appName, description, technologies, existingFiles, missingFiles, userId } = await request.json() + const { appName, description, technologies, existingFiles, missingFiles } = await request.json() const user = await getCurrentUser() - if (!user) { + if (!user?.id) { return NextResponse.json({ error: 'Sign in with GitHub to generate scaffolds.' }, { status: 401 }) } @@ -40,19 +36,17 @@ export async function POST(request: NextRequest) { } // Check credit balance before proceeding - if (userId) { - const currentBalance = await getCreditBalance(userId) - if (currentBalance < CREDITS.SCAFFOLD_COST) { - return NextResponse.json( - { - error: 'Insufficient credits', - required: CREDITS.SCAFFOLD_COST, - available: currentBalance, - message: 'Upgrade to Pro to get unlimited scaffold generation with 5,000 monthly credits.', - }, - { status: 402 } - ) - } + const currentBalance = await getCreditBalance(user.id) + if (currentBalance < CREDITS.SCAFFOLD_COST) { + return NextResponse.json( + { + error: 'Insufficient credits', + required: CREDITS.SCAFFOLD_COST, + available: currentBalance, + message: 'Upgrade to Pro to get unlimited scaffold generation with 5,000 monthly credits.', + }, + { status: 402 } + ) } console.log('[v0] Generating scaffold for app:', appName) @@ -140,18 +134,21 @@ Example structure: // Deduct credits after successful generation let creditsUsed = 0 - if (userId) { - const deductResult = await deductCredits(userId, CREDITS.SCAFFOLD_COST, 'scaffold', { - appName, - technologies, - }) - - if (deductResult.success) { - creditsUsed = CREDITS.SCAFFOLD_COST - console.log(`[v0] Deducted ${CREDITS.SCAFFOLD_COST} credits from user ${userId}`) - } + const deductResult = await deductCredits(user.id, CREDITS.SCAFFOLD_COST, 'scaffold', { + appName, + technologies, + }) + + if (!deductResult.success) { + return NextResponse.json( + { error: deductResult.error || 'Insufficient credits' }, + { status: 402 } + ) } + creditsUsed = CREDITS.SCAFFOLD_COST + console.log(`[v0] Deducted ${CREDITS.SCAFFOLD_COST} credits from user ${user.id}`) + return NextResponse.json({ success: true, scaffold, diff --git a/components/credits-display.tsx b/components/credits-display.tsx index 7787ade..07918b1 100644 --- a/components/credits-display.tsx +++ b/components/credits-display.tsx @@ -21,7 +21,7 @@ export function CreditsDisplay({ userId }: CreditsDisplayProps) { const fetchCredits = async () => { try { setLoading(true) - const response = await fetch(`/api/credits/summary?userId=${userId}`) + const response = await fetch('/api/credits/summary') if (!response.ok) throw new Error('Failed to fetch credits') const data = await response.json() setCredits(data.credits)