103 lines
3.5 KiB
TypeScript
103 lines
3.5 KiB
TypeScript
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 });
|
|
}
|
|
}
|