import { criarLink, enderecoBase, ErroDeValidacao, listarLinks, paraJson } from '@/lib/links'; // CORS aberto só na API: qualquer site (ou outro app seu) pode chamar /api/*. const CORS = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type', }; // Freio simples contra abuso: no máximo 30 links novos a cada 10 minutos por IP. const LIMITE_POR_IP = 30; const JANELA_MS = 10 * 60 * 1000; const tentativas = new Map(); function passouDoLimite(ip: string): boolean { const agora = Date.now(); if (tentativas.size > 10_000) tentativas.clear(); const atual = tentativas.get(ip); if (!atual || atual.expiraEm <= agora) { tentativas.set(ip, { total: 1, expiraEm: agora + JANELA_MS }); return false; } atual.total += 1; return atual.total > LIMITE_POR_IP; } const erro = (status: number, mensagem: string) => Response.json({ erro: mensagem }, { status, headers: CORS }); export function OPTIONS() { return new Response(null, { status: 204, headers: CORS }); } export function GET(request: Request) { const base = enderecoBase(request.headers); return Response.json( { links: listarLinks().map((link) => paraJson(link, base)) }, { headers: { ...CORS, 'Cache-Control': 'no-store' } }, ); } export async function POST(request: Request) { const ip = request.headers.get('cf-connecting-ip') ?? request.headers.get('x-forwarded-for')?.split(',')[0].trim() ?? '?'; if (passouDoLimite(ip)) return erro(429, 'Muitos links em pouco tempo. Espere alguns minutos e tente de novo.'); let corpo: { url?: unknown } | null; try { corpo = await request.json(); } catch { return erro(400, 'Corpo inválido. Envie JSON no formato {"url": "https://..."}.'); } try { const link = criarLink(corpo?.url); return Response.json(paraJson(link, enderecoBase(request.headers)), { status: 201, headers: CORS }); } catch (e) { if (e instanceof ErroDeValidacao) return erro(400, e.message); throw e; } }