// Task 1670 — the house credential is a minter. Each broker/calendar consumer // mints (and thereafter reuses) a scoped data token from it via cf-token.sh, the // single Cloudflare mint/reuse state machine. This wrapper shells that script // against the house env file and reads back the persisted key value. The mint // logic itself is not duplicated here — it lives only in cf-token.sh. import { readFileSync } from "node:fs"; import { execFile } from "node:child_process"; import type { RunFn } from "./cf-exec.js"; const defaultRun: RunFn = (cmd, args, env) => new Promise((resolve, reject) => { execFile(cmd, args, { env }, (err, stdout, stderr) => { if (err) { reject(new Error(`${cmd} ${args.join(" ")} failed: ${err.message}\n${stderr}`)); return; } resolve({ stdout: stdout.toString() }); }); }); function readKey(path: string, key: string): string | undefined { for (const line of readFileSync(path, "utf8").split("\n")) { const m = line.match(/^([A-Z0-9_]+)=(.*)$/); if (m && m[1] === key) return m[2].trim(); } return undefined; } /** * Resolve a scoped data token (e.g. "storage" = D1+R2) from the house minter. * Shells cf-token.sh, which mints or reuses the scope and persists the key into * the house env file, echoing the key name. Reads that key back and returns its * value. Throws if the key is absent after the run (never returns the minter). */ export async function resolveHouseScopedToken( scope: string, houseEnvPath: string, cfTokenShPath: string, run: RunFn = defaultRun, ): Promise { const preexisting = readKey(houseEnvPath, keyForScope(scope)) !== undefined; const { stdout } = await run( "bash", [cfTokenShPath, scope, houseEnvPath], { ...process.env } as Record, ); const keyName = stdout.trim().split("\n").pop()?.trim() ?? ""; if (!keyName) throw new Error(`storage-broker: cf-token.sh ${scope} returned no key name`); const value = readKey(houseEnvPath, keyName); if (!value) { throw new Error(`storage-broker: scoped token ${keyName} absent in ${houseEnvPath} after mint`); } console.error( `[storage-broker] op=house-scoped-token src=house scope=${scope} action=${preexisting ? "reuse" : "mint"} result=active`, ); return value; } // The persisted key name for each scope, mirroring cf-token.sh's scope table. // Used only to derive the mint/reuse action for the observability line; the // authoritative key is whatever cf-token.sh echoes. function keyForScope(scope: string): string { switch (scope) { case "storage": return "CF_STORAGE_TOKEN"; case "calendar-d1": return "CF_CALENDAR_D1_TOKEN"; case "pages": // cf-token.sh's scope table maps pages and d1 to the same minted token. return "CF_PAGES_D1_TOKEN"; default: return ""; } }