import { fetchRequestHandler } from '@trpc/server/adapters/fetch' import { appRouter } from '@/server/routers/_app' import { createContext } from '@/server/context' import { checkRateLimit } from '@/lib/rate-limit' const RATE_LIMIT = 100 // requests per window const RATE_WINDOW_MS = 60 * 1000 // 1 minute function getClientIp(req: Request): string { return ( req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || req.headers.get('x-real-ip') || 'unknown' ) } const handler = (req: Request) => { const ip = getClientIp(req) const { success, remaining, resetAt } = checkRateLimit(`trpc:${ip}`, RATE_LIMIT, RATE_WINDOW_MS) if (!success) { return new Response(JSON.stringify({ error: 'Too many requests' }), { status: 429, headers: { 'Content-Type': 'application/json', 'Retry-After': String(Math.ceil((resetAt - Date.now()) / 1000)), 'X-RateLimit-Limit': String(RATE_LIMIT), 'X-RateLimit-Remaining': '0', }, }) } return fetchRequestHandler({ endpoint: '/api/trpc', req, router: appRouter, createContext, responseMeta() { return { headers: { 'X-RateLimit-Limit': String(RATE_LIMIT), 'X-RateLimit-Remaining': String(remaining), }, } }, onError: ({ path, error }) => { console.error(`tRPC failed on ${path ?? ''}:`, error.message) }, }) } export { handler as GET, handler as POST }