Phase 0: fix typecheck, format, build; remove stray emit; pin port via env
CI / Lint, typecheck, test, build (push) Failing after 22s
CI / Lint, typecheck, test, build (push) Failing after 22s
This commit is contained in:
+2
-3
@@ -5,7 +5,7 @@
|
||||
import { Hono } from 'hono';
|
||||
import { cors } from 'hono/cors';
|
||||
import { logger } from 'hono/logger';
|
||||
import { UniverseSnapshotSchema, type AppType as _ } from '@kerbal-rt/shared-types';
|
||||
import { UniverseSnapshotSchema } from '@kerbal-rt/shared-types';
|
||||
import { z } from 'zod';
|
||||
import { state } from './state.js';
|
||||
|
||||
@@ -58,8 +58,7 @@ export function buildApp() {
|
||||
// ─── read-only endpoints ───────────────────────────────────────────────
|
||||
app.get('/api/v1/state', (c) => {
|
||||
const snap = state.latestSnapshot();
|
||||
if (!snap)
|
||||
return c.json({ error: true, code: 'NO_DATA', message: 'No snapshot yet' }, 503);
|
||||
if (!snap) return c.json({ error: true, code: 'NO_DATA', message: 'No snapshot yet' }, 503);
|
||||
return c.json({ error: false, data: snap });
|
||||
});
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ app.get(
|
||||
})),
|
||||
);
|
||||
|
||||
// Suppress unused-import warning when no upgrade happens
|
||||
void upgradeWebSocket;
|
||||
|
||||
const port = Number(process.env.PORT ?? 4000);
|
||||
|
||||
const server: ServerType = serve({ fetch: app.fetch, port }, (info) => {
|
||||
|
||||
+22
-7
@@ -6,33 +6,48 @@
|
||||
*
|
||||
* Phase 1 will wire this to a Redis pubsub channel so multiple API
|
||||
* instances can share the fan-out load.
|
||||
*
|
||||
* Hono's @hono/node-ws gives us a `WSContext` that wraps a `ws` WebSocket
|
||||
* with extra Hono-specific methods. We use a thin adapter type so this
|
||||
* module doesn't need to import from hono.
|
||||
*/
|
||||
import type { LiveMessage } from '@kerbal-rt/shared-types';
|
||||
import type { WebSocket } from 'ws';
|
||||
|
||||
const clients = new Set<WebSocket>();
|
||||
/** Anything with .send(string) and a .readyState we can inspect. */
|
||||
export interface WsLike {
|
||||
send(data: string): void;
|
||||
readonly readyState: number;
|
||||
}
|
||||
|
||||
function send(ws: WebSocket, msg: LiveMessage): void {
|
||||
if (ws.readyState === 1 /* OPEN */) {
|
||||
const READY_STATE_OPEN = 1;
|
||||
const clients = new Set<WsLike>();
|
||||
|
||||
function send(ws: WsLike, msg: LiveMessage): void {
|
||||
if (ws.readyState === READY_STATE_OPEN) {
|
||||
ws.send(JSON.stringify(msg));
|
||||
}
|
||||
}
|
||||
|
||||
export const handleLiveSocket = {
|
||||
onOpen(ws: WebSocket): void {
|
||||
onOpen(ws: WsLike): void {
|
||||
clients.add(ws);
|
||||
},
|
||||
|
||||
onMessage(_evt: { data: unknown }, _ws: WebSocket): void {
|
||||
onMessage(_evt: { data: unknown }, _ws: WsLike): void {
|
||||
// Phase 0: clients are read-only, ignore incoming.
|
||||
// Phase 2: accept subscriptions like { type: 'subscribe', vesselId: '...' }
|
||||
},
|
||||
|
||||
onClose(ws: WebSocket): void {
|
||||
onClose(ws: WsLike): void {
|
||||
clients.delete(ws);
|
||||
},
|
||||
|
||||
broadcast(msg: LiveMessage): void {
|
||||
for (const ws of clients) send(ws, msg);
|
||||
},
|
||||
|
||||
/** For tests / introspection. */
|
||||
get clientCount(): number {
|
||||
return clients.size;
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user