Skip to content

Commit 44abf97

Browse files
backnotpropclaude
andcommitted
Fix: embed HTML at compile time for binary distribution
The server was reading dist/index.html from filesystem at runtime, which fails in compiled standalone binaries. Changed to use Bun's import attributes to embed the HTML at compile time. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4138dc0 commit 44abf97

1 file changed

Lines changed: 7 additions & 39 deletions

File tree

apps/hook/server/index.ts

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
*/
99

1010
import { $ } from "bun";
11-
import { join, dirname } from "path";
11+
12+
// Embed the built HTML at compile time
13+
import indexHtml from "../dist/index.html" with { type: "text" };
1214

1315
// Read hook event from stdin
1416
const eventJson = await Bun.stdin.text();
@@ -33,10 +35,6 @@ const decisionPromise = new Promise<{ approved: boolean; feedback?: string }>(
3335
(resolve) => { resolveDecision = resolve; }
3436
);
3537

36-
// Resolve paths relative to this script
37-
const serverDir = dirname(import.meta.path);
38-
const distDir = join(serverDir, "..", "dist");
39-
4038
const server = Bun.serve({
4139
port: 0, // Random available port - critical for multi-instance support
4240

@@ -65,43 +63,13 @@ const server = Bun.serve({
6563
return Response.json({ ok: true });
6664
}
6765

68-
// Serve static files from dist/
69-
let filePath = url.pathname;
70-
if (filePath === "/" || filePath === "") {
71-
filePath = "/index.html";
72-
}
73-
74-
const file = Bun.file(join(distDir, filePath));
75-
if (await file.exists()) {
76-
const contentType = getContentType(filePath);
77-
return new Response(file, {
78-
headers: contentType ? { "Content-Type": contentType } : {}
79-
});
80-
}
81-
82-
// Fallback to index.html for SPA routing
83-
const indexFile = Bun.file(join(distDir, "index.html"));
84-
if (await indexFile.exists()) {
85-
return new Response(indexFile, {
86-
headers: { "Content-Type": "text/html" }
87-
});
88-
}
89-
90-
return new Response("Not found", { status: 404 });
66+
// Serve embedded HTML for all other routes (SPA)
67+
return new Response(indexHtml, {
68+
headers: { "Content-Type": "text/html" }
69+
});
9170
},
9271
});
9372

94-
function getContentType(path: string): string | null {
95-
if (path.endsWith(".html")) return "text/html";
96-
if (path.endsWith(".js")) return "application/javascript";
97-
if (path.endsWith(".css")) return "text/css";
98-
if (path.endsWith(".json")) return "application/json";
99-
if (path.endsWith(".svg")) return "image/svg+xml";
100-
if (path.endsWith(".png")) return "image/png";
101-
if (path.endsWith(".ico")) return "image/x-icon";
102-
return null;
103-
}
104-
10573
// Log to stderr so it doesn't interfere with hook stdout
10674
console.error(`Plannotator server running on http://localhost:${server.port}`);
10775

0 commit comments

Comments
 (0)