src/http/server.ts — Fastify factory
Pure factory that wires Fastify to our pino logger and registers every HTTP
route. Returns an unconfigured FastifyInstance — the entrypoint in
src/index.ts is the only place that calls .listen(),
so tests can use app.inject() against the exact same wiring.
Public surface
| Export | Shape | Purpose |
|---|---|---|
createServer(opts) | (CreateServerOptions) => FastifyInstance | Build the app |
CreateServerOptions | {logger, telegram?} |
The telegram field is optional so isolated tests of unrelated routes (e.g.
/healthz, request-logging) don’t have to stand up a fake Telegram handler.
Behaviors
- Request IDs: Fastify generates a UUID per request and surfaces it as
requestId(not the defaultreqId) so it matches the design contract in design-overview.md. - Request logging: built-in per-request info logs are suppressed
(
disableRequestLogging: true). A singleonResponsehook emits one canonical summary line per request —{ route, statusCode, durationMs, outcome }— whereoutcomeisok | rejected | errorbased on status code. - FastifyInstance widening: pino’s
Loggerdoesn’t carry Fastify’s internalmsgPrefix, which breaks the strongly-typed instance Fastify v5 infers. We widen to the defaultFastifyInstanceat the construction boundary so plugin-style registrars don’t need workaround signatures. Runtime behavior is unchanged.
Routes registered
GET /healthz— see healthzPOST /telegram/webhook(only whenopts.telegramis provided) — see telegramWebhook
Future phases will add /mcp (Phase 2) and /api/inngest (Phase 5).
Tests
- test/unit/healthz.test.ts — sanity check
- test/unit/logger.test.ts — request-ID + summary line behavior
- test/unit/webhook.test.ts — exercises the telegram-opts wiring