-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdev.mjs
More file actions
86 lines (77 loc) · 3 KB
/
dev.mjs
File metadata and controls
86 lines (77 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/env node
import { createServer, request as httpRequest } from 'node:http';
import { spawn } from 'node:child_process';
import { connect } from 'node:net';
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
const PROXY_PORT = Number(process.env.PORT || 3001);
const ROOT = process.cwd();
const MINT_PORT_START = 40000 + Math.floor(Math.random() * 10000);
const mint = spawn('npx', ['mint', 'dev', '--port', String(MINT_PORT_START), '--no-open'], {
stdio: ['inherit', 'pipe', 'pipe'],
});
const cleanup = () => { mint.kill('SIGTERM'); process.exit(0); };
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
mint.on('exit', (code) => { console.log(`mint dev exited (${code})`); process.exit(code ?? 1); });
let mintPort = null;
let started = false;
const watchForPort = (chunk) => {
process.stdout.write(chunk);
if (mintPort) return;
const match = chunk.toString().match(/localhost:(\d+)/);
if (match) {
mintPort = Number(match[1]);
if (mintPort !== PROXY_PORT && !started) {
started = true;
startProxy();
}
}
};
mint.stdout.on('data', watchForPort);
mint.stderr.on('data', (chunk) => process.stderr.write(chunk));
const STATIC_PREFIXES = ['/resources/', '/api-reference/specs/'];
const isStaticJson = (url) => {
const path = url.split('?')[0];
return path.endsWith('.json') && STATIC_PREFIXES.some((p) => path.startsWith(p));
};
function startProxy() {
const server = createServer(async (req, res) => {
if ((req.method === 'GET' || req.method === 'HEAD') && isStaticJson(req.url)) {
try {
const data = await readFile(join(ROOT, req.url.split('?')[0]));
const headers = {
'content-type': 'application/json; charset=utf-8',
'content-length': String(data.length),
};
res.writeHead(200, headers);
res.end(req.method === 'HEAD' ? undefined : data);
return;
} catch {}
}
const proxyReq = httpRequest(
{ hostname: 'localhost', port: mintPort, method: req.method, path: req.url, headers: req.headers },
(proxyRes) => {
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res);
},
);
proxyReq.on('error', (err) => { res.writeHead(502); res.end(`proxy error: ${err.message}`); });
req.pipe(proxyReq);
});
server.on('upgrade', (req, socket, head) => {
const upstream = connect(mintPort, 'localhost', () => {
upstream.write(`${req.method} ${req.url} HTTP/${req.httpVersion}\r\n`);
for (const [k, v] of Object.entries(req.headers)) upstream.write(`${k}: ${v}\r\n`);
upstream.write('\r\n');
if (head?.length) upstream.write(head);
socket.pipe(upstream).pipe(socket);
});
upstream.on('error', () => socket.end());
socket.on('error', () => upstream.end());
});
server.listen(PROXY_PORT, () => {
console.log(`\n unified dev server → http://localhost:${PROXY_PORT}`);
console.log(` static JSON from disk; everything else proxied to mint dev (:${mintPort})\n`);
});
}