v0.2.2 balance peek endpoint
This commit is contained in:
@@ -21,6 +21,7 @@ import {
|
||||
import { transcribeRouter } from "./routes/transcribe.js";
|
||||
import { analyzeRouter } from "./routes/analyze.js";
|
||||
import { healthRouter } from "./routes/health.js";
|
||||
import { balanceRouter } from "./routes/balance.js";
|
||||
import { adminRouter } from "./routes/admin.js";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
@@ -46,6 +47,7 @@ setupAdminAuthRoutes(app);
|
||||
// authenticates per-call via headers (X-Recap-Install-Id required,
|
||||
// Authorization optional).
|
||||
app.use("/relay", healthRouter());
|
||||
app.use("/relay", balanceRouter());
|
||||
app.use("/relay", transcribeRouter());
|
||||
app.use("/relay", analyzeRouter());
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user