// Production server for DSS Team Portal import { createServer } from 'http'; import { readFile, stat } from 'fs/promises'; import { join, extname } from 'path'; import { fileURLToPath } from 'url'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); const DIST_DIR = join(__dirname, 'dist'); const PORT = process.env.PORT || 3457; const API_PROXY = process.env.API_PROXY || 'http://localhost:3456'; const MIME_TYPES = { '.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript', '.json': 'application/json', '.svg': 'image/svg+xml', '.png': 'image/png', '.jpg': 'image/jpeg', '.ico': 'image/x-icon', '.woff': 'font/woff', '.woff2': 'font/woff2' }; async function serveFile(res, filePath) { try { const content = await readFile(filePath); const ext = extname(filePath); const contentType = MIME_TYPES[ext] || 'application/octet-stream'; res.writeHead(200, { 'Content-Type': contentType, 'Cache-Control': ext === '.html' ? 'no-cache' : 'public, max-age=31536000' }); res.end(content); } catch (err) { // File not found, serve index.html for SPA routing const indexPath = join(DIST_DIR, 'index.html'); const content = await readFile(indexPath); res.writeHead(200, { 'Content-Type': 'text/html', 'Cache-Control': 'no-cache' }); res.end(content); } } async function proxyRequest(req, res) { const url = new URL(req.url, `http://localhost:${PORT}`); const proxyUrl = `${API_PROXY}${url.pathname}${url.search}`; try { const proxyRes = await fetch(proxyUrl, { method: req.method, headers: { 'Content-Type': 'application/json', ...Object.fromEntries( Object.entries(req.headers).filter(([k]) => !['host', 'connection'].includes(k)) ) }, body: ['POST', 'PUT', 'PATCH'].includes(req.method) ? await getRequestBody(req) : undefined }); const data = await proxyRes.text(); res.writeHead(proxyRes.status, { 'Content-Type': 'application/json' }); res.end(data); } catch (err) { console.error('[Proxy Error]', err.message); res.writeHead(502, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Proxy error', message: err.message })); } } function getRequestBody(req) { return new Promise((resolve, reject) => { let body = ''; req.on('data', chunk => body += chunk); req.on('end', () => resolve(body)); req.on('error', reject); }); } const server = createServer(async (req, res) => { const url = new URL(req.url, `http://localhost:${PORT}`); // Health check if (url.pathname === '/health') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ status: 'ok', service: 'dss-team-portal' })); return; } // Proxy API requests to DSS MCP server if (url.pathname.startsWith('/api/')) { url.pathname = url.pathname.replace('/api', ''); req.url = url.pathname + url.search; await proxyRequest(req, res); return; } // Serve static files const filePath = join(DIST_DIR, url.pathname === '/' ? 'index.html' : url.pathname); await serveFile(res, filePath); }); server.listen(PORT, () => { console.log(`[DSS Team Portal] Running on http://localhost:${PORT}`); console.log(`[DSS Team Portal] API Proxy: ${API_PROXY}`); });