feat: improvements to web dashboard

This commit is contained in:
syntaxbullet
2026-01-08 13:56:25 +01:00
parent 47507dd65a
commit 9e7f18787b
9 changed files with 332 additions and 108 deletions

View File

@@ -1,46 +1,18 @@
import { serve } from "bun";
import index from "./index.html";
/**
* Web server entry point.
*
* This file can be run directly for standalone development:
* bun --hot src/index.ts
*
* Or the server can be started in-process by importing from ./server.ts
*/
import { createWebServer } from "./server";
const server = serve({
routes: {
// Serve index.html for all unmatched routes.
"/*": index,
"/api/hello": {
async GET(req) {
return Response.json({
message: "Hello, world!",
method: "GET",
});
},
async PUT(req) {
return Response.json({
message: "Hello, world!",
method: "PUT",
});
},
},
"/api/hello/:name": async req => {
const name = req.params.name;
return Response.json({
message: `Hello, ${name}!`,
});
},
},
development: process.env.NODE_ENV !== "production" && {
// Enable browser hot reloading in development
hmr: true,
// Echo console logs from the browser to the server
console: true,
},
// Auto-start when run directly
const instance = await createWebServer({
port: Number(process.env.WEB_PORT) || 3000,
hostname: process.env.WEB_HOST || "localhost",
});
export const webServer = { start: () => server, stop: () => server.stop() };
console.log(`🌐 Web server is running at ${instance.url}`);

105
src/web/src/server.ts Normal file
View File

@@ -0,0 +1,105 @@
/**
* Web server factory module.
* Exports a function to create and start the web server.
* This allows the server to be started in-process from the main application.
*/
import { serve } from "bun";
export interface WebServerConfig {
port?: number;
hostname?: string;
}
export interface WebServerInstance {
server: ReturnType<typeof serve>;
stop: () => Promise<void>;
url: string;
}
/**
* Creates and starts the web server.
*
* IMPORTANT: This function must be called from within the web project directory
* or the bundler won't resolve paths correctly. Use `startWebServerFromRoot`
* if calling from the main application.
*/
export async function createWebServer(config: WebServerConfig = {}): Promise<WebServerInstance> {
const { port = 3000, hostname = "localhost" } = config;
// Dynamic import of the HTML to ensure bundler context is correct
const index = await import("./index.html");
const server = serve({
port,
hostname,
routes: {
// Serve index.html for all unmatched routes (SPA catch-all)
"/*": index.default,
"/api/hello": {
async GET(req) {
return Response.json({
message: "Hello, world!",
method: "GET",
});
},
async PUT(req) {
return Response.json({
message: "Hello, world!",
method: "PUT",
});
},
},
"/api/hello/:name": async (req) => {
const name = req.params.name;
return Response.json({
message: `Hello, ${name}!`,
});
},
"/api/health": () => Response.json({ status: "ok", timestamp: Date.now() }),
},
development: process.env.NODE_ENV !== "production" && {
hmr: true,
console: true,
},
});
const url = `http://${hostname}:${port}`;
return {
server,
url,
stop: async () => {
server.stop(true);
},
};
}
/**
* Starts the web server from the main application root.
* Handles the working directory context switch needed for bundler resolution.
*/
export async function startWebServerFromRoot(
webProjectPath: string,
config: WebServerConfig = {}
): Promise<WebServerInstance> {
const originalCwd = process.cwd();
try {
// Change to web project directory for correct bundler resolution
process.chdir(webProjectPath);
const instance = await createWebServer(config);
console.log(`🌐 Web server running at ${instance.url}`);
return instance;
} finally {
// Restore original working directory
process.chdir(originalCwd);
}
}