MCPcopy
hub / github.com/garrytan/gstack / serve

Function serve

design/src/serve.ts:55–239  ·  view source on GitHub ↗
(options: ServeOptions)

Source from the content-addressed store, hash-verified

53type ServerState = "serving" | "regenerating" | "done";
54
55export async function serve(options: ServeOptions): Promise<void> {
56 const { html, port = 0, hostname = "127.0.0.1", timeout = 600 } = options;
57
58 // Validate HTML file exists
59 if (!fs.existsSync(html)) {
60 console.error(`SERVE_ERROR: HTML file not found: ${html}`);
61 process.exit(1);
62 }
63
64 // Security: anchor all file reads to the initial HTML's directory.
65 // Prevents /api/reload from reading arbitrary files via path traversal.
66 const allowedDir = fs.realpathSync(path.dirname(path.resolve(html)));
67
68 let htmlContent = fs.readFileSync(html, "utf-8");
69 let state: ServerState = "serving";
70 let timeoutTimer: ReturnType<typeof setTimeout> | null = null;
71
72 const server = Bun.serve({
73 port,
74 hostname,
75 fetch(req) {
76 const url = new URL(req.url);
77
78 // Serve the comparison board HTML. The board JS uses relative paths
79 // (./api/feedback, ./api/progress) and a location.protocol
80 // feature-detect, so no per-request injection is needed.
81 if (
82 req.method === "GET" &&
83 (url.pathname === "/" || url.pathname === "/index.html")
84 ) {
85 return new Response(htmlContent, {
86 headers: { "Content-Type": "text/html; charset=utf-8" },
87 });
88 }
89
90 // Progress polling endpoint (used by board during regeneration)
91 if (req.method === "GET" && url.pathname === "/api/progress") {
92 return Response.json({ status: state });
93 }
94
95 // Feedback submission from the board
96 if (req.method === "POST" && url.pathname === "/api/feedback") {
97 return handleFeedback(req);
98 }
99
100 // Reload endpoint (used by the agent to swap in new board HTML)
101 if (req.method === "POST" && url.pathname === "/api/reload") {
102 return handleReload(req);
103 }
104
105 return new Response("Not found", { status: 404 });
106 },
107 });
108
109 const actualPort = server.port;
110 const boardUrl = `http://127.0.0.1:${actualPort}`;
111
112 console.error(`SERVE_STARTED: port=${actualPort} html=${html}`);

Callers 1

mainFunction · 0.90

Calls 2

stopMethod · 0.80
openBrowserFunction · 0.70

Tested by

no test coverage detected