elemes/frontend/src/hooks.server.ts

80 lines
2.5 KiB
TypeScript
Raw Normal View History

2026-03-25 09:39:51 +07:00
/**
* SvelteKit server hook proxies /api/* requests to the Flask backend.
*
* Uses API_BACKEND env var (set in podman-compose.yml).
* Falls back to http://elemes:5000, then tries container IP resolution.
*/
import type { Handle } from '@sveltejs/kit';
function resolveBackend(): string {
const env = process.env.API_BACKEND;
if (env) return env;
return 'http://elemes:5000';
}
const API_BACKEND = resolveBackend();
export const handle: Handle = async ({ event, resolve }) => {
// Proxy /api/* and /assets/* to Flask backend
const isApi = event.url.pathname.startsWith('/api/');
const isAsset = event.url.pathname.startsWith('/assets/');
const isVelxioCompile = event.url.pathname === '/velxio/api/compile' || event.url.pathname === '/velxio/api/compile/';
if (isApi || isAsset || isVelxioCompile) {
let backendPath = '';
if (isVelxioCompile) {
backendPath = '/velxio-compile/';
} else if (isApi) {
backendPath = event.url.pathname.replace(/^\/api/, '');
} else {
backendPath = event.url.pathname;
}
2026-03-25 09:39:51 +07:00
const backendUrl = `${API_BACKEND}${backendPath}${event.url.search}`;
try {
const headers: Record<string, string> = {};
const contentType = event.request.headers.get('content-type');
if (contentType) headers['content-type'] = contentType;
const accept = event.request.headers.get('accept');
if (accept) headers['accept'] = accept;
const cookie = event.request.headers.get('cookie');
if (cookie) headers['cookie'] = cookie;
2026-03-25 09:39:51 +07:00
const init: RequestInit = {
method: event.request.method,
headers,
};
if (event.request.method !== 'GET' && event.request.method !== 'HEAD') {
init.body = await event.request.text();
}
const res = await fetch(backendUrl, init);
// Use arrayBuffer for binary content (images), text for API JSON
const resContentType = res.headers.get('content-type') ?? 'application/json';
const isBinary = !resContentType.startsWith('text/') && !resContentType.includes('json');
const body = isBinary ? await res.arrayBuffer() : await res.text();
2026-03-25 09:39:51 +07:00
const resHeaders: Record<string, string> = { 'content-type': resContentType };
const setCookie = res.headers.get('set-cookie');
if (setCookie) resHeaders['set-cookie'] = setCookie;
2026-03-25 09:39:51 +07:00
return new Response(body, {
status: res.status,
headers: resHeaders,
2026-03-25 09:39:51 +07:00
});
} catch (err) {
console.error(`API proxy error (${backendUrl}):`, err);
return new Response(JSON.stringify({ error: 'Backend unavailable' }), {
status: 502,
headers: { 'content-type': 'application/json' },
});
}
}
return resolve(event);
};