Files
recap-relay/server/routes/health.js
T

52 lines
1.8 KiB
JavaScript

// GET /relay/health — public liveness check. No auth, no credit
// accounting. Returns a minimal status object so monitoring + Recap's
// /api/relay/status can verify the relay is reachable.
import express from "express";
import { readFileSync } from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { getConfigSnapshot } from "../config.js";
// Pull the version off server/package.json once at module load — the
// build pipeline bumps that file in lockstep with each StartOS version
// bump, so the health endpoint always reports a meaningful number.
const __dirname = path.dirname(fileURLToPath(import.meta.url));
let VERSION = "unknown";
try {
const pkg = JSON.parse(
readFileSync(path.join(__dirname, "..", "package.json"), "utf8")
);
VERSION = pkg.version || "unknown";
} catch {
// Read failure is non-fatal — health still works, just reports
// "unknown". Build pipeline shouldn't ever ship a missing
// package.json so this branch is defensive only.
}
export function healthRouter() {
const router = express.Router();
router.get("/health", async (_req, res) => {
const cfg = await getConfigSnapshot();
res.json({
ok: true,
service: "recap-relay",
version: VERSION,
backends: {
gemini: !!cfg.relay_gemini_api_key,
// Whether the operator-hardware path is wired up at all.
// Hardware backends are now sourced from Spark Control
// discovery — see hardware-config.js. Empty discovery URL
// means no hardware path; downstream details (which model is
// ready, transcribe vs analyze availability) are surfaced via
// /admin/config's effective_* fields.
hardware: !!cfg.relay_spark_control_url,
},
admin_enabled: !!cfg.relay_admin_password_hash,
});
});
return router;
}