2026-07-19 21:17:57 +08:00
|
|
|
|
/**
|
2026-07-25 14:37:57 +08:00
|
|
|
|
* `dsh web` — thin bin over the config-tree boot: run AppCLIEntry with the
|
|
|
|
|
|
* already-parsed host/port/dev, print the URL line, wire signals. All
|
|
|
|
|
|
* composition lives in cordis.yml; all boot glue lives in AppCLIEntry. The
|
|
|
|
|
|
* argument adapter validated host (loopback/all-interfaces) and port (0–65535).
|
2026-07-19 21:17:57 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import { networkInterfaces } from 'node:os'
|
2026-07-25 01:19:47 +08:00
|
|
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
|
|
import { AppCLIEntry } from './app-cli-entry.ts'
|
2026-07-24 19:43:59 +08:00
|
|
|
|
import { ALL_INTERFACES_HOST, LOOPBACK_HOST } from './args.ts'
|
2026-07-19 21:17:57 +08:00
|
|
|
|
|
2026-07-25 01:19:47 +08:00
|
|
|
|
const CONFIG_PATH = fileURLToPath(new URL('../cordis.yml', import.meta.url))
|
2026-07-23 21:56:18 +08:00
|
|
|
|
|
2026-07-24 19:43:59 +08:00
|
|
|
|
/**
|
2026-07-25 14:37:57 +08:00
|
|
|
|
* Serve the browser UI from the shipped config tree.
|
2026-07-24 19:43:59 +08:00
|
|
|
|
* @param hostAddress - the bind host: {@link LOOPBACK_HOST} or {@link ALL_INTERFACES_HOST}.
|
|
|
|
|
|
* @param port - the listen port; `0` lets the OS choose a free port.
|
2026-07-25 12:02:28 +08:00
|
|
|
|
* @param dev - mount the client HMR driver and watch plugin bundles for rebuilds.
|
2026-07-24 19:43:59 +08:00
|
|
|
|
*/
|
2026-07-25 12:02:28 +08:00
|
|
|
|
export async function runWeb(hostAddress: string, port: number, dev: boolean): Promise<void> {
|
2026-07-25 14:37:57 +08:00
|
|
|
|
const entry = new AppCLIEntry({ configPath: CONFIG_PATH, dev, host: hostAddress, port })
|
2026-07-25 01:19:47 +08:00
|
|
|
|
const { ctx, port: boundPort } = await entry.run()
|
2026-07-19 21:17:57 +08:00
|
|
|
|
|
|
|
|
|
|
let exiting = false
|
2026-07-25 01:19:47 +08:00
|
|
|
|
const shutdown = (code: number): void => {
|
2026-07-19 21:17:57 +08:00
|
|
|
|
if (exiting) return
|
|
|
|
|
|
exiting = true
|
2026-07-25 01:19:47 +08:00
|
|
|
|
void Promise.resolve(ctx.fiber.dispose()).finally(() => { process.exit(code) })
|
2026-07-19 21:17:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-25 14:37:57 +08:00
|
|
|
|
const lanCandidate = hostAddress === ALL_INTERFACES_HOST
|
2026-07-22 20:35:38 +08:00
|
|
|
|
? Object.values(networkInterfaces()).flat()
|
|
|
|
|
|
.find(iface => iface !== undefined && iface.family === 'IPv4' && !iface.internal)
|
|
|
|
|
|
: undefined
|
2026-07-25 01:19:47 +08:00
|
|
|
|
const localUrl = `http://${LOOPBACK_HOST}:${boundPort}`
|
|
|
|
|
|
console.log(`dsh web: ${localUrl}${lanCandidate === undefined ? '' : ` (LAN: http://${lanCandidate.address}:${boundPort})`}`)
|
2026-07-19 21:17:57 +08:00
|
|
|
|
|
2026-07-25 01:19:47 +08:00
|
|
|
|
process.on('SIGTERM', () => { shutdown(0) })
|
|
|
|
|
|
process.on('SIGINT', () => { shutdown(130) })
|
2026-07-19 21:17:57 +08:00
|
|
|
|
}
|