ui redesign, markdown fix + metadata and auth header

This commit is contained in:
2026-05-09 05:09:07 +02:00
parent 7f8a66f360
commit bc6a34cf1f
42 changed files with 3093 additions and 517 deletions
+17 -32
View File
@@ -1,57 +1,45 @@
import type { APIRoute } from 'astro';
const FORBIDDEN_HEADERS = new Set([
'host', 'connection', 'content-length', 'transfer-encoding', 'origin', 'referer',
]);
export const ALL: APIRoute = async ({ request, params }) => {
const API_URL = process.env.PUBLIC_API_URL || 'http://backend:3000';
const path = params.path;
if (!path) {
return new Response(JSON.stringify({ error: 'Missing path' }), { status: 400 });
}
// Ensure path is properly encoded
const url = new URL(`${API_URL}/api/${path}`);
const requestUrl = new URL(request.url);
url.search = requestUrl.search;
const headers = new Headers();
// Filter headers to avoid conflicts.
const forbiddenHeaders = ['host', 'connection', 'content-length', 'transfer-encoding', 'origin', 'referer'];
request.headers.forEach((value, key) => {
if (!forbiddenHeaders.includes(key.toLowerCase())) {
if (!FORBIDDEN_HEADERS.has(key.toLowerCase())) {
headers.set(key, value);
}
});
console.log(`\n[Proxy Req] ${request.method} -> ${url.toString()}`);
console.log(`[Proxy Req] Auth Header Present:`, headers.has('authorization'));
console.log(`[Proxy Req] Content-Type:`, headers.get('content-type'));
try {
const fetchOptions: RequestInit = {
method: request.method,
headers: headers,
headers,
};
// Safely handle body for mutating requests
if (request.method !== 'GET' && request.method !== 'HEAD') {
// Clone the request to safely access the body stream
const reqClone = request.clone();
// For DELETE requests, check if a body actually exists before attaching it
// Some fetch implementations fail if a body is provided for DELETE
if (request.method !== 'DELETE' || reqClone.body) {
fetchOptions.body = reqClone.body;
// Required by Node.js fetch when body is a ReadableStream
// @ts-ignore
fetchOptions.duplex = 'half';
}
const reqClone = request.clone();
if (request.method !== 'DELETE' || reqClone.body) {
fetchOptions.body = reqClone.body;
// @ts-ignore — required by Node fetch when body is a stream
fetchOptions.duplex = 'half';
}
}
const response = await fetch(url.toString(), fetchOptions);
console.log(`[Proxy Res] Backend returned ${response.status}`);
const responseHeaders = new Headers();
response.headers.forEach((value, key) => {
responseHeaders.set(key, value);
@@ -59,16 +47,13 @@ export const ALL: APIRoute = async ({ request, params }) => {
return new Response(response.body, {
status: response.status,
headers: responseHeaders
headers: responseHeaders,
});
} catch (e) {
console.error(`[Proxy Error] ${request.method} ${url}:`, e);
return new Response(JSON.stringify({
error: 'Proxy connection failed',
details: e instanceof Error ? e.message : String(e)
}), {
console.error(`[Proxy] ${request.method} ${url} failed:`, e);
return new Response(JSON.stringify({ error: 'Proxy connection failed' }), {
status: 502,
headers: { 'Content-Type': 'application/json' }
headers: { 'Content-Type': 'application/json' },
});
}
};