// Server-side proxy helper for Next.js API routes. // Forwards requests to the NestJS backend, including the Bearer token. import { NextRequest, NextResponse } from "next/server"; const BASE_URL = process.env.LEDGERONE_API_URL ?? "http://localhost:3051"; export function getBackendUrl(path: string): string { return `${BASE_URL}/api/${path.replace(/^\//, "")}`; } interface ProxyOptions { method?: string; body?: BodyInit | null; extraHeaders?: Record; search?: string; } export async function proxyRequest( req: NextRequest, backendPath: string, options: ProxyOptions = {} ): Promise { const url = new URL(req.url); const search = options.search !== undefined ? options.search : url.search; const targetUrl = `${getBackendUrl(backendPath)}${search}`; const method = options.method ?? req.method; const auth = req.headers.get("authorization") ?? ""; const contentType = req.headers.get("content-type") ?? ""; const headers: Record = { ...options.extraHeaders }; if (auth) headers["Authorization"] = auth; let body: BodyInit | null | undefined = undefined; if (method !== "GET" && method !== "HEAD") { if (options.body !== undefined) { body = options.body; if (contentType) headers["Content-Type"] = contentType; } else if (contentType.includes("multipart/form-data")) { body = await req.formData(); // Do not set Content-Type — fetch sets it with boundary automatically } else { body = await req.text(); if (contentType) headers["Content-Type"] = contentType; } } try { const res = await fetch(targetUrl, { method, headers, body: body ?? undefined, }); const payload = await res.text(); return new NextResponse(payload, { status: res.status, headers: { "Content-Type": res.headers.get("content-type") ?? "application/json", }, }); } catch { return NextResponse.json( { data: null, meta: { timestamp: new Date().toISOString(), version: "v1" }, error: { message: "Backend unavailable." }, }, { status: 503 } ); } }