From 25695d69b21e7b938f87747b4c686a36ecf36f39 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Thu, 16 Apr 2026 17:03:42 -0600 Subject: [PATCH] feat(server): scaffold Bun HTTP+WS server with health + logging (P4.1) --- packages/server/package.json | 3 ++ packages/server/src/index.ts | 53 ++++++++++++++++++++++++++++++++++- packages/server/src/logger.ts | 3 ++ packages/server/tsconfig.json | 1 + 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 packages/server/src/logger.ts diff --git a/packages/server/package.json b/packages/server/package.json index 11fca93..66b0832 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -11,5 +11,8 @@ "@paratype/rete": "workspace:*", "pino": "^9.0.0", "zod": "^3.23.0" + }, + "devDependencies": { + "bun-types": "^1.3.12" } } diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index f9e0f4f..251d02c 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1,2 +1,53 @@ // @paratype/chess-server — authoritative Bun WebSocket server -export {}; +import { randomUUID } from "node:crypto"; +import { logger } from "./logger.js"; + +interface ClientData { + clientId: string; +} + +const port = parseInt(process.env["PORT"] ?? "7357", 10); + +export const server = Bun.serve({ + port, + fetch(req, srv) { + const url = new URL(req.url); + + if (url.pathname === "/ws") { + const upgraded = srv.upgrade(req, { + data: { clientId: randomUUID() }, + }); + if (upgraded) return undefined; + return new Response("Upgrade failed", { status: 500 }); + } + + if (url.pathname === "/healthz") { + return Response.json({ ok: true, version: "1.0.0" }); + } + + return new Response("Not Found", { status: 404 }); + }, + websocket: { + open(ws) { + const log = logger.child({ clientId: ws.data.clientId }); + log.info("ws connected"); + }, + message(ws, msg) { + const log = logger.child({ clientId: ws.data.clientId }); + const length = typeof msg === "string" ? msg.length : msg.byteLength; + log.info({ length }, "ws message"); + }, + close(ws, code, reason) { + const log = logger.child({ clientId: ws.data.clientId }); + log.info({ code, reason }, "ws closed"); + }, + }, +}); + +logger.info({ port }, "server started"); + +process.on("SIGINT", () => { + logger.info("shutting down"); + server.stop(true); + process.exit(0); +}); diff --git a/packages/server/src/logger.ts b/packages/server/src/logger.ts new file mode 100644 index 0000000..152b49a --- /dev/null +++ b/packages/server/src/logger.ts @@ -0,0 +1,3 @@ +import pino from "pino"; + +export const logger = pino({ level: process.env["LOG_LEVEL"] ?? "info" }); diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index 04c5039..5f7e1a2 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "lib": ["ES2022"], + "types": ["bun-types"], "composite": true, "outDir": "dist", "rootDir": "src"