// GET /relay/balance — peek at the current install's credit balance + // tier WITHOUT charging anything. Recap clients call this to populate // the "N credits remaining · Tier: X" banner before the user runs any // transcribe/analyze, so the display is accurate on first load instead // of saying "balance unknown — no relay calls yet". // // Same auth surface as the metered endpoints: // X-Recap-Install-Id (required) // Authorization (optional Bearer LIC1-... — absent = Core) // // Returns the standard envelope shape with result=null and // credit_charged=0. The license-resolution path is identical to // /relay/transcribe and /relay/analyze, so the cached online check // against keysat happens here too — but no row mutation, no job-id // reservation, no upstream backend call. import express from "express"; import { resolveLicense } from "../keysat-client.js"; import { getOrCreateRow } from "../credits.js"; import { envelope, errorEnvelope } from "./envelope.js"; export function balanceRouter() { const router = express.Router(); router.get("/balance", async (req, res) => { const installId = req.header("X-Recap-Install-Id"); const auth = req.header("Authorization"); if (!installId) { const e = await errorEnvelope({ error: "missing X-Recap-Install-Id header", statusHint: 400, }); return res.status(400).json(e.body); } const license = await resolveLicense(auth); const tier = license.tier; // Touch the row so tier_snapshot reflects the most recently seen // license tier — same as the metered endpoints do — but commit // nothing. const row = await getOrCreateRow(installId); row.tier_snapshot = tier; const body = await envelope({ result: null, installId, tier, creditCharged: 0, }); res.json(body); }); return router; }