1- import { NextRequest , NextResponse } from 'next/server' ;
2- import { getServerSession } from 'next-auth' ;
3- import { authOptions } from '@/lib/auth' ;
4- import { ai } from '@/lib/ai' ;
5- import { canUserPost , appendPost , ensureUserExists } from '@/lib/db' ;
6- import { generateRequestId , trace } from '@/lib/trace' ;
7- import { withRateLimit } from '@/lib/rate-limit' ;
8- import { z } from 'zod' ;
1+ import { NextRequest , NextResponse } from "next/server" ;
2+ import { getServerSession } from "next-auth" ;
3+ import { authOptions } from "@/lib/auth" ;
4+ import { prisma } from "@/lib/prisma" ;
5+ import { canUserPost , appendPost , ensureUserExists } from "@/lib/db" ;
6+ import { generateRequestId , trace } from "@/lib/trace" ;
7+ import { withRateLimit } from "@/lib/rate-limit" ;
8+ import { z } from "zod" ;
9+ import { Anthropic } from "@anthropic-ai/sdk" ;
910
10- const generateSchema = z . object ( {
11- prompt : z . string ( ) . trim ( ) . min ( 10 ) . max ( 500 ) ,
12- platform : z . enum ( [ "x" , "instagram" , "linkedin" ] ) ,
13- } ) ;
11+ const ALLOWED_PLATFORMS = [ "x" , "facebook" , "instagram" , "linkedin" , "threads" ] as const ;
1412
15- const postSchema = z . object ( {
16- post : z . string ( ) ,
17- hashtags : z . array ( z . string ( ) ) . min ( 3 ) . max ( 5 ) ,
13+ const generateSchema = z . object ( {
14+ prompt : z . string ( ) . min ( 5 ) . max ( 500 ) ,
15+ platform : z . enum ( ALLOWED_PLATFORMS ) ,
1816} ) ;
1917
2018const platformMap : Record < string , string > = {
2119 x : "X (Twitter)" ,
20+ facebook : "Facebook" ,
2221 instagram : "Instagram" ,
2322 linkedin : "LinkedIn" ,
23+ threads : "Threads" ,
2424} ;
2525
2626export async function POST ( req : NextRequest ) {
@@ -31,12 +31,12 @@ export async function POST(req: NextRequest) {
3131 try {
3232 const session = await getServerSession ( authOptions ) ;
3333 if ( ! session ?. user ?. email ) {
34- return NextResponse . json ( { error : "Unauthorized" } , { status : 401 } ) ;
34+ return NextResponse . json ( { error : "Unauthorized. Please sign in. " } , { status : 401 } ) ;
3535 }
3636
3737 const parsed = generateSchema . safeParse ( await req . json ( ) ) ;
3838 if ( ! parsed . success ) {
39- return NextResponse . json ( { error : "Invalid request" , details : parsed . error . flatten ( ) } , { status : 400 } ) ;
39+ return NextResponse . json ( { error : "Invalid platform or prompt." } , { status : 400 } ) ;
4040 }
4141
4242 const { prompt, platform } = parsed . data ;
@@ -45,26 +45,59 @@ export async function POST(req: NextRequest) {
4545
4646 const check = await canUserPost ( user . id , user . plan ) ;
4747 if ( ! check . allowed ) {
48- return NextResponse . json ( {
48+ return NextResponse . json ( {
4949 error : check . reason ,
50- limitReached : true
50+ limitReached : true ,
5151 } , { status : 429 } ) ;
5252 }
5353
54- const result = await ai . generate ( {
55- prompt : `Write a concise ${ platformMap [ platform ] } post about: ${ prompt } . Keep it sharp and useful. Include relevant hashtags.` ,
56- schema : postSchema ,
57- config : { provider : "gemini" } ,
58- trace : { requestId, event : "generate.post" } ,
54+ if ( user . plan === "lifetime" ) {
55+ const allowedLifetimePlatforms = [ "x" , "facebook" , "instagram" ] ;
56+ if ( ! allowedLifetimePlatforms . includes ( platform ) ) {
57+ return NextResponse . json ( {
58+ error : `The Lifetime plan only supports: X, Facebook, and Instagram. Please upgrade to the Agency plan to unlock ${ platform . toUpperCase ( ) } !` ,
59+ } , { status : 403 } ) ;
60+ }
61+ }
62+
63+ const anthropicApiKey = process . env . ANTHROPIC_API_KEY ;
64+ if ( ! anthropicApiKey ) {
65+ throw new Error ( "CRITICAL: ANTHROPIC_API_KEY is missing." ) ;
66+ }
67+
68+ const anthropic = new Anthropic ( { apiKey : anthropicApiKey } ) ;
69+
70+ const completion = await anthropic . messages . create ( {
71+ model : "claude-3-haiku-20240307" ,
72+ max_tokens : 1000 ,
73+ messages : [
74+ {
75+ role : "user" ,
76+ content : `Write a high-converting post optimized specifically for ${ platformMap [ platform ] } based on this request: ${ prompt } ` ,
77+ } ,
78+ ] ,
5979 } ) ;
6080
61- await appendPost ( {
81+ const generatedText =
82+ completion . content [ 0 ] . type === "text"
83+ ? completion . content [ 0 ] . text
84+ : "No text generated" ;
85+
86+ const post = await appendPost ( {
6287 userId : user . id ,
63- content : result . post ,
88+ content : generatedText ,
6489 platform,
6590 prompt,
6691 } ) ;
6792
93+ await prisma . auditLog . create ( {
94+ data : {
95+ userId : user . id ,
96+ action : "generation" ,
97+ metadata : { platform, prompt, characterCount : generatedText . length , postId : post . id } as any ,
98+ } ,
99+ } ) ;
100+
68101 trace ( {
69102 requestId,
70103 event : "generate.post.completed" ,
@@ -75,21 +108,21 @@ export async function POST(req: NextRequest) {
75108
76109 return NextResponse . json ( {
77110 success : true ,
78- post : result . post ,
79- hashtags : result . hashtags ,
111+ platform ,
112+ content : generatedText ,
80113 remaining : check . limit ? check . limit - ( user . dailyPostsUsed + 1 ) : null ,
81114 } ) ;
82-
83- } catch ( error : any ) {
115+ } catch ( error : unknown ) {
116+ const message = error instanceof Error ? error . message : "Internal Server Error during generation." ;
84117 trace ( {
85118 requestId,
86119 event : "generate.post.error" ,
87120 durationMs : Date . now ( ) - start ,
88121 status : "error" ,
89- error : error . message ,
122+ error : message ,
90123 } ) ;
91124
92- return NextResponse . json ( { error : "Failed to generate post" , detail : error . message } , { status : 500 } ) ;
125+ return NextResponse . json ( { error : message } , { status : 500 } ) ;
93126 }
94127 } ) ;
95128}
0 commit comments