114 lines · 3.7 KB · TypeScript
RawDownload
import { NextRequest, NextResponse } from 'next/server';import { getApiSettings } from '@/lib/api-settings'; export async function GET(  request: NextRequest,  { params }: { params: Promise<{ path: string[] }> }) {  const { path } = await params;  return handleRequest(request, 'GET', path);} export async function POST(  request: NextRequest,  { params }: { params: Promise<{ path: string[] }> }) {  const { path } = await params;  return handleRequest(request, 'POST', path);} export async function PUT(  request: NextRequest,  { params }: { params: Promise<{ path: string[] }> }) {  const { path } = await params;  return handleRequest(request, 'PUT', path);} export async function DELETE(  request: NextRequest,  { params }: { params: Promise<{ path: string[] }> }) {  const { path } = await params;  return handleRequest(request, 'DELETE', path);} function getClientInfo(request: NextRequest) {  const ip = request.headers.get('CF-Connecting-IP') ||             request.headers.get('X-Forwarded-For')?.split(',')[0]?.trim() ||             request.headers.get('X-Real-IP') ||             'unknown';  const country = request.headers.get('CF-IPCountry') || '-';  const ua = request.headers.get('User-Agent')?.slice(0, 80) || 'unknown';  return { ip, country, ua };} async function handleRequest(request: NextRequest, method: string, path: string[]) {  const startTime = Date.now();  const client = getClientInfo(request);   try {    // Get dynamic settings    const settings = await getApiSettings();    const BACKEND_URL = settings.backendUrl;    const API_KEY = settings.apiKey;     const url = new URL(request.url);    const searchParams = url.searchParams.toString();    const targetUrl = `${BACKEND_URL}/${path.join('/')}${searchParams ? `?${searchParams}` : ''}`;    const hasAuth = Boolean(request.headers.get('authorization'));     console.log(`[PROXY] ip=${client.ip} | country=${client.country} | method=${method} | path=/${path.join('/')} | backend=${BACKEND_URL} | auth=${hasAuth ? 'present' : 'none'}`);     const headers: HeadersInit = {      ...(request.headers.get('accept') ? { Accept: request.headers.get('accept') as string } : {}),    };     const incomingContentType = request.headers.get('content-type');    if (incomingContentType) headers['Content-Type'] = incomingContentType;     // Prefer per-user Authorization header passed from the browser; fallback to configured API key.    const incomingAuth = request.headers.get('authorization');    if (incomingAuth) {      headers['Authorization'] = incomingAuth;    } else if (API_KEY) {      headers['Authorization'] = `Bearer ${API_KEY}`;    }     const body = method !== 'GET' && method !== 'DELETE'       ? await request.text()       : undefined;     const response = await fetch(targetUrl, {      method,      headers,      body,    });     const contentType = response.headers.get('content-type') || 'application/json';     if (contentType.includes('text/event-stream') && response.body) {      return new NextResponse(response.body, {        status: response.status,        headers: {          'Content-Type': contentType,          'Cache-Control': response.headers.get('cache-control') || 'no-cache',        },      });    }     const data = await response.text();    return new NextResponse(data, {      status: response.status,      headers: { 'Content-Type': contentType },    });   } catch (error) {    const duration = Date.now() - startTime;    console.error(`[PROXY ERROR] ip=${client.ip} | country=${client.country} | method=${method} | path=/${path.join('/')} | duration=${duration}ms | error=${String(error)}`);    return NextResponse.json(      { error: 'Internal server error', details: String(error) },      { status: 500 }    );  }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t