()
| 165 | let server: ReturnType<typeof Bun.serve> | undefined |
| 166 | |
| 167 | export async function start(): Promise<{ port: number; url: string }> { |
| 168 | if (server) { |
| 169 | const port = server.port! |
| 170 | return { port, url: `http://localhost:${port}` } |
| 171 | } |
| 172 | |
| 173 | const staticPath = path.join(import.meta.dirname, "../../ui-dist/settings") |
| 174 | const hasStatic = await Bun.file(path.join(staticPath, "index.html")).exists() |
| 175 | |
| 176 | const finalApp = hasStatic |
| 177 | ? new Hono() |
| 178 | .route("/", app) |
| 179 | .get("*", async (c, next) => { |
| 180 | if (c.req.path.startsWith("/api/")) { |
| 181 | return next() |
| 182 | } |
| 183 | const filePath = path.join(staticPath, c.req.path) |
| 184 | const file = Bun.file(filePath) |
| 185 | if (await file.exists()) { |
| 186 | const ext = path.extname(filePath) |
| 187 | const mimeTypes: Record<string, string> = { |
| 188 | ".html": "text/html", |
| 189 | ".js": "application/javascript", |
| 190 | ".css": "text/css", |
| 191 | ".json": "application/json", |
| 192 | ".png": "image/png", |
| 193 | ".jpg": "image/jpeg", |
| 194 | ".svg": "image/svg+xml", |
| 195 | ".woff": "font/woff", |
| 196 | ".woff2": "font/woff2", |
| 197 | } |
| 198 | const contentType = mimeTypes[ext] || "application/octet-stream" |
| 199 | return new Response(file, { |
| 200 | headers: { "Content-Type": contentType }, |
| 201 | }) |
| 202 | } |
| 203 | const html = await Bun.file(path.join(staticPath, "index.html")).text() |
| 204 | return c.html(html) |
| 205 | }) |
| 206 | : app |
| 207 | |
| 208 | server = Bun.serve({ |
| 209 | port: 0, |
| 210 | fetch: finalApp.fetch, |
| 211 | }) |
| 212 | |
| 213 | const port = server.port! |
| 214 | log.info("started", { port }) |
| 215 | return { port, url: `http://localhost:${port}` } |
| 216 | } |
| 217 | |
| 218 | export async function stop() { |
| 219 | if (server) { |
no test coverage detected