import { NextRequest, NextResponse } from 'next/server'; // Resuelve la URL del backend: // 1. POS_BACKEND_URL: explícito (dev por IP LAN, prod con traefik en otro host) // 2. Mismo origen que el navegador: funciona en dev local y prod detrás de traefik // (traefik sirve frontend+backend en el mismo dominio, routando /api/* al backend) function getBackendUrl(request: NextRequest): string { const backendUrl = process.env.POS_BACKEND_URL; if (backendUrl) { const base = backendUrl.replace(/\/$/, ''); return `${base}/${apiPath(request)}${request.nextUrl.search}`; } // Fallback: mismo origen que el navegador (dev local y prod traefik) const protocol = request.headers.get('x-forwarded-proto') ?? request.nextUrl.protocol; const host = request.headers.get('x-forwarded-host') ?? request.nextUrl.host; return `${protocol}//${host}/${apiPath(request)}${request.nextUrl.search}`; } function apiPath(request: NextRequest): string { return request.nextUrl.pathname.replace(/^\/api\//, ''); } function requestHeaders(request: NextRequest, hasBody = false): Headers { const headers = new Headers(); const cookie = request.headers.get('cookie'); const terminalId = request.headers.get('x-terminal-id') ?? request.cookies.get('pos_terminal_id')?.value; if (cookie) headers.set('cookie', cookie); if (terminalId) headers.set('x-terminal-id', terminalId); if (hasBody) headers.set('content-type', request.headers.get('content-type') ?? 'application/json'); return headers; } function proxyResponse(backendResponse: Response): NextResponse { const response = new NextResponse(backendResponse.body, { status: backendResponse.status, statusText: backendResponse.statusText, }); const contentType = backendResponse.headers.get('content-type'); const setCookie = backendResponse.headers.get('set-cookie'); if (contentType) response.headers.set('content-type', contentType); if (setCookie) response.headers.set('set-cookie', setCookie); return response; } export async function GET(request: NextRequest) { try { const response = await fetch(getBackendUrl(request), { headers: requestHeaders(request), cache: 'no-store', }); return proxyResponse(response); } catch { return NextResponse.json({ message: 'Backend no disponible' }, { status: 502 }); } } export async function POST(request: NextRequest) { try { const body = await request.text(); const response = await fetch(getBackendUrl(request), { method: 'POST', headers: requestHeaders(request, true), body, cache: 'no-store', }); const bindingPayload = response.ok && apiPath(request) === 'pos/terminals/bind' ? await response.clone().json() as { terminalId?: string } : null; const proxied = proxyResponse(response); if (bindingPayload?.terminalId) { proxied.cookies.set('pos_terminal_id', bindingPayload.terminalId, { httpOnly: true, sameSite: 'lax', secure: process.env.NODE_ENV === 'production', maxAge: 365 * 24 * 60 * 60, path: '/', }); } return proxied; } catch { return NextResponse.json({ message: 'Backend no disponible' }, { status: 502 }); } } export async function DELETE(request: NextRequest) { try { const response = await fetch(getBackendUrl(request), { method: 'DELETE', headers: requestHeaders(request), cache: 'no-store', }); return proxyResponse(response); } catch { return NextResponse.json({ message: 'Backend no disponible' }, { status: 502 }); } }