apiblaze 0.21.45 → 0.21.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +647 -401
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ var __toESM = (mod, isNodeMode, target2) => (target2 = mod != null ? __create(__
34
34
  var version;
35
35
  var init_package = __esm({
36
36
  "package.json"() {
37
- version = "0.21.45";
37
+ version = "0.21.46";
38
38
  }
39
39
  });
40
40
 
@@ -2996,12 +2996,12 @@ function openBrowser2(url) {
2996
2996
  } catch {
2997
2997
  }
2998
2998
  }
2999
- async function deviceLogin(clientId, scope, onPrompt, resource) {
2999
+ async function deviceLogin(clientId, scope2, onPrompt, resource) {
3000
3000
  const { verifier, challenge } = pkce();
3001
3001
  const startRes = await fetch(`${AUTH_BASE}/device_authorization`, {
3002
3002
  method: "POST",
3003
3003
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
3004
- body: new URLSearchParams({ client_id: clientId, scope, code_challenge: challenge, code_challenge_method: "S256", ...resource ? { resource } : {} })
3004
+ body: new URLSearchParams({ client_id: clientId, scope: scope2, code_challenge: challenge, code_challenge_method: "S256", ...resource ? { resource } : {} })
3005
3005
  });
3006
3006
  const start = await startRes.json().catch(() => ({}));
3007
3007
  if (!startRes.ok) {
@@ -8949,7 +8949,7 @@ async function runOpAnon(o = {}) {
8949
8949
  const log4 = (s) => {
8950
8950
  if (!o.json) console.log(s);
8951
8951
  };
8952
- log4(import_chalk70.default.bold(`${B.cli} op anon \u2014 a first-time visitor's demo, against production`));
8952
+ log4(import_chalk71.default.bold(`${B.cli} op anon \u2014 a first-time visitor's demo, against production`));
8953
8953
  try {
8954
8954
  await journey("first", work, home, checks);
8955
8955
  const env = await journey("rerun", work, home, checks);
@@ -8972,18 +8972,18 @@ async function runOpAnon(o = {}) {
8972
8972
  checks.push({ id: "stop", ok: stop.code === 0 && portsFree, detail: `exit ${stop.code}${portsFree ? "" : " \xB7 ports still answering"}` });
8973
8973
  import_fs10.default.rmSync(root, { recursive: true, force: true });
8974
8974
  }
8975
- for (const c of checks) log4(` ${c.skipped ? import_chalk70.default.yellow("\u2013") : c.ok ? import_chalk70.default.green("\u2713") : import_chalk70.default.red("\u2717")} ${c.id.padEnd(24)} ${import_chalk70.default.dim(c.detail)}`);
8975
+ for (const c of checks) log4(` ${c.skipped ? import_chalk71.default.yellow("\u2013") : c.ok ? import_chalk71.default.green("\u2713") : import_chalk71.default.red("\u2717")} ${c.id.padEnd(24)} ${import_chalk71.default.dim(c.detail)}`);
8976
8976
  const failed = checks.filter((c) => !c.ok).length;
8977
8977
  const skipped = checks.filter((c) => c.skipped).length;
8978
8978
  const passed = checks.length - failed - skipped;
8979
8979
  const secs = Math.round((Date.now() - t0) / 1e3);
8980
8980
  const tail = `${skipped ? `, ${skipped} skipped` : ""} (${secs} s)`;
8981
- log4(failed ? import_chalk70.default.red(`${passed}/${checks.length - skipped} passed, ${failed} failed${tail}`) : import_chalk70.default.green(`${passed}/${checks.length - skipped} passed${tail}`));
8981
+ log4(failed ? import_chalk71.default.red(`${passed}/${checks.length - skipped} passed, ${failed} failed${tail}`) : import_chalk71.default.green(`${passed}/${checks.length - skipped} passed${tail}`));
8982
8982
  if (o.json) process.stdout.write(JSON.stringify({ ok: !failed, checks }, null, 2) + "\n");
8983
8983
  if (failed) process.exitCode = 1;
8984
8984
  return { ok: !failed, checks };
8985
8985
  }
8986
- var import_fs10, import_os3, import_path7, import_child_process6, import_chalk70, SECRET, SANDBOX_TEAM;
8986
+ var import_fs10, import_os3, import_path7, import_child_process6, import_chalk71, SECRET, SANDBOX_TEAM;
8987
8987
  var init_op_anon = __esm({
8988
8988
  "src/commands/op-anon.ts"() {
8989
8989
  "use strict";
@@ -8991,7 +8991,7 @@ var init_op_anon = __esm({
8991
8991
  import_os3 = __toESM(require("os"));
8992
8992
  import_path7 = __toESM(require("path"));
8993
8993
  import_child_process6 = require("child_process");
8994
- import_chalk70 = __toESM(require("chalk"));
8994
+ import_chalk71 = __toESM(require("chalk"));
8995
8995
  init_brand();
8996
8996
  init_api();
8997
8997
  init_admin();
@@ -9004,7 +9004,7 @@ var init_op_anon = __esm({
9004
9004
  // src/index.ts
9005
9005
  var import_fs11 = __toESM(require("fs"));
9006
9006
  var import_commander = require("commander");
9007
- var import_chalk72 = __toESM(require("chalk"));
9007
+ var import_chalk73 = __toESM(require("chalk"));
9008
9008
  init_package();
9009
9009
  init_cli_run_context();
9010
9010
  init_version_guard();
@@ -11392,8 +11392,13 @@ function withOverride(cat, tool, flags) {
11392
11392
  for (const k of ["readOnly", "destructive", "idempotent", "confirm", "alwaysAsync"]) {
11393
11393
  if (typeof flags[k] === "boolean") patch[k] = flags[k];
11394
11394
  }
11395
+ if (typeof flags.title === "string") {
11396
+ const t = flags.title.trim().slice(0, 120);
11397
+ if (!t) throw new Error('--title needs some text (a short human label, e.g. "List pets").');
11398
+ patch.title = t;
11399
+ }
11395
11400
  if (Object.keys(patch).length === 0) {
11396
- throw new Error("Nothing to set. Pass --read-only, --destructive, --idempotent, --confirm, --always-async (or their --no-\u2026 forms).");
11401
+ throw new Error("Nothing to set. Pass --title, --read-only, --destructive, --idempotent, --confirm, --always-async (or their --no-\u2026 forms).");
11397
11402
  }
11398
11403
  return { ...cat, overrides: { ...cat.overrides ?? {}, [tool]: { ...cat.overrides?.[tool] ?? {}, ...patch } } };
11399
11404
  }
@@ -14032,15 +14037,15 @@ async function runDomainAdd(project, opts) {
14032
14037
  console.error(import_chalk50.default.red(`A ${kind} domain belongs to a proxy: apiblaze domain add <project> --kind ${kind} --domain ${opts.domain}`));
14033
14038
  process.exit(1);
14034
14039
  }
14035
- const scope = await scopeFor(project, opts);
14040
+ const scope2 = await scopeFor(project, opts);
14036
14041
  const spinner = (0, import_ora20.default)(`Registering ${opts.domain}...`).start();
14037
14042
  try {
14038
- const body = scope.kind === "project" ? { hostname: opts.domain, api_version: scope.apiVersion, kind, ...opts.tenant ? { tenant_name: opts.tenant.toLowerCase() } : {} } : { hostname: opts.domain, kind };
14043
+ const body = scope2.kind === "project" ? { hostname: opts.domain, api_version: scope2.apiVersion, kind, ...opts.tenant ? { tenant_name: opts.tenant.toLowerCase() } : {} } : { hostname: opts.domain, kind };
14039
14044
  const out = await admin({
14040
14045
  method: "POST",
14041
- path: scope.base,
14046
+ path: scope2.base,
14042
14047
  body,
14043
- summary: `Add custom ${kind} domain ${opts.domain} to ${scope.label}${scope.kind === "project" && opts.tenant ? ` (tenant ${opts.tenant})` : ""}`
14048
+ summary: `Add custom ${kind} domain ${opts.domain} to ${scope2.label}${scope2.kind === "project" && opts.tenant ? ` (tenant ${opts.tenant})` : ""}`
14044
14049
  });
14045
14050
  spinner.succeed(`Registered ${out?.hostname ?? opts.domain} (${describeKind(out)}). Add these DNS records, then run \`apiblaze domain status\`:`);
14046
14051
  if (opts.json) {
@@ -14057,11 +14062,11 @@ async function runDomainAdd(project, opts) {
14057
14062
  }
14058
14063
  }
14059
14064
  async function runDomainList(project, opts) {
14060
- const scope = await scopeFor(project, opts);
14065
+ const scope2 = await scopeFor(project, opts);
14061
14066
  const out = await admin({
14062
14067
  method: "GET",
14063
- path: scope.kind === "project" ? `${scope.base}?api_version=${encodeURIComponent(scope.apiVersion)}` : scope.base,
14064
- summary: `List custom domains for ${scope.label}`
14068
+ path: scope2.kind === "project" ? `${scope2.base}?api_version=${encodeURIComponent(scope2.apiVersion)}` : scope2.base,
14069
+ summary: `List custom domains for ${scope2.label}`
14065
14070
  });
14066
14071
  const domains = out?.domains ?? [];
14067
14072
  if (opts.json) {
@@ -14073,7 +14078,7 @@ async function runDomainList(project, opts) {
14073
14078
  return;
14074
14079
  }
14075
14080
  for (const d of domains) {
14076
- const pin = scope.kind === "project" && d.tenant ? import_chalk50.default.dim(` tenant ${d.tenant}`) : "";
14081
+ const pin = scope2.kind === "project" && d.tenant ? import_chalk50.default.dim(` tenant ${d.tenant}`) : "";
14077
14082
  console.log(` ${import_chalk50.default.bold(d.hostname)} ${statusColor2(d.status)} ${import_chalk50.default.dim(describeKind(d))}${pin} ${import_chalk50.default.dim(d.id ?? "")}`);
14078
14083
  }
14079
14084
  }
@@ -14082,10 +14087,10 @@ async function runDomainStatus(project, opts) {
14082
14087
  console.error(import_chalk50.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
14083
14088
  process.exit(1);
14084
14089
  }
14085
- const scope = await scopeFor(project, opts);
14090
+ const scope2 = await scopeFor(project, opts);
14086
14091
  const out = await admin({
14087
14092
  method: "GET",
14088
- path: `${scope.base}/${encodeURIComponent(opts.id)}/status`,
14093
+ path: `${scope2.base}/${encodeURIComponent(opts.id)}/status`,
14089
14094
  summary: `Check custom-domain status`
14090
14095
  });
14091
14096
  if (opts.json) {
@@ -14107,12 +14112,12 @@ async function runDomainRemove(project, opts) {
14107
14112
  console.error(import_chalk50.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
14108
14113
  process.exit(1);
14109
14114
  }
14110
- const scope = await scopeFor(project, opts);
14115
+ const scope2 = await scopeFor(project, opts);
14111
14116
  const spinner = (0, import_ora20.default)("Removing domain...").start();
14112
14117
  try {
14113
14118
  await admin({
14114
14119
  method: "DELETE",
14115
- path: `${scope.base}/${encodeURIComponent(opts.id)}`,
14120
+ path: `${scope2.base}/${encodeURIComponent(opts.id)}`,
14116
14121
  summary: `Remove custom domain ${opts.id}`
14117
14122
  });
14118
14123
  spinner.succeed("Removed. Billing for it stops now.");
@@ -14728,7 +14733,8 @@ function randomSecret() {
14728
14733
  (0, import_crypto2.randomFillSync)(bytes);
14729
14734
  return Buffer.from(bytes).toString("base64url");
14730
14735
  }
14731
- var PROVIDER_TYPES = ["google", "github", "microsoft", "facebook", "auth0", "other"];
14736
+ var PROVIDER_TYPES = ["google", "github", "microsoft", "facebook", "auth0", "oidc"];
14737
+ var PASSWORD_TYPE = "password";
14732
14738
  var DEFAULT_SCOPES2 = {
14733
14739
  google: "openid email profile",
14734
14740
  microsoft: "openid email profile",
@@ -14762,8 +14768,15 @@ async function providersMenu(cBase, clientLabel) {
14762
14768
  }]);
14763
14769
  if (act === "back") return;
14764
14770
  if (act === "add") {
14765
- const { type } = await inquirer3.prompt([{ type: "list", name: "type", message: "Provider:", choices: PROVIDER_TYPES }]);
14771
+ const showPassword = providers.some((p) => String(p.type).toLowerCase() === PASSWORD_TYPE) || process.env.APIBLAZE_ADVANCED === "1";
14772
+ const typeChoices = showPassword ? [...PROVIDER_TYPES, { name: "password (APIblaze-hosted username & password \u2014 reviewer / test accounts)", value: PASSWORD_TYPE }] : PROVIDER_TYPES;
14773
+ const { type } = await inquirer3.prompt([{ type: "list", name: "type", message: "Provider:", choices: typeChoices }]);
14766
14774
  let body;
14775
+ if (type === PASSWORD_TYPE) {
14776
+ await admin({ method: "POST", path: `${cBase}/providers`, body: { type: PASSWORD_TYPE }, summary: "Enable username & password sign-in" });
14777
+ console.log(import_chalk54.default.green(" Username & password sign-in enabled. Add people: apiblaze tenant password add <username>"));
14778
+ continue;
14779
+ }
14767
14780
  if (type === "github") {
14768
14781
  const { managed } = await inquirer3.prompt([{
14769
14782
  type: "confirm",
@@ -14777,7 +14790,7 @@ async function providersMenu(cBase, clientLabel) {
14777
14790
  const a = await inquirer3.prompt([
14778
14791
  { type: "input", name: "clientId", message: `${type} OAuth client id:`, validate: (s) => !!s.trim() || "required" },
14779
14792
  { type: "password", name: "clientSecret", mask: "*", message: `${type} OAuth client secret:`, validate: (s) => s.length >= 6 && s.length <= 200 || "6\u2013200 chars" },
14780
- ...type === "auth0" || type === "other" ? [{ type: "input", name: "domain", message: "Issuer / domain (e.g. your-tenant.auth0.com):" }] : [],
14793
+ ...type === "auth0" || type === "oidc" ? [{ type: "input", name: "domain", message: "Issuer / domain (e.g. your-tenant.auth0.com):" }] : [],
14781
14794
  { type: "input", name: "scopes", message: "Scopes:", default: DEFAULT_SCOPES2[type] ?? "" }
14782
14795
  ]);
14783
14796
  body = {
@@ -16223,9 +16236,230 @@ async function agentsMenu(proj2, opts) {
16223
16236
  else await runMcp(proj2.projectName, proj2.apiVersion, {});
16224
16237
  }
16225
16238
 
16226
- // src/commands/group.ts
16239
+ // src/commands/tenant-password.ts
16227
16240
  var import_chalk59 = __toESM(require("chalk"));
16228
16241
  var import_ora28 = __toESM(require("ora"));
16242
+ init_admin();
16243
+ init_api();
16244
+ init_resolve();
16245
+ init_auth();
16246
+ init_tenant_pick();
16247
+ async function teamHasTenant(teamId, slug) {
16248
+ const out = await admin({
16249
+ method: "GET",
16250
+ path: `/teams/${encodeURIComponent(teamId)}/tenants?limit=200&q=${encodeURIComponent(slug)}`,
16251
+ summary: `Look for tenant ${slug}`
16252
+ }).catch(() => null);
16253
+ const names = (out?.tenants ?? []).map((t) => typeof t === "string" ? t : t.tenant_name ?? "");
16254
+ return names.includes(slug);
16255
+ }
16256
+ async function teamForTenant(slug) {
16257
+ const { teamId: active } = await resolveTeam(void 0);
16258
+ if (await teamHasTenant(active, slug)) return active;
16259
+ const teams = (await getTeams().catch(() => [])).filter((t) => t.teamId !== active);
16260
+ for (const t of teams) {
16261
+ if (await teamHasTenant(t.teamId, slug)) {
16262
+ console.error(import_chalk59.default.dim(` (tenant ${slug} is on team ${t.name})`));
16263
+ return t.teamId;
16264
+ }
16265
+ }
16266
+ console.error(import_chalk59.default.red(`No tenant "${slug}" on any of your teams.`) + import_chalk59.default.dim(" (apiblaze tenant list)"));
16267
+ process.exit(1);
16268
+ }
16269
+ async function scope(opts, message, positional) {
16270
+ const named = (positional ?? opts.tenant)?.trim();
16271
+ let teamId;
16272
+ let tenant2;
16273
+ if (named) {
16274
+ tenant2 = named;
16275
+ teamId = await teamForTenant(named);
16276
+ } else {
16277
+ ({ teamId } = await resolveTeam(void 0));
16278
+ tenant2 = loadCredentials()?.activeTenant || null;
16279
+ if (!tenant2) tenant2 = await pickTenant(teamId, { message });
16280
+ }
16281
+ if (!tenant2) process.exit(1);
16282
+ return { teamId, tenant: tenant2, base: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}` };
16283
+ }
16284
+ async function serverSupportsPasswordProvider(s) {
16285
+ try {
16286
+ await admin({ method: "GET", path: `${s.base}/password-accounts`, summary: "Check server capabilities" });
16287
+ return true;
16288
+ } catch (e) {
16289
+ return !/\b404\b|not found/i.test(e instanceof Error ? e.message : String(e));
16290
+ }
16291
+ }
16292
+ async function defaultAppClient(s) {
16293
+ const auth = await admin({ method: "GET", path: `${s.base}/auth`, summary: "Read tenant login config" }).catch(() => null);
16294
+ let defaultId = auth?.default_app_client_id ?? null;
16295
+ if (!defaultId) {
16296
+ const clients = await admin({ method: "GET", path: `${s.base}/app-clients`, summary: "List app clients" }).catch(() => null);
16297
+ const list = Array.isArray(clients) ? clients : Array.isArray(clients?.app_clients) ? clients.app_clients : [];
16298
+ defaultId = list.length === 1 ? list[0].id ?? list[0].client_id ?? list[0].clientId ?? null : null;
16299
+ }
16300
+ if (!defaultId) return null;
16301
+ const providers = await admin({ method: "GET", path: `${s.base}/app-clients/${encodeURIComponent(defaultId)}/providers`, summary: "List login providers" }).catch(() => []);
16302
+ return { clientId: defaultId, providers: Array.isArray(providers) ? providers : [] };
16303
+ }
16304
+ async function runTenantPasswordEnable(tenantArg2, opts) {
16305
+ const s = await scope(opts, "Enable username & password sign-in on which tenant?", tenantArg2);
16306
+ if (!await serverSupportsPasswordProvider(s)) {
16307
+ console.error(import_chalk59.default.red("This APIblaze deployment does not offer username & password sign-in yet."));
16308
+ process.exit(1);
16309
+ }
16310
+ const spinner = (0, import_ora28.default)("Checking the tenant's default app client...").start();
16311
+ const dc = await defaultAppClient(s);
16312
+ if (!dc) {
16313
+ spinner.fail(`Tenant ${s.tenant} has no login yet.`);
16314
+ console.error(import_chalk59.default.dim(` Attach it to a proxy with a sign-in first: apiblaze tenant attach <project> --tenant ${s.tenant}`));
16315
+ process.exit(1);
16316
+ }
16317
+ const existing = dc.providers.find((p) => String(p.type).toLowerCase() === "password");
16318
+ if (existing) {
16319
+ spinner.succeed(`Username & password sign-in is already enabled on ${s.tenant}.`);
16320
+ if (opts.json) console.log(JSON.stringify({ enabled: true, provider_id: existing.id, client_id: dc.clientId }));
16321
+ else console.log(import_chalk59.default.dim(` Add people: apiblaze tenant password add <username> ${s.tenant}`));
16322
+ return;
16323
+ }
16324
+ spinner.text = "Adding the provider...";
16325
+ const created = await admin({ method: "POST", path: `${s.base}/app-clients/${encodeURIComponent(dc.clientId)}/providers`, body: { type: "password" }, summary: "Enable username & password sign-in" });
16326
+ spinner.succeed(`Username & password sign-in enabled on ${import_chalk59.default.bold(s.tenant)}.`);
16327
+ if (opts.json) {
16328
+ console.log(JSON.stringify({ enabled: true, provider_id: created?.id ?? created?.provider?.id ?? null, client_id: dc.clientId }));
16329
+ return;
16330
+ }
16331
+ console.log(import_chalk59.default.dim(` The hosted login page now shows a username & password form next to the other sign-in buttons.
16332
+ Add people: apiblaze tenant password add <username> ${s.tenant}`));
16333
+ }
16334
+ async function runTenantPasswordDisable(tenantArg2, opts) {
16335
+ const s = await scope(opts, "Disable username & password sign-in on which tenant?", tenantArg2);
16336
+ const dc = await defaultAppClient(s);
16337
+ const existing = dc?.providers.find((p) => String(p.type).toLowerCase() === "password");
16338
+ if (!dc || !existing) {
16339
+ console.log(import_chalk59.default.dim(`Username & password sign-in is not enabled on ${s.tenant}.`));
16340
+ return;
16341
+ }
16342
+ if (!opts.yes) {
16343
+ const { default: inquirer3 } = await import("inquirer");
16344
+ const { ok } = await inquirer3.prompt([{ type: "confirm", name: "ok", default: false, message: `Remove username & password sign-in from ${s.tenant}? Every password account on it is deleted too.` }]);
16345
+ if (!ok) return;
16346
+ }
16347
+ await admin({ method: "DELETE", path: `${s.base}/app-clients/${encodeURIComponent(dc.clientId)}/providers/${encodeURIComponent(existing.id)}`, summary: "Disable username & password sign-in" });
16348
+ console.log(import_chalk59.default.green(`Username & password sign-in removed from ${s.tenant}.`));
16349
+ if (opts.json) console.log(JSON.stringify({ enabled: false }));
16350
+ }
16351
+ function printAccount(a) {
16352
+ const flags = [a.disabled ? import_chalk59.default.red("blocked") : import_chalk59.default.green("active"), a.locked_until ? import_chalk59.default.yellow(`locked until ${a.locked_until}`) : "", a.purpose === "reviewer" ? import_chalk59.default.cyan("reviewer") : ""].filter(Boolean).join(" \xB7 ");
16353
+ console.log(` ${import_chalk59.default.bold(a.username)} ${flags}${a.email ? import_chalk59.default.dim(` ${a.email}`) : ""}${a.last_login_at ? import_chalk59.default.dim(` last login ${a.last_login_at}`) : ""}`);
16354
+ }
16355
+ async function runTenantPasswordList(tenantArg2, opts) {
16356
+ const s = await scope(opts, "List password accounts on which tenant?", tenantArg2);
16357
+ const out = await admin({ method: "GET", path: `${s.base}/password-accounts`, summary: "List password accounts" });
16358
+ if (opts.json) {
16359
+ console.log(JSON.stringify(out, null, 2));
16360
+ return;
16361
+ }
16362
+ if (!out?.enabled) {
16363
+ console.log(import_chalk59.default.dim(`Username & password sign-in is not enabled on ${s.tenant}. Enable: apiblaze tenant password enable ${s.tenant}`));
16364
+ return;
16365
+ }
16366
+ const accounts = out.accounts ?? [];
16367
+ if (!accounts.length) {
16368
+ console.log(import_chalk59.default.dim(` No password accounts yet on ${s.tenant}. Add one: apiblaze tenant password add <username> ${s.tenant}`));
16369
+ return;
16370
+ }
16371
+ console.log(import_chalk59.default.dim(` ${s.tenant}`));
16372
+ for (const a of accounts) printAccount(a);
16373
+ }
16374
+ async function readPasswordFromStdin() {
16375
+ const chunks = [];
16376
+ for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
16377
+ return Buffer.concat(chunks).toString("utf8").replace(/\r?\n$/, "");
16378
+ }
16379
+ function revealOnce(s, username, password) {
16380
+ console.log();
16381
+ console.log(import_chalk59.default.bold(" Password (shown once, never stored in clear):"));
16382
+ console.log(` ${import_chalk59.default.cyan(username)} ${import_chalk59.default.bgWhite.black(` ${password} `)}`);
16383
+ console.log(import_chalk59.default.dim(` New one any time: apiblaze tenant password rotate ${username} ${s.tenant}`));
16384
+ console.log();
16385
+ }
16386
+ async function runTenantPasswordAdd(username, tenantArg2, opts) {
16387
+ const s = await scope(opts, "Add the account on which tenant?", tenantArg2);
16388
+ const body = { username };
16389
+ if (opts.email) body.email = opts.email;
16390
+ if (opts.displayName) body.displayName = opts.displayName;
16391
+ if (opts.purpose) body.purpose = opts.purpose;
16392
+ if (opts.passwordStdin) body.password = await readPasswordFromStdin();
16393
+ const r = await admin({ method: "POST", path: `${s.base}/password-accounts`, body, summary: `Add password account ${username}` });
16394
+ if (opts.json) {
16395
+ console.log(JSON.stringify(r));
16396
+ return;
16397
+ }
16398
+ console.log(import_chalk59.default.green(`Account ${import_chalk59.default.bold(r.account?.username ?? username)} created on ${s.tenant}.`));
16399
+ if (r.adopts?.abz_sub) console.log(import_chalk59.default.yellow(` This login signs in AS the existing user ${r.adopts.abz_sub} (same email, pre-provisioned on this tenant).`));
16400
+ if (!opts.passwordStdin && r.password) revealOnce(s, r.account?.username ?? username, r.password);
16401
+ }
16402
+ async function findAccount(s, username) {
16403
+ const out = await admin({ method: "GET", path: `${s.base}/password-accounts`, summary: "List password accounts" });
16404
+ const a = (out?.accounts ?? []).find((x) => x.username === username.trim().toLowerCase() || x.id === username);
16405
+ if (!a) {
16406
+ console.error(import_chalk59.default.red(`No password account "${username}" on ${s.tenant}.`));
16407
+ process.exit(1);
16408
+ }
16409
+ return a;
16410
+ }
16411
+ async function runTenantPasswordRotate(username, tenantArg2, opts) {
16412
+ const s = await scope(opts, "Rotate the password on which tenant?", tenantArg2);
16413
+ const a = await findAccount(s, username);
16414
+ const body = {};
16415
+ if (opts.passwordStdin) body.password = await readPasswordFromStdin();
16416
+ const r = await admin({ method: "POST", path: `${s.base}/password-accounts/${encodeURIComponent(a.id)}/rotate`, body, summary: `Rotate password for ${a.username}` });
16417
+ if (opts.json) {
16418
+ console.log(JSON.stringify(r));
16419
+ return;
16420
+ }
16421
+ console.log(import_chalk59.default.green(`Password rotated for ${import_chalk59.default.bold(a.username)}. Existing sessions end at their next refresh.`));
16422
+ if (!opts.passwordStdin && r.password) revealOnce(s, a.username, r.password);
16423
+ }
16424
+ async function runTenantPasswordSetBlocked(username, tenantArg2, blocked, opts) {
16425
+ const s = await scope(opts, `${blocked ? "Block" : "Unblock"} the account on which tenant?`, tenantArg2);
16426
+ const a = await findAccount(s, username);
16427
+ const r = await admin({ method: "PATCH", path: `${s.base}/password-accounts/${encodeURIComponent(a.id)}`, body: { disabled: blocked }, summary: `${blocked ? "Block" : "Unblock"} ${a.username}` });
16428
+ if (opts.json) {
16429
+ console.log(JSON.stringify(r));
16430
+ return;
16431
+ }
16432
+ console.log(import_chalk59.default.green(`${a.username} ${blocked ? "blocked: sign-in refused until unblocked" : "unblocked"}.`));
16433
+ }
16434
+ async function runTenantPasswordUnlock(username, tenantArg2, opts) {
16435
+ const s = await scope(opts, "Unlock the account on which tenant?", tenantArg2);
16436
+ const a = await findAccount(s, username);
16437
+ const r = await admin({ method: "POST", path: `${s.base}/password-accounts/${encodeURIComponent(a.id)}/unlock`, body: {}, summary: `Unlock ${a.username}` });
16438
+ if (opts.json) {
16439
+ console.log(JSON.stringify(r));
16440
+ return;
16441
+ }
16442
+ console.log(import_chalk59.default.green(`${a.username} unlocked.`));
16443
+ }
16444
+ async function runTenantPasswordRemove(username, tenantArg2, opts) {
16445
+ const s = await scope(opts, "Remove the account from which tenant?", tenantArg2);
16446
+ const a = await findAccount(s, username);
16447
+ if (!opts.yes) {
16448
+ const { default: inquirer3 } = await import("inquirer");
16449
+ const { ok } = await inquirer3.prompt([{ type: "confirm", name: "ok", default: false, message: `Remove password account ${a.username}?` }]);
16450
+ if (!ok) return;
16451
+ }
16452
+ const r = await admin({ method: "DELETE", path: `${s.base}/password-accounts/${encodeURIComponent(a.id)}`, summary: `Remove ${a.username}` });
16453
+ if (opts.json) {
16454
+ console.log(JSON.stringify(r));
16455
+ return;
16456
+ }
16457
+ console.log(import_chalk59.default.green(`${a.username} removed.`));
16458
+ }
16459
+
16460
+ // src/commands/group.ts
16461
+ var import_chalk60 = __toESM(require("chalk"));
16462
+ var import_ora29 = __toESM(require("ora"));
16229
16463
  init_auth();
16230
16464
  init_consumer_auth();
16231
16465
  init_admin();
@@ -16327,7 +16561,7 @@ async function userByRefOrCreate(t, ref) {
16327
16561
  if (!ref.includes("@")) throw e;
16328
16562
  const created = await t.call("/v1/admin/users", "POST", { email: ref.trim().toLowerCase() });
16329
16563
  if (!created?.abz_sub) throw e;
16330
- console.log(import_chalk59.default.dim(` ${ref} wasn't a user yet \u2014 created.`));
16564
+ console.log(import_chalk60.default.dim(` ${ref} wasn't a user yet \u2014 created.`));
16331
16565
  return { abz_sub: created.abz_sub, email: created.email ?? ref, display_name: null };
16332
16566
  }
16333
16567
  }
@@ -16335,11 +16569,11 @@ async function runGroupList(opts) {
16335
16569
  const t = await resolveTransport(opts);
16336
16570
  const groups = await listGroups(t);
16337
16571
  if (opts.json) return void console.log(JSON.stringify(groups));
16338
- if (!groups.length) return void console.log(import_chalk59.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
16339
- console.log(import_chalk59.default.dim(`Tenant ${t.tenant}:`));
16572
+ if (!groups.length) return void console.log(import_chalk60.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
16573
+ console.log(import_chalk60.default.dim(`Tenant ${t.tenant}:`));
16340
16574
  for (const g of groups) {
16341
- const sealed = g.name === "apiblaze_admins" ? import_chalk59.default.dim(" (admins \u2014 managed by allowlist)") : "";
16342
- console.log(` ${import_chalk59.default.bold(g.name)} ${import_chalk59.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
16575
+ const sealed = g.name === "apiblaze_admins" ? import_chalk60.default.dim(" (admins \u2014 managed by allowlist)") : "";
16576
+ console.log(` ${import_chalk60.default.bold(g.name)} ${import_chalk60.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
16343
16577
  }
16344
16578
  }
16345
16579
  async function runGroupCreate(name, opts) {
@@ -16364,10 +16598,10 @@ async function runGroupCreate(name, opts) {
16364
16598
  }
16365
16599
  }
16366
16600
  }
16367
- const spinner = (0, import_ora28.default)(`Creating group ${name}...`).start();
16601
+ const spinner = (0, import_ora29.default)(`Creating group ${name}...`).start();
16368
16602
  try {
16369
16603
  await t.call("/v1/admin/groups", "POST", { name, admins: [adminSub] });
16370
- spinner.succeed(`Group ${import_chalk59.default.bold(name)} created in ${t.tenant}.`);
16604
+ spinner.succeed(`Group ${import_chalk60.default.bold(name)} created in ${t.tenant}.`);
16371
16605
  } catch (e) {
16372
16606
  spinner.fail("Create failed.");
16373
16607
  throw e;
@@ -16376,10 +16610,10 @@ async function runGroupCreate(name, opts) {
16376
16610
  async function runGroupDelete(name, opts) {
16377
16611
  const t = await resolveTransport(opts);
16378
16612
  const g = await groupByName(t, name);
16379
- const spinner = (0, import_ora28.default)(`Deleting group ${name}...`).start();
16613
+ const spinner = (0, import_ora29.default)(`Deleting group ${name}...`).start();
16380
16614
  try {
16381
16615
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}`, "DELETE");
16382
- spinner.succeed(`Group ${import_chalk59.default.bold(name)} deleted.`);
16616
+ spinner.succeed(`Group ${import_chalk60.default.bold(name)} deleted.`);
16383
16617
  } catch (e) {
16384
16618
  spinner.fail("Delete failed.");
16385
16619
  throw e;
@@ -16398,21 +16632,21 @@ async function runGroupMembers(name, opts) {
16398
16632
  return void console.log(JSON.stringify({ ...detail, members: walkedMembers.items, subgroups: subs?.subgroups ?? [] }));
16399
16633
  }
16400
16634
  const members = walkedMembers.items;
16401
- console.log(import_chalk59.default.bold(`${g.name}`) + import_chalk59.default.dim(` (${t.tenant})`));
16402
- for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk59.default.cyan("group-admin") : import_chalk59.default.dim("member")}`);
16403
- if (!members.length) console.log(import_chalk59.default.dim(" no members"));
16635
+ console.log(import_chalk60.default.bold(`${g.name}`) + import_chalk60.default.dim(` (${t.tenant})`));
16636
+ for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk60.default.cyan("group-admin") : import_chalk60.default.dim("member")}`);
16637
+ if (!members.length) console.log(import_chalk60.default.dim(" no members"));
16404
16638
  const sg = subs?.subgroups ?? [];
16405
- if (sg.length) console.log(import_chalk59.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
16639
+ if (sg.length) console.log(import_chalk60.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
16406
16640
  }
16407
16641
  async function runGroupAddUser(userRef, groupName, opts) {
16408
16642
  const t = await resolveTransport(opts);
16409
16643
  const g = await groupByName(t, groupName);
16410
16644
  const u = await userByRefOrCreate(t, userRef);
16411
16645
  const role = opts.role === "admin" ? "admin" : "member";
16412
- const spinner = (0, import_ora28.default)(`Adding ${label2(u)} to ${g.name}...`).start();
16646
+ const spinner = (0, import_ora29.default)(`Adding ${label2(u)} to ${g.name}...`).start();
16413
16647
  try {
16414
16648
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members`, "POST", { abz_sub: u.abz_sub, role });
16415
- spinner.succeed(`${import_chalk59.default.bold(label2(u))} added to ${import_chalk59.default.bold(g.name)} as ${role}.`);
16649
+ spinner.succeed(`${import_chalk60.default.bold(label2(u))} added to ${import_chalk60.default.bold(g.name)} as ${role}.`);
16416
16650
  } catch (e) {
16417
16651
  spinner.fail("Add failed.");
16418
16652
  throw e;
@@ -16421,10 +16655,10 @@ async function runGroupAddUser(userRef, groupName, opts) {
16421
16655
  async function runGroupRemoveUser(userRef, groupName, opts) {
16422
16656
  const t = await resolveTransport(opts);
16423
16657
  const [g, u] = [await groupByName(t, groupName), await userByRef(t, userRef)];
16424
- const spinner = (0, import_ora28.default)(`Removing ${label2(u)} from ${g.name}...`).start();
16658
+ const spinner = (0, import_ora29.default)(`Removing ${label2(u)} from ${g.name}...`).start();
16425
16659
  try {
16426
16660
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members/_?abz_sub=${encodeURIComponent(u.abz_sub)}`, "DELETE");
16427
- spinner.succeed(`${import_chalk59.default.bold(label2(u))} removed from ${import_chalk59.default.bold(g.name)}.`);
16661
+ spinner.succeed(`${import_chalk60.default.bold(label2(u))} removed from ${import_chalk60.default.bold(g.name)}.`);
16428
16662
  } catch (e) {
16429
16663
  spinner.fail("Remove failed.");
16430
16664
  throw e;
@@ -16433,10 +16667,10 @@ async function runGroupRemoveUser(userRef, groupName, opts) {
16433
16667
  async function runGroupAddGroup(childName, parentName, opts) {
16434
16668
  const t = await resolveTransport(opts);
16435
16669
  const [child, parent] = [await groupByName(t, childName), await groupByName(t, parentName)];
16436
- const spinner = (0, import_ora28.default)(`Nesting ${child.name} under ${parent.name}...`).start();
16670
+ const spinner = (0, import_ora29.default)(`Nesting ${child.name} under ${parent.name}...`).start();
16437
16671
  try {
16438
16672
  await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups`, "POST", { child_group_id: child.id });
16439
- spinner.succeed(`${import_chalk59.default.bold(child.name)} is now a subgroup of ${import_chalk59.default.bold(parent.name)}.`);
16673
+ spinner.succeed(`${import_chalk60.default.bold(child.name)} is now a subgroup of ${import_chalk60.default.bold(parent.name)}.`);
16440
16674
  } catch (e) {
16441
16675
  spinner.fail("Nest failed.");
16442
16676
  throw e;
@@ -16445,10 +16679,10 @@ async function runGroupAddGroup(childName, parentName, opts) {
16445
16679
  async function runGroupRemoveGroup(childName, parentName, opts) {
16446
16680
  const t = await resolveTransport(opts);
16447
16681
  const [child, parent] = [await groupByName(t, childName), await groupByName(t, parentName)];
16448
- const spinner = (0, import_ora28.default)(`Un-nesting ${child.name} from ${parent.name}...`).start();
16682
+ const spinner = (0, import_ora29.default)(`Un-nesting ${child.name} from ${parent.name}...`).start();
16449
16683
  try {
16450
16684
  await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups/${encodeURIComponent(child.id)}`, "DELETE");
16451
- spinner.succeed(`${import_chalk59.default.bold(child.name)} un-nested from ${import_chalk59.default.bold(parent.name)}.`);
16685
+ spinner.succeed(`${import_chalk60.default.bold(child.name)} un-nested from ${import_chalk60.default.bold(parent.name)}.`);
16452
16686
  } catch (e) {
16453
16687
  spinner.fail("Un-nest failed.");
16454
16688
  throw e;
@@ -16459,13 +16693,13 @@ async function runGroupUsers(opts) {
16459
16693
  const users = await listUsers(t);
16460
16694
  const observed = await t.call("/v1/admin/observed-identities").catch(() => ({ identities: [] }));
16461
16695
  if (opts.json) return void console.log(JSON.stringify({ users, observed: observed?.identities ?? [] }));
16462
- console.log(import_chalk59.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
16463
- for (const u of users) console.log(` ${label2(u)} ${import_chalk59.default.dim(u.abz_sub)}`);
16464
- if (!users.length) console.log(import_chalk59.default.dim(" no users yet"));
16696
+ console.log(import_chalk60.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
16697
+ for (const u of users) console.log(` ${label2(u)} ${import_chalk60.default.dim(u.abz_sub)}`);
16698
+ if (!users.length) console.log(import_chalk60.default.dim(" no users yet"));
16465
16699
  const fresh = (observed?.identities ?? []).filter((o) => !o.provisioned);
16466
16700
  if (fresh.length) {
16467
- console.log(import_chalk59.default.dim("Seen in traffic (not yet users):"));
16468
- for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk59.default.dim(o.source_label ?? "")}`);
16701
+ console.log(import_chalk60.default.dim("Seen in traffic (not yet users):"));
16702
+ for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk60.default.dim(o.source_label ?? "")}`);
16469
16703
  }
16470
16704
  }
16471
16705
 
@@ -16475,8 +16709,8 @@ init_iam();
16475
16709
  init_admins();
16476
16710
 
16477
16711
  // src/commands/preapprove.ts
16478
- var import_chalk60 = __toESM(require("chalk"));
16479
- var import_ora29 = __toESM(require("ora"));
16712
+ var import_chalk61 = __toESM(require("chalk"));
16713
+ var import_ora30 = __toESM(require("ora"));
16480
16714
  init_preapproval();
16481
16715
  async function runPreapprove(who, opts) {
16482
16716
  const tenant2 = await resolveProducerTenant(opts.tenant);
@@ -16484,14 +16718,14 @@ async function runPreapprove(who, opts) {
16484
16718
  const rules = await listPreapprovalRules(tenant2);
16485
16719
  if (opts.json) return void console.log(JSON.stringify(rules, null, 2));
16486
16720
  if (!rules.length) {
16487
- console.log(import_chalk60.default.dim(`No pre-approval rules in ${tenant2}. Anyone who signs in can access (unless access is restricted).`));
16488
- console.log(import_chalk60.default.dim(`Add one: apiblaze preapprove someone@acme.com`));
16721
+ console.log(import_chalk61.default.dim(`No pre-approval rules in ${tenant2}. Anyone who signs in can access (unless access is restricted).`));
16722
+ console.log(import_chalk61.default.dim(`Add one: apiblaze preapprove someone@acme.com`));
16489
16723
  return;
16490
16724
  }
16491
- console.log(import_chalk60.default.dim(`Pre-approved for ${import_chalk60.default.bold(tenant2)}:`));
16725
+ console.log(import_chalk61.default.dim(`Pre-approved for ${import_chalk61.default.bold(tenant2)}:`));
16492
16726
  for (const r of rules) {
16493
- const tag = r.kind === "domain" ? import_chalk60.default.cyan("@" + r.value + " (whole domain)") : r.value;
16494
- const grp = r.groups?.length ? import_chalk60.default.dim(` \u2192 groups: ${r.groups.join(", ")}`) : "";
16727
+ const tag = r.kind === "domain" ? import_chalk61.default.cyan("@" + r.value + " (whole domain)") : r.value;
16728
+ const grp = r.groups?.length ? import_chalk61.default.dim(` \u2192 groups: ${r.groups.join(", ")}`) : "";
16495
16729
  console.log(` ${tag}${grp}`);
16496
16730
  }
16497
16731
  return;
@@ -16500,19 +16734,19 @@ async function runPreapprove(who, opts) {
16500
16734
  throw new Error("Who? Pass an email or a domain: `apiblaze preapprove someone@acme.com` (or `apiblaze preapprove --list`).");
16501
16735
  }
16502
16736
  if (opts.remove) {
16503
- const spinner2 = (0, import_ora29.default)(`Removing ${who} from ${tenant2}\u2026`).start();
16737
+ const spinner2 = (0, import_ora30.default)(`Removing ${who} from ${tenant2}\u2026`).start();
16504
16738
  const { removed, value } = await removePreapprovalRule(tenant2, who);
16505
- if (removed) spinner2.succeed(`${import_chalk60.default.bold(value)} is no longer pre-approved for ${tenant2}.`);
16506
- else spinner2.warn(`No pre-approval rule for ${import_chalk60.default.bold(value)} in ${tenant2} \u2014 nothing to remove.`);
16739
+ if (removed) spinner2.succeed(`${import_chalk61.default.bold(value)} is no longer pre-approved for ${tenant2}.`);
16740
+ else spinner2.warn(`No pre-approval rule for ${import_chalk61.default.bold(value)} in ${tenant2} \u2014 nothing to remove.`);
16507
16741
  return;
16508
16742
  }
16509
- const spinner = (0, import_ora29.default)(`Pre-approving ${who} for ${tenant2}\u2026`).start();
16743
+ const spinner = (0, import_ora30.default)(`Pre-approving ${who} for ${tenant2}\u2026`).start();
16510
16744
  try {
16511
16745
  const { kind, value } = await addPreapprovalRule(tenant2, who, opts.group);
16512
16746
  const what = kind === "domain" ? `Anyone @${value}` : value;
16513
- spinner.succeed(`${import_chalk60.default.bold(what)} can now sign in to ${import_chalk60.default.bold(tenant2)}.`);
16514
- if (opts.group?.length) console.log(import_chalk60.default.dim(` They'll join group(s) ${opts.group.join(", ")} on first sign-in.`));
16515
- console.log(import_chalk60.default.dim(` See the full list: apiblaze preapprove --list`));
16747
+ spinner.succeed(`${import_chalk61.default.bold(what)} can now sign in to ${import_chalk61.default.bold(tenant2)}.`);
16748
+ if (opts.group?.length) console.log(import_chalk61.default.dim(` They'll join group(s) ${opts.group.join(", ")} on first sign-in.`));
16749
+ console.log(import_chalk61.default.dim(` See the full list: apiblaze preapprove --list`));
16516
16750
  } catch (err) {
16517
16751
  spinner.fail("Could not add the rule.");
16518
16752
  throw err;
@@ -16524,8 +16758,8 @@ init_apichat();
16524
16758
  init_llm();
16525
16759
 
16526
16760
  // src/commands/consumer.ts
16527
- var import_chalk61 = __toESM(require("chalk"));
16528
- var import_ora30 = __toESM(require("ora"));
16761
+ var import_chalk62 = __toESM(require("chalk"));
16762
+ var import_ora31 = __toESM(require("ora"));
16529
16763
  init_admin();
16530
16764
  init_resolve();
16531
16765
  init_caller();
@@ -16548,7 +16782,7 @@ async function consumerFetch(creds, suffix, init) {
16548
16782
  function requireConsumer2() {
16549
16783
  const c = loadConsumer();
16550
16784
  if (!c) {
16551
- console.error(import_chalk61.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
16785
+ console.error(import_chalk62.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
16552
16786
  process.exit(1);
16553
16787
  }
16554
16788
  return c;
@@ -16559,7 +16793,7 @@ async function runConsumerLogin(opts) {
16559
16793
  let clientId = opts.client;
16560
16794
  if (clientId) {
16561
16795
  if (!tenant2) {
16562
- console.error(import_chalk61.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
16796
+ console.error(import_chalk62.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
16563
16797
  process.exit(1);
16564
16798
  }
16565
16799
  } else {
@@ -16571,24 +16805,24 @@ async function runConsumerLogin(opts) {
16571
16805
  if (!picked) process.exit(1);
16572
16806
  tenant2 = picked;
16573
16807
  }
16574
- const s2 = (0, import_ora30.default)("Finding the login app...").start();
16808
+ const s2 = (0, import_ora31.default)("Finding the login app...").start();
16575
16809
  const clients = await admin({ method: "GET", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/app-clients`, summary: `List app clients for ${tenant2}` }).catch(() => []);
16576
16810
  s2.stop();
16577
16811
  const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
16578
16812
  const pick3 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
16579
16813
  if (!pick3) {
16580
- console.error(import_chalk61.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
16814
+ console.error(import_chalk62.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
16581
16815
  process.exit(1);
16582
16816
  }
16583
16817
  clientId = pick3.client_id ?? pick3.clientId;
16584
16818
  }
16585
- console.log(`${import_chalk61.default.cyan("\u2192")} Logging in to ${import_chalk61.default.bold(tenant2)} as a consumer...`);
16819
+ console.log(`${import_chalk62.default.cyan("\u2192")} Logging in to ${import_chalk62.default.bold(tenant2)} as a consumer...`);
16586
16820
  const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
16587
16821
  console.log(`
16588
- Open: ${import_chalk61.default.underline(verificationUri)}`);
16589
- console.log(` Code: ${import_chalk61.default.bold(userCode)}
16822
+ Open: ${import_chalk62.default.underline(verificationUri)}`);
16823
+ console.log(` Code: ${import_chalk62.default.bold(userCode)}
16590
16824
  `);
16591
- console.log(import_chalk61.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
16825
+ console.log(import_chalk62.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
16592
16826
  });
16593
16827
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
16594
16828
  const creds = {
@@ -16603,7 +16837,7 @@ async function runConsumerLogin(opts) {
16603
16837
  obtainedAt: Date.now()
16604
16838
  };
16605
16839
  saveConsumer(creds);
16606
- console.log(import_chalk61.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
16840
+ console.log(import_chalk62.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
16607
16841
  }
16608
16842
  async function runConsumerTokens(opts) {
16609
16843
  const creds = requireConsumer2();
@@ -16616,28 +16850,28 @@ async function runConsumerTokens(opts) {
16616
16850
  console.log(JSON.stringify({ tenant: fresh.tenant, access_token: fresh.accessToken, refresh_token: fresh.refreshToken, id_token: fresh.idToken, expires_at: new Date(fresh.expiresAt).toISOString() }, null, 2));
16617
16851
  return;
16618
16852
  }
16619
- console.log(`${import_chalk61.default.cyan("Consumer")} ${import_chalk61.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk61.default.bold(fresh.tenant)}
16853
+ console.log(`${import_chalk62.default.cyan("Consumer")} ${import_chalk62.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk62.default.bold(fresh.tenant)}
16620
16854
  `);
16621
- console.log(`${import_chalk61.default.bold("access_token")} ${import_chalk61.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
16855
+ console.log(`${import_chalk62.default.bold("access_token")} ${import_chalk62.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
16622
16856
  ${fresh.accessToken}
16623
16857
  `);
16624
- if (fresh.idToken) console.log(`${import_chalk61.default.bold("id_token")} ${import_chalk61.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
16858
+ if (fresh.idToken) console.log(`${import_chalk62.default.bold("id_token")} ${import_chalk62.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
16625
16859
  ${fresh.idToken}
16626
16860
  `);
16627
- if (fresh.refreshToken) console.log(`${import_chalk61.default.bold("refresh_token")}
16861
+ if (fresh.refreshToken) console.log(`${import_chalk62.default.bold("refresh_token")}
16628
16862
  ${fresh.refreshToken}
16629
16863
  `);
16630
- console.log(import_chalk61.default.dim("These are your own tokens \u2014 keep them secret."));
16864
+ console.log(import_chalk62.default.dim("These are your own tokens \u2014 keep them secret."));
16631
16865
  }
16632
16866
  async function runConsumerApikeys(opts) {
16633
16867
  const creds = requireConsumer2();
16634
16868
  const { default: inquirer3 } = await import("inquirer");
16635
- const spinner = (0, import_ora30.default)("Loading your API keys...").start();
16869
+ const spinner = (0, import_ora31.default)("Loading your API keys...").start();
16636
16870
  const list = await consumerFetch(creds, withPage("/apikeys", null));
16637
16871
  if (list.status >= 400) {
16638
16872
  spinner.stop();
16639
- console.error(import_chalk61.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
16640
- if (list.status === 401) console.error(import_chalk61.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
16873
+ console.error(import_chalk62.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
16874
+ if (list.status === 401) console.error(import_chalk62.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
16641
16875
  process.exit(1);
16642
16876
  }
16643
16877
  let walkCreds = list.creds;
@@ -16666,16 +16900,16 @@ async function runConsumerApikeys(opts) {
16666
16900
  if (opts.json) {
16667
16901
  console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
16668
16902
  } else if (!keys.length) {
16669
- console.log(import_chalk61.default.yellow("No API keys yet."));
16903
+ console.log(import_chalk62.default.yellow("No API keys yet."));
16670
16904
  } else {
16671
16905
  for (const k of keys) {
16672
16906
  const clear = revealMap[k.environment]?.key;
16673
- const shown = clear ? import_chalk61.default.green(clear) : import_chalk61.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
16674
- const exp = k.expires_at ? import_chalk61.default.dim(`exp ${k.expires_at}`) : import_chalk61.default.dim("no expiry");
16675
- console.log(` ${import_chalk61.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk61.default.dim(k.description ?? "")}`);
16907
+ const shown = clear ? import_chalk62.default.green(clear) : import_chalk62.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
16908
+ const exp = k.expires_at ? import_chalk62.default.dim(`exp ${k.expires_at}`) : import_chalk62.default.dim("no expiry");
16909
+ console.log(` ${import_chalk62.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk62.default.dim(k.description ?? "")}`);
16676
16910
  }
16677
16911
  if (Object.keys(revealMap).length === 0 && keys.some((k) => !k.expires_at)) {
16678
- console.log(import_chalk61.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
16912
+ console.log(import_chalk62.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
16679
16913
  }
16680
16914
  }
16681
16915
  if (opts.json) return;
@@ -16689,7 +16923,7 @@ async function runConsumerApikeys(opts) {
16689
16923
  const body = { environment: answers.environment };
16690
16924
  if (answers.description) body.description = answers.description;
16691
16925
  if (answers.expiresDays) body.expires_in_seconds = Number(answers.expiresDays) * 86400;
16692
- const s2 = (0, import_ora30.default)("Creating key...").start();
16926
+ const s2 = (0, import_ora31.default)("Creating key...").start();
16693
16927
  const created = await consumerFetch(list.creds, "/apikeys", { method: "POST", body: JSON.stringify(body) });
16694
16928
  if (created.status >= 400) {
16695
16929
  s2.fail(`Create failed (${created.status}): ${created.data?.error ?? ""}`);
@@ -16697,13 +16931,13 @@ async function runConsumerApikeys(opts) {
16697
16931
  }
16698
16932
  s2.succeed("Key created.");
16699
16933
  const key = created.data?.key ?? created.data?.fullKey;
16700
- if (key) console.log(` ${import_chalk61.default.green(key)} ${import_chalk61.default.dim("(shown once \u2014 store it now)")}`);
16701
- else console.log(import_chalk61.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
16934
+ if (key) console.log(` ${import_chalk62.default.green(key)} ${import_chalk62.default.dim("(shown once \u2014 store it now)")}`);
16935
+ else console.log(import_chalk62.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
16702
16936
  }
16703
16937
 
16704
16938
  // src/commands/sidecar.ts
16705
- var import_chalk62 = __toESM(require("chalk"));
16706
- var import_ora31 = __toESM(require("ora"));
16939
+ var import_chalk63 = __toESM(require("chalk"));
16940
+ var import_ora32 = __toESM(require("ora"));
16707
16941
  var fs18 = __toESM(require("fs"));
16708
16942
  var path14 = __toESM(require("path"));
16709
16943
  init_admin();
@@ -16745,18 +16979,18 @@ function upsertEnvLocal(root, token) {
16745
16979
  }
16746
16980
  function installSidecarPackage(root) {
16747
16981
  if (fs18.existsSync(path14.join(root, "node_modules", "apiblaze", "package.json"))) {
16748
- console.log(` ${import_chalk62.default.green("\u2713")} apiblaze package already installed`);
16982
+ console.log(` ${import_chalk63.default.green("\u2713")} apiblaze package already installed`);
16749
16983
  return;
16750
16984
  }
16751
16985
  const has = (f) => fs18.existsSync(path14.join(root, f));
16752
16986
  const pm = has("bun.lockb") || has("bun.lock") ? { cmd: "bun", add: "add" } : has("pnpm-lock.yaml") ? { cmd: "pnpm", add: "add" } : has("yarn.lock") ? { cmd: "yarn", add: "add" } : { cmd: "npm", add: "install" };
16753
- const spinner = (0, import_ora31.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
16987
+ const spinner = (0, import_ora32.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
16754
16988
  try {
16755
16989
  const { execSync } = require("child_process");
16756
16990
  execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
16757
16991
  spinner.succeed("Installed apiblaze (the sidecar runtime).");
16758
16992
  } catch {
16759
- spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk62.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk62.default.cyan("npm run dev")}.`);
16993
+ spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk63.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk63.default.cyan("npm run dev")}.`);
16760
16994
  }
16761
16995
  }
16762
16996
  function readEnvKey(root) {
@@ -16899,7 +17133,7 @@ async function runAnonymousInit(root, router, opts) {
16899
17133
  const { sidecarInitAnonymous: sidecarInitAnonymous2 } = await Promise.resolve().then(() => (init_api(), api_exports));
16900
17134
  const { saveAnonCred: saveAnonCred2, clearAnonCred: clearAnonCred2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
16901
17135
  if (opts.newSession) clearAnonCred2();
16902
- const spinner = (0, import_ora31.default)("Setting up a sidecar (no login needed)...").start();
17136
+ const spinner = (0, import_ora32.default)("Setting up a sidecar (no login needed)...").start();
16903
17137
  let out;
16904
17138
  try {
16905
17139
  out = await sidecarInitAnonymous2();
@@ -16911,29 +17145,29 @@ async function runAnonymousInit(root, router, opts) {
16911
17145
  if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
16912
17146
  const envState = upsertEnvLocal(root, out.token);
16913
17147
  ensureGitignored(root);
16914
- console.log(` ${import_chalk62.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
16915
- console.log(` ${import_chalk62.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
17148
+ console.log(` ${import_chalk63.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
17149
+ console.log(` ${import_chalk63.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
16916
17150
  installSidecarPackage(root);
16917
17151
  let inspectorPath = null;
16918
17152
  if (!opts.noInspector) {
16919
17153
  inspectorPath = generateInspector(root, router);
16920
- if (inspectorPath) console.log(` ${import_chalk62.default.green("\u2713")} inspector at ${inspectorPath}`);
17154
+ if (inspectorPath) console.log(` ${import_chalk63.default.green("\u2713")} inspector at ${inspectorPath}`);
16921
17155
  }
16922
17156
  console.log("");
16923
- console.log(import_chalk62.default.bold("Done (no account needed). What happens next:"));
16924
- console.log(` 1. ${import_chalk62.default.cyan("npm run dev")} and use your app.`);
17157
+ console.log(import_chalk63.default.bold("Done (no account needed). What happens next:"));
17158
+ console.log(` 1. ${import_chalk63.default.cyan("npm run dev")} and use your app.`);
16925
17159
  console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
16926
- console.log(` ${import_chalk62.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
17160
+ console.log(` ${import_chalk63.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
16927
17161
  console.log("");
16928
- console.log(import_chalk62.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
16929
- console.log(` ${import_chalk62.default.cyan("apiblaze login")} then ${import_chalk62.default.cyan("apiblaze claim")} ${import_chalk62.default.dim("(no code needed here)")}`);
16930
- console.log(import_chalk62.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
17162
+ console.log(import_chalk63.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
17163
+ console.log(` ${import_chalk63.default.cyan("apiblaze login")} then ${import_chalk63.default.cyan("apiblaze claim")} ${import_chalk63.default.dim("(no code needed here)")}`);
17164
+ console.log(import_chalk63.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
16931
17165
  }
16932
17166
  async function runSidecar(opts) {
16933
17167
  const root = path14.resolve(opts.dir ?? process.cwd());
16934
17168
  const detected2 = detectNextProject(root);
16935
17169
  if (!detected2.found) {
16936
- console.log(import_chalk62.default.yellow(`No Next.js project detected in ${root}.`));
17170
+ console.log(import_chalk63.default.yellow(`No Next.js project detected in ${root}.`));
16937
17171
  console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
16938
17172
  return;
16939
17173
  }
@@ -16944,10 +17178,10 @@ async function runSidecar(opts) {
16944
17178
  if (!loadCredentials()) {
16945
17179
  upsertEnvLocal(root, readEnvKey(root));
16946
17180
  ensureGitignored(root);
16947
- console.log(` ${import_chalk62.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
16948
- console.log(` ${import_chalk62.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
17181
+ console.log(` ${import_chalk63.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
17182
+ console.log(` ${import_chalk63.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
16949
17183
  installSidecarPackage(root);
16950
- console.log(import_chalk62.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
17184
+ console.log(import_chalk63.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
16951
17185
  return;
16952
17186
  }
16953
17187
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -16956,7 +17190,7 @@ async function runSidecar(opts) {
16956
17190
  const mustMint = !existingKey || opts.rotate || switchingTeam;
16957
17191
  let token = existingKey ?? "";
16958
17192
  if (mustMint) {
16959
- const spinner = (0, import_ora31.default)(existingKey ? "Re-establishing the sidecar (minting a fresh invoke key)..." : "Setting up the sidecar (tenant + non-expiring invoke key)...").start();
17193
+ const spinner = (0, import_ora32.default)(existingKey ? "Re-establishing the sidecar (minting a fresh invoke key)..." : "Setting up the sidecar (tenant + non-expiring invoke key)...").start();
16960
17194
  try {
16961
17195
  const out = await admin({
16962
17196
  method: "POST",
@@ -16970,39 +17204,39 @@ async function runSidecar(opts) {
16970
17204
  throw err;
16971
17205
  }
16972
17206
  } else {
16973
- console.log(import_chalk62.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
17207
+ console.log(import_chalk63.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
16974
17208
  }
16975
17209
  const envState = upsertEnvLocal(root, token);
16976
17210
  ensureGitignored(root);
16977
- console.log(` ${import_chalk62.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
17211
+ console.log(` ${import_chalk63.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
16978
17212
  const wireState = wireInstrumentation(root);
16979
- console.log(` ${import_chalk62.default.green("\u2713")} instrumentation.ts ${wireState}`);
17213
+ console.log(` ${import_chalk63.default.green("\u2713")} instrumentation.ts ${wireState}`);
16980
17214
  installSidecarPackage(root);
16981
17215
  let inspectorPath = null;
16982
17216
  if (!opts.noInspector) {
16983
17217
  inspectorPath = generateInspector(root, detected2.router);
16984
- if (inspectorPath) console.log(` ${import_chalk62.default.green("\u2713")} inspector at ${inspectorPath}`);
17218
+ if (inspectorPath) console.log(` ${import_chalk63.default.green("\u2713")} inspector at ${inspectorPath}`);
16985
17219
  }
16986
17220
  console.log("");
16987
- console.log(import_chalk62.default.bold("Done. What happens next:"));
16988
- console.log(` 1. ${import_chalk62.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
16989
- console.log(` 2. The origins your app calls appear as ${import_chalk62.default.bold("candidates")} \u2014 list them: ${import_chalk62.default.cyan("apiblaze sidecar")}`);
16990
- console.log(` 3. Approve the ones to route: ${import_chalk62.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
17221
+ console.log(import_chalk63.default.bold("Done. What happens next:"));
17222
+ console.log(` 1. ${import_chalk63.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
17223
+ console.log(` 2. The origins your app calls appear as ${import_chalk63.default.bold("candidates")} \u2014 list them: ${import_chalk63.default.cyan("apiblaze sidecar")}`);
17224
+ console.log(` 3. Approve the ones to route: ${import_chalk63.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
16991
17225
  console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
16992
- if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk62.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path14.dirname(inspectorPath)} before shipping)`);
16993
- if (switchingTeam) console.log(import_chalk62.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
17226
+ if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk63.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path14.dirname(inspectorPath)} before shipping)`);
17227
+ if (switchingTeam) console.log(import_chalk63.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
16994
17228
  console.log("");
16995
- console.log(import_chalk62.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
16996
- console.log(import_chalk62.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
16997
- console.log(import_chalk62.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
17229
+ console.log(import_chalk63.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
17230
+ console.log(import_chalk63.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
17231
+ console.log(import_chalk63.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
16998
17232
  console.log("");
16999
- console.log(import_chalk62.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
17000
- console.log(import_chalk62.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
17233
+ console.log(import_chalk63.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
17234
+ console.log(import_chalk63.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
17001
17235
  }
17002
17236
 
17003
17237
  // src/commands/origins.ts
17004
- var import_chalk63 = __toESM(require("chalk"));
17005
- var import_ora32 = __toESM(require("ora"));
17238
+ var import_chalk64 = __toESM(require("chalk"));
17239
+ var import_ora33 = __toESM(require("ora"));
17006
17240
  init_admin();
17007
17241
  init_resolve();
17008
17242
  init_auth();
@@ -17012,7 +17246,7 @@ async function runOriginsList(opts) {
17012
17246
  if (!loadCredentials()) {
17013
17247
  const cred = loadAnonCred();
17014
17248
  if (!cred) {
17015
- console.log(import_chalk63.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
17249
+ console.log(import_chalk64.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
17016
17250
  return;
17017
17251
  }
17018
17252
  out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
@@ -17030,30 +17264,30 @@ async function runOriginsList(opts) {
17030
17264
  }
17031
17265
  const routed = out.routed ?? [];
17032
17266
  const candidates = out.candidates ?? [];
17033
- console.log(import_chalk63.default.bold(`
17267
+ console.log(import_chalk64.default.bold(`
17034
17268
  Routed through APIblaze (${routed.length})`));
17035
- if (!routed.length) console.log(import_chalk63.default.dim(" none yet"));
17036
- for (const r of routed) console.log(` ${import_chalk63.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk63.default.dim(`\u2192 ${r.project_id}`)}`);
17037
- console.log(import_chalk63.default.bold(`
17269
+ if (!routed.length) console.log(import_chalk64.default.dim(" none yet"));
17270
+ for (const r of routed) console.log(` ${import_chalk64.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk64.default.dim(`\u2192 ${r.project_id}`)}`);
17271
+ console.log(import_chalk64.default.bold(`
17038
17272
  Candidates \u2014 going direct, not yet approved (${candidates.length})`));
17039
- if (!candidates.length) console.log(import_chalk63.default.dim(" none \u2014 run your app to discover the origins it calls"));
17273
+ if (!candidates.length) console.log(import_chalk64.default.dim(" none \u2014 run your app to discover the origins it calls"));
17040
17274
  for (const c of candidates) {
17041
- console.log(` ${import_chalk63.default.yellow("\u25CB")} ${c.origin} ${import_chalk63.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
17275
+ console.log(` ${import_chalk64.default.yellow("\u25CB")} ${c.origin} ${import_chalk64.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
17042
17276
  }
17043
17277
  if (candidates.length) {
17044
- console.log(import_chalk63.default.dim(`
17278
+ console.log(import_chalk64.default.dim(`
17045
17279
  Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
17046
- console.log(import_chalk63.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
17280
+ console.log(import_chalk64.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
17047
17281
  }
17048
17282
  }
17049
17283
  async function runOriginsApprove(origin, opts) {
17050
17284
  if (!loadCredentials()) {
17051
17285
  const cred = loadAnonCred();
17052
17286
  if (!cred) {
17053
- console.error(import_chalk63.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
17287
+ console.error(import_chalk64.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
17054
17288
  process.exit(1);
17055
17289
  }
17056
- const spinner2 = (0, import_ora32.default)(`Approving ${origin} (anonymous)...`).start();
17290
+ const spinner2 = (0, import_ora33.default)(`Approving ${origin} (anonymous)...`).start();
17057
17291
  try {
17058
17292
  const out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/approve`, { method: "POST", body: JSON.stringify({ origin }) });
17059
17293
  spinner2.succeed(`Approved ${origin} \u2192 proxy ${out.project_id}. Routing within ~5 min.`);
@@ -17064,7 +17298,7 @@ async function runOriginsApprove(origin, opts) {
17064
17298
  return;
17065
17299
  }
17066
17300
  const { teamId } = await resolveTeam(opts.team);
17067
- const spinner = (0, import_ora32.default)(`Approving ${origin}...`).start();
17301
+ const spinner = (0, import_ora33.default)(`Approving ${origin}...`).start();
17068
17302
  try {
17069
17303
  const out = await admin({
17070
17304
  method: "POST",
@@ -17081,7 +17315,7 @@ async function runOriginsApprove(origin, opts) {
17081
17315
  }
17082
17316
  async function runOriginsDeny(origin, opts) {
17083
17317
  const { teamId } = await resolveTeam(opts.team);
17084
- const spinner = (0, import_ora32.default)(`Dismissing ${origin}...`).start();
17318
+ const spinner = (0, import_ora33.default)(`Dismissing ${origin}...`).start();
17085
17319
  try {
17086
17320
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/dismiss`, body: { origin }, summary: `Dismiss sidecar origin ${origin}` });
17087
17321
  spinner.succeed(`Dismissed ${origin}. It won't be suggested again.`);
@@ -17092,7 +17326,7 @@ async function runOriginsDeny(origin, opts) {
17092
17326
  }
17093
17327
  async function runOriginsRemove(origin, opts) {
17094
17328
  const { teamId } = await resolveTeam(opts.team);
17095
- const spinner = (0, import_ora32.default)(`Removing the proxy for ${origin}...`).start();
17329
+ const spinner = (0, import_ora33.default)(`Removing the proxy for ${origin}...`).start();
17096
17330
  try {
17097
17331
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/remove`, body: { origin }, summary: `Un-route sidecar origin ${origin}` });
17098
17332
  spinner.succeed(`Removed ${origin}. Your app will stop routing it (goes direct) within ~5 min.`);
@@ -17103,7 +17337,7 @@ async function runOriginsRemove(origin, opts) {
17103
17337
  }
17104
17338
 
17105
17339
  // src/commands/op.ts
17106
- var import_chalk71 = __toESM(require("chalk"));
17340
+ var import_chalk72 = __toESM(require("chalk"));
17107
17341
  init_auth();
17108
17342
 
17109
17343
  // src/lib/op-call.ts
@@ -17132,7 +17366,7 @@ async function opCall(call3) {
17132
17366
  }
17133
17367
 
17134
17368
  // src/commands/op-money.ts
17135
- var import_chalk64 = __toESM(require("chalk"));
17369
+ var import_chalk65 = __toESM(require("chalk"));
17136
17370
  init_admin();
17137
17371
  init_types();
17138
17372
  var money2 = (cents2) => typeof cents2 === "number" ? `$${usdStr(cents2)}` : "\u2014";
@@ -17154,60 +17388,60 @@ async function opWalletList(opts) {
17154
17388
  const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list wallets" });
17155
17389
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
17156
17390
  const accounts = data?.accounts ?? [];
17157
- if (accounts.length === 0) return void console.log(import_chalk64.default.dim("No wallets."));
17158
- console.log(import_chalk64.default.dim(`
17391
+ if (accounts.length === 0) return void console.log(import_chalk65.default.dim("No wallets."));
17392
+ console.log(import_chalk65.default.dim(`
17159
17393
  ${"available".padStart(10)} ${"in use".padStart(9)} ${"grace".padStart(8)} ${"status".padEnd(11)} ${"gen".padStart(3)} wallet`));
17160
17394
  for (const a of accounts) {
17161
- const flags = [a.frozen ? import_chalk64.default.red("FROZEN") : "", a.closed ? import_chalk64.default.red("closed") : "", a.terms && a.terms !== "prepaid" ? import_chalk64.default.yellow(a.terms) : ""].filter(Boolean).join(" ");
17162
- const who = a.owner_email ? import_chalk64.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk64.default.dim(" \u2014 anon") : a.name ? import_chalk64.default.dim(` \u2014 ${a.name}`) : "";
17395
+ const flags = [a.frozen ? import_chalk65.default.red("FROZEN") : "", a.closed ? import_chalk65.default.red("closed") : "", a.terms && a.terms !== "prepaid" ? import_chalk65.default.yellow(a.terms) : ""].filter(Boolean).join(" ");
17396
+ const who = a.owner_email ? import_chalk65.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk65.default.dim(" \u2014 anon") : a.name ? import_chalk65.default.dim(` \u2014 ${a.name}`) : "";
17163
17397
  console.log(
17164
- ` ${import_chalk64.default.bold(money2(a.available_cents ?? a.balance_cents).padStart(10))} ${money2(a.in_use_cents ?? 0).padStart(9)} ${money2(a.grace_used_cents ?? 0).padStart(8)} ${String(a.status ?? "").padEnd(11)} ${String(a.generation ?? "").padStart(3)} ${a.walletId}${who}${flags ? " " + flags : ""}`
17398
+ ` ${import_chalk65.default.bold(money2(a.available_cents ?? a.balance_cents).padStart(10))} ${money2(a.in_use_cents ?? 0).padStart(9)} ${money2(a.grace_used_cents ?? 0).padStart(8)} ${String(a.status ?? "").padEnd(11)} ${String(a.generation ?? "").padStart(3)} ${a.walletId}${who}${flags ? " " + flags : ""}`
17165
17399
  );
17166
17400
  }
17167
- if (data?.truncated) console.log(import_chalk64.default.yellow(`
17401
+ if (data?.truncated) console.log(import_chalk65.default.yellow(`
17168
17402
  List truncated \u2014 inspect one wallet with: apiblaze op wallet inspect <wallet>`));
17169
17403
  console.log("");
17170
17404
  }
17171
17405
  async function opWalletInspect(ref, opts) {
17172
- if (!ref) return void console.log(import_chalk64.default.red("Which wallet?") + import_chalk64.default.cyan(" apiblaze op wallet inspect <wallet id | team id>"));
17406
+ if (!ref) return void console.log(import_chalk65.default.red("Which wallet?") + import_chalk65.default.cyan(" apiblaze op wallet inspect <wallet id | team id>"));
17173
17407
  const ba = await resolveWalletId(ref);
17174
17408
  const w = await opCall({ method: "GET", path: `/operator/wallets/${encodeURIComponent(ba)}`, summary: `inspect wallet ${ba}` });
17175
17409
  if (opts.json) return void console.log(JSON.stringify(w, null, 2));
17176
17410
  const st = w?.state ?? {};
17177
- console.log(import_chalk64.default.bold(`
17178
- Wallet ${w?.billing_account_id ?? ba}`) + (ref !== ba ? import_chalk64.default.dim(` (team ${ref})`) : ""));
17179
- console.log(` ${"status".padEnd(16)} ${w?.status ?? "?"}${w?.frozen ? import_chalk64.default.red(" FROZEN") : ""}${w?.closed ? import_chalk64.default.red(" closed") : ""}${w?.terms && w.terms !== "prepaid" ? import_chalk64.default.yellow(` ${w.terms}`) : ""}`);
17180
- console.log(` ${"available".padEnd(16)} ${import_chalk64.default.bold(money2(w?.available_cents ?? w?.balance_cents ?? w?.balance))}`);
17181
- console.log(` ${"in use".padEnd(16)} ${money2(w?.in_use_cents)}${import_chalk64.default.dim(" \u03A3 floats + budgets + reserves out at the shards")}`);
17411
+ console.log(import_chalk65.default.bold(`
17412
+ Wallet ${w?.billing_account_id ?? ba}`) + (ref !== ba ? import_chalk65.default.dim(` (team ${ref})`) : ""));
17413
+ console.log(` ${"status".padEnd(16)} ${w?.status ?? "?"}${w?.frozen ? import_chalk65.default.red(" FROZEN") : ""}${w?.closed ? import_chalk65.default.red(" closed") : ""}${w?.terms && w.terms !== "prepaid" ? import_chalk65.default.yellow(` ${w.terms}`) : ""}`);
17414
+ console.log(` ${"available".padEnd(16)} ${import_chalk65.default.bold(money2(w?.available_cents ?? w?.balance_cents ?? w?.balance))}`);
17415
+ console.log(` ${"in use".padEnd(16)} ${money2(w?.in_use_cents)}${import_chalk65.default.dim(" \u03A3 floats + budgets + reserves out at the shards")}`);
17182
17416
  console.log(` ${"grace".padEnd(16)} ${money2(w?.grace_used_cents)} of ${money2(w?.grace_limit_cents)}`);
17183
17417
  console.log(` ${"epoch / gen".padEnd(16)} ${st.epoch ?? "?"} / ${st.generation ?? w?.generation ?? "?"}`);
17184
17418
  const unsent = unsentLedgerEntries(st);
17185
17419
  const lastSend = lastLedgerSendAtMs(st);
17186
- console.log(` ${"unsent ledger".padEnd(16)} ${unsent ?? "\u2014"} entries${import_chalk64.default.dim(" made by the wallet, not yet sent to the ledger")}`);
17187
- console.log(` ${"last ledger send".padEnd(16)} ${lastSend ? new Date(lastSend).toISOString() : import_chalk64.default.dim("never")}`);
17420
+ console.log(` ${"unsent ledger".padEnd(16)} ${unsent ?? "\u2014"} entries${import_chalk65.default.dim(" made by the wallet, not yet sent to the ledger")}`);
17421
+ console.log(` ${"last ledger send".padEnd(16)} ${lastSend ? new Date(lastSend).toISOString() : import_chalk65.default.dim("never")}`);
17188
17422
  if (st.counters && typeof st.counters === "object") {
17189
17423
  const c = Object.entries(st.counters).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
17190
- if (c) console.log(import_chalk64.default.dim(` counters ${c}`));
17424
+ if (c) console.log(import_chalk65.default.dim(` counters ${c}`));
17191
17425
  }
17192
17426
  const shards = st.shards ?? [];
17193
17427
  if (shards.length) {
17194
- console.log(import_chalk64.default.bold(`
17428
+ console.log(import_chalk65.default.bold(`
17195
17429
  Shards (${shards.length})`));
17196
- console.log(import_chalk64.default.dim(` ${"shard".padEnd(14)} ${"team".padEnd(26)} ${"float".padStart(9)} ${"budget".padStart(9)} ${"acq/s".padStart(6)} ${"adm/s".padStart(6)} expires`));
17430
+ console.log(import_chalk65.default.dim(` ${"shard".padEnd(14)} ${"team".padEnd(26)} ${"float".padStart(9)} ${"budget".padStart(9)} ${"acq/s".padStart(6)} ${"adm/s".padStart(6)} expires`));
17197
17431
  for (const s of shards) {
17198
17432
  const exp = s.expiresAtMs ? `${Math.max(0, Math.round((s.expiresAtMs - Date.now()) / 1e3))}s` : "\u2014";
17199
17433
  console.log(
17200
- ` ${String(s.shardId ?? "").slice(0, 14).padEnd(14)} ${String(s.teamId ?? "").slice(0, 26).padEnd(26)} ${String(s.floatUnits ?? 0).padStart(9)} ${String(s.budgetUnits ?? 0).padStart(9)} ${String(s.acquiresPerS ?? 0).padStart(6)} ${String(s.admittedPerS ?? 0).padStart(6)} ${exp}${s.degraded ? import_chalk64.default.red(" degraded") : ""}`
17434
+ ` ${String(s.shardId ?? "").slice(0, 14).padEnd(14)} ${String(s.teamId ?? "").slice(0, 26).padEnd(26)} ${String(s.floatUnits ?? 0).padStart(9)} ${String(s.budgetUnits ?? 0).padStart(9)} ${String(s.acquiresPerS ?? 0).padStart(6)} ${String(s.admittedPerS ?? 0).padStart(6)} ${exp}${s.degraded ? import_chalk65.default.red(" degraded") : ""}`
17201
17435
  );
17202
17436
  }
17203
- console.log(import_chalk64.default.dim(" float/budget in ledger units (10,000 per cent)"));
17437
+ console.log(import_chalk65.default.dim(" float/budget in ledger units (10,000 per cent)"));
17204
17438
  } else {
17205
- console.log(import_chalk64.default.dim("\n No live shards (no traffic in the last window)."));
17439
+ console.log(import_chalk65.default.dim("\n No live shards (no traffic in the last window)."));
17206
17440
  }
17207
17441
  const teams = w?.teams ?? [];
17208
- if (teams.length) console.log(import_chalk64.default.dim(`
17442
+ if (teams.length) console.log(import_chalk65.default.dim(`
17209
17443
  Teams on this wallet: ${teams.map((t) => typeof t === "string" ? t : t.team_id ?? t.teamId ?? JSON.stringify(t)).join(", ")}`));
17210
- console.log(import_chalk64.default.dim(`
17444
+ console.log(import_chalk65.default.dim(`
17211
17445
  Act on it (dashboard only): ${walletPage(ba)}
17212
17446
  `));
17213
17447
  }
@@ -17236,11 +17470,11 @@ function opWalletMutation(action2, ref, opts) {
17236
17470
  const target2 = ref ?? "<wallet>";
17237
17471
  const url = ref && !isTeamId(ref) ? walletPage(ref) : `${DASHBOARD_BASE10}/operator/wallets`;
17238
17472
  if (opts.json) return void console.log(JSON.stringify({ action: action2, wallet: ref ?? null, dashboard_only: true, url, requires: need ?? "a reason" }));
17239
- console.log(import_chalk64.default.yellow(`
17473
+ console.log(import_chalk65.default.yellow(`
17240
17474
  \`op wallet ${action2}\` is dashboard-only \u2014 it writes an operator_audit row with YOUR reason before touching the root.`));
17241
- console.log(` ${import_chalk64.default.cyan(url)}`);
17242
- console.log(import_chalk64.default.dim(` ${target2}: needs ${need ?? "a reason (required)"}`));
17243
- if (ref && isTeamId(ref)) console.log(import_chalk64.default.dim(` (that is a team id \u2014 \`apiblaze op wallet inspect ${ref}\` prints its wallet id and page)`));
17475
+ console.log(` ${import_chalk65.default.cyan(url)}`);
17476
+ console.log(import_chalk65.default.dim(` ${target2}: needs ${need ?? "a reason (required)"}`));
17477
+ if (ref && isTeamId(ref)) console.log(import_chalk65.default.dim(` (that is a team id \u2014 \`apiblaze op wallet inspect ${ref}\` prints its wallet id and page)`));
17244
17478
  console.log("");
17245
17479
  }
17246
17480
  async function opMoneyExposure(opts) {
@@ -17248,24 +17482,24 @@ async function opMoneyExposure(opts) {
17248
17482
  const data = await opCall({ method: "GET", path: `/operator/exposure${qs}`, summary: "money exposure" });
17249
17483
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
17250
17484
  const m = data?.money;
17251
- console.log(import_chalk64.default.bold("\n Exposure") + import_chalk64.default.dim(` source: ${data?.source ?? "?"}${data?.source === "ae" ? " (Analytics Engine fallback \u2014 approximate; the root did not answer)" : " (the root \u2014 exact)"}`));
17252
- if (data?.money_error) console.log(import_chalk64.default.yellow(` root error: ${data.money_error}`));
17485
+ console.log(import_chalk65.default.bold("\n Exposure") + import_chalk65.default.dim(` source: ${data?.source ?? "?"}${data?.source === "ae" ? " (Analytics Engine fallback \u2014 approximate; the root did not answer)" : " (the root \u2014 exact)"}`));
17486
+ if (data?.money_error) console.log(import_chalk65.default.yellow(` root error: ${data.money_error}`));
17253
17487
  if (m) {
17254
- console.log(` ${"in use".padEnd(14)} ${import_chalk64.default.bold(money2(m.total_in_use_cents))}${import_chalk64.default.dim(" customer money out at the shards, pre-paid (\u2264 0.15 \xD7 unallocated)")}`);
17255
- console.log(` ${"grace used".padEnd(14)} ${money2(m.total_grace_used_cents)}${import_chalk64.default.dim(" platform loss bound: \u03A3 grace + chargebacks")}`);
17488
+ console.log(` ${"in use".padEnd(14)} ${import_chalk65.default.bold(money2(m.total_in_use_cents))}${import_chalk65.default.dim(" customer money out at the shards, pre-paid (\u2264 0.15 \xD7 unallocated)")}`);
17489
+ console.log(` ${"grace used".padEnd(14)} ${money2(m.total_grace_used_cents)}${import_chalk65.default.dim(" platform loss bound: \u03A3 grace + chargebacks")}`);
17256
17490
  const wallets = m.wallets ?? [];
17257
17491
  if (wallets.length) {
17258
- console.log(import_chalk64.default.dim(`
17492
+ console.log(import_chalk65.default.dim(`
17259
17493
  ${"in use".padStart(10)} ${"grace".padStart(8)} wallet`));
17260
17494
  for (const w of wallets.slice(0, 40)) {
17261
- console.log(` ${money2(w.in_use_cents).padStart(10)} ${money2(w.grace_used_cents ?? (typeof w.grace_used_units === "number" ? w.grace_used_units / 1e4 : void 0)).padStart(8)} ${w.billing_account_id ?? w.walletId}${w.frozen ? import_chalk64.default.red(" FROZEN") : ""}`);
17495
+ console.log(` ${money2(w.in_use_cents).padStart(10)} ${money2(w.grace_used_cents ?? (typeof w.grace_used_units === "number" ? w.grace_used_units / 1e4 : void 0)).padStart(8)} ${w.billing_account_id ?? w.walletId}${w.frozen ? import_chalk65.default.red(" FROZEN") : ""}`);
17262
17496
  }
17263
- if (wallets.length > 40) console.log(import_chalk64.default.dim(` \u2026 ${wallets.length - 40} more (--json)`));
17497
+ if (wallets.length > 40) console.log(import_chalk65.default.dim(` \u2026 ${wallets.length - 40} more (--json)`));
17264
17498
  }
17265
17499
  }
17266
17500
  const ae = data?.ae;
17267
17501
  if (ae && typeof ae === "object") {
17268
- console.log(import_chalk64.default.bold("\n Analytics Engine view") + import_chalk64.default.dim(" admission by gate source, last window"));
17502
+ console.log(import_chalk65.default.bold("\n Analytics Engine view") + import_chalk65.default.dim(" admission by gate source, last window"));
17269
17503
  for (const [k, v] of Object.entries(ae)) console.log(` ${k.padEnd(18)} ${typeof v === "object" ? JSON.stringify(v) : String(v)}`);
17270
17504
  }
17271
17505
  console.log("");
@@ -17279,24 +17513,24 @@ async function opIncidentStatus(opts) {
17279
17513
  const data = await opCall({ method: "GET", path: "/operator/incident/degraded-mode", summary: "degraded-mode switch" });
17280
17514
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
17281
17515
  const mode = String(data?.mode ?? "allow");
17282
- const colour = mode === "allow" ? import_chalk64.default.green : mode === "deny" ? import_chalk64.default.red : import_chalk64.default.yellow;
17283
- console.log(import_chalk64.default.bold("\n Degraded mode: ") + colour(mode) + import_chalk64.default.dim(` \u2014 ${MODE_WORDS[mode] ?? ""}`));
17284
- if (data?.reason) console.log(import_chalk64.default.dim(` reason: ${data.reason}`));
17285
- if (data?.actor || data?.at) console.log(import_chalk64.default.dim(` set by ${data?.actor ?? "?"}${data?.at ? ` at ${data.at}` : ""}`));
17286
- console.log(import_chalk64.default.dim(`
17516
+ const colour = mode === "allow" ? import_chalk65.default.green : mode === "deny" ? import_chalk65.default.red : import_chalk65.default.yellow;
17517
+ console.log(import_chalk65.default.bold("\n Degraded mode: ") + colour(mode) + import_chalk65.default.dim(` \u2014 ${MODE_WORDS[mode] ?? ""}`));
17518
+ if (data?.reason) console.log(import_chalk65.default.dim(` reason: ${data.reason}`));
17519
+ if (data?.actor || data?.at) console.log(import_chalk65.default.dim(` set by ${data?.actor ?? "?"}${data?.at ? ` at ${data.at}` : ""}`));
17520
+ console.log(import_chalk65.default.dim(`
17287
17521
  Change it (dashboard only, reason required): ${incidentPage()}
17288
17522
  `));
17289
17523
  }
17290
17524
  function opIncidentMutation(mode, opts) {
17291
17525
  if (opts.json) return void console.log(JSON.stringify({ action: `incident ${mode}`, dashboard_only: true, url: incidentPage(), requires: "a reason (required); the switch is written to operator_audit, then KV" }));
17292
- console.log(import_chalk64.default.yellow(`
17526
+ console.log(import_chalk65.default.yellow(`
17293
17527
  \`op incident ${mode}\` is dashboard-only \u2014 ${MODE_WORDS[mode] ?? mode}.`));
17294
- console.log(` ${import_chalk64.default.cyan(incidentPage())}`);
17295
- console.log(import_chalk64.default.dim(" Needs a reason (required); it is written to operator_audit before the switch flips. Check with: apiblaze op incident status\n"));
17528
+ console.log(` ${import_chalk65.default.cyan(incidentPage())}`);
17529
+ console.log(import_chalk65.default.dim(" Needs a reason (required); it is written to operator_audit before the switch flips. Check with: apiblaze op incident status\n"));
17296
17530
  }
17297
17531
 
17298
17532
  // src/commands/op-ceiling.ts
17299
- var import_chalk65 = __toESM(require("chalk"));
17533
+ var import_chalk66 = __toESM(require("chalk"));
17300
17534
  init_types();
17301
17535
  var STATUSES = ["pending", "decided", "all"];
17302
17536
  var rpsStr = (n) => typeof n === "number" && Number.isFinite(n) ? n.toLocaleString("en-US") : "\u2014";
@@ -17310,7 +17544,7 @@ function ageStr(iso, now = Date.now()) {
17310
17544
  return `${Math.floor(s / 86400)}d`;
17311
17545
  }
17312
17546
  var trunc = (s, n) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
17313
- var STATUS_COLOUR = { pending: import_chalk65.default.yellow, approved: import_chalk65.default.green, denied: import_chalk65.default.red, expired: import_chalk65.default.dim };
17547
+ var STATUS_COLOUR = { pending: import_chalk66.default.yellow, approved: import_chalk66.default.green, denied: import_chalk66.default.red, expired: import_chalk66.default.dim };
17314
17548
  function printDecideError(err, id, opts) {
17315
17549
  if (!(err instanceof ApiError) || ![400, 404, 409].includes(err.status)) return false;
17316
17550
  const body = err.body ?? {};
@@ -17323,12 +17557,12 @@ function printDecideError(err, id, opts) {
17323
17557
  if (err.status === 409) {
17324
17558
  const d = body.request;
17325
17559
  const by = d?.decided_by ? ` by ${d.decided_by}${d.decided_at ? ` at ${d.decided_at}` : ""}` : "";
17326
- console.log(import_chalk65.default.red(` Ceiling request ${id} was not changed: ${why}${by}.`));
17327
- console.log(import_chalk65.default.dim(" See the decision: apiblaze op ceiling list --status decided"));
17560
+ console.log(import_chalk66.default.red(` Ceiling request ${id} was not changed: ${why}${by}.`));
17561
+ console.log(import_chalk66.default.dim(" See the decision: apiblaze op ceiling list --status decided"));
17328
17562
  } else if (err.status === 404) {
17329
- console.log(import_chalk65.default.red(` Not found: ${why.replace(/^Not found:\s*/i, "")}.`) + import_chalk65.default.dim(" (ids: apiblaze op ceiling list)"));
17563
+ console.log(import_chalk66.default.red(` Not found: ${why.replace(/^Not found:\s*/i, "")}.`) + import_chalk66.default.dim(" (ids: apiblaze op ceiling list)"));
17330
17564
  } else {
17331
- console.log(import_chalk65.default.red(` Ceiling request ${id} not decided: ${why}.`));
17565
+ console.log(import_chalk66.default.red(` Ceiling request ${id} not decided: ${why}.`));
17332
17566
  }
17333
17567
  return true;
17334
17568
  }
@@ -17336,31 +17570,31 @@ async function opCeilingList(opts) {
17336
17570
  const status2 = String(opts.status ?? "pending").trim().toLowerCase();
17337
17571
  if (!STATUSES.includes(status2)) {
17338
17572
  process.exitCode = 1;
17339
- return void console.log(import_chalk65.default.red(`--status must be one of ${STATUSES.join(" | ")}.`));
17573
+ return void console.log(import_chalk66.default.red(`--status must be one of ${STATUSES.join(" | ")}.`));
17340
17574
  }
17341
17575
  const data = await opCall(
17342
17576
  { method: "GET", path: `/operator/ceiling-requests?status=${status2}`, summary: `${status2} ceiling requests` }
17343
17577
  );
17344
17578
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
17345
17579
  const rows = data?.requests ?? [];
17346
- console.log(import_chalk65.default.bold("\n Maximum-rate requests") + import_chalk65.default.dim(` ${status2} \xB7 all consumers together, per project`));
17347
- if (!rows.length) return void console.log(import_chalk65.default.dim(` No ${status2 === "all" ? "" : `${status2} `}requests.
17580
+ console.log(import_chalk66.default.bold("\n Maximum-rate requests") + import_chalk66.default.dim(` ${status2} \xB7 all consumers together, per project`));
17581
+ if (!rows.length) return void console.log(import_chalk66.default.dim(` No ${status2 === "all" ? "" : `${status2} `}requests.
17348
17582
  `));
17349
- console.log(import_chalk65.default.dim(` ${"id".padEnd(10)} ${"project/version".padEnd(26)} ${"team".padEnd(16)} ${"current \u2192 requested req/s".padEnd(25)} ${"age".padStart(4)} ${"requested by".padEnd(24)} ${"status".padEnd(8)} use case`));
17583
+ console.log(import_chalk66.default.dim(` ${"id".padEnd(10)} ${"project/version".padEnd(26)} ${"team".padEnd(16)} ${"current \u2192 requested req/s".padEnd(25)} ${"age".padStart(4)} ${"requested by".padEnd(24)} ${"status".padEnd(8)} use case`));
17350
17584
  for (const r of rows) {
17351
17585
  const rate = `${rpsStr(r.current_ceiling_rps)} \u2192 ${rpsStr(r.requested_rps)}`;
17352
- const granted = r.status === "approved" && typeof r.granted_rps === "number" && r.granted_rps !== r.requested_rps ? import_chalk65.default.dim(` (granted ${rpsStr(r.granted_rps)})`) : "";
17586
+ const granted = r.status === "approved" && typeof r.granted_rps === "number" && r.granted_rps !== r.requested_rps ? import_chalk66.default.dim(` (granted ${rpsStr(r.granted_rps)})`) : "";
17353
17587
  const colour = STATUS_COLOUR[r.status] ?? ((s) => s);
17354
17588
  console.log(
17355
- ` ${trunc(String(r.id), 10).padEnd(10)} ${trunc(`${r.project_id}/${r.api_version}`, 26).padEnd(26)} ${trunc(r.team_id ?? "\u2014", 16).padEnd(16)} ${rate.padEnd(25)} ${ageStr(r.created_at).padStart(4)} ${trunc(r.requested_by ?? "\u2014", 24).padEnd(24)} ${colour(r.status.padEnd(8))} ${import_chalk65.default.dim(trunc((r.use_case ?? "").replace(/\s+/g, " "), 48))}${granted}`
17589
+ ` ${trunc(String(r.id), 10).padEnd(10)} ${trunc(`${r.project_id}/${r.api_version}`, 26).padEnd(26)} ${trunc(r.team_id ?? "\u2014", 16).padEnd(16)} ${rate.padEnd(25)} ${ageStr(r.created_at).padStart(4)} ${trunc(r.requested_by ?? "\u2014", 24).padEnd(24)} ${colour(r.status.padEnd(8))} ${import_chalk66.default.dim(trunc((r.use_case ?? "").replace(/\s+/g, " "), 48))}${granted}`
17356
17590
  );
17357
17591
  if (r.status !== "pending" && (r.decided_by || r.decision_note)) {
17358
- console.log(import_chalk65.default.dim(` ${"".padEnd(10)} ${r.decided_by ?? "?"}${r.decided_at ? ` \xB7 ${ageStr(r.decided_at)} ago` : ""}${r.decision_note ? ` \xB7 ${trunc(r.decision_note, 80)}` : ""}`));
17592
+ console.log(import_chalk66.default.dim(` ${"".padEnd(10)} ${r.decided_by ?? "?"}${r.decided_at ? ` \xB7 ${ageStr(r.decided_at)} ago` : ""}${r.decision_note ? ` \xB7 ${trunc(r.decision_note, 80)}` : ""}`));
17359
17593
  }
17360
17594
  }
17361
17595
  if (status2 === "pending") {
17362
17596
  const presets = (data?.presets_rps ?? []).map(rpsStr).join(" / ");
17363
- console.log(import_chalk65.default.dim(`
17597
+ console.log(import_chalk66.default.dim(`
17364
17598
  Decide: apiblaze op ceiling approve <id> [--rps N${presets ? ` e.g. ${presets}` : ""}] [--note "\u2026"] \xB7 apiblaze op ceiling deny <id> --note "why"`));
17365
17599
  }
17366
17600
  console.log("");
@@ -17368,23 +17602,23 @@ async function opCeilingList(opts) {
17368
17602
  async function opCeilingDecide(decision, id, opts) {
17369
17603
  if (!id) {
17370
17604
  process.exitCode = 1;
17371
- return void console.log(import_chalk65.default.red("Which request?") + import_chalk65.default.cyan(` apiblaze op ceiling ${decision} <id>${decision === "deny" ? ' --note "why"' : ' [--rps N] [--note "\u2026"]'}`) + import_chalk65.default.dim(" (ids: apiblaze op ceiling list)"));
17605
+ return void console.log(import_chalk66.default.red("Which request?") + import_chalk66.default.cyan(` apiblaze op ceiling ${decision} <id>${decision === "deny" ? ' --note "why"' : ' [--rps N] [--note "\u2026"]'}`) + import_chalk66.default.dim(" (ids: apiblaze op ceiling list)"));
17372
17606
  }
17373
17607
  const note = typeof opts.note === "string" ? opts.note.trim() : "";
17374
17608
  if (decision === "deny" && !note) {
17375
17609
  process.exitCode = 1;
17376
- return void console.log(import_chalk65.default.red("A denial needs a reason the producer will read:") + import_chalk65.default.cyan(` apiblaze op ceiling deny ${id} --note "why"`));
17610
+ return void console.log(import_chalk66.default.red("A denial needs a reason the producer will read:") + import_chalk66.default.cyan(` apiblaze op ceiling deny ${id} --note "why"`));
17377
17611
  }
17378
17612
  let rps;
17379
17613
  if (opts.rps !== void 0 && opts.rps !== null && opts.rps !== "") {
17380
17614
  if (decision === "deny") {
17381
17615
  process.exitCode = 1;
17382
- return void console.log(import_chalk65.default.red("--rps only applies to approve."));
17616
+ return void console.log(import_chalk66.default.red("--rps only applies to approve."));
17383
17617
  }
17384
17618
  rps = Number(String(opts.rps).replace(/[,_]/g, ""));
17385
17619
  if (!Number.isInteger(rps) || rps <= 0) {
17386
17620
  process.exitCode = 1;
17387
- return void console.log(import_chalk65.default.red("--rps must be a whole number of requests per second (e.g. 5000)."));
17621
+ return void console.log(import_chalk66.default.red("--rps must be a whole number of requests per second (e.g. 5000)."));
17388
17622
  }
17389
17623
  }
17390
17624
  const body = { decision };
@@ -17409,19 +17643,19 @@ async function opCeilingDecide(decision, id, opts) {
17409
17643
  const where = r ? `${r.project_id}/${r.api_version}` : `request ${id}`;
17410
17644
  if (decision === "approve") {
17411
17645
  const to = res?.limits?.ceilingRps ?? res?.request?.granted_rps ?? rps ?? r?.requested_rps;
17412
- console.log(import_chalk65.default.green(`
17646
+ console.log(import_chalk66.default.green(`
17413
17647
  project ${where}: maximum rate ${rpsStr(from)} \u2192 ${rpsStr(to)} req/s`));
17414
- if (r?.requested_rps !== void 0 && to !== void 0 && to !== r.requested_rps) console.log(import_chalk65.default.dim(` (asked for ${rpsStr(r.requested_rps)} req/s)`));
17648
+ if (r?.requested_rps !== void 0 && to !== void 0 && to !== r.requested_rps) console.log(import_chalk66.default.dim(` (asked for ${rpsStr(r.requested_rps)} req/s)`));
17415
17649
  } else {
17416
- console.log(import_chalk65.default.yellow(`
17417
- project ${where}: request for ${rpsStr(r?.requested_rps)} req/s denied`) + (typeof from === "number" ? import_chalk65.default.dim(` \u2014 maximum rate stays ${rpsStr(from)} req/s`) : ""));
17650
+ console.log(import_chalk66.default.yellow(`
17651
+ project ${where}: request for ${rpsStr(r?.requested_rps)} req/s denied`) + (typeof from === "number" ? import_chalk66.default.dim(` \u2014 maximum rate stays ${rpsStr(from)} req/s`) : ""));
17418
17652
  }
17419
- if (note) console.log(import_chalk65.default.dim(` note: ${note}`));
17653
+ if (note) console.log(import_chalk66.default.dim(` note: ${note}`));
17420
17654
  console.log("");
17421
17655
  }
17422
17656
 
17423
17657
  // src/commands/op-ledger.ts
17424
- var import_chalk66 = __toESM(require("chalk"));
17658
+ var import_chalk67 = __toESM(require("chalk"));
17425
17659
  init_admin();
17426
17660
  init_types();
17427
17661
  var UNITS_PER_CENT = 1e4;
@@ -17448,7 +17682,7 @@ function parseLimit(raw, max) {
17448
17682
  function fail6(opts, msg) {
17449
17683
  process.exitCode = 1;
17450
17684
  if (opts.json) return void console.log(JSON.stringify({ ok: false, error: msg }));
17451
- console.log(import_chalk66.default.red(msg));
17685
+ console.log(import_chalk67.default.red(msg));
17452
17686
  }
17453
17687
  function printLedgerError(err, what, opts) {
17454
17688
  if (!(err instanceof ApiError) || ![400, 403, 404, 500, 502, 503].includes(err.status)) return false;
@@ -17459,9 +17693,9 @@ function printLedgerError(err, what, opts) {
17459
17693
  return true;
17460
17694
  }
17461
17695
  const code = body.error && body.error !== err.message ? ` ${body.error}` : "";
17462
- console.log(import_chalk66.default.red(` ${what} failed (${err.status}${code}): ${body.details ?? err.message}`));
17463
- if (err.status === 503 && body.error === "money_unreachable") console.log(import_chalk66.default.dim(" The money worker did not answer \u2014 retry in a minute; nothing was changed."));
17464
- if (err.status === 503 && body.error === "audit_unavailable") console.log(import_chalk66.default.dim(" The operator_audit row could not be written, so the action was refused."));
17696
+ console.log(import_chalk67.default.red(` ${what} failed (${err.status}${code}): ${body.details ?? err.message}`));
17697
+ if (err.status === 503 && body.error === "money_unreachable") console.log(import_chalk67.default.dim(" The money worker did not answer \u2014 retry in a minute; nothing was changed."));
17698
+ if (err.status === 503 && body.error === "audit_unavailable") console.log(import_chalk67.default.dim(" The operator_audit row could not be written, so the action was refused."));
17465
17699
  return true;
17466
17700
  }
17467
17701
  async function call(opts, what, req) {
@@ -17474,33 +17708,33 @@ async function call(opts, what, req) {
17474
17708
  }
17475
17709
  function renderLedger2(data, opts = {}) {
17476
17710
  const out = [];
17477
- out.push(import_chalk66.default.bold(`
17478
- Ledger \u2014 ${data.billing_account_id}`) + import_chalk66.default.dim(` money_ledger, oldest first${opts.since ? ` since ${opts.since}` : ""}${opts.kind ? ` \xB7 kind=${opts.kind}` : ""}`));
17711
+ out.push(import_chalk67.default.bold(`
17712
+ Ledger \u2014 ${data.billing_account_id}`) + import_chalk67.default.dim(` money_ledger, oldest first${opts.since ? ` since ${opts.since}` : ""}${opts.kind ? ` \xB7 kind=${opts.kind}` : ""}`));
17479
17713
  const h = data.head;
17480
17714
  if (h) {
17481
- const gap = h.contiguous_to < h.head_seq ? import_chalk66.default.yellow(` GAP: ${h.head_seq - h.contiguous_to} seq missing after ${h.contiguous_to}`) : import_chalk66.default.green(" contiguous");
17715
+ const gap = h.contiguous_to < h.head_seq ? import_chalk67.default.yellow(` GAP: ${h.head_seq - h.contiguous_to} seq missing after ${h.contiguous_to}`) : import_chalk67.default.green(" contiguous");
17482
17716
  out.push(` head gen ${h.generation} \xB7 seq ${h.head_seq} \xB7 balance ${money3(cents(h.head_balance))} \xB7 at ${ts(h.head_ts)} \xB7 contiguous to ${h.contiguous_to}${gap}`);
17483
17717
  } else {
17484
- out.push(import_chalk66.default.dim(" head none \u2014 Neon has no row for this wallet yet"));
17718
+ out.push(import_chalk67.default.dim(" head none \u2014 Neon has no row for this wallet yet"));
17485
17719
  }
17486
17720
  const rows = data.rows ?? [];
17487
17721
  if (!rows.length) {
17488
- out.push(import_chalk66.default.dim(" No rows."));
17722
+ out.push(import_chalk67.default.dim(" No rows."));
17489
17723
  return out;
17490
17724
  }
17491
- out.push(import_chalk66.default.dim(` ${"gen".padStart(3)} ${"seq".padStart(13)} ${"ts".padEnd(19)} ${"class".padEnd(5)} ${"kind".padEnd(18)} ${"amount".padStart(12)} ${"balance after".padStart(13)} flag`));
17725
+ out.push(import_chalk67.default.dim(` ${"gen".padStart(3)} ${"seq".padStart(13)} ${"ts".padEnd(19)} ${"class".padEnd(5)} ${"kind".padEnd(18)} ${"amount".padStart(12)} ${"balance after".padStart(13)} flag`));
17492
17726
  for (const r of rows) {
17493
17727
  const c = typeof r.units_cents === "number" ? r.units_cents : cents(r.units);
17494
17728
  const amt = signedMoney2(c);
17495
17729
  const bal = typeof r.balance_after_cents === "number" ? r.balance_after_cents : cents(r.balance_after);
17496
- const flag = r.flag ? import_chalk66.default.red(r.flag) : "";
17497
- const n = r.class === "flow" && (r.count ?? 0) > 1 ? import_chalk66.default.dim(` \xD7${r.count}`) : "";
17730
+ const flag = r.flag ? import_chalk67.default.red(r.flag) : "";
17731
+ const n = r.class === "flow" && (r.count ?? 0) > 1 ? import_chalk67.default.dim(` \xD7${r.count}`) : "";
17498
17732
  out.push(
17499
- ` ${String(r.generation).padStart(3)} ${seqRange(r).padStart(13)} ${ts(r.ts_to).padEnd(19)} ${r.class.padEnd(5)} ${trunc2(String(r.kind ?? ""), 18).padEnd(18)} ${(typeof c === "number" && c < 0 ? import_chalk66.default.red : import_chalk66.default.green)(amt.padStart(12))} ${money3(bal).padStart(13)} ${flag}${n}`
17733
+ ` ${String(r.generation).padStart(3)} ${seqRange(r).padStart(13)} ${ts(r.ts_to).padEnd(19)} ${r.class.padEnd(5)} ${trunc2(String(r.kind ?? ""), 18).padEnd(18)} ${(typeof c === "number" && c < 0 ? import_chalk67.default.red : import_chalk67.default.green)(amt.padStart(12))} ${money3(bal).padStart(13)} ${flag}${n}`
17500
17734
  );
17501
17735
  }
17502
- out.push(import_chalk66.default.bold(` ${"\u03A3".padStart(17)} ${"".padEnd(19)} ${"".padEnd(5)} ${"".padEnd(18)} ${signedMoney2(cents(data.sum_units)).padStart(12)}`));
17503
- if (data.partial) out.push(import_chalk66.default.yellow(` More than ${data.limit} rows in the window \u2014 narrow --since / --kind or raise --limit (\u2264 1000) before trusting the sum.`));
17736
+ out.push(import_chalk67.default.bold(` ${"\u03A3".padStart(17)} ${"".padEnd(19)} ${"".padEnd(5)} ${"".padEnd(18)} ${signedMoney2(cents(data.sum_units)).padStart(12)}`));
17737
+ if (data.partial) out.push(import_chalk67.default.yellow(` More than ${data.limit} rows in the window \u2014 narrow --since / --kind or raise --limit (\u2264 1000) before trusting the sum.`));
17504
17738
  return out;
17505
17739
  }
17506
17740
  async function opLedgerShow(ref, opts) {
@@ -17525,25 +17759,25 @@ async function opLedgerLag(opts) {
17525
17759
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
17526
17760
  const newest = data.newest_received_at;
17527
17761
  const ageS = newest ? Math.max(0, Math.round((Date.now() - Date.parse(newest)) / 1e3)) : null;
17528
- console.log(import_chalk66.default.bold("\n Ledger lag") + import_chalk66.default.dim(" money_ledger health (gaps, flags, quarantine)"));
17529
- console.log(` ${"newest row".padEnd(16)} ${newest ? `${ts(newest)} (${ageS}s ago)` : import_chalk66.default.dim("none")}`);
17530
- console.log(` ${"gaps".padEnd(16)} ${(data.gap_count ? import_chalk66.default.yellow : import_chalk66.default.green)(String(data.gap_count))}${import_chalk66.default.dim(" wallets whose contiguous_to < head_seq")}`);
17531
- console.log(` ${"flagged 24h".padEnd(16)} ${(data.flagged_24h?.count ? import_chalk66.default.red : import_chalk66.default.green)(String(data.flagged_24h?.count ?? 0))}${import_chalk66.default.dim(" mismatch flags on rows received in the last 24 h")}`);
17532
- console.log(` ${"quarantine 24h".padEnd(16)} ${(data.quarantine_24h ? import_chalk66.default.red : import_chalk66.default.green)(String(data.quarantine_24h))}${import_chalk66.default.dim(" apiblaze op ledger quarantine")}`);
17762
+ console.log(import_chalk67.default.bold("\n Ledger lag") + import_chalk67.default.dim(" money_ledger health (gaps, flags, quarantine)"));
17763
+ console.log(` ${"newest row".padEnd(16)} ${newest ? `${ts(newest)} (${ageS}s ago)` : import_chalk67.default.dim("none")}`);
17764
+ console.log(` ${"gaps".padEnd(16)} ${(data.gap_count ? import_chalk67.default.yellow : import_chalk67.default.green)(String(data.gap_count))}${import_chalk67.default.dim(" wallets whose contiguous_to < head_seq")}`);
17765
+ console.log(` ${"flagged 24h".padEnd(16)} ${(data.flagged_24h?.count ? import_chalk67.default.red : import_chalk67.default.green)(String(data.flagged_24h?.count ?? 0))}${import_chalk67.default.dim(" mismatch flags on rows received in the last 24 h")}`);
17766
+ console.log(` ${"quarantine 24h".padEnd(16)} ${(data.quarantine_24h ? import_chalk67.default.red : import_chalk67.default.green)(String(data.quarantine_24h))}${import_chalk67.default.dim(" apiblaze op ledger quarantine")}`);
17533
17767
  if (data.gaps?.length) {
17534
- console.log(import_chalk66.default.bold("\n Gaps") + import_chalk66.default.dim(" (biggest first)"));
17535
- console.log(import_chalk66.default.dim(` ${"missing".padStart(7)} ${"gen".padStart(3)} ${"contig \u2192 head".padEnd(17)} ${"head at".padEnd(19)} wallet`));
17768
+ console.log(import_chalk67.default.bold("\n Gaps") + import_chalk67.default.dim(" (biggest first)"));
17769
+ console.log(import_chalk67.default.dim(` ${"missing".padStart(7)} ${"gen".padStart(3)} ${"contig \u2192 head".padEnd(17)} ${"head at".padEnd(19)} wallet`));
17536
17770
  for (const g of data.gaps.slice(0, 40)) {
17537
- console.log(` ${import_chalk66.default.yellow(String(g.missing).padStart(7))} ${String(g.generation).padStart(3)} ${`${g.contiguous_to} \u2192 ${g.head_seq}`.padEnd(17)} ${ts(g.head_ts).padEnd(19)} ${g.billing_account_id}`);
17771
+ console.log(` ${import_chalk67.default.yellow(String(g.missing).padStart(7))} ${String(g.generation).padStart(3)} ${`${g.contiguous_to} \u2192 ${g.head_seq}`.padEnd(17)} ${ts(g.head_ts).padEnd(19)} ${g.billing_account_id}`);
17538
17772
  }
17539
- if (data.gaps.length > 40) console.log(import_chalk66.default.dim(` \u2026 ${data.gaps.length - 40} more (--json)`));
17540
- console.log(import_chalk66.default.dim(" A gap the queue is not about to fill (> 30 min): apiblaze op ledger cut <wallet>, or backfill (\xA76.4)."));
17773
+ if (data.gaps.length > 40) console.log(import_chalk67.default.dim(` \u2026 ${data.gaps.length - 40} more (--json)`));
17774
+ console.log(import_chalk67.default.dim(" A gap the queue is not about to fill (> 30 min): apiblaze op ledger cut <wallet>, or backfill (\xA76.4)."));
17541
17775
  }
17542
17776
  const flagged = data.flagged_24h?.rows ?? [];
17543
17777
  if (flagged.length) {
17544
- console.log(import_chalk66.default.bold("\n Flagged rows (24 h)"));
17545
- for (const f of flagged.slice(0, 40)) console.log(` ${ts(f.received_at)} gen ${f.generation} seq ${seqRange(f).padEnd(11)} ${trunc2(f.kind, 14).padEnd(14)} ${import_chalk66.default.red(f.flag)} ${f.billing_account_id}`);
17546
- if (flagged.length > 40) console.log(import_chalk66.default.dim(` \u2026 ${flagged.length - 40} more (--json)`));
17778
+ console.log(import_chalk67.default.bold("\n Flagged rows (24 h)"));
17779
+ for (const f of flagged.slice(0, 40)) console.log(` ${ts(f.received_at)} gen ${f.generation} seq ${seqRange(f).padEnd(11)} ${trunc2(f.kind, 14).padEnd(14)} ${import_chalk67.default.red(f.flag)} ${f.billing_account_id}`);
17780
+ if (flagged.length > 40) console.log(import_chalk67.default.dim(` \u2026 ${flagged.length - 40} more (--json)`));
17547
17781
  }
17548
17782
  console.log("");
17549
17783
  }
@@ -17556,14 +17790,14 @@ async function opLedgerQuarantine(opts) {
17556
17790
  const data = await call(opts, "Quarantine read", { method: "GET", path: `/operator/ledger/quarantine${qs.toString() ? `?${qs}` : ""}`, summary: "ledger quarantine" });
17557
17791
  if (!data) return;
17558
17792
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
17559
- console.log(import_chalk66.default.bold("\n Ledger quarantine") + import_chalk66.default.dim(` newest first${data.ba ? ` \xB7 ${data.ba}` : ""} \xB7 ${data.count_24h} in the last 24 h`));
17793
+ console.log(import_chalk67.default.bold("\n Ledger quarantine") + import_chalk67.default.dim(` newest first${data.ba ? ` \xB7 ${data.ba}` : ""} \xB7 ${data.count_24h} in the last 24 h`));
17560
17794
  const rows = data.rows ?? [];
17561
- if (!rows.length) return void console.log(import_chalk66.default.green(" Empty.\n"));
17562
- console.log(import_chalk66.default.dim(` ${"received".padEnd(19)} ${"reason".padEnd(10)} ${"gen".padStart(3)} ${"seq".padStart(13)} wallet`));
17795
+ if (!rows.length) return void console.log(import_chalk67.default.green(" Empty.\n"));
17796
+ console.log(import_chalk67.default.dim(` ${"received".padEnd(19)} ${"reason".padEnd(10)} ${"gen".padStart(3)} ${"seq".padStart(13)} wallet`));
17563
17797
  for (const r of rows) {
17564
- console.log(` ${ts(r.received_at).padEnd(19)} ${import_chalk66.default.red(trunc2(String(r.reason), 10).padEnd(10))} ${String(r.generation).padStart(3)} ${seqRange(r).padStart(13)} ${r.billing_account_id}${r.existing ? import_chalk66.default.dim(" (differs from the stored row)") : ""}`);
17798
+ console.log(` ${ts(r.received_at).padEnd(19)} ${import_chalk67.default.red(trunc2(String(r.reason), 10).padEnd(10))} ${String(r.generation).padStart(3)} ${seqRange(r).padStart(13)} ${r.billing_account_id}${r.existing ? import_chalk67.default.dim(" (differs from the stored row)") : ""}`);
17565
17799
  }
17566
- console.log(import_chalk66.default.dim("\n Both versions: --json. The fix is always wallet-side (code fix, and an `adjust` if money was wrong) \u2014 never an edit of Neon (\xA76.6).\n"));
17800
+ console.log(import_chalk67.default.dim("\n Both versions: --json. The fix is always wallet-side (code fix, and an `adjust` if money was wrong) \u2014 never an edit of Neon (\xA76.6).\n"));
17567
17801
  }
17568
17802
  async function opLedgerCut(ref, opts) {
17569
17803
  if (!ref) return fail6(opts, 'Which wallet? apiblaze op ledger cut <wallet id | team id> [--reason "\u2026"]');
@@ -17574,9 +17808,9 @@ async function opLedgerCut(ref, opts) {
17574
17808
  const res = await call(opts, "Ledger cut", { method: "POST", path: "/operator/ledger/cut", body, summary: `cut ledger for ${ba}` });
17575
17809
  if (!res) return;
17576
17810
  if (opts.json) return void console.log(JSON.stringify(res, null, 2));
17577
- console.log(import_chalk66.default.green(`
17811
+ console.log(import_chalk67.default.green(`
17578
17812
  ${res.billing_account_id ?? ba}: cut and sent ${res.rows ?? 0} row${res.rows === 1 ? "" : "s"}.`));
17579
- console.log(import_chalk66.default.dim(` They land in Neon within seconds: apiblaze op ledger show ${ba}
17813
+ console.log(import_chalk67.default.dim(` They land in Neon within seconds: apiblaze op ledger show ${ba}
17580
17814
  `));
17581
17815
  }
17582
17816
  async function opLedgerBackfill(opts) {
@@ -17592,33 +17826,33 @@ async function opLedgerBackfill(opts) {
17592
17826
  const res = await call(opts, "Ledger backfill", { method: "POST", path: "/operator/ledger/backfill", body, summary: `ledger backfill since ${new Date(sinceMs).toISOString()}` });
17593
17827
  if (!res) return;
17594
17828
  if (opts.json) return void console.log(JSON.stringify(res, null, 2));
17595
- console.log(import_chalk66.default.bold(`
17596
- Ledger backfill since ${new Date(res.since_ms ?? sinceMs).toISOString()}`) + import_chalk66.default.dim(" verbatim re-send of stored cuts, never a re-cut"));
17829
+ console.log(import_chalk67.default.bold(`
17830
+ Ledger backfill since ${new Date(res.since_ms ?? sinceMs).toISOString()}`) + import_chalk67.default.dim(" verbatim re-send of stored cuts, never a re-cut"));
17597
17831
  console.log(` ${"wallets checked".padEnd(16)} ${res.wallets_checked}`);
17598
17832
  console.log(` ${"resent".padEnd(16)} ${res.resent_rows} row${res.resent_rows === 1 ? "" : "s"} across ${res.resent_wallets} wallet${res.resent_wallets === 1 ? "" : "s"}`);
17599
17833
  console.log(` ${"in sync".padEnd(16)} ${res.in_sync}`);
17600
- console.log(` ${"uncut".padEnd(16)} ${res.uncut}${import_chalk66.default.dim(" entries not cut yet \u2014 reported, not cut (op ledger cut <wallet>)")}`);
17601
- console.log(` ${"neon ahead".padEnd(16)} ${(res.neon_ahead ? import_chalk66.default.yellow : (s) => s)(String(res.neon_ahead))}`);
17602
- console.log(` ${"unrecoverable".padEnd(16)} ${(res.unrecoverable ? import_chalk66.default.red : (s) => s)(String(res.unrecoverable))}${import_chalk66.default.dim(" the wallet no longer keeps the cuts after Neon's head (> 30 d)")}`);
17603
- console.log(` ${"errors".padEnd(16)} ${(res.errors ? import_chalk66.default.red : (s) => s)(String(res.errors))}`);
17834
+ console.log(` ${"uncut".padEnd(16)} ${res.uncut}${import_chalk67.default.dim(" entries not cut yet \u2014 reported, not cut (op ledger cut <wallet>)")}`);
17835
+ console.log(` ${"neon ahead".padEnd(16)} ${(res.neon_ahead ? import_chalk67.default.yellow : (s) => s)(String(res.neon_ahead))}`);
17836
+ console.log(` ${"unrecoverable".padEnd(16)} ${(res.unrecoverable ? import_chalk67.default.red : (s) => s)(String(res.unrecoverable))}${import_chalk67.default.dim(" the wallet no longer keeps the cuts after Neon's head (> 30 d)")}`);
17837
+ console.log(` ${"errors".padEnd(16)} ${(res.errors ? import_chalk67.default.red : (s) => s)(String(res.errors))}`);
17604
17838
  const notable = (res.results ?? []).filter((r) => r.action !== "in_sync");
17605
17839
  if (notable.length) {
17606
- console.log(import_chalk66.default.dim(`
17840
+ console.log(import_chalk67.default.dim(`
17607
17841
  ${"action".padEnd(10)} ${"wallet gen/seq/cut".padEnd(20)} ${"neon gen/head/contig".padEnd(20)} wallet`));
17608
17842
  for (const r of notable.slice(0, 60)) {
17609
17843
  const w = r.wallet ? `${r.wallet.generation}/${r.wallet.seq}/${r.wallet.cut_to}` : "\u2014";
17610
17844
  const n = r.neon ? `${r.neon.generation}/${r.neon.head_seq}/${r.neon.contiguous_to}` : "\u2014";
17611
- const colour = r.action === "error" || r.unrecoverable ? import_chalk66.default.red : r.action === "resent" ? import_chalk66.default.green : import_chalk66.default.yellow;
17845
+ const colour = r.action === "error" || r.unrecoverable ? import_chalk67.default.red : r.action === "resent" ? import_chalk67.default.green : import_chalk67.default.yellow;
17612
17846
  const note = [r.resent !== void 0 ? `resent ${r.resent}` : "", r.unrecoverable ? `UNRECOVERABLE (oldest kept seq ${r.oldest_kept_seq ?? "?"})` : "", r.error ?? ""].filter(Boolean).join(" \xB7 ");
17613
- console.log(` ${colour(r.action.padEnd(10))} ${w.padEnd(20)} ${n.padEnd(20)} ${r.billing_account_id}${note ? import_chalk66.default.dim(` ${note}`) : ""}`);
17847
+ console.log(` ${colour(r.action.padEnd(10))} ${w.padEnd(20)} ${n.padEnd(20)} ${r.billing_account_id}${note ? import_chalk67.default.dim(` ${note}`) : ""}`);
17614
17848
  }
17615
- if (notable.length > 60) console.log(import_chalk66.default.dim(` \u2026 ${notable.length - 60} more (--json)`));
17849
+ if (notable.length > 60) console.log(import_chalk67.default.dim(` \u2026 ${notable.length - 60} more (--json)`));
17616
17850
  }
17617
17851
  console.log("");
17618
17852
  }
17619
17853
 
17620
17854
  // src/commands/op-test.ts
17621
- var import_chalk67 = __toESM(require("chalk"));
17855
+ var import_chalk68 = __toESM(require("chalk"));
17622
17856
  init_auth();
17623
17857
  init_types();
17624
17858
  var DASHBOARD_BASE11 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
@@ -17643,10 +17877,10 @@ async function scrubSandboxKeys(timeoutS = 150) {
17643
17877
  try {
17644
17878
  const r = await runnerCall({ action: "gut", id: TEARDOWN_GUT_ID }, timeoutS);
17645
17879
  const first = r.results?.[0]?.detail ?? r.error ?? "";
17646
- log(import_chalk67.default.dim(`teardown: ${first || (r.ok ? "sandbox fixture keys scrubbed" : "scrub reported a problem")}`));
17880
+ log(import_chalk68.default.dim(`teardown: ${first || (r.ok ? "sandbox fixture keys scrubbed" : "scrub reported a problem")}`));
17647
17881
  return r.ok;
17648
17882
  } catch (e) {
17649
- log(import_chalk67.default.dim(`teardown: sandbox key scrub skipped (${e instanceof Error ? e.message : String(e)}) \u2014 leftovers expire within 14 days; scripts/purge-test-keys.mjs reaps them`));
17883
+ log(import_chalk68.default.dim(`teardown: sandbox key scrub skipped (${e instanceof Error ? e.message : String(e)}) \u2014 leftovers expire within 14 days; scripts/purge-test-keys.mjs reaps them`));
17650
17884
  return false;
17651
17885
  }
17652
17886
  }
@@ -17668,23 +17902,23 @@ async function runOpTest(o = {}) {
17668
17902
  const guts = o.skipGuts ? [] : listing.guts.filter((g) => g.id !== TEARDOWN_GUT_ID && matches(g.id, void 0, { ...o, group: void 0 }));
17669
17903
  const total = specs.length + guts.length;
17670
17904
  if (total === 0) {
17671
- log(import_chalk67.default.yellow("nothing matched"));
17905
+ log(import_chalk68.default.yellow("nothing matched"));
17672
17906
  process.exitCode = 2;
17673
17907
  return;
17674
17908
  }
17675
- log(import_chalk67.default.bold(`apiblaze op test \u2014 ${specs.length} spec(s) + ${guts.length} gut check(s) on sandbox ${listing.sandbox_team}`));
17909
+ log(import_chalk68.default.bold(`apiblaze op test \u2014 ${specs.length} spec(s) + ${guts.length} gut check(s) on sandbox ${listing.sandbox_team}`));
17676
17910
  const results = [];
17677
17911
  let failed = 0;
17678
17912
  const started = Date.now();
17679
17913
  const record = (r) => {
17680
17914
  results.push(r);
17681
17915
  if (!r.ok) failed += 1;
17682
- const mark = r.ok ? import_chalk67.default.green("PASS") : import_chalk67.default.red("FAIL");
17916
+ const mark = r.ok ? import_chalk68.default.green("PASS") : import_chalk68.default.red("FAIL");
17683
17917
  log(`[${mark}] ${r.id} \u2014 ${r.label} (${ms(r.duration_ms)})`);
17684
17918
  if (!r.ok) {
17685
- if (r.kind === "spec") for (const c of r.cases.filter((c2) => !c2.ok)) log(import_chalk67.default.red(` \u2717 ${c.name}: ${c.detail}`));
17686
- else if (r.error) log(import_chalk67.default.red(` \u2717 ${r.error}`));
17687
- else for (const x of r.results.filter((x2) => x2 && x2.ok === false)) log(import_chalk67.default.red(` \u2717 ${x.name ?? ""}: ${x.detail ?? JSON.stringify(x)}`));
17919
+ if (r.kind === "spec") for (const c of r.cases.filter((c2) => !c2.ok)) log(import_chalk68.default.red(` \u2717 ${c.name}: ${c.detail}`));
17920
+ else if (r.error) log(import_chalk68.default.red(` \u2717 ${r.error}`));
17921
+ else for (const x of r.results.filter((x2) => x2 && x2.ok === false)) log(import_chalk68.default.red(` \u2717 ${x.name ?? ""}: ${x.detail ?? JSON.stringify(x)}`));
17688
17922
  }
17689
17923
  };
17690
17924
  try {
@@ -17715,13 +17949,13 @@ async function runOpTest(o = {}) {
17715
17949
  }
17716
17950
  const summary = { ran: results.length, passed: results.length - failed, failed, duration_ms: Date.now() - started, sandbox_team: listing.sandbox_team };
17717
17951
  log("");
17718
- log(failed ? import_chalk67.default.red(`${summary.passed}/${summary.ran} passed, ${failed} failed (${ms(summary.duration_ms)})`) : import_chalk67.default.green(`${summary.passed}/${summary.ran} passed (${ms(summary.duration_ms)})`));
17952
+ log(failed ? import_chalk68.default.red(`${summary.passed}/${summary.ran} passed, ${failed} failed (${ms(summary.duration_ms)})`) : import_chalk68.default.green(`${summary.passed}/${summary.ran} passed (${ms(summary.duration_ms)})`));
17719
17953
  if (o.json) process.stdout.write(JSON.stringify({ ...summary, results }, null, 2) + "\n");
17720
17954
  if (failed) process.exitCode = 1;
17721
17955
  }
17722
17956
 
17723
17957
  // src/commands/op-consumer.ts
17724
- var import_chalk68 = __toESM(require("chalk"));
17958
+ var import_chalk69 = __toESM(require("chalk"));
17725
17959
  init_consumer_auth();
17726
17960
  var SANDBOX_TENANT = "portalteststenant";
17727
17961
  var SANDBOX_PROXY = "portaltestproxypreapproved@2.7.0";
@@ -17764,9 +17998,9 @@ async function runOpConsumer(o = {}) {
17764
17998
  const creds = loadConsumer();
17765
17999
  const done = (r) => {
17766
18000
  const out = { kind: "consumer", id: "consumer-door", label: "Consumer door: the stored consumer token opens its tenant's OAuth-door proxy", duration_ms: Date.now() - t0, ...r };
17767
- const mark = out.skipped ? import_chalk68.default.yellow("SKIP") : out.ok ? import_chalk68.default.green("PASS") : import_chalk68.default.red("FAIL");
18001
+ const mark = out.skipped ? import_chalk69.default.yellow("SKIP") : out.ok ? import_chalk69.default.green("PASS") : import_chalk69.default.red("FAIL");
17768
18002
  log2(`[${mark}] ${out.id} \u2014 ${out.label}${out.tenant ? ` (tenant ${out.tenant})` : ""}${out.url ? ` \u2192 ${out.url}` : ""}`);
17769
- for (const c of out.cases) if (!c.ok || out.skipped) log2((c.ok ? import_chalk68.default.dim : import_chalk68.default.red)(` ${c.ok ? "ok " : "\u2717"} ${c.name}: ${c.detail}`));
18003
+ for (const c of out.cases) if (!c.ok || out.skipped) log2((c.ok ? import_chalk69.default.dim : import_chalk69.default.red)(` ${c.ok ? "ok " : "\u2717"} ${c.name}: ${c.detail}`));
17770
18004
  if (o.json) process.stdout.write(JSON.stringify(out, null, 2) + "\n");
17771
18005
  if (!out.ok && !out.skipped) process.exitCode = 1;
17772
18006
  if (out.skipped) process.exitCode = 2;
@@ -17806,7 +18040,7 @@ async function runOpConsumer(o = {}) {
17806
18040
  }
17807
18041
 
17808
18042
  // src/commands/op-perf.ts
17809
- var import_chalk69 = __toESM(require("chalk"));
18043
+ var import_chalk70 = __toESM(require("chalk"));
17810
18044
  var RPS_DEFAULT = 100;
17811
18045
  var RPS_CAP = 300;
17812
18046
  var SECONDS_DEFAULT = 60;
@@ -17990,10 +18224,10 @@ async function readGateway(proxy, sent, signal) {
17990
18224
  }
17991
18225
  const left = deadline - Date.now();
17992
18226
  if (left <= 0) {
17993
- log3(import_chalk69.default.yellow(` gateway: not available \u2014 Analytics Engine had ${lastSeen}/${sent} rows for ${proxy} after ${GATEWAY_WAIT_MS / 1e3}s${lastErr ? ` (last error: ${lastErr})` : ""}`));
18227
+ log3(import_chalk70.default.yellow(` gateway: not available \u2014 Analytics Engine had ${lastSeen}/${sent} rows for ${proxy} after ${GATEWAY_WAIT_MS / 1e3}s${lastErr ? ` (last error: ${lastErr})` : ""}`));
17994
18228
  return null;
17995
18229
  }
17996
- log3(import_chalk69.default.dim(` waiting for the latency ledger\u2026 ${lastSeen}/${sent} rows for ${proxy}${lastErr ? ` (${lastErr})` : ""}`));
18230
+ log3(import_chalk70.default.dim(` waiting for the latency ledger\u2026 ${lastSeen}/${sent} rows for ${proxy}${lastErr ? ` (${lastErr})` : ""}`));
17997
18231
  await sleep(Math.min(GATEWAY_POLL_MS, left), signal);
17998
18232
  }
17999
18233
  }
@@ -18002,7 +18236,7 @@ async function runOpPerf(o = {}) {
18002
18236
  const thresholds = thresholdsFrom(o);
18003
18237
  const ctrl = new AbortController();
18004
18238
  const onSigint = () => {
18005
- log3(import_chalk69.default.yellow("\ninterrupted \u2014 stopping the load and tearing down the fixture"));
18239
+ log3(import_chalk70.default.yellow("\ninterrupted \u2014 stopping the load and tearing down the fixture"));
18006
18240
  ctrl.abort();
18007
18241
  };
18008
18242
  process.once("SIGINT", onSigint);
@@ -18011,7 +18245,7 @@ async function runOpPerf(o = {}) {
18011
18245
  if (!o.key) throw new Error("--url needs --key (the fixture proxy's API key)");
18012
18246
  fixture = { url: o.url, key: o.key, proxy: proxyFromUrl(o.url), provisioned: false };
18013
18247
  } else {
18014
- log3(import_chalk69.default.dim("provisioning the perf fixture through the runner\u2026"));
18248
+ log3(import_chalk70.default.dim("provisioning the perf fixture through the runner\u2026"));
18015
18249
  const f = await runnerCall({ action: "perf-fixture" }, 120);
18016
18250
  if (!f?.url || !f?.key) throw new Error(`perf-fixture returned no url/key: ${JSON.stringify(f).slice(0, 200)}`);
18017
18251
  fixture = { url: f.url, key: f.key, proxy: f.proxy || proxyFromUrl(f.url), team: f.team, provisioned: true };
@@ -18019,7 +18253,7 @@ async function runOpPerf(o = {}) {
18019
18253
  try {
18020
18254
  const total = Math.round(rps * seconds);
18021
18255
  const intervalMs = 1e3 / rps;
18022
- log3(import_chalk69.default.bold(`apiblaze op test --perf \u2014 ${rps} rps \xD7 ${seconds}s (${total} requests) against ${fixture.url}${fixture.team ? ` (sandbox ${fixture.team})` : ""}`));
18256
+ log3(import_chalk70.default.bold(`apiblaze op test --perf \u2014 ${rps} rps \xD7 ${seconds}s (${total} requests) against ${fixture.url}${fixture.team ? ` (sandbox ${fixture.team})` : ""}`));
18023
18257
  const samples = [];
18024
18258
  const inflight = /* @__PURE__ */ new Set();
18025
18259
  let fired = 0;
@@ -18027,7 +18261,7 @@ async function runOpPerf(o = {}) {
18027
18261
  const progress = setInterval(() => {
18028
18262
  const m = summarize(samples, Date.now() - t0);
18029
18263
  const secs = (Date.now() - t0) / 1e3;
18030
- log3(import_chalk69.default.dim(` ${Math.round(secs)}s sent ${fired} ok ${m.ok} err ${m.errors} p50 ${fmtMs(m.p50)} p95 ${fmtMs(m.p95)} (${(fired / secs).toFixed(1)} rps)`));
18264
+ log3(import_chalk70.default.dim(` ${Math.round(secs)}s sent ${fired} ok ${m.ok} err ${m.errors} p50 ${fmtMs(m.p50)} p95 ${fmtMs(m.p95)} (${(fired / secs).toFixed(1)} rps)`));
18031
18265
  }, PROGRESS_EVERY_MS);
18032
18266
  const { sent, elapsedMs } = await schedule({
18033
18267
  total,
@@ -18041,21 +18275,21 @@ async function runOpPerf(o = {}) {
18041
18275
  }
18042
18276
  });
18043
18277
  clearInterval(progress);
18044
- if (inflight.size) log3(import_chalk69.default.dim(` load sent; waiting for ${inflight.size} in-flight response(s) (\u2264 ${REQUEST_TIMEOUT_MS / 1e3}s)\u2026`));
18278
+ if (inflight.size) log3(import_chalk70.default.dim(` load sent; waiting for ${inflight.size} in-flight response(s) (\u2264 ${REQUEST_TIMEOUT_MS / 1e3}s)\u2026`));
18045
18279
  await Promise.all([...inflight]);
18046
18280
  const client = summarize(samples, elapsedMs);
18047
18281
  log3("");
18048
- log3(` ${import_chalk69.default.bold("client ")} p50 ${fmtMs(client.p50).padStart(7)} p95 ${fmtMs(client.p95).padStart(7)} p99 ${fmtMs(client.p99).padStart(7)} errors ${client.error_rate_pct.toFixed(2)}% (${client.errors}/${client.sent}: ${client.non2xx} non-2xx, ${client.timeouts} timeouts, ${client.network} network) achieved ${client.rps_achieved} rps of ${rps}`);
18282
+ log3(` ${import_chalk70.default.bold("client ")} p50 ${fmtMs(client.p50).padStart(7)} p95 ${fmtMs(client.p95).padStart(7)} p99 ${fmtMs(client.p99).padStart(7)} errors ${client.error_rate_pct.toFixed(2)}% (${client.errors}/${client.sent}: ${client.non2xx} non-2xx, ${client.timeouts} timeouts, ${client.network} network) achieved ${client.rps_achieved} rps of ${rps}`);
18049
18283
  const gateway = ctrl.signal.aborted ? null : await readGateway(fixture.proxy, sent, ctrl.signal);
18050
18284
  if (gateway) {
18051
18285
  const extras = [
18052
18286
  gateway.kv_per_req !== void 0 ? `kv/req ${gateway.kv_per_req}` : "",
18053
18287
  gateway.redis_per_req !== void 0 ? `redis/req ${gateway.redis_per_req}` : ""
18054
18288
  ].filter(Boolean).join(" ");
18055
- log3(` ${import_chalk69.default.bold("gateway")} p50 ${fmtMs(gateway.p50).padStart(7)} p95 ${fmtMs(gateway.p95).padStart(7)}${gateway.p99 !== void 0 ? ` p99 ${fmtMs(gateway.p99).padStart(7)}` : ""} ${import_chalk69.default.dim(`(${gateway.requests} ledger rows${extras ? `, ${extras}` : ""})`)}`);
18056
- for (const b of gateway.blame ?? []) log3(import_chalk69.default.dim(` ${(b.share * 100).toFixed(1).padStart(5)}% p95 ${fmtMs(b.p95_ms).padStart(6)} ${b.feature} \u2192 ${b.dep}`));
18289
+ log3(` ${import_chalk70.default.bold("gateway")} p50 ${fmtMs(gateway.p50).padStart(7)} p95 ${fmtMs(gateway.p95).padStart(7)}${gateway.p99 !== void 0 ? ` p99 ${fmtMs(gateway.p99).padStart(7)}` : ""} ${import_chalk70.default.dim(`(${gateway.requests} ledger rows${extras ? `, ${extras}` : ""})`)}`);
18290
+ for (const b of gateway.blame ?? []) log3(import_chalk70.default.dim(` ${(b.share * 100).toFixed(1).padStart(5)}% p95 ${fmtMs(b.p95_ms).padStart(6)} ${b.feature} \u2192 ${b.dep}`));
18057
18291
  } else {
18058
- log3(` ${import_chalk69.default.bold("gateway")} ${import_chalk69.default.yellow("not available")} ${import_chalk69.default.dim("(gateway thresholds not evaluated)")}`);
18292
+ log3(` ${import_chalk70.default.bold("gateway")} ${import_chalk70.default.yellow("not available")} ${import_chalk70.default.dim("(gateway thresholds not evaluated)")}`);
18059
18293
  }
18060
18294
  const breaches = evaluate(client, gateway, thresholds);
18061
18295
  const aborted = ctrl.signal.aborted;
@@ -18063,7 +18297,7 @@ async function runOpPerf(o = {}) {
18063
18297
  log3("");
18064
18298
  const row = (metric, value, limit, unit) => {
18065
18299
  const hit = breaches.find((b) => b.metric === metric);
18066
- log3(`[${hit ? import_chalk69.default.red("FAIL") : import_chalk69.default.green("PASS")}] ${metric.padEnd(11)} ${String(value)}${unit} ${hit ? ">" : "\u2264"} ${limit}${unit}`);
18300
+ log3(`[${hit ? import_chalk70.default.red("FAIL") : import_chalk70.default.green("PASS")}] ${metric.padEnd(11)} ${String(value)}${unit} ${hit ? ">" : "\u2264"} ${limit}${unit}`);
18067
18301
  };
18068
18302
  row("client_p50", client.p50, thresholds.p50_ms, "ms");
18069
18303
  row("client_p95", client.p95, thresholds.p95_ms, "ms");
@@ -18072,12 +18306,12 @@ async function runOpPerf(o = {}) {
18072
18306
  row("gateway_p50", gateway.p50, thresholds.gateway_p50_ms, "ms");
18073
18307
  row("gateway_p95", gateway.p95, thresholds.gateway_p95_ms, "ms");
18074
18308
  } else {
18075
- log3(`[${import_chalk69.default.yellow("SKIP")}] gateway_p50 / gateway_p95 \u2014 ledger rows not available`);
18309
+ log3(`[${import_chalk70.default.yellow("SKIP")}] gateway_p50 / gateway_p95 \u2014 ledger rows not available`);
18076
18310
  }
18077
18311
  log3("");
18078
- if (aborted) log3(import_chalk69.default.red(`FAIL \u2014 interrupted after ${sent}/${total} requests`));
18079
- else if (ok) log3(import_chalk69.default.green(`PASS \u2014 ${client.sent} requests at ${client.rps_achieved} rps, no threshold breached`));
18080
- else log3(import_chalk69.default.red(`FAIL \u2014 ${breaches.length} threshold(s) breached: ${breaches.map((b) => `${b.metric} ${b.value} > ${b.limit}`).join(", ")}`));
18312
+ if (aborted) log3(import_chalk70.default.red(`FAIL \u2014 interrupted after ${sent}/${total} requests`));
18313
+ else if (ok) log3(import_chalk70.default.green(`PASS \u2014 ${client.sent} requests at ${client.rps_achieved} rps, no threshold breached`));
18314
+ else log3(import_chalk70.default.red(`FAIL \u2014 ${breaches.length} threshold(s) breached: ${breaches.map((b) => `${b.metric} ${b.value} > ${b.limit}`).join(", ")}`));
18081
18315
  if (o.json) {
18082
18316
  const doc = {
18083
18317
  kind: "perf",
@@ -18115,9 +18349,9 @@ async function runOpPerf(o = {}) {
18115
18349
  if (fixture.provisioned) {
18116
18350
  try {
18117
18351
  await runnerCall({ action: "perf-teardown", proxy: fixture.proxy }, 120);
18118
- log3(import_chalk69.default.dim(`fixture ${fixture.proxy} torn down`));
18352
+ log3(import_chalk70.default.dim(`fixture ${fixture.proxy} torn down`));
18119
18353
  } catch (e) {
18120
- log3(import_chalk69.default.red(`teardown of ${fixture.proxy} failed: ${e instanceof Error ? e.message : String(e)} \u2014 run \`apiblaze op residue\` / clean the sandbox`));
18354
+ log3(import_chalk70.default.red(`teardown of ${fixture.proxy} failed: ${e instanceof Error ? e.message : String(e)} \u2014 run \`apiblaze op residue\` / clean the sandbox`));
18121
18355
  process.exitCode = 1;
18122
18356
  }
18123
18357
  await scrubSandboxKeys(120);
@@ -18167,79 +18401,79 @@ var OP_COMMANDS = [
18167
18401
  function renderOpCommands() {
18168
18402
  const width = Math.max(...OP_COMMANDS.map((c) => c.cmd.length)) + 10;
18169
18403
  const lines = OP_COMMANDS.map((c) => {
18170
- const left = ` ${import_chalk71.default.cyan(`apiblaze ${c.cmd}`)}`;
18404
+ const left = ` ${import_chalk72.default.cyan(`apiblaze ${c.cmd}`)}`;
18171
18405
  const pad = " ".repeat(Math.max(1, width - c.cmd.length));
18172
- return `${left}${pad}${c.blurb}${c.extra ? " " + import_chalk71.default.dim(`(${c.extra})`) : ""}`;
18406
+ return `${left}${pad}${c.blurb}${c.extra ? " " + import_chalk72.default.dim(`(${c.extra})`) : ""}`;
18173
18407
  });
18174
18408
  return [
18175
- import_chalk71.default.bold("Operator commands"),
18409
+ import_chalk72.default.bold("Operator commands"),
18176
18410
  ...lines,
18177
18411
  "",
18178
- import_chalk71.default.dim(" Operators only. The gate is server-side (dashboard /api/cli/op checks the"),
18179
- import_chalk71.default.dim(" signed-in email, admin-api re-checks with operatorGate) \u2014 a patched CLI just"),
18180
- import_chalk71.default.dim(" gets 403s. Every op call is read-only except `op sweep`."),
18412
+ import_chalk72.default.dim(" Operators only. The gate is server-side (dashboard /api/cli/op checks the"),
18413
+ import_chalk72.default.dim(" signed-in email, admin-api re-checks with operatorGate) \u2014 a patched CLI just"),
18414
+ import_chalk72.default.dim(" gets 403s. Every op call is read-only except `op sweep`."),
18181
18415
  "",
18182
- import_chalk71.default.dim(" Not a CLI command: to prune all non-CP data run scripts/nuke-but-cp.sh --apply --sweep"),
18183
- import_chalk71.default.dim(" in the repo. Wallet and incident MUTATIONS are dashboard-only (/operator/wallets/<id>,"),
18184
- import_chalk71.default.dim(" /operator/incident) \u2014 they need a typed reason and an audit row. Billing conformance"),
18185
- import_chalk71.default.dim(" (every door metered, 1 request = 1 charge) runs inside `op test`. Operator dashboards"),
18186
- import_chalk71.default.dim(" (dlq, thresholds, limits, pricing, agent-spend, teams, tests, leak-detection,"),
18187
- import_chalk71.default.dim(" lifecycle) live at /operator/* in the app.")
18416
+ import_chalk72.default.dim(" Not a CLI command: to prune all non-CP data run scripts/nuke-but-cp.sh --apply --sweep"),
18417
+ import_chalk72.default.dim(" in the repo. Wallet and incident MUTATIONS are dashboard-only (/operator/wallets/<id>,"),
18418
+ import_chalk72.default.dim(" /operator/incident) \u2014 they need a typed reason and an audit row. Billing conformance"),
18419
+ import_chalk72.default.dim(" (every door metered, 1 request = 1 charge) runs inside `op test`. Operator dashboards"),
18420
+ import_chalk72.default.dim(" (dlq, thresholds, limits, pricing, agent-spend, teams, tests, leak-detection,"),
18421
+ import_chalk72.default.dim(" lifecycle) live at /operator/* in the app.")
18188
18422
  ].join("\n");
18189
18423
  }
18190
18424
  function printResidue(report, applied) {
18191
18425
  const fga = report?.fga ?? {};
18192
18426
  const ghosts = report?.ghosts ?? {};
18193
- console.log(import_chalk71.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
18194
- console.log(import_chalk71.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
18427
+ console.log(import_chalk72.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
18428
+ console.log(import_chalk72.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
18195
18429
  if (applied) {
18196
18430
  const swept = fga?.swept ?? [];
18197
- if (swept.length === 0) console.log(import_chalk71.default.green(" no orphaned stores"));
18431
+ if (swept.length === 0) console.log(import_chalk72.default.green(" no orphaned stores"));
18198
18432
  for (const s of swept) {
18199
18433
  console.log(
18200
- ` ${import_chalk71.default.yellow(s.store_id)} ${import_chalk71.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
18434
+ ` ${import_chalk72.default.yellow(s.store_id)} ${import_chalk72.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
18201
18435
  );
18202
18436
  }
18203
- if (fga?.remaining) console.log(import_chalk71.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
18437
+ if (fga?.remaining) console.log(import_chalk72.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
18204
18438
  const st = fga?.side_tables;
18205
- if (st) console.log(import_chalk71.default.dim(` Neon side-tables purged: ${st.soft_deleted_stores} store records, ${st.orphan_models} models, ${st.orphan_changelog} changelog rows${st.error ? ` (${st.error})` : ""}`));
18439
+ if (st) console.log(import_chalk72.default.dim(` Neon side-tables purged: ${st.soft_deleted_stores} store records, ${st.orphan_models} models, ${st.orphan_changelog} changelog rows${st.error ? ` (${st.error})` : ""}`));
18206
18440
  } else {
18207
18441
  const fgaOrphans = fga?.orphans ?? [];
18208
- if (fgaOrphans.length === 0) console.log(import_chalk71.default.green(" no orphaned stores"));
18442
+ if (fgaOrphans.length === 0) console.log(import_chalk72.default.green(" no orphaned stores"));
18209
18443
  for (const s of fgaOrphans) {
18210
18444
  const src = s.in_openfga ? "live in OpenFGA" : "Neon tuples only";
18211
- console.log(` ${import_chalk71.default.yellow(s.store_id)} ${import_chalk71.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
18445
+ console.log(` ${import_chalk72.default.yellow(s.store_id)} ${import_chalk72.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
18212
18446
  }
18213
- console.log(import_chalk71.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
18447
+ console.log(import_chalk72.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
18214
18448
  const st = fga?.side_tables;
18215
- if (st) console.log(import_chalk71.default.dim(` Neon side-table residue: ${st.soft_deleted_stores} soft-deleted store records, ${st.orphan_models} orphan models, ${st.orphan_changelog} orphan changelog rows`));
18449
+ if (st) console.log(import_chalk72.default.dim(` Neon side-table residue: ${st.soft_deleted_stores} soft-deleted store records, ${st.orphan_models} orphan models, ${st.orphan_changelog} orphan changelog rows`));
18216
18450
  }
18217
- for (const e of fga?.errors ?? []) console.log(import_chalk71.default.red(` error: ${e}`));
18218
- console.log(import_chalk71.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
18451
+ for (const e of fga?.errors ?? []) console.log(import_chalk72.default.red(` error: ${e}`));
18452
+ console.log(import_chalk72.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
18219
18453
  if (applied) {
18220
- if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk71.default.green(" no ghost tuples"));
18221
- else console.log(` ${import_chalk71.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk71.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
18454
+ if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk72.default.green(" no ghost tuples"));
18455
+ else console.log(` ${import_chalk72.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk72.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
18222
18456
  } else {
18223
18457
  const n = ghosts?.ghost_count ?? 0;
18224
- if (n === 0) console.log(import_chalk71.default.green(` no ghost tuples ${import_chalk71.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
18458
+ if (n === 0) console.log(import_chalk72.default.green(` no ghost tuples ${import_chalk72.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
18225
18459
  else {
18226
- console.log(import_chalk71.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
18460
+ console.log(import_chalk72.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
18227
18461
  for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
18228
- console.log(import_chalk71.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
18462
+ console.log(import_chalk72.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
18229
18463
  }
18230
- if (n > 20) console.log(import_chalk71.default.dim(` \u2026 and ${n - 20} more`));
18464
+ if (n > 20) console.log(import_chalk72.default.dim(` \u2026 and ${n - 20} more`));
18231
18465
  }
18232
18466
  }
18233
- for (const e of ghosts?.errors ?? []) console.log(import_chalk71.default.red(` error: ${e}`));
18467
+ for (const e of ghosts?.errors ?? []) console.log(import_chalk72.default.red(` error: ${e}`));
18234
18468
  console.log();
18235
18469
  }
18236
18470
  async function runOp(sub, opts = {}, view, arg) {
18237
18471
  if (!loadCredentials()) {
18238
- console.log(import_chalk71.default.dim("Not logged in. Run `apiblaze login`."));
18472
+ console.log(import_chalk72.default.dim("Not logged in. Run `apiblaze login`."));
18239
18473
  return;
18240
18474
  }
18241
18475
  if (!isOperatorLogin()) {
18242
- console.log(import_chalk71.default.dim("`apiblaze op` is only available to platform operators."));
18476
+ console.log(import_chalk72.default.dim("`apiblaze op` is only available to platform operators."));
18243
18477
  return;
18244
18478
  }
18245
18479
  switch (sub) {
@@ -18308,11 +18542,11 @@ async function runOp(sub, opts = {}, view, arg) {
18308
18542
  }
18309
18543
  if (opts.json) return void console.log(JSON.stringify(out, null, 2));
18310
18544
  console.log("");
18311
- console.log(` Minimum CLI version: ${import_chalk71.default.bold(out.min_version)}${out.min_version === "0.0.0" ? import_chalk71.default.dim(" (no minimum)") : ""}`);
18312
- console.log(` Refuse unversioned: ${out.reject_unversioned ? import_chalk71.default.yellow("yes \u2014 CLIs released before 2026-09-27 get a 426 (cheap refusals; they keep retrying)") : "no"}`);
18313
- console.log(` Message: ${out.message ?? import_chalk71.default.dim("(default)")}`);
18314
- if (out.updated_at) console.log(import_chalk71.default.dim(` Updated ${out.updated_at}${out.updated_by ? ` by ${out.updated_by}` : ""}`));
18315
- console.log(import_chalk71.default.dim(" Takes effect within ~1 minute on the CLI lane; running `dev` sessions re-check every 10 minutes."));
18545
+ console.log(` Minimum CLI version: ${import_chalk72.default.bold(out.min_version)}${out.min_version === "0.0.0" ? import_chalk72.default.dim(" (no minimum)") : ""}`);
18546
+ console.log(` Refuse unversioned: ${out.reject_unversioned ? import_chalk72.default.yellow("yes \u2014 CLIs released before 2026-09-27 get a 426 (cheap refusals; they keep retrying)") : "no"}`);
18547
+ console.log(` Message: ${out.message ?? import_chalk72.default.dim("(default)")}`);
18548
+ if (out.updated_at) console.log(import_chalk72.default.dim(` Updated ${out.updated_at}${out.updated_by ? ` by ${out.updated_by}` : ""}`));
18549
+ console.log(import_chalk72.default.dim(" Takes effect within ~1 minute on the CLI lane; running `dev` sessions re-check every 10 minutes."));
18316
18550
  console.log("");
18317
18551
  return;
18318
18552
  }
@@ -18330,17 +18564,17 @@ async function runOp(sub, opts = {}, view, arg) {
18330
18564
  const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
18331
18565
  printResidue(report, false);
18332
18566
  if (nFga + nGhost + nSide === 0) {
18333
- console.log(import_chalk71.default.green("Nothing to sweep."));
18567
+ console.log(import_chalk72.default.green("Nothing to sweep."));
18334
18568
  return;
18335
18569
  }
18336
18570
  if (!opts.yes) {
18337
18571
  const readline3 = await import("readline/promises");
18338
18572
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
18339
18573
  const answer = await rl.question(
18340
- import_chalk71.default.red(`Delete ${nFga} OpenFGA store(s) + ${nGhost} ghost tuple(s) + ${nSide} Neon side-table row(s)? Type 'sweep' to confirm: `)
18574
+ import_chalk72.default.red(`Delete ${nFga} OpenFGA store(s) + ${nGhost} ghost tuple(s) + ${nSide} Neon side-table row(s)? Type 'sweep' to confirm: `)
18341
18575
  );
18342
18576
  rl.close();
18343
- if (answer.trim() !== "sweep") return void console.log(import_chalk71.default.dim("Aborted."));
18577
+ if (answer.trim() !== "sweep") return void console.log(import_chalk72.default.dim("Aborted."));
18344
18578
  }
18345
18579
  const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
18346
18580
  if (opts.json) return void console.log(JSON.stringify(result, null, 2));
@@ -18350,15 +18584,15 @@ async function runOp(sub, opts = {}, view, arg) {
18350
18584
  case "mark": {
18351
18585
  const label3 = (view ?? "").trim();
18352
18586
  if (!label3) {
18353
- console.log(import_chalk71.default.red("Give the change a name:") + import_chalk71.default.cyan(' apiblaze op mark "cached tenant count"'));
18587
+ console.log(import_chalk72.default.red("Give the change a name:") + import_chalk72.default.cyan(' apiblaze op mark "cached tenant count"'));
18354
18588
  return;
18355
18589
  }
18356
18590
  const res = await opCall({ method: "POST", path: "/operator/latency/mark", body: { label: label3 }, summary: "record change marker" });
18357
18591
  const ts2 = new Date(res?.marker?.ts ?? Date.now()).toISOString();
18358
- console.log(import_chalk71.default.green(`
18359
- Marked: `) + import_chalk71.default.bold(label3));
18360
- console.log(import_chalk71.default.dim(` ${ts2}`));
18361
- console.log(import_chalk71.default.dim(` Once traffic has run on both sides, compare with: `) + import_chalk71.default.cyan("apiblaze op latency compare") + "\n");
18592
+ console.log(import_chalk72.default.green(`
18593
+ Marked: `) + import_chalk72.default.bold(label3));
18594
+ console.log(import_chalk72.default.dim(` ${ts2}`));
18595
+ console.log(import_chalk72.default.dim(` Once traffic has run on both sides, compare with: `) + import_chalk72.default.cyan("apiblaze op latency compare") + "\n");
18362
18596
  return;
18363
18597
  }
18364
18598
  // ── MONEY (specs/TQC §11 "Operator console") — commands/op-money.ts ────
@@ -18369,14 +18603,14 @@ async function runOp(sub, opts = {}, view, arg) {
18369
18603
  if (which === "list") return void await opWalletList(opts);
18370
18604
  if (which === "inspect") return void await opWalletInspect(arg, opts);
18371
18605
  if (which in WALLET_MUTATIONS) return void opWalletMutation(which, arg, opts);
18372
- return void console.log(import_chalk71.default.red(`Unknown: apiblaze op wallet ${which}. Use list | inspect <wallet> | ${Object.keys(WALLET_MUTATIONS).join(" | ")}.`));
18606
+ return void console.log(import_chalk72.default.red(`Unknown: apiblaze op wallet ${which}. Use list | inspect <wallet> | ${Object.keys(WALLET_MUTATIONS).join(" | ")}.`));
18373
18607
  }
18374
18608
  case "money": {
18375
18609
  const which = (view ?? "").trim().toLowerCase();
18376
18610
  if (which === "exposure") return void await opMoneyExposure(opts);
18377
18611
  if (which === "journal") return void await opLedgerShow(arg, opts);
18378
18612
  process.exitCode = 1;
18379
- return void console.log(import_chalk71.default.red(`Unknown: apiblaze op money ${which}. Use exposure; the money ledger is`) + import_chalk71.default.cyan(" apiblaze op ledger show <wallet> | lag") + import_chalk71.default.red("."));
18613
+ return void console.log(import_chalk72.default.red(`Unknown: apiblaze op money ${which}. Use exposure; the money ledger is`) + import_chalk72.default.cyan(" apiblaze op ledger show <wallet> | lag") + import_chalk72.default.red("."));
18380
18614
  }
18381
18615
  // ── MONEY LEDGER (specs/noreconciliations.MD §6/§7) — commands/op-ledger.ts ──
18382
18616
  case "ledger": {
@@ -18387,20 +18621,20 @@ async function runOp(sub, opts = {}, view, arg) {
18387
18621
  if (which === "cut") return void await opLedgerCut(arg, opts);
18388
18622
  if (which === "backfill") return void await opLedgerBackfill(opts);
18389
18623
  process.exitCode = 1;
18390
- return void console.log(import_chalk71.default.red(`Unknown: apiblaze op ledger ${which}. Use show <wallet> | lag | quarantine | cut <wallet> | backfill --since <ISO|ms>.`));
18624
+ return void console.log(import_chalk72.default.red(`Unknown: apiblaze op ledger ${which}. Use show <wallet> | lag | quarantine | cut <wallet> | backfill --since <ISO|ms>.`));
18391
18625
  }
18392
18626
  // ── MAXIMUM RATE (project ceiling) requests — commands/op-ceiling.ts ──
18393
18627
  case "ceiling": {
18394
18628
  const which = (view ?? "list").trim().toLowerCase();
18395
18629
  if (which === "list") return void await opCeilingList(opts);
18396
18630
  if (which === "approve" || which === "deny") return void await opCeilingDecide(which, arg, opts);
18397
- return void console.log(import_chalk71.default.red(`Unknown: apiblaze op ceiling ${which}. Use list | approve <id> | deny <id> --note "why".`));
18631
+ return void console.log(import_chalk72.default.red(`Unknown: apiblaze op ceiling ${which}. Use list | approve <id> | deny <id> --note "why".`));
18398
18632
  }
18399
18633
  case "incident": {
18400
18634
  const which = (view ?? "status").trim().toLowerCase();
18401
18635
  if (which === "status" || which === "degraded-mode") return void await opIncidentStatus(opts);
18402
18636
  if (which === "allow" || which === "deny" || which === "extend") return void opIncidentMutation(which, opts);
18403
- return void console.log(import_chalk71.default.red(`Unknown: apiblaze op incident ${which}. Use status | allow | deny | extend.`));
18637
+ return void console.log(import_chalk72.default.red(`Unknown: apiblaze op incident ${which}. Use status | allow | deny | extend.`));
18404
18638
  }
18405
18639
  // ── LATENCY (specs/latency/ §7.4) ─────────────────────────────────────
18406
18640
  // The blame table first: level 1 (which feature) and level 2 (what inside
@@ -18450,29 +18684,29 @@ async function runOp(sub, opts = {}, view, arg) {
18450
18684
  const data = await opCall({ method: "GET", path: `/operator/latency/grades${q}`, summary: "latency grades" });
18451
18685
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
18452
18686
  const t = data.thresholds_ms;
18453
- console.log(import_chalk71.default.bold("\nHow good was apiblaze itself?") + import_chalk71.default.dim(" (our overhead only \u2014 a slow customer API never counts against us)"));
18454
- console.log(import_chalk71.default.dim(` excellent <${t.excellent.replace("<", "")}ms \xB7 okay ${t.okay}ms \xB7 bad ${t.bad}ms \xB7 terrible ${t.terrible.replace(">=", "")}ms+
18687
+ console.log(import_chalk72.default.bold("\nHow good was apiblaze itself?") + import_chalk72.default.dim(" (our overhead only \u2014 a slow customer API never counts against us)"));
18688
+ console.log(import_chalk72.default.dim(` excellent <${t.excellent.replace("<", "")}ms \xB7 okay ${t.okay}ms \xB7 bad ${t.bad}ms \xB7 terrible ${t.terrible.replace(">=", "")}ms+
18455
18689
  `));
18456
- console.log(import_chalk71.default.dim(" date reqs excellent okay bad terrible"));
18690
+ console.log(import_chalk72.default.dim(" date reqs excellent okay bad terrible"));
18457
18691
  for (const d of data.days ?? []) {
18458
18692
  const p = d.pct;
18459
- const cell = (v, colour) => v > 0 ? colour(`${String(v).padStart(5)}%`) : import_chalk71.default.dim(`${String(v).padStart(5)}%`);
18693
+ const cell = (v, colour) => v > 0 ? colour(`${String(v).padStart(5)}%`) : import_chalk72.default.dim(`${String(v).padStart(5)}%`);
18460
18694
  console.log(
18461
- ` ${d.date} ${String(d.total).padStart(5)} ${cell(p.excellent, import_chalk71.default.green)} ${cell(p.okay, import_chalk71.default.cyan)} ${cell(p.bad, import_chalk71.default.yellow)} ${cell(p.terrible, import_chalk71.default.red)}`
18695
+ ` ${d.date} ${String(d.total).padStart(5)} ${cell(p.excellent, import_chalk72.default.green)} ${cell(p.okay, import_chalk72.default.cyan)} ${cell(p.bad, import_chalk72.default.yellow)} ${cell(p.terrible, import_chalk72.default.red)}`
18462
18696
  );
18463
18697
  }
18464
18698
  const cul = data.culprits ?? [];
18465
18699
  if (cul.length) {
18466
- console.log(import_chalk71.default.bold("\n Who caused the bad and terrible ones\n"));
18467
- console.log(import_chalk71.default.dim(" bad terrible feature \u2192 dependency"));
18700
+ console.log(import_chalk72.default.bold("\n Who caused the bad and terrible ones\n"));
18701
+ console.log(import_chalk72.default.dim(" bad terrible feature \u2192 dependency"));
18468
18702
  for (const r of cul.slice(0, 12)) {
18469
18703
  if (!r.bad && !r.terrible) continue;
18470
18704
  console.log(
18471
- ` ${String(r.bad).padStart(6)} ${import_chalk71.default.red(String(r.terrible).padStart(8))} ${import_chalk71.default.yellow(r.feature)} ${import_chalk71.default.dim("\u2192")} ${import_chalk71.default.cyan(r.dep)}`
18705
+ ` ${String(r.bad).padStart(6)} ${import_chalk72.default.red(String(r.terrible).padStart(8))} ${import_chalk72.default.yellow(r.feature)} ${import_chalk72.default.dim("\u2192")} ${import_chalk72.default.cyan(r.dep)}`
18472
18706
  );
18473
18707
  }
18474
18708
  }
18475
- if (data.caveat) console.log(import_chalk71.default.dim(`
18709
+ if (data.caveat) console.log(import_chalk72.default.dim(`
18476
18710
  \u26A0 ${data.caveat}
18477
18711
  `));
18478
18712
  return;
@@ -18481,24 +18715,24 @@ async function runOp(sub, opts = {}, view, arg) {
18481
18715
  const data = await opCall({ method: "GET", path: `/operator/latency/compare${q}`, summary: "latency before/after" });
18482
18716
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
18483
18717
  const b = data.before, a = data.after, d = data.delta;
18484
- console.log(import_chalk71.default.bold(`
18485
- Before vs after: `) + import_chalk71.default.cyan(data.marker.label));
18486
- console.log(import_chalk71.default.dim(` marked ${new Date(data.marker.ts).toISOString()} \xB7 ${data.window_hours}h either side
18718
+ console.log(import_chalk72.default.bold(`
18719
+ Before vs after: `) + import_chalk72.default.cyan(data.marker.label));
18720
+ console.log(import_chalk72.default.dim(` marked ${new Date(data.marker.ts).toISOString()} \xB7 ${data.window_hours}h either side
18487
18721
  `));
18488
18722
  const row = (name, before, after, delta) => {
18489
18723
  const arrow = delta === 0 ? "=" : delta < 0 ? "\u2193" : "\u2191";
18490
18724
  const txt = `${String(before).padStart(6)}ms \u2192${String(after).padStart(7)}ms ${arrow}${Math.abs(delta)}ms`;
18491
- console.log(` ${name.padEnd(22)}${data.trustworthy ? delta <= 0 ? import_chalk71.default.green(txt) : import_chalk71.default.red(txt) : import_chalk71.default.dim(txt)}`);
18725
+ console.log(` ${name.padEnd(22)}${data.trustworthy ? delta <= 0 ? import_chalk72.default.green(txt) : import_chalk72.default.red(txt) : import_chalk72.default.dim(txt)}`);
18492
18726
  };
18493
- console.log(import_chalk71.default.dim(" metric before after change"));
18727
+ console.log(import_chalk72.default.dim(" metric before after change"));
18494
18728
  row("total p50", b.total_p50, a.total_p50, d.total_p50);
18495
18729
  row("total p95", b.total_p95, a.total_p95, d.total_p95);
18496
18730
  row("apiblaze overhead p50", b.gw_p50, a.gw_p50, d.gw_p50);
18497
18731
  row("apiblaze overhead p95", b.gw_p95, a.gw_p95, d.gw_p95);
18498
- console.log(import_chalk71.default.dim(`
18732
+ console.log(import_chalk72.default.dim(`
18499
18733
  requests: ${b.requests} before \xB7 ${a.requests} after`));
18500
18734
  for (const w of data.warnings ?? []) {
18501
- console.log((data.trustworthy ? import_chalk71.default.dim : import_chalk71.default.yellow)(` ${data.trustworthy ? "\xB7" : "\u26A0"} ${w}`));
18735
+ console.log((data.trustworthy ? import_chalk72.default.dim : import_chalk72.default.yellow)(` ${data.trustworthy ? "\xB7" : "\u26A0"} ${w}`));
18502
18736
  }
18503
18737
  console.log("");
18504
18738
  return;
@@ -18507,19 +18741,19 @@ Before vs after: `) + import_chalk71.default.cyan(data.marker.label));
18507
18741
  const data = await opCall({ method: "GET", path: `/operator/latency/slow${q}`, summary: "slowest requests" });
18508
18742
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
18509
18743
  const rows2 = data?.rows ?? [];
18510
- if (!rows2.length) return void console.log(import_chalk71.default.dim("No requests over the threshold in that window."));
18511
- console.log(import_chalk71.default.bold(`
18744
+ if (!rows2.length) return void console.log(import_chalk72.default.dim("No requests over the threshold in that window."));
18745
+ console.log(import_chalk72.default.bold(`
18512
18746
  Slowest requests \u2014 last ${data.window_hours}h, over ${data.min_ms}ms
18513
18747
  `));
18514
- console.log(import_chalk71.default.dim(" total ours theirs blame request id"));
18748
+ console.log(import_chalk72.default.dim(" total ours theirs blame request id"));
18515
18749
  for (const r of rows2.slice(0, 30)) {
18516
18750
  console.log(
18517
- ` ${String(Math.round(r.duration_ms)).padStart(6)} ${String(Math.round(r.gateway_ms)).padStart(5)} ${String(Math.round(r.upstream_ttfb_ms)).padStart(6)} ${import_chalk71.default.yellow(`${r.slow_gw_feature || "-"}\u2192${r.slow_dep || "-"}`.padEnd(20))} ${import_chalk71.default.dim(r.request_id || "")}`
18751
+ ` ${String(Math.round(r.duration_ms)).padStart(6)} ${String(Math.round(r.gateway_ms)).padStart(5)} ${String(Math.round(r.upstream_ttfb_ms)).padStart(6)} ${import_chalk72.default.yellow(`${r.slow_gw_feature || "-"}\u2192${r.slow_dep || "-"}`.padEnd(20))} ${import_chalk72.default.dim(r.request_id || "")}`
18518
18752
  );
18519
18753
  }
18520
- console.log(import_chalk71.default.dim(`
18754
+ console.log(import_chalk72.default.dim(`
18521
18755
  The last column is the request id (Cloudflare calls it a "cf-ray"). Look one up with`));
18522
- console.log(import_chalk71.default.dim(` \`apiblaze logs\` for that request's exact per-feature breakdown \u2014 unsampled, unlike the table above.
18756
+ console.log(import_chalk72.default.dim(` \`apiblaze logs\` for that request's exact per-feature breakdown \u2014 unsampled, unlike the table above.
18523
18757
  `));
18524
18758
  return;
18525
18759
  }
@@ -18527,18 +18761,18 @@ Slowest requests \u2014 last ${data.window_hours}h, over ${data.min_ms}ms
18527
18761
  const data = await opCall({ method: "GET", path: `/operator/latency/llm${q}`, summary: "llm latency" });
18528
18762
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
18529
18763
  const rows2 = data?.rows ?? [];
18530
- if (!rows2.length) return void console.log(import_chalk71.default.dim("No LLM traffic in that window."));
18531
- console.log(import_chalk71.default.bold(`
18764
+ if (!rows2.length) return void console.log(import_chalk72.default.dim("No LLM traffic in that window."));
18765
+ console.log(import_chalk72.default.bold(`
18532
18766
  LLM timing \u2014 last ${data.window_hours}h
18533
18767
  `));
18534
- console.log(import_chalk71.default.dim(" turns turn p95 ttfc p95 gen p95 reserve p95 in/out tokens p95 model"));
18768
+ console.log(import_chalk72.default.dim(" turns turn p95 ttfc p95 gen p95 reserve p95 in/out tokens p95 model"));
18535
18769
  for (const r of rows2) {
18536
18770
  const n = r.turns ?? r.requests ?? 0;
18537
18771
  console.log(
18538
18772
  ` ${String(Math.round(n)).padStart(8)} ${String(Math.round(r.turn_p95_ms ?? 0)).padStart(6)}ms ${String(Math.round(r.ttfc_p95_ms ?? 0)).padStart(6)}ms ${String(Math.round(r.gen_p95_ms ?? 0)).padStart(6)}ms ${String(Math.round(r.reserve_p95_ms ?? 0)).padStart(9)}ms ${String(Math.round(r.input_tokens_p95 ?? 0)).padStart(6)}/${String(Math.round(r.output_tokens_p95 ?? 0)).padEnd(6)} ${r.model || "-"}`
18539
18773
  );
18540
18774
  }
18541
- console.log(import_chalk71.default.dim(`
18775
+ console.log(import_chalk72.default.dim(`
18542
18776
  ${data.note}
18543
18777
  `));
18544
18778
  return;
@@ -18549,26 +18783,26 @@ LLM timing \u2014 last ${data.window_hours}h
18549
18783
  ]);
18550
18784
  if (opts.json) return void console.log(JSON.stringify({ blame, summary }, null, 2));
18551
18785
  const ov = summary?.apiblaze_overhead_ms ?? {};
18552
- console.log(import_chalk71.default.bold(`
18786
+ console.log(import_chalk72.default.bold(`
18553
18787
  Latency \u2014 last ${summary?.window_hours ?? "?"}h, ${Number(summary?.requests ?? 0).toLocaleString()} requests
18554
18788
  `));
18555
- console.log(` ${import_chalk71.default.bold("apiblaze overhead")} p50 ${String(ov.p50 ?? 0).padStart(5)}ms p95 ${String(ov.p95 ?? 0).padStart(6)}ms p99 ${String(ov.p99 ?? 0).padStart(6)}ms ${import_chalk71.default.dim("\u2190 ours")}`);
18556
- console.log(` ${import_chalk71.default.bold("upstream ttfb ")} ${" ".repeat(24)}p95 ${String(summary?.upstream_ttfb_p95_ms ?? 0).padStart(6)}ms ${import_chalk71.default.dim("\u2190 theirs")}`);
18557
- console.log(import_chalk71.default.dim(` (per-request percentiles \u2014 never subtract one from the other)
18789
+ console.log(` ${import_chalk72.default.bold("apiblaze overhead")} p50 ${String(ov.p50 ?? 0).padStart(5)}ms p95 ${String(ov.p95 ?? 0).padStart(6)}ms p99 ${String(ov.p99 ?? 0).padStart(6)}ms ${import_chalk72.default.dim("\u2190 ours")}`);
18790
+ console.log(` ${import_chalk72.default.bold("upstream ttfb ")} ${" ".repeat(24)}p95 ${String(summary?.upstream_ttfb_p95_ms ?? 0).padStart(6)}ms ${import_chalk72.default.dim("\u2190 theirs")}`);
18791
+ console.log(import_chalk72.default.dim(` (per-request percentiles \u2014 never subtract one from the other)
18558
18792
  `));
18559
18793
  const rows = blame?.blame ?? [];
18560
- if (!rows.length) return void console.log(import_chalk71.default.dim("No latency rows in that window."));
18561
- console.log(import_chalk71.default.bold(" Which feature ate the time, and what inside it\n"));
18562
- console.log(import_chalk71.default.dim(" share p95 feature \u2192 dependency"));
18794
+ if (!rows.length) return void console.log(import_chalk72.default.dim("No latency rows in that window."));
18795
+ console.log(import_chalk72.default.bold(" Which feature ate the time, and what inside it\n"));
18796
+ console.log(import_chalk72.default.dim(" share p95 feature \u2192 dependency"));
18563
18797
  for (const r of rows.slice(0, 15)) {
18564
18798
  const share = `${(r.share * 100).toFixed(1)}%`;
18565
- console.log(` ${share.padStart(6)} ${String(r.p95_ms).padStart(6)}ms ${import_chalk71.default.yellow(r.feature)} ${import_chalk71.default.dim("\u2192")} ${import_chalk71.default.cyan(r.dep)}`);
18799
+ console.log(` ${share.padStart(6)} ${String(r.p95_ms).padStart(6)}ms ${import_chalk72.default.yellow(r.feature)} ${import_chalk72.default.dim("\u2192")} ${import_chalk72.default.cyan(r.dep)}`);
18566
18800
  }
18567
18801
  console.log("");
18568
18802
  return;
18569
18803
  }
18570
18804
  default:
18571
- console.log(import_chalk71.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
18805
+ console.log(import_chalk72.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
18572
18806
  }
18573
18807
  }
18574
18808
  function printDistance(data) {
@@ -18576,17 +18810,17 @@ function printDistance(data) {
18576
18810
  const p = (v) => `${n(v).toFixed(1)}%`;
18577
18811
  const msf = (v) => `${Math.round(n(v))}ms`;
18578
18812
  const thr = n(data?.threshold_ms) || 50;
18579
- const scope = data?.team ? ` \xB7 team ${data.team}` : "";
18580
- console.log(import_chalk71.default.bold(`
18581
- Durable Object distance \u2014 last ${data?.window_hours ?? "?"}h${scope}, ${n(data?.total_requests).toLocaleString()} requests, ${n(data?.do_calls).toLocaleString()} DO calls
18813
+ const scope2 = data?.team ? ` \xB7 team ${data.team}` : "";
18814
+ console.log(import_chalk72.default.bold(`
18815
+ Durable Object distance \u2014 last ${data?.window_hours ?? "?"}h${scope2}, ${n(data?.total_requests).toLocaleString()} requests, ${n(data?.do_calls).toLocaleString()} DO calls
18582
18816
  `));
18583
18817
  console.log(
18584
- ` ${import_chalk71.default.bold(p(data?.requests_with_do_call_pct))} of requests made a Durable Object call; ${import_chalk71.default.bold(p(data?.far_pct))} of those crossed colos; ${import_chalk71.default.bold((n(data?.problem_pct?.of_all_requests) >= 1 ? import_chalk71.default.red : import_chalk71.default.green)(p(data?.problem_pct?.of_all_requests)))} of all requests paid > ${thr} ms of distance.`
18818
+ ` ${import_chalk72.default.bold(p(data?.requests_with_do_call_pct))} of requests made a Durable Object call; ${import_chalk72.default.bold(p(data?.far_pct))} of those crossed colos; ${import_chalk72.default.bold((n(data?.problem_pct?.of_all_requests) >= 1 ? import_chalk72.default.red : import_chalk72.default.green)(p(data?.problem_pct?.of_all_requests)))} of all requests paid > ${thr} ms of distance.`
18585
18819
  );
18586
- console.log(import_chalk71.default.dim(` (${p(data?.problem_pct?.of_do_calls)} of DO calls over ${thr} ms network \xB7 entry or object colo unknown on ${p(data?.unknown_pct)} of calls)
18820
+ console.log(import_chalk72.default.dim(` (${p(data?.problem_pct?.of_do_calls)} of DO calls over ${thr} ms network \xB7 entry or object colo unknown on ${p(data?.unknown_pct)} of calls)
18587
18821
  `));
18588
18822
  const nm = data?.network_ms ?? {};
18589
- console.log(import_chalk71.default.dim(" network ms calls p50 p95 p99 >thr"));
18823
+ console.log(import_chalk72.default.dim(" network ms calls p50 p95 p99 >thr"));
18590
18824
  const line = (label3, r) => {
18591
18825
  if (!r) return;
18592
18826
  console.log(
@@ -18600,32 +18834,32 @@ Durable Object distance \u2014 last ${data?.window_hours ?? "?"}h${scope}, ${n(d
18600
18834
  line("kind: throttle", nm.throttle);
18601
18835
  const modes = data?.by_mode ?? [];
18602
18836
  if (modes.length) {
18603
- console.log(import_chalk71.default.dim("\n mode calls share p95 >thr"));
18837
+ console.log(import_chalk72.default.dim("\n mode calls share p95 >thr"));
18604
18838
  for (const m of modes) {
18605
18839
  console.log(` ${String(m.mode).padEnd(14)} ${String(n(m.calls).toLocaleString()).padStart(9)} ${p(m.share_pct).padStart(6)} ${msf(m.p95_ms).padStart(7)} ${String(n(m.problem_calls).toLocaleString()).padStart(5)}`);
18606
18840
  }
18607
18841
  }
18608
18842
  const routes = data?.routes ?? [];
18609
18843
  if (routes.length) {
18610
- console.log(import_chalk71.default.bold("\n Routes (worker colo \u2192 object colo)") + import_chalk71.default.dim(` added ms = network above the same-colo p50 (${msf(data?.same_colo_p50_baseline_ms)}), summed`));
18611
- console.log(import_chalk71.default.dim(" route calls p50 p95 added ms"));
18844
+ console.log(import_chalk72.default.bold("\n Routes (worker colo \u2192 object colo)") + import_chalk72.default.dim(` added ms = network above the same-colo p50 (${msf(data?.same_colo_p50_baseline_ms)}), summed`));
18845
+ console.log(import_chalk72.default.dim(" route calls p50 p95 added ms"));
18612
18846
  for (const r of routes) {
18613
18847
  const cross = r.worker_colo !== r.object_colo;
18614
18848
  const route = `${r.worker_colo} \u2192 ${r.object_colo}`;
18615
- console.log(` ${(cross ? import_chalk71.default.yellow : import_chalk71.default.dim)(route.padEnd(16))} ${String(n(r.calls).toLocaleString()).padStart(8)} ${msf(r.p50_ms).padStart(7)} ${msf(r.p95_ms).padStart(7)} ${String(n(r.added_ms_total).toLocaleString()).padStart(12)}`);
18849
+ console.log(` ${(cross ? import_chalk72.default.yellow : import_chalk72.default.dim)(route.padEnd(16))} ${String(n(r.calls).toLocaleString()).padStart(8)} ${msf(r.p50_ms).padStart(7)} ${msf(r.p95_ms).padStart(7)} ${String(n(r.added_ms_total).toLocaleString()).padStart(12)}`);
18616
18850
  }
18617
18851
  }
18618
18852
  const teams = data?.teams ?? [];
18619
18853
  if (teams.length) {
18620
- console.log(import_chalk71.default.bold(`
18854
+ console.log(import_chalk72.default.bold(`
18621
18855
  Teams paying the most distance (> ${thr} ms)`));
18622
- console.log(import_chalk71.default.dim(" >thr calls of calls object colo worker colos team"));
18856
+ console.log(import_chalk72.default.dim(" >thr calls of calls object colo worker colos team"));
18623
18857
  for (const t of teams) {
18624
18858
  const w = (t.top_worker_colos ?? []).map((x) => `${x.colo} ${n(x.problem_calls).toLocaleString()}`).join(", ");
18625
- console.log(` ${String(n(t.problem_calls).toLocaleString()).padStart(10)} ${p(t.problem_pct).padStart(8)} ${String(t.dominant_object_colo).padEnd(11)} ${w.padEnd(24)} ${import_chalk71.default.dim(t.team)}`);
18859
+ console.log(` ${String(n(t.problem_calls).toLocaleString()).padStart(10)} ${p(t.problem_pct).padStart(8)} ${String(t.dominant_object_colo).padEnd(11)} ${w.padEnd(24)} ${import_chalk72.default.dim(t.team)}`);
18626
18860
  }
18627
18861
  } else if (!n(data?.do_calls)) {
18628
- console.log(import_chalk71.default.dim("\n No Durable Object calls in that window (warm leases write no gate rows)."));
18862
+ console.log(import_chalk72.default.dim("\n No Durable Object calls in that window (warm leases write no gate rows)."));
18629
18863
  }
18630
18864
  console.log("");
18631
18865
  }
@@ -18691,7 +18925,7 @@ agent.command("authz").description("Chat to design and turn on access rules for
18691
18925
  program.command("rule").description("Lock resources to the person who created them \u2014 or describe any access rule in plain English (that one is billed per turn)").argument("<project>", "Project name or id").argument("[sentence]", 'Optional rule in plain English, e.g. "users see only their own rows". Omit to pick from what the spec can protect.').option("--enforce", "Turn enforcement on right after saving (default: save in shadow mode, then ask)").option("--apiversion <version>", "API version (defaults to the project's)").action(action((project, sentence, opts) => runRule(project, sentence, opts)));
18692
18926
  agent.command("openapi").description("Chat to build your API spec from real traffic").argument("<project>", "Project name or id").argument("[apiVersion]", "API version (defaults to the project's)").action(action((project, apiVersion) => runOpenapi(project, apiVersion)));
18693
18927
  agent.command("mcp").description("Chat to build an MCP server for an API").argument("<project>", "Project name or id").argument("[apiVersion]", "API version (defaults to the project's)").option("--environment <env>", "Environment to publish (default: prod)").action(action((project, apiVersion, opts) => runMcp(project, apiVersion, opts)));
18694
- var mcpCmd = program.command("mcp").description("Optional tweaks to a proxy's MCP server: prompts, per-tool behavior (read-only / destructive / confirm / always-async), UI resource");
18928
+ var mcpCmd = program.command("mcp").description("Optional tweaks to a proxy's MCP server: prompts, per-tool behavior (title / read-only / destructive / confirm / always-async), UI resource");
18695
18929
  var mcpCommon = (c) => c.option("--apiversion <version>", "API version (defaults to the project's)").option("--environment <env>", "Catalogue environment (default: prod)").option("--json", "Output machine-readable JSON");
18696
18930
  var mcpPrompts = mcpCmd.command("prompts").description("Prompts the MCP server offers (drafted by the MCP agent; editable here)");
18697
18931
  mcpCommon(mcpPrompts.command("list").description("List the prompts").argument("<project>", "Project name or id")).action(action((project, opts) => runMcpPrompts("list", project, void 0, opts)));
@@ -18700,7 +18934,7 @@ mcpCommon(mcpPrompts.command("set").description("Add or replace a prompt from a
18700
18934
  mcpCommon(mcpPrompts.command("rm").description("Remove a prompt").argument("<project>", "Project name or id").argument("<name>", "Prompt name")).action(action((project, name, opts) => runMcpPrompts("rm", project, name, opts)));
18701
18935
  var mcpOps = mcpCmd.command("ops").description("Per-tool behavior. Default from the HTTP method: GET/HEAD/OPTIONS read-only, PUT/DELETE idempotent, DELETE destructive + asks to confirm");
18702
18936
  mcpCommon(mcpOps.command("list").description("Every tool with its effective behavior (overrides marked)").argument("<project>", "Project name or id")).action(action((project, opts) => runMcpOps("list", project, void 0, opts)));
18703
- mcpCommon(mcpOps.command("set").description("Override one tool").argument("<project>", "Project name or id").argument("<tool>", "Tool name").option("--read-only", "Safe to call, changes nothing (e.g. a POST search)").option("--no-read-only", "Not read-only").option("--destructive", "Changes or deletes data (e.g. a GET with side effects)").option("--no-destructive", "Not destructive").option("--idempotent", "Repeating it has no extra effect").option("--no-idempotent", "Not idempotent").option("--confirm", "Ask the user to confirm before running").option("--no-confirm", "Never ask to confirm").option("--always-async", "Return a task handle immediately (long jobs)").option("--no-always-async", "Wait for the result (default)")).action(action((project, tool, opts) => runMcpOps("set", project, tool, opts)));
18937
+ mcpCommon(mcpOps.command("set").description("Override one tool").argument("<project>", "Project name or id").argument("<tool>", "Tool name").option("--title <text>", "Human label clients and directories show (default: the OpenAPI summary, else the name spelled out)").option("--read-only", "Safe to call, changes nothing (e.g. a POST search)").option("--no-read-only", "Not read-only").option("--destructive", "Changes or deletes data (e.g. a GET with side effects)").option("--no-destructive", "Not destructive").option("--idempotent", "Repeating it has no extra effect").option("--no-idempotent", "Not idempotent").option("--confirm", "Ask the user to confirm before running").option("--no-confirm", "Never ask to confirm").option("--always-async", "Return a task handle immediately (long jobs)").option("--no-always-async", "Wait for the result (default)")).action(action((project, tool, opts) => runMcpOps("set", project, tool, opts)));
18704
18938
  mcpCommon(mcpOps.command("reset").description("Back to the automatic default for one tool").argument("<project>", "Project name or id").argument("<tool>", "Tool name")).action(action((project, tool, opts) => runMcpOps("reset", project, tool, opts)));
18705
18939
  mcpCommon(mcpCmd.command("ui").description("Print a tool's MCP Apps UI resource (ui://{project}/{tool}) \u2014 the automatic viewer").argument("<project>", "Project name or id").argument("<tool>", "Tool name")).action(action((project, tool, opts) => runMcpUi(project, tool, opts)));
18706
18940
  program.command("apichat [project]").alias("chat").description("Turn any API into a chat: point at an OpenAPI spec \u2014 or chat an EXISTING proxy by name (no login needed)").option("--target <url|file>", "What to chat with \u2014 pass ANY of: a target server base URL (spec auto-discovered at /openapi.json etc.), a local OpenAPI file (./openapi.yaml), or a remote OpenAPI URL (https://acme.com/openapi.yaml)").addOption(new import_commander.Option("--openapi <file|url>", "Deprecated alias \u2014 --target now detects spec files/URLs itself").hideHelp()).addOption(new import_commander.Option("--openapispec <file|url>", "Deprecated alias for --openapi").hideHelp()).option("--name <name>", "Proxy name (defaults to the target host)").option("--apiversion <version>", "API version to create (e.g. 1.0.0)").option("--environment <env>", "Environment to chat against (default: prod anonymous / dev logged-in)").option("--access <mode>", 'Who can call this API once connected (e.g. via Claude): "open" = anyone who signs in, "invite" = only you + emails you pre-approve. Default: invite when logged in, open when anonymous.').option("--target-auth-env <ENV_VAR>", "Read the upstream credential from this env var (CI-safe; required when there is no TTY and the API needs auth)").option("--force", "Proceed even if the API uses oauth2/openIdConnect target auth (you configure target auth yourself later)").option("-y, --yes", "Skip confirmation prompts").option("--tenant <slug>", "Tenant (consumer namespace: portal, login, users) for the new proxy; omit to be asked").option("--apikey <key>", "Use this API key for the proxy's door (api_key proxies). Without it, apichat detects the door and asks \u2014 or runs the consumer login for OAuth doors.").option("--xenduserid <id>", "Assert this end-user id (X-End-User-Id) \u2014 required by proxies with identified/pre-approved enforcement; you are asked for one when the proxy demands it.").option("--verbose", "Show the per-turn proxy curl trace (hidden by default)").option("-p, --prompt <question>", "One-shot question: answered through the external agent CLI after an MCP install, or by apichat itself (exits after answering when there is no TTY)").option("--install-mcp <cli>", "Install this proxy's MCP into an external agent CLI without asking: claude | codex. Also re-offers after an earlier decline.").option("--remove-mcp <cli>", "Disconnect this proxy from an external agent CLI (claude | codex): removes the MCP server and the standing instruction").action(action((project, opts) => {
@@ -18724,7 +18958,7 @@ program.command("dev").description(`Put the app running on THIS machine on the i
18724
18958
  try {
18725
18959
  const resolved = parseInt(port ?? opts.port, 10);
18726
18960
  if (Number.isNaN(resolved)) {
18727
- console.error(import_chalk72.default.red(`Invalid port: ${port ?? opts.port}`));
18961
+ console.error(import_chalk73.default.red(`Invalid port: ${port ?? opts.port}`));
18728
18962
  process.exit(1);
18729
18963
  }
18730
18964
  await runDev({ ...opts, port: resolved });
@@ -18836,6 +19070,18 @@ program.command("preapprove").description("Allow an email or company domain to s
18836
19070
  var tenant = program.command("tenant").description("Manage tenants \u2014 bare command opens the interactive picker (settings, OAuth sign-in providers, app clients)").action(action(() => runTenantManage(void 0, {})));
18837
19071
  tenant.command("manage").description("Browse & edit one tenant: settings, OAuth sign-in providers (swap or add one \u2014 this is how you change sign-in after create), login app clients, issuers (search-first picker)").argument("[query]", "Search by tenant name/display name (omit to use your tenant scope or pick)").option("--tenant <slug>", "Exact tenant slug (skips the picker)").option("--team <id|name>", "Team (defaults to active team)").action(action((query, opts) => runTenantManage(query, opts)));
18838
19072
  tenant.command("use").description("Set the sticky tenant scope for future commands (search-first; --clear to unset)").argument("[query]", "Search by tenant name/display name").option("--clear", "Clear the tenant scope").option("--team <id|name>", "Team (defaults to active team)").action(action((query, opts) => runTenantUse(query, opts)));
19073
+ var tenantPassword = tenant.command("password").description("APIblaze-hosted username & password sign-in on a tenant (reviewer / test accounts; advanced)");
19074
+ var tenantArg = (cmd) => cmd.argument("[tenant]", "Tenant (defaults to your tenant scope, else a picker)").option("--tenant <slug>", "Same as the positional").option("--json", "Output machine-readable JSON");
19075
+ tenantArg(tenantPassword.command("enable").description("Add username & password sign-in to the tenant's login (idempotent)")).action(action((t, opts) => runTenantPasswordEnable(t, opts)));
19076
+ tenantArg(tenantPassword.command("disable").description("Remove username & password sign-in from the tenant (deletes its accounts)")).option("-y, --yes", "Skip the confirmation").action(action((t, opts) => runTenantPasswordDisable(t, opts)));
19077
+ tenantArg(tenantPassword.command("list").description("List the accounts")).action(action((t, opts) => runTenantPasswordList(t, opts)));
19078
+ var accountCmd = (name, desc) => tenantArg(tenantPassword.command(name).description(desc).argument("<username>", "3\u201364 chars: a\u2013z 0\u20139 . _ -"));
19079
+ accountCmd("add", "Create an account; the password is generated and printed once (or read from stdin with --password-stdin)").option("--email <email>", "Optional: lets a pre-provisioned user/admin with this address adopt the login").option("--display-name <name>", "Display name").option("--purpose <user|reviewer>", "`reviewer` marks a directory test account").option("--password-stdin", "Read the password from stdin instead of generating one").action(action((username, t, opts) => runTenantPasswordAdd(username, t, opts)));
19080
+ accountCmd("rotate", "New password (generated, printed once; or --password-stdin); existing sessions end at their next refresh").option("--password-stdin", "Read the new password from stdin").action(action((username, t, opts) => runTenantPasswordRotate(username, t, opts)));
19081
+ accountCmd("block", "Refuse sign-in for an account (keeps it)").action(action((username, t, opts) => runTenantPasswordSetBlocked(username, t, true, opts)));
19082
+ accountCmd("unblock", "Allow sign-in again").action(action((username, t, opts) => runTenantPasswordSetBlocked(username, t, false, opts)));
19083
+ accountCmd("unlock", "Clear the lockout after repeated failed sign-ins").action(action((username, t, opts) => runTenantPasswordUnlock(username, t, opts)));
19084
+ accountCmd("remove", "Delete an account").option("-y, --yes", "Skip the confirmation").action(action((username, t, opts) => runTenantPasswordRemove(username, t, opts)));
18839
19085
  tenant.command("list").description("List tenants in your team (--q searches server-side)").option("--q <search>", "Filter by tenant name or display name").option("--limit <n>", "Page size (max 200)").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Output machine-readable JSON").action(action((opts) => runTenantList(opts)));
18840
19086
  tenant.command("create").description("Create a tenant in your team (tenant names are lowercase alphanumeric and globally unique)").requiredOption("--name <name>", "Tenant name \u2014 becomes the slug ({name}.portal.apiblaze.com) unless --slug overrides; also the display label").option("--slug <tenant_name>", "Explicit tenant slug when it should differ from --name").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Output machine-readable JSON").action(action((opts) => runTenantCreate(opts)));
18841
19087
  tenant.command("attach").description("Attach a tenant to a proxy").argument("<project>", "Project name or id").requiredOption("--tenant <slug>", "Tenant slug to attach").option("--auth-config <id>", "Auth config id to bind").option("--no-login", "Do not give the tenant a dev-portal sign-in (by default it gets the zero-config GitHub one, unless it already has one)").option("--team <id|name>", "Team the project is in").option("--apiversion <version>", "API version").option("--json", "Output machine-readable JSON").action(action((project, opts) => runTenantAttach(project, opts)));
@@ -18894,7 +19140,7 @@ function groupedCommandHelp() {
18894
19140
  const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
18895
19141
  return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
18896
19142
  }).filter(Boolean).join("\n");
18897
- return `${import_chalk72.default.bold(g.title)}
19143
+ return `${import_chalk73.default.bold(g.title)}
18898
19144
  ${rows}`;
18899
19145
  }).join("\n\n");
18900
19146
  }
@@ -18907,7 +19153,7 @@ program.configureHelp({
18907
19153
  program.addHelpText("before", () => isBetaCached() ? `${betaNotice()}
18908
19154
  ` : "");
18909
19155
  program.addHelpText("after", () => `
18910
- ${import_chalk72.default.bold("Don't like reading docs?")} Run ${import_chalk72.default.bgCyan.black.bold(` npx ${B.cli} docs `)} ${import_chalk72.default.cyan(`\u2014 ask an AI chatbot about ${B.product}, and let it act on your account.`)}
19156
+ ${import_chalk73.default.bold("Don't like reading docs?")} Run ${import_chalk73.default.bgCyan.black.bold(` npx ${B.cli} docs `)} ${import_chalk73.default.cyan(`\u2014 ask an AI chatbot about ${B.product}, and let it act on your account.`)}
18911
19157
 
18912
19158
  ${groupedCommandHelp()}
18913
19159
 
@@ -18944,14 +19190,14 @@ async function recoverStaleTeam() {
18944
19190
  const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
18945
19191
  const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
18946
19192
  if (!linked) {
18947
- console.error(import_chalk72.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
19193
+ console.error(import_chalk73.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
18948
19194
  return;
18949
19195
  }
18950
19196
  if (linked.teamId === creds.teamId) return;
18951
19197
  const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
18952
19198
  delete next.activeTenant;
18953
19199
  saveCredentials(next);
18954
- console.error(import_chalk72.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk72.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
19200
+ console.error(import_chalk73.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk73.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
18955
19201
  } catch {
18956
19202
  }
18957
19203
  }
@@ -18963,28 +19209,28 @@ async function printError(err) {
18963
19209
  if (err instanceof ApiError) {
18964
19210
  const data = err.body;
18965
19211
  const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
18966
- console.error(import_chalk72.default.red(`
19212
+ console.error(import_chalk73.default.red(`
18967
19213
  API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
18968
19214
  if (err.status === 403 || err.status === 404) {
18969
19215
  await recoverStaleTeam();
18970
19216
  }
18971
19217
  } else if (err instanceof Error) {
18972
- console.error(import_chalk72.default.red(`
19218
+ console.error(import_chalk73.default.red(`
18973
19219
  Error: ${err.message}`));
18974
19220
  } else {
18975
- console.error(import_chalk72.default.red("\nUnknown error"));
19221
+ console.error(import_chalk73.default.red("\nUnknown error"));
18976
19222
  }
18977
19223
  }
18978
19224
  function hintStaleCacheOnUnknownOption(cmd) {
18979
19225
  cmd.exitOverride((err) => {
18980
19226
  if (err.code === "commander.unknownOption") {
18981
- console.error(import_chalk72.default.yellow(
19227
+ console.error(import_chalk73.default.yellow(
18982
19228
  `
18983
19229
  This is ${B.cli} v${version}. If that option is documented but this build
18984
19230
  does not have it, your npx cache is serving an older copy \u2014 re-run as:
18985
19231
  `
18986
19232
  ));
18987
- console.error(import_chalk72.default.cyan(` npx ${B.cli}@latest ${process.argv.slice(2).join(" ")}
19233
+ console.error(import_chalk73.default.cyan(` npx ${B.cli}@latest ${process.argv.slice(2).join(" ")}
18988
19234
  `));
18989
19235
  }
18990
19236
  process.exit(err.exitCode);