Skip to Content

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

ExportShapePurpose
createServer(opts)(CreateServerOptions) => FastifyInstanceBuild 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 default reqId) so it matches the design contract in design-overview.md.
  • Request logging: built-in per-request info logs are suppressed (disableRequestLogging: true). A single onResponse hook emits one canonical summary line per request — { route, statusCode, durationMs, outcome } — where outcome is ok | rejected | error based on status code.
  • FastifyInstance widening: pino’s Logger doesn’t carry Fastify’s internal msgPrefix, which breaks the strongly-typed instance Fastify v5 infers. We widen to the default FastifyInstance at the construction boundary so plugin-style registrars don’t need workaround signatures. Runtime behavior is unchanged.

Routes registered

  • GET /healthz — see healthz
  • POST /telegram/webhook (only when opts.telegram is provided) — see telegramWebhook

Future phases will add /mcp (Phase 2) and /api/inngest (Phase 5).

Tests