scripts/proxy.mjs
scripts/proxy.mjsBrowse 2 files
778 tokens
2,717 bytes
Token encoding: o200k_base
Snapshot 24fd22b
← Back to SKILL.md
1/**2 * GitNexus reverse proxy — serves production web UI + proxies /api/* to backend.3 * Zero dependencies, Node.js built-ins only.4 *5 * Usage: node proxy.mjs <dist-dir> [port]6 * dist-dir: path to gitnexus-web/dist (production build)7 * port: listen port (default: 8888)8 *9 * Environment:10 * API_PORT: GitNexus serve backend port (default: 4747)11 */12import http from 'node:http';13import fs from 'node:fs';14import path from 'node:path';15 16const API_PORT = parseInt(process.env.API_PORT || '4747');17const DIST_DIR = process.argv[2] || './dist';18const PORT = parseInt(process.argv[3] || '8888');19 20const MIME = {21 '.html': 'text/html',22 '.js': 'application/javascript',23 '.css': 'text/css',24 '.json': 'application/json',25 '.png': 'image/png',26 '.svg': 'image/svg+xml',27 '.ico': 'image/x-icon',28 '.woff2': 'font/woff2',29 '.woff': 'font/woff',30 '.wasm': 'application/wasm',31 '.ttf': 'font/ttf',32 '.map': 'application/json',33};34 35function proxyToApi(req, res) {36 const opts = {37 hostname: '127.0.0.1',38 port: API_PORT,39 path: req.url,40 method: req.method,41 headers: { ...req.headers, host: `127.0.0.1:${API_PORT}` },42 };43 const proxy = http.request(opts, (upstream) => {44 res.writeHead(upstream.statusCode, upstream.headers);45 upstream.pipe(res, { end: true });46 });47 proxy.on('error', () => {48 res.writeHead(502, { 'Content-Type': 'text/plain' });49 res.end('GitNexus backend unavailable — is `npx gitnexus serve` running?');50 });51 req.pipe(proxy, { end: true });52}53 54function serveStatic(req, res) {55 const urlPath = req.url.split('?')[0];56 let filePath = path.join(DIST_DIR, urlPath === '/' ? 'index.html' : urlPath);57 58 // SPA fallback: if file doesn't exist and isn't a static asset, serve index.html59 if (!fs.existsSync(filePath) && !path.extname(filePath)) {60 filePath = path.join(DIST_DIR, 'index.html');61 }62 63 const ext = path.extname(filePath);64 const mime = MIME[ext] || 'application/octet-stream';65 66 try {67 const data = fs.readFileSync(filePath);68 res.writeHead(200, {69 'Content-Type': mime,70 'Cache-Control': ext === '.html' ? 'no-cache' : 'public, max-age=86400',71 });72 res.end(data);73 } catch {74 res.writeHead(404, { 'Content-Type': 'text/plain' });75 res.end('Not found');76 }77}78 79const server = http.createServer((req, res) => {80 if (req.url.startsWith('/api')) {81 proxyToApi(req, res);82 } else {83 serveStatic(req, res);84 }85});86 87server.listen(PORT, () => {88 console.log(`GitNexus proxy listening on http://localhost:${PORT}`);89 console.log(` Web UI: http://localhost:${PORT}/`);90 console.log(` API: http://localhost:${PORT}/api/repos`);91 console.log(` Backend: http://127.0.0.1:${API_PORT}`);92});93