Add operator console (Fleet, Trace, Docs) with screenshots
Some checks are pending
offline / test (push) Waiting to run

Unify loopback ops, hop testing, and reading order. Overview lists
high-level docs first, then architecture, then the rest. Credits:
Scott Lindsey, George Lambert, NATS.IO, Grok-Code by Grok.com.
This commit is contained in:
George Lambert 2026-09-11 14:06:14 -04:00
parent a32c91475c
commit cf4ef9e3af
17 changed files with 457 additions and 143 deletions

View file

@ -9,6 +9,7 @@ import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { listServices } from './load.js';
import { ACTIONS, Simulator } from '../../verae-zapier-simulator/src/pipeline.js';
const PUBLIC = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'public');
@ -24,12 +25,27 @@ function json(res, code, obj) {
export function startControlServer(sup, mon) {
const bind = sup.loaded.control?.bind || '127.0.0.1';
const port = Number(sup.loaded.control?.port || 3850);
const sim = new Simulator();
const server = http.createServer(async (req, res) => {
const url = new URL(req.url, `http://${bind}:${port}`);
try {
if (req.method === 'GET' && url.pathname === '/health') {
return json(res, 200, { ok: true, role: 'fleet-control' });
return json(res, 200, { ok: true, role: 'operator-console' });
}
if (req.method === 'GET' && url.pathname === '/api/sim/actions') {
return json(res, 200, { actions: ACTIONS, state: sim.snapshot() });
}
if (req.method === 'POST' && url.pathname === '/api/sim/reset') {
sim.reset();
return json(res, 200, { ok: true, state: sim.snapshot() });
}
if (req.method === 'POST' && url.pathname === '/api/sim/run') {
const chunks = [];
for await (const c of req) chunks.push(c);
const body = JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}');
const result = await sim.run(body);
return json(res, 200, result);
}
if (req.method === 'GET' && url.pathname === '/api/services') {
return json(res, 200, { services: listServices(sup.loaded), fleetPath: sup.loaded.fleetPath });
@ -92,6 +108,14 @@ export function startControlServer(sup, mon) {
fs.createReadStream(dest).pipe(res);
return;
}
if (req.method === 'GET' && url.pathname.startsWith('/docs/screenshots/')) {
const dest = path.normalize(path.join(PUBLIC, '..', url.pathname));
const root = path.normalize(path.join(PUBLIC, '..'));
if (!dest.startsWith(root) || !fs.existsSync(dest)) return json(res, 404, { error: 'not found' });
res.writeHead(200, { 'content-type': 'image/png' });
fs.createReadStream(dest).pipe(res);
return;
}
json(res, 404, { error: 'not found' });
} catch (err) {
json(res, 400, { error: err.message });