import { createReadStream } from 'node:fs'; import { stat } from 'node:fs/promises'; import http from 'node:http'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const root = fileURLToPath(new URL('../apps/web-ele/dist', import.meta.url)); const host = process.env.HOST || '127.0.0.1'; const port = Number(process.env.PORT || 5777); const basePath = process.env.BASE_PATH || '/ai-agent-admin'; const apiPrefix = `${basePath}/basic-api`; const rootApiPrefix = '/basic-api'; const apiTarget = process.env.API_TARGET || 'http://124.220.21.25/zq-ai-admin/basic-api'; const mime = { '.css': 'text/css; charset=utf-8', '.html': 'text/html; charset=utf-8', '.ico': 'image/x-icon', '.js': 'application/javascript; charset=utf-8', '.json': 'application/json; charset=utf-8', '.mjs': 'application/javascript; charset=utf-8', '.mp3': 'audio/mpeg', '.png': 'image/png', '.svg': 'image/svg+xml', }; async function exists(filePath) { try { return (await stat(filePath)).isFile(); } catch { return false; } } async function proxy(req, res) { const targetBase = apiTarget.replace(/\/$/, ''); const apiPath = req.url.startsWith(apiPrefix) ? req.url.replace(apiPrefix, '') : req.url.replace(rootApiPrefix, ''); const target = new URL(`${targetBase}${apiPath}`); const headers = { ...req.headers }; delete headers.host; let upstream; try { upstream = await fetch(target, { body: ['GET', 'HEAD'].includes(req.method) ? undefined : req, duplex: 'half', headers, method: req.method, }); } catch (error) { res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' }); res.end(`Proxy upstream unavailable: ${target}\n${error.message}`); return; } res.writeHead(upstream.status, Object.fromEntries(upstream.headers)); if (upstream.body) { res.end(Buffer.from(await upstream.arrayBuffer())); } else { res.end(); } } async function serve(req, res) { const url = new URL(req.url || '/', `http://${host}:${port}`); if ( url.pathname.startsWith(apiPrefix) || url.pathname.startsWith(rootApiPrefix) ) { await proxy(req, res); return; } if (url.pathname === '/' || url.pathname === '') { res.writeHead(302, { Location: `${basePath}/` }); res.end(); return; } if (!url.pathname.startsWith(basePath)) { res.writeHead(404); res.end('Not Found'); return; } let rel = url.pathname.slice(basePath.length) || '/index.html'; if (rel === '/') rel = '/index.html'; let filePath = path.join(root, rel); if (!(await exists(filePath))) { filePath = path.join(root, 'index.html'); } const ext = path.extname(filePath); res.setHeader('Content-Type', mime[ext] || 'application/octet-stream'); createReadStream(filePath).pipe(res); } const server = http.createServer((req, res) => { serve(req, res).catch((error) => { res.writeHead(500); res.end(error?.stack || String(error)); }); }); server.listen(port, host, () => { console.log(`web-ele dist server: http://${host}:${port}${basePath}/`); console.log(`api proxy: ${apiPrefix} -> ${apiTarget}`); });