TypeScript 97.6%
SQL 1.4%
JavaScript 0.5%
1import type { FastifyInstance } from "fastify";2import os from "node:os";3import { pingDb } from "@spinza/database";4import { CryptoRng, runSpin } from "@spinza/game-core";5import { GAMES } from "@spinza/games";6import { pingRedis, redis } from "../lib/redis";7import { config } from "../config";8import { maintenance } from "../lib/settings";910const startedAt = Date.now();1112export async function healthRoutes(app: FastifyInstance) {13 app.get("/api/health", async () => ({14 status: "ok",15 service: "spinza-api",16 version: config.version,17 uptime: Math.round((Date.now() - startedAt) / 1000),18 node: os.hostname(),19 maintenance: maintenance().enabled,20 time: new Date().toISOString(),21 }));2223 app.get("/api/health/database", async (reply) => {24 try {25 const latency = await pingDb();26 return { status: "ok", latencyMs: latency };27 } catch (e) {28 return { status: "down", error: (e as Error).message };29 }30 });3132 app.get("/api/health/redis", async () => {33 try {34 const latency = await pingRedis();35 return { status: "ok", latencyMs: latency };36 } catch (e) {37 return { status: "down", error: (e as Error).message };38 }39 });4041 app.get("/api/health/game-engine", async () => {42 const t = Date.now();43 const def = GAMES[0];44 const out = runSpin(def, 100, { rng: new CryptoRng() });45 return { status: "ok", games: GAMES.length, sampleGame: def.slug, steps: out.steps.length, latencyMs: Date.now() - t };46 });4748 app.get("/api/ready", async (_req, reply) => {49 try {50 await Promise.all([pingDb(), pingRedis()]);51 return { ready: true };52 } catch (e) {53 reply.code(503);54 return { ready: false, error: (e as Error).message };55 }56 });5758 app.get("/api/live", async () => {59 const cutoff = Date.now() - 5 * 60_000;60 const players = await redis().zcount("live:players", cutoff, "+inf");61 return { players };62 });63}64