Phase 0: fix typecheck, format, build; remove stray emit; pin port via env
CI / Lint, typecheck, test, build (push) Failing after 22s

This commit is contained in:
Mavis
2026-06-02 16:07:09 +00:00
parent 7b19c54943
commit 938ba042b3
23 changed files with 6693 additions and 83 deletions
+2 -3
View File
@@ -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 });
});
+3
View File
@@ -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
View File
@@ -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;
},
};
+1 -1
View File
@@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
+2 -2
View File
@@ -4,9 +4,9 @@
"private": true,
"description": "Marketing/operations hub: mission calendar, crew, media, Spacenomicon",
"scripts": {
"dev": "next dev --port 3000",
"dev": "next dev --port ${PORT:-3000}",
"build": "next build",
"start": "next start --port 3000",
"start": "next start --port ${PORT:-3000}",
"typecheck": "tsc --noEmit",
"lint": "next lint",
"test": "echo 'no tests yet'"
+2 -1
View File
@@ -3,7 +3,8 @@ import type { ReactNode } from 'react';
export const metadata = {
title: 'Kerbal RT — Real-time KSP server',
description: 'A no-warp Kerbal Space Program multiplayer server, mirrored to the web in real time.',
description:
'A no-warp Kerbal Space Program multiplayer server, mirrored to the web in real time.',
};
export default function RootLayout({ children }: { children: ReactNode }) {
+3 -1
View File
@@ -3,7 +3,9 @@ import { Card, Pill } from '@kerbal-rt/ui';
export default function HomePage() {
return (
<main style={{ maxWidth: 960, margin: '0 auto', padding: '2rem 1rem' }}>
<header style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', marginBottom: '1.5rem' }}>
<header
style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', marginBottom: '1.5rem' }}
>
<h1 style={{ fontSize: '1.75rem', margin: 0 }}>Kerbal RT</h1>
<Pill tone="success">Phase 0 skeleton</Pill>
</header>
+6 -1
View File
@@ -7,7 +7,12 @@
"incremental": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"plugins": [{ "name": "next" }]
"plugins": [
{
"name": "next"
}
],
"allowJs": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
+1 -1
View File
@@ -6,7 +6,7 @@
"description": "3D real-time solar system viewer",
"scripts": {
"dev": "vite --port 3001",
"build": "tsc -p tsconfig.build.json && vite build",
"build": "tsc --noEmit && vite build",
"preview": "vite preview --port 3001",
"typecheck": "tsc --noEmit",
"lint": "echo 'no linter yet'",
+2 -8
View File
@@ -148,11 +148,7 @@ function Scene({ bodies, ut }: { bodies: CelestialBody[]; ut: number }) {
if (body.sphereOfInfluence === 0 || body.sphereOfInfluence === Infinity) {
// Star: render but skip orbit
if (body.kind === 'star') {
const geo = new THREE.SphereGeometry(
Math.max(body.radius, 1e8),
32,
16,
);
const geo = new THREE.SphereGeometry(Math.max(body.radius, 1e8), 32, 16);
const mat = new THREE.MeshBasicMaterial({ color: 0xffcc33 });
const mesh = new THREE.Mesh(geo, mat);
scene.add(mesh);
@@ -287,9 +283,7 @@ export function App() {
</div>
<div style={{ marginTop: 4 }}>UT {formatUtAsKspDate(ut)}</div>
<div style={{ display: 'flex', gap: '0.25rem', marginTop: 8 }}>
<button onClick={() => setPlaying((p) => !p)}>
{playing ? '⏸' : '▶'}
</button>
<button onClick={() => setPlaying((p) => !p)}>{playing ? '⏸' : '▶'}</button>
<button onClick={() => setUt(0)}>Reset</button>
{[1, 60, 3600, 86400].map((s) => (
<button
-7
View File
@@ -1,7 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false
},
"include": ["src/**/*"]
}
+1 -1
View File
@@ -7,6 +7,6 @@
"module": "ESNext",
"moduleResolution": "Bundler"
},
"include": ["src/**/*"],
"include": ["src/**/*", "src/**/*.d.ts"],
"references": [{ "path": "./tsconfig.node.json" }]
}