11#!/usr/bin/env bun
2- import { Hono } from 'hono'
32import * as fs from "node:fs"
43import { basename , join } from 'node:path'
5- import { parseArgs } from 'util'
4+ import { parseArgs } from 'node:util'
5+ import { Hono } from 'hono'
6+ import { addOrUpdateSource , listSources } from "../ingest/sources-registry"
7+ import { getLegacyStorageRootForBackend , selectStorageBackend } from "../ingest/storage-backend"
68import { createApi } from "./api"
79import { createDashboardStore , type DashboardStore } from "./dashboard"
8- import { getLegacyStorageRootForBackend , selectStorageBackend } from "../ingest/storage-backend "
9- import { addOrUpdateSource , listSources } from "../ingest/sources-registry "
10+ import { getPublicHost , resolveServerHost } from "./host "
11+ import { resolveStaticFilePath } from "./static-file "
1012
1113function isBunxInvocation ( argv : string [ ] ) : boolean {
1214 if ( process . env . BUN_INSTALL_CACHE_DIR ) return true
@@ -20,14 +22,16 @@ const { values, positionals } = parseArgs({
2022 options : {
2123 project : { type : 'string' } ,
2224 port : { type : 'string' } ,
25+ host : { type : 'string' } ,
2326 name : { type : 'string' } ,
2427 } ,
2528 allowPositionals : true ,
2629} )
2730
2831const project = values . project ?? process . cwd ( )
2932
30- const port = parseInt ( values . port || '51234' )
33+ const port = parseInt ( values . port || '51234' , 10 )
34+ const host = resolveServerHost ( { cliHost : values . host , envHost : process . env . OMO_DASHBOARD_HOST } )
3135
3236const cleanedPositionals = [ ...positionals ]
3337if ( cleanedPositionals [ 0 ] === Bun . argv [ 0 ] ) cleanedPositionals . shift ( )
@@ -111,12 +115,12 @@ const distRoot = join(import.meta.dir, '../../dist')
111115// SPA fallback middleware
112116app . use ( '*' , async ( c , next ) => {
113117 const path = c . req . path
114-
118+
115119 // Skip API routes - let them pass through
116120 if ( path . startsWith ( '/api/' ) ) {
117121 return await next ( )
118122 }
119-
123+
120124 // For non-API routes without extensions, serve index.html
121125 if ( ! path . includes ( '.' ) ) {
122126 const indexFile = Bun . file ( join ( distRoot , 'index.html' ) )
@@ -125,18 +129,22 @@ app.use('*', async (c, next) => {
125129 }
126130 return c . notFound ( )
127131 }
128-
132+
129133 // For static files with extensions, try to serve them
130- const relativePath = path . startsWith ( '/' ) ? path . slice ( 1 ) : path
131- const file = Bun . file ( join ( distRoot , relativePath ) )
134+ const filePath = resolveStaticFilePath ( distRoot , path )
135+ if ( ! filePath ) {
136+ return c . notFound ( )
137+ }
138+
139+ const file = Bun . file ( filePath )
132140 if ( await file . exists ( ) ) {
133141 const ext = path . split ( '.' ) . pop ( ) || ''
134142 const contentType = getContentType ( ext )
135143 return new Response ( file , {
136144 headers : { 'Content-Type' : contentType }
137145 } )
138146 }
139-
147+
140148 return c . notFound ( )
141149} )
142150
@@ -162,8 +170,13 @@ function getContentType(ext: string): string {
162170
163171Bun . serve ( {
164172 fetch : app . fetch ,
165- hostname : '127.0.0.1' ,
173+ hostname : host ,
166174 port,
167175} )
168176
169- console . log ( `Server running on http://127.0.0.1:${ port } ` )
177+ const publicHost = getPublicHost ( host )
178+ if ( publicHost === host ) {
179+ console . log ( `Server running on http://${ publicHost } :${ port } ` )
180+ } else {
181+ console . log ( `Server running on http://${ publicHost } :${ port } (bound to ${ host } )` )
182+ }
0 commit comments