import { NextResponse } from 'next/server'; const MUAPI_BASE = 'https://api.muapi.ai'; function getApiKey(request) { // Only accept x-api-key header. Cookie-based auth is removed for security: // cookies without HttpOnly flag can be stolen by XSS (CWE-522). const headerKey = request.headers.get('x-api-key'); return headerKey || null; } function cleanHeaders(request) { const headers = new Headers(request.headers); headers.delete('host'); headers.delete('connection'); headers.delete('cookie'); // CRITICAL: Stop forwarding browser cookies to MuAPI return headers; } // Build the target URL without a trailing slash when path is empty. // e.g. GET /api/agents?is_template=true → https://api.muapi.ai/agents?is_template=true // e.g. GET /api/agents/by-slug/foo → https://api.muapi.ai/agents/by-slug/foo function buildTargetUrl(pathSegments, search) { const path = pathSegments.join('/'); const base = `${MUAPI_BASE}/agents`; return path ? `${base}/${path}${search}` : `${base}${search}`; } export async function GET(request, { params }) { const slug = await params; const pathSegments = slug.path || []; const { search } = new URL(request.url); const targetUrl = buildTargetUrl(pathSegments, search); const headers = cleanHeaders(request); const apiKey = getApiKey(request); // NOTE: credential logging removed for security (CWE-200) if (apiKey) headers.set('x-api-key', apiKey); try { const response = await fetch(targetUrl, { headers, method: 'GET' }); const data = await response.json(); return NextResponse.json(data, { status: response.status }); } catch (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } } export async function POST(request, { params }) { const slug = await params; const pathSegments = slug.path || []; const { search } = new URL(request.url); const targetUrl = buildTargetUrl(pathSegments, search); const headers = cleanHeaders(request); const apiKey = getApiKey(request); // NOTE: credential logging removed for security (CWE-200) if (apiKey) headers.set('x-api-key', apiKey); try { const body = await request.arrayBuffer(); const response = await fetch(targetUrl, { method: 'POST', headers, body }); const data = await response.json(); return NextResponse.json(data, { status: response.status }); } catch (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } } export async function DELETE(request, { params }) { const slug = await params; const pathSegments = slug.path || []; const { search } = new URL(request.url); const targetUrl = buildTargetUrl(pathSegments, search); const headers = cleanHeaders(request); const apiKey = getApiKey(request); if (apiKey) headers.set('x-api-key', apiKey); try { const response = await fetch(targetUrl, { method: 'DELETE', headers }); const data = await response.json(); return NextResponse.json(data, { status: response.status }); } catch (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } } export async function PUT(request, { params }) { const slug = await params; const pathSegments = slug.path || []; const { search } = new URL(request.url); const targetUrl = buildTargetUrl(pathSegments, search); const headers = cleanHeaders(request); const apiKey = getApiKey(request); if (apiKey) headers.set('x-api-key', apiKey); try { const body = await request.arrayBuffer(); const response = await fetch(targetUrl, { method: 'PUT', headers, body }); const data = await response.json(); return NextResponse.json(data, { status: response.status }); } catch (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } }