#!/usr/bin/env node import { startServer, previewOptions, DEFAULT_BOARD } from './serve.mjs'; import { busReader } from './bus.mjs'; import { loadSystem, socketPath, REPO, rolesDir } from '../../cli/src/config.mjs'; import { configDir } from '../../business/src/business.mjs'; import { consoleReads, redactor } from './reads.mjs'; import { ID_PATTERN } from '../../business/src/vocabulary.mjs'; const args = process.argv.slice(2); const usage = 'node packages/webui/src/cli.mjs serve [--port N] [--board http://127.0.0.1:7331] [--business ID] [--public-host NAME --auth-header HEADER --allow-user ID]'; try { if (args.length === 1 && ['--help', '-h'].includes(args[0])) { console.log(usage); process.exit(0); } if (args.shift() !== 'serve') throw new Error(usage); const options = { board: DEFAULT_BOARD, port: 7330 }, preview = {}; while (args.length) { const flag = args.shift(), value = args.shift(); if (!value) throw new Error(`missing value for ${flag}`); if (flag === '--port') { if (!/^\d+$/.test(value) || Number(value) > 65535) throw new Error('port must be 0..65535'); options.port = Number(value); } else if (flag === '--board') options.board = value; else if (flag === '--business') { if (!ID_PATTERN.test(value)) throw new Error('business must be a business id'); options.business = value; } // Row 74 (#1568): the preview mode, all three or none, checked before any config is read. else if (flag === '--public-host') preview.publicHost = value; else if (flag === '--auth-header') preview.authHeader = value; else if (flag === '--allow-user') preview.allowUser = value; else throw new Error(`unknown option: ${flag}`); } options.preview = previewOptions(preview); // The bus views (slice 1 S5) need the system config. Without it the // board still serves and the bus routes answer not-configured. // The Queue, Business and Settings reads (row 54) need no bus; without // the system config, Business can't resolve authority and Settings has // no notifier. A refusal printed here names no path (redactor). let bus = null, busLine, system = null; try { system = loadSystem(); const { dataRoot } = system; bus = busReader({ dataRoot, socket: socketPath(dataRoot), business: options.business ?? null }); busLine = `Bus: ${options.business ?? 'the running bus host\'s business'}`; } catch (err) { busLine = `Bus: not configured (${redactor({ configDir: configDir() })(err.message)})`; } const reads = consoleReads({ root: REPO, system, configDir: configDir(), rolesDir: rolesDir(), business: options.business ?? null }); const server = await startServer({ board: options.board, port: options.port, bus, reads, preview: options.preview }); const previewLine = options.preview ? `\nPreview: https://${options.preview.host}/ through the proxy, signed-in user from ${options.preview.header}, read-only` : ''; console.log(`Mosaic Console: http://127.0.0.1:${server.address().port}/\nBoard: ${options.board}\n${busLine}${previewLine}\nCtrl-C stops this server.`); for (const signal of ['SIGINT', 'SIGTERM']) process.once(signal, () => server.close()); } catch (err) { console.error(`refused: ${err.message}`); process.exitCode = 2; }