Reference implementation for the Phoenix Architecture. Work in progress.
aicoding.leaflet.pub/
ai
coding
crazy
1/**
2 * Server — HTTP Server
3 *
4 * AUTO-GENERATED by Phoenix VCS
5 * Provides health check, metrics, and module endpoints.
6 */
7
8import { createServer, IncomingMessage, ServerResponse } from 'node:http';
9
10import * as connectionHandling from './connection-handling.js';
11import * as rooms from './rooms.js';
12
13// ─── Metrics ─────────────────────────────────────────────────────────────────
14
15const _svcMetrics = {
16 requests_total: 0,
17 requests_by_path: {} as Record<string, number>,
18 errors_total: 0,
19 uptime_start: Date.now(),
20};
21
22// ─── Module Registry ─────────────────────────────────────────────────────────
23
24const _svcModules = {
25 'connection-handling': connectionHandling,
26 'rooms': rooms,
27};
28
29// ─── Router ──────────────────────────────────────────────────────────────────
30
31type Handler = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
32
33const routes: Record<string, Handler> = {
34 '/health': (_req, res) => {
35 res.writeHead(200, { 'Content-Type': 'application/json' });
36 res.end(JSON.stringify({
37 status: 'ok',
38 service: 'Server',
39 uptime: Math.floor((Date.now() - _svcMetrics.uptime_start) / 1000),
40 modules: Object.keys(_svcModules),
41 }));
42 },
43
44 '/metrics': (_req, res) => {
45 res.writeHead(200, { 'Content-Type': 'application/json' });
46 res.end(JSON.stringify({
47 ..._svcMetrics,
48 uptime_seconds: Math.floor((Date.now() - _svcMetrics.uptime_start) / 1000),
49 }, null, 2));
50 },
51
52 '/modules': (_req, res) => {
53 const info = Object.entries(_svcModules).map(([name, mod]) => {
54 const phoenix = (mod as Record<string, unknown>)._phoenix as Record<string, unknown> | undefined;
55 return {
56 name,
57 risk_tier: phoenix?.risk_tier ?? 'unknown',
58 exports: Object.keys(mod).filter(k => k !== '_phoenix'),
59 };
60 });
61 res.writeHead(200, { 'Content-Type': 'application/json' });
62 res.end(JSON.stringify(info, null, 2));
63 },
64};
65
66// ─── Server ──────────────────────────────────────────────────────────────────
67
68function handleRequest(req: IncomingMessage, res: ServerResponse): void {
69 const url = req.url ?? '/';
70 const path = url.split('?')[0];
71
72 _svcMetrics.requests_total++;
73 _svcMetrics.requests_by_path[path] = (_svcMetrics.requests_by_path[path] ?? 0) + 1;
74
75 const handler = routes[path];
76 if (handler) {
77 try {
78 handler(req, res);
79 } catch (err) {
80 _svcMetrics.errors_total++;
81 res.writeHead(500, { 'Content-Type': 'application/json' });
82 res.end(JSON.stringify({ error: String(err) }));
83 }
84 } else {
85 res.writeHead(404, { 'Content-Type': 'application/json' });
86 res.end(JSON.stringify({
87 error: 'Not Found',
88 path,
89 available: Object.keys(routes),
90 }));
91 }
92}
93
94export function startServer(port?: number): { server: ReturnType<typeof createServer>; port: number; ready: Promise<void> } {
95 const requestedPort = port ?? parseInt(process.env.SERVER_PORT ?? process.env.PORT ?? '3001', 10);
96 const server = createServer(handleRequest);
97 let actualPort = requestedPort;
98
99 const ready = new Promise<void>(resolve => {
100 server.listen(requestedPort, () => {
101 const addr = server.address();
102 if (addr && typeof addr === 'object') actualPort = addr.port;
103 result.port = actualPort;
104 console.log(`Server listening on http://localhost:${actualPort}`);
105 console.log(` /health — health check`);
106 console.log(` /metrics — request metrics`);
107 console.log(` /modules — registered modules`);
108 resolve();
109 });
110 });
111
112 const result = { server, port: actualPort, ready };
113 return result;
114}
115
116// Start when run directly
117const isMain = process.argv[1]?.endsWith('/server/server.js') ||
118 process.argv[1]?.endsWith('/server/server.ts');
119if (isMain) {
120 startServer();
121}