File: //workspace/rollout/frontend-route.ts.expected
import { NextRequest } from "next/server";
const RAW_INTERNAL_API_URL = process.env.INTERNAL_API_URL ?? "";
const INTERNAL_API_URL =
RAW_INTERNAL_API_URL.trim().replace(/\/+$/, "") || "http://127.0.0.1:3411";
const LOCAL_MODE = (process.env.NEXT_PUBLIC_AUTH_MODE ?? "").trim() === "local";
const CONFIGURED_LOCAL_TOKEN = (
process.env.NEXT_PUBLIC_LOCAL_AUTH_TOKEN ?? process.env.LOCAL_AUTH_TOKEN ?? ""
)
.trim();
const HOP_BY_HOP_REQUEST_HEADERS = new Set([
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"te",
"trailer",
"transfer-encoding",
"upgrade",
"host",
]);
const HOP_BY_HOP_RESPONSE_HEADERS = new Set([
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"te",
"trailer",
"transfer-encoding",
"upgrade",
]);
function targetUrlFrom(req: NextRequest, path: string[] | undefined): string {
const joined = (path ?? []).join("/");
const suffix = joined ? `/${joined}` : "";
const search = req.nextUrl.search || "";
return `${INTERNAL_API_URL}/api${suffix}${search}`;
}
function prepareRequestHeaders(req: NextRequest): Headers {
const headers = new Headers(req.headers);
for (const name of HOP_BY_HOP_REQUEST_HEADERS) {
headers.delete(name);
}
const overrideToken = (headers.get("x-mc-local-token") ?? "").trim();
headers.delete("x-mc-local-token");
if (LOCAL_MODE) {
if (overrideToken) {
headers.set("authorization", `Bearer ${overrideToken}`);
} else if (!headers.has("authorization")) {
const effective = CONFIGURED_LOCAL_TOKEN;
if (!effective) {
throw new Error(
"Local auth mode is enabled but no token is configured in frontend environment.",
);
}
headers.set("authorization", `Bearer ${effective}`);
}
}
return headers;
}
function prepareResponseHeaders(upstream: Headers): Headers {
const headers = new Headers(upstream);
for (const name of HOP_BY_HOP_RESPONSE_HEADERS) {
headers.delete(name);
}
return headers;
}
async function proxy(req: NextRequest, path: string[] | undefined): Promise<Response> {
let requestHeaders: Headers;
try {
requestHeaders = prepareRequestHeaders(req);
} catch (error) {
const message = error instanceof Error ? error.message : "Proxy auth setup failed";
return Response.json({ detail: message }, { status: 500 });
}
const method = req.method.toUpperCase();
const hasBody = method !== "GET" && method !== "HEAD";
const body = hasBody ? await req.arrayBuffer() : undefined;
const upstream = await fetch(targetUrlFrom(req, path), {
method,
headers: requestHeaders,
body,
redirect: "manual",
cache: "no-store",
});
return new Response(upstream.body, {
status: upstream.status,
statusText: upstream.statusText,
headers: prepareResponseHeaders(upstream.headers),
});
}
type RouteContext = {
params: Promise<{
path: string[];
}>;
};
export async function GET(req: NextRequest, ctx: RouteContext): Promise<Response> {
const { path } = await ctx.params;
return proxy(req, path);
}
export async function POST(req: NextRequest, ctx: RouteContext): Promise<Response> {
const { path } = await ctx.params;
return proxy(req, path);
}
export async function PUT(req: NextRequest, ctx: RouteContext): Promise<Response> {
const { path } = await ctx.params;
return proxy(req, path);
}
export async function PATCH(req: NextRequest, ctx: RouteContext): Promise<Response> {
const { path } = await ctx.params;
return proxy(req, path);
}
export async function DELETE(req: NextRequest, ctx: RouteContext): Promise<Response> {
const { path } = await ctx.params;
return proxy(req, path);
}
export async function OPTIONS(req: NextRequest, ctx: RouteContext): Promise<Response> {
const { path } = await ctx.params;
return proxy(req, path);
}