@@ -2,6 +2,11 @@ import { type NextRequest, NextResponse } from 'next/server';
22import generateDescription from '~/server/google-ai' ;
33import { aiSchema } from './schema' ;
44import { authorize } from '~/lib/authorize' ;
5+ import { enforceRateLimit } from '~/lib/rate-limit' ;
6+
7+ const RATE_LIMIT_KEY = 'generateDescription' ;
8+ const RATE_LIMIT_MAX_REQUESTS = 60 ;
9+ const RATE_LIMIT_WINDOW_MS = 60_000 ;
510
611export async function POST ( req : NextRequest ) {
712 const authToken = req . headers . get ( 'X-Auth-Token' ) || 'missing' ;
@@ -10,6 +15,27 @@ export async function POST(req: NextRequest) {
1015 return new NextResponse ( 'Unauthorized' , { status : 401 } ) ;
1116 }
1217
18+ const clientIdentifier =
19+ req . headers . get ( 'x-forwarded-for' ) ?. split ( ',' ) [ 0 ] ?. trim ( ) || req . ip || 'unknown' ;
20+ const rateLimit = await enforceRateLimit (
21+ `${ RATE_LIMIT_KEY } :${ clientIdentifier } ` ,
22+ { windowMs : RATE_LIMIT_WINDOW_MS , maxRequests : RATE_LIMIT_MAX_REQUESTS }
23+ ) ;
24+
25+ if ( ! rateLimit . allowed ) {
26+ const retryAfter = Math . max ( 0 , Math . ceil ( ( rateLimit . reset - Date . now ( ) ) / 1000 ) ) ;
27+
28+ return new NextResponse ( 'Too Many Requests' , {
29+ status : 429 ,
30+ headers : {
31+ 'Retry-After' : retryAfter . toString ( ) ,
32+ 'X-RateLimit-Limit' : rateLimit . limit . toString ( ) ,
33+ 'X-RateLimit-Remaining' : rateLimit . remaining . toString ( ) ,
34+ 'X-RateLimit-Reset' : rateLimit . reset . toString ( ) ,
35+ } ,
36+ } ) ;
37+ }
38+
1339 const data : unknown = await req . json ( ) ;
1440 const parsedParams = aiSchema . safeParse ( data ) ;
1541
@@ -19,5 +45,11 @@ export async function POST(req: NextRequest) {
1945
2046 const description = await generateDescription ( parsedParams . data ) ;
2147
22- return NextResponse . json ( { description } ) ;
48+ const response = NextResponse . json ( { description } ) ;
49+
50+ response . headers . set ( 'X-RateLimit-Limit' , rateLimit . limit . toString ( ) ) ;
51+ response . headers . set ( 'X-RateLimit-Remaining' , rateLimit . remaining . toString ( ) ) ;
52+ response . headers . set ( 'X-RateLimit-Reset' , rateLimit . reset . toString ( ) ) ;
53+
54+ return response ;
2355}
0 commit comments