apiblaze 0.19.26 → 0.19.29

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 +1597 -608
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -237,7 +237,7 @@ var init_api = __esm({
237
237
  "use strict";
238
238
  init_auth();
239
239
  init_types();
240
- DASHBOARD_BASE = "https://dashboard.apiblaze.com";
240
+ DASHBOARD_BASE = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
241
241
  PUBLIC_API_BASE = "https://api.apiblaze.com";
242
242
  }
243
243
  });
@@ -272,14 +272,14 @@ async function resolveLinkedTeam(opts) {
272
272
  return { teamId: picked2.teamId, teamName: picked2.name };
273
273
  }
274
274
  if (opts.preferredId) {
275
- console.log(import_chalk.default.yellow("\nYour previously linked team is no longer available."));
275
+ console.error(import_chalk.default.yellow("\nYour previously linked team is no longer available."));
276
276
  }
277
277
  if (teams.length === 1) {
278
- console.log(`${import_chalk.default.cyan("\u2192")} Linking to your team ${import_chalk.default.bold(teams[0].name)}.`);
278
+ console.error(`${import_chalk.default.cyan("\u2192")} Linking to your team ${import_chalk.default.bold(teams[0].name)}.`);
279
279
  return { teamId: teams[0].teamId, teamName: teams[0].name };
280
280
  }
281
281
  if (!opts.interactive) {
282
- console.log(import_chalk.default.yellow(`Linking to "${teams[0].name}" \u2014 pass --team to choose another.`));
282
+ console.error(import_chalk.default.yellow(`Linking to "${teams[0].name}" \u2014 pass --team to choose another.`));
283
283
  return { teamId: teams[0].teamId, teamName: teams[0].name };
284
284
  }
285
285
  const { default: inquirer3 } = await import("inquirer");
@@ -392,24 +392,24 @@ function maskBody(body) {
392
392
  }
393
393
  function renderTrace() {
394
394
  if (!verbose || entries.length === 0) return;
395
- console.log(import_chalk6.default.dim("\n" + "\u2500".repeat(64)));
396
- console.log(import_chalk6.default.bold(`--verbose: ${entries.length} API call${entries.length === 1 ? "" : "s"} this command made`));
397
- console.log(
395
+ console.error(import_chalk6.default.dim("\n" + "\u2500".repeat(64)));
396
+ console.error(import_chalk6.default.bold(`--verbose: ${entries.length} API call${entries.length === 1 ? "" : "s"} this command made`));
397
+ console.error(
398
398
  import_chalk6.default.dim("The same thing on the official API \u2014 copy/paste with your control-plane key\n(get one from the Developers section of dashboard.apiblaze.com, then\n`export APIBLAZE_CONTROLPLANE_APIKEY=sk_...`).\nFull API reference: https://api.apiblaze.com/openapi.json\n")
399
399
  );
400
400
  entries.forEach((e, i) => {
401
401
  const n = entries.length > 1 ? import_chalk6.default.bold(`${i + 1}. `) : "";
402
- if (e.summary) console.log(`${n}${import_chalk6.default.cyan(e.summary)}${e.status ? import_chalk6.default.dim(` (HTTP ${e.status})`) : ""}`);
402
+ if (e.summary) console.error(`${n}${import_chalk6.default.cyan(e.summary)}${e.status ? import_chalk6.default.dim(` (HTTP ${e.status})`) : ""}`);
403
403
  const url = `https://api.apiblaze.com/${CONTROL_API_VERSION}/prod${e.path}`;
404
404
  const masked = maskBody(e.body);
405
405
  const hasBody = e.method !== "GET" && masked !== void 0;
406
- console.log(import_chalk6.default.green(` curl -sS -X ${e.method} ${url}` + (hasBody ? " \\" : "")));
407
- console.log(import_chalk6.default.green(' -H "X-API-Key: $APIBLAZE_CONTROLPLANE_APIKEY"' + (hasBody ? " \\" : "")));
406
+ console.error(import_chalk6.default.green(` curl -sS -X ${e.method} ${url}` + (hasBody ? " \\" : "")));
407
+ console.error(import_chalk6.default.green(' -H "X-API-Key: $APIBLAZE_CONTROLPLANE_APIKEY"' + (hasBody ? " \\" : "")));
408
408
  if (hasBody) {
409
- console.log(import_chalk6.default.green(" -H 'Content-Type: application/json' \\"));
410
- console.log(import_chalk6.default.green(` -d '${masked}'`));
409
+ console.error(import_chalk6.default.green(" -H 'Content-Type: application/json' \\"));
410
+ console.error(import_chalk6.default.green(` -d '${masked}'`));
411
411
  }
412
- if (i < entries.length - 1) console.log();
412
+ if (i < entries.length - 1) console.error();
413
413
  });
414
414
  entries.length = 0;
415
415
  }
@@ -458,7 +458,7 @@ function formatBilling(billing) {
458
458
  }
459
459
  function maybePrintBilling(data) {
460
460
  const line = formatBilling(data?.billing);
461
- if (line) console.log(import_chalk7.default.magenta(` ${line}`));
461
+ if (line) console.error(import_chalk7.default.magenta(` ${line}`));
462
462
  }
463
463
  var import_chalk7, DASHBOARD_BASE3;
464
464
  var init_admin = __esm({
@@ -476,7 +476,7 @@ var init_admin = __esm({
476
476
  function requireAuth() {
477
477
  const creds = loadCredentials();
478
478
  if (!creds) {
479
- console.error(import_chalk8.default.red("Not logged in. Run `apiblaze login` first."));
479
+ console.error(import_chalk9.default.red("Not logged in. Run `apiblaze login` first."));
480
480
  process.exit(1);
481
481
  }
482
482
  return creds;
@@ -485,7 +485,7 @@ async function resolveTeam(opt) {
485
485
  const creds = requireAuth();
486
486
  if (!opt) {
487
487
  if (!creds.teamId) {
488
- console.error(import_chalk8.default.red("No active team. Run `apiblaze login` or pass --team."));
488
+ console.error(import_chalk9.default.red("No active team. Run `apiblaze login` or pass --team."));
489
489
  process.exit(1);
490
490
  }
491
491
  return { teamId: creds.teamId, teamName: creds.teamName };
@@ -494,7 +494,7 @@ async function resolveTeam(opt) {
494
494
  const teams = await getTeams().catch(() => []);
495
495
  const match = teams.find((t) => t.name === opt || t.teamId === opt);
496
496
  if (!match) {
497
- console.error(import_chalk8.default.red(`Team "${opt}" not found.${teams.length ? " Available: " + teams.map((t) => t.name).join(", ") : ""}`));
497
+ console.error(import_chalk9.default.red(`Team "${opt}" not found.${teams.length ? " Available: " + teams.map((t) => t.name).join(", ") : ""}`));
498
498
  process.exit(1);
499
499
  }
500
500
  return { teamId: match.teamId, teamName: match.name };
@@ -505,13 +505,13 @@ async function resolveProject(teamId, nameOrId, version2) {
505
505
  (p) => p.projectId === nameOrId || p.projectName === nameOrId
506
506
  );
507
507
  if (candidates.length === 0) {
508
- console.error(import_chalk8.default.red(`Project "${nameOrId}" not found in this team.`));
509
- if (projects.length) console.error(import_chalk8.default.dim(" Known: " + projects.map((p) => p.projectName).join(", ")));
508
+ console.error(import_chalk9.default.red(`Project "${nameOrId}" not found in this team.`));
509
+ if (projects.length) console.error(import_chalk9.default.dim(" Known: " + projects.map((p) => p.projectName).join(", ")));
510
510
  process.exit(1);
511
511
  }
512
512
  const chosen = version2 ? candidates.find((p) => p.apiVersion === version2) : candidates[0];
513
513
  if (!chosen) {
514
- console.error(import_chalk8.default.red(`Project "${nameOrId}" has no version ${version2}. Versions: ${candidates.map((p) => p.apiVersion).join(", ")}`));
514
+ console.error(import_chalk9.default.red(`Project "${nameOrId}" has no version ${version2}. Versions: ${candidates.map((p) => p.apiVersion).join(", ")}`));
515
515
  process.exit(1);
516
516
  }
517
517
  return {
@@ -522,11 +522,11 @@ async function resolveProject(teamId, nameOrId, version2) {
522
522
  tenant: chosen.tenant
523
523
  };
524
524
  }
525
- var import_chalk8;
525
+ var import_chalk9;
526
526
  var init_resolve = __esm({
527
527
  "src/lib/resolve.ts"() {
528
528
  "use strict";
529
- import_chalk8 = __toESM(require("chalk"));
529
+ import_chalk9 = __toESM(require("chalk"));
530
530
  init_auth();
531
531
  init_api();
532
532
  }
@@ -635,12 +635,12 @@ async function runIamToggle(project, state, opts) {
635
635
  summary: `IAM ${state} for tenant ${tenant2}`
636
636
  });
637
637
  if (opts.quiet) return;
638
- spinner?.succeed(`IAM is ${import_chalk9.default.bold(state)} for tenant ${tenant2}.`);
638
+ spinner?.succeed(`IAM is ${import_chalk10.default.bold(state)} for tenant ${tenant2}.`);
639
639
  if (opts.json) console.log(JSON.stringify(out ?? { iam_enabled: enabled }));
640
640
  else if (enabled) {
641
- console.log(import_chalk9.default.dim(" Groups now apply to identified calls. Identify callers with"));
642
- console.log(import_chalk9.default.dim(" X-End-User-Id, a login token, or per-user keys \u2014 and consider"));
643
- console.log(import_chalk9.default.dim(` \`apiblaze identified ${project} require\` to reject unattributed traffic.`));
641
+ console.log(import_chalk10.default.dim(" Groups now apply to identified calls. Identify callers with"));
642
+ console.log(import_chalk10.default.dim(" X-End-User-Id, a login token, or per-user keys \u2014 and consider"));
643
+ console.log(import_chalk10.default.dim(` \`apiblaze identified ${project} require\` to reject unattributed traffic.`));
644
644
  }
645
645
  } catch (err) {
646
646
  spinner?.fail(`IAM ${state} failed.`);
@@ -692,11 +692,11 @@ async function runIdentifiedToggle(project, mode, opts) {
692
692
  throw err;
693
693
  }
694
694
  }
695
- var import_chalk9, import_ora4;
695
+ var import_chalk10, import_ora4;
696
696
  var init_iam = __esm({
697
697
  "src/commands/iam.ts"() {
698
698
  "use strict";
699
- import_chalk9 = __toESM(require("chalk"));
699
+ import_chalk10 = __toESM(require("chalk"));
700
700
  import_ora4 = __toESM(require("ora"));
701
701
  init_caller();
702
702
  }
@@ -714,7 +714,7 @@ async function createTenantRow(teamId) {
714
714
  const { name } = await inquirer3.prompt([{
715
715
  type: "input",
716
716
  name: "name",
717
- message: `Tenant name ${import_chalk26.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
717
+ message: `Tenant name ${import_chalk30.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
718
718
  validate: (s) => /^[a-z0-9]+$/.test(s.trim()) ? true : "lowercase letters and numbers only"
719
719
  }]);
720
720
  const slug = name.trim();
@@ -729,7 +729,7 @@ async function createTenantRow(teamId) {
729
729
  } catch (err) {
730
730
  const msg = err instanceof Error ? err.message : String(err);
731
731
  if (/taken|unique|exists|reserved|conflict/i.test(msg)) {
732
- console.log(import_chalk26.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
732
+ console.log(import_chalk30.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
733
733
  continue;
734
734
  }
735
735
  throw err;
@@ -746,11 +746,11 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
746
746
  pageSize: 10,
747
747
  choices: [
748
748
  ...PROVIDERS.map((p) => ({ name: p.label, value: p.id })),
749
- ...opts.allowSkip ? [new inquirer3.Separator(), { name: import_chalk26.default.dim("Skip for now \u2014 set up a login method later"), value: null }] : []
749
+ ...opts.allowSkip ? [new inquirer3.Separator(), { name: import_chalk30.default.dim("Skip for now \u2014 set up a login method later"), value: null }] : []
750
750
  ]
751
751
  }]);
752
752
  if (!provider) {
753
- console.log(import_chalk26.default.dim(" No login method yet \u2014 add one later under Login methods."));
753
+ console.log(import_chalk30.default.dim(" No login method yet \u2014 add one later under Login methods."));
754
754
  return false;
755
755
  }
756
756
  const opt = PROVIDERS.find((p) => p.id === provider);
@@ -796,26 +796,26 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
796
796
  async function createTenantInteractive(teamId) {
797
797
  const { default: inquirer3 } = await import("inquirer");
798
798
  const tenant2 = await createTenantRow(teamId);
799
- console.log(import_chalk26.default.green(` Tenant ${import_chalk26.default.bold(tenant2)} created.`));
799
+ console.log(import_chalk30.default.green(` Tenant ${import_chalk30.default.bold(tenant2)} created.`));
800
800
  const { users } = await inquirer3.prompt([{
801
801
  type: "confirm",
802
802
  name: "users",
803
803
  default: false,
804
- message: `Enable Users & groups? ${import_chalk26.default.dim(`(identity/key management at iam.apiblaze.com)`)}`
804
+ message: `Enable Users & groups? ${import_chalk30.default.dim(`(identity/key management at iam.apiblaze.com)`)}`
805
805
  }]);
806
806
  if (users) {
807
807
  await admin({ method: "PATCH", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/iam`, body: { enabled: true }, summary: "Enable Users & groups" }).catch(() => {
808
808
  });
809
- console.log(import_chalk26.default.green(" Users & groups enabled."));
809
+ console.log(import_chalk30.default.green(" Users & groups enabled."));
810
810
  }
811
811
  await addApiblazeHostedLogin(teamId, tenant2, { allowSkip: true });
812
812
  return tenant2;
813
813
  }
814
- var import_chalk26, import_ora10, PROVIDERS, DEFAULT_SCOPES;
814
+ var import_chalk30, import_ora10, PROVIDERS, DEFAULT_SCOPES;
815
815
  var init_tenant_create = __esm({
816
816
  "src/lib/tenant-create.ts"() {
817
817
  "use strict";
818
- import_chalk26 = __toESM(require("chalk"));
818
+ import_chalk30 = __toESM(require("chalk"));
819
819
  import_ora10 = __toESM(require("ora"));
820
820
  init_admin();
821
821
  PROVIDERS = [
@@ -841,7 +841,7 @@ var tenant_pick_exports = {};
841
841
  __export(tenant_pick_exports, {
842
842
  pickTenant: () => pickTenant
843
843
  });
844
- async function fetchPage(teamId, q) {
844
+ async function fetchPage2(teamId, q) {
845
845
  const out = await admin({
846
846
  method: "GET",
847
847
  path: `/teams/${encodeURIComponent(teamId)}/tenants?detail=1&limit=${PAGE}${q ? `&q=${encodeURIComponent(q)}` : ""}`,
@@ -854,10 +854,10 @@ async function fetchPage(teamId, q) {
854
854
  }
855
855
  function label(t, defaultTenant, active) {
856
856
  const tags = [
857
- t.tenant_name === active ? import_chalk27.default.cyan("active scope") : "",
858
- t.tenant_name === defaultTenant ? import_chalk27.default.dim("team default") : ""
857
+ t.tenant_name === active ? import_chalk31.default.cyan("active scope") : "",
858
+ t.tenant_name === defaultTenant ? import_chalk31.default.dim("team default") : ""
859
859
  ].filter(Boolean).join(", ");
860
- const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk27.default.dim(` ${t.display_name}`) : "";
860
+ const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk31.default.dim(` ${t.display_name}`) : "";
861
861
  return `${t.tenant_name}${disp}${tags ? ` (${tags})` : ""}`;
862
862
  }
863
863
  async function pickTenant(teamId, opts = {}) {
@@ -866,13 +866,13 @@ async function pickTenant(teamId, opts = {}) {
866
866
  let q = opts.initialQuery ?? "";
867
867
  for (; ; ) {
868
868
  const spinner = (0, import_ora11.default)(q ? `Searching tenants for "${q}"...` : "Loading tenants...").start();
869
- const page = await fetchPage(teamId, q).finally(() => spinner.stop());
869
+ const page = await fetchPage2(teamId, q).finally(() => spinner.stop());
870
870
  if (!page.total && !q) {
871
871
  if (opts.allowCreate) {
872
872
  const { make } = await inquirer3.prompt([{ type: "confirm", name: "make", message: "No tenants yet \u2014 create one?", default: true }]);
873
873
  if (make) return await createTenantInline(teamId);
874
874
  }
875
- console.error(import_chalk27.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
875
+ console.error(import_chalk31.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
876
876
  return null;
877
877
  }
878
878
  const truncated = page.total > page.rows.length;
@@ -881,7 +881,7 @@ async function pickTenant(teamId, opts = {}) {
881
881
  value: t.tenant_name
882
882
  }));
883
883
  if (truncated || q) {
884
- choices.push(new inquirer3.Separator(import_chalk27.default.dim(
884
+ choices.push(new inquirer3.Separator(import_chalk31.default.dim(
885
885
  truncated ? `showing ${page.rows.length} of ${page.total}${q ? ` matching "${q}"` : ""} \u2014 search to narrow` : `matches for "${q}"`
886
886
  )));
887
887
  choices.push({ name: `\u{1F50D} Search${q ? " again" : ""}\u2026`, value: "\0search" });
@@ -915,11 +915,11 @@ async function createTenantInline(teamId) {
915
915
  const { createTenantInteractive: createTenantInteractive2 } = await Promise.resolve().then(() => (init_tenant_create(), tenant_create_exports));
916
916
  return createTenantInteractive2(teamId);
917
917
  }
918
- var import_chalk27, import_ora11, PAGE;
918
+ var import_chalk31, import_ora11, PAGE;
919
919
  var init_tenant_pick = __esm({
920
920
  "src/lib/tenant-pick.ts"() {
921
921
  "use strict";
922
- import_chalk27 = __toESM(require("chalk"));
922
+ import_chalk31 = __toESM(require("chalk"));
923
923
  import_ora11 = __toESM(require("ora"));
924
924
  init_admin();
925
925
  init_auth();
@@ -929,10 +929,10 @@ var init_tenant_pick = __esm({
929
929
 
930
930
  // src/index.ts
931
931
  var import_commander = require("commander");
932
- var import_chalk44 = __toESM(require("chalk"));
932
+ var import_chalk48 = __toESM(require("chalk"));
933
933
 
934
934
  // package.json
935
- var version = "0.19.26";
935
+ var version = "0.19.29";
936
936
 
937
937
  // src/index.ts
938
938
  init_types();
@@ -942,7 +942,7 @@ var import_chalk2 = __toESM(require("chalk"));
942
942
  var import_ora = __toESM(require("ora"));
943
943
  init_auth();
944
944
  init_team();
945
- var DASHBOARD_BASE2 = "https://dashboard.apiblaze.com";
945
+ var DASHBOARD_BASE2 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
946
946
  function openBrowser(url) {
947
947
  const { exec } = require("child_process");
948
948
  const cmd = process.platform === "darwin" ? `open "${url}"` : process.platform === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
@@ -1936,8 +1936,79 @@ ${projects.length} project${projects.length === 1 ? "" : "s"}`));
1936
1936
 
1937
1937
  // src/commands/create.ts
1938
1938
  var import_fs2 = __toESM(require("fs"));
1939
+
1940
+ // src/lib/tenant-choice.ts
1941
+ var import_chalk8 = __toESM(require("chalk"));
1942
+ init_admin();
1943
+ function decideTenant(input) {
1944
+ if (input.tenant) {
1945
+ const slug = input.tenant.toLowerCase().replace(/[^a-z0-9]/g, "");
1946
+ return slug ? { kind: "use", tenant: slug } : { kind: "server-default" };
1947
+ }
1948
+ if (input.existing.length === 0) return { kind: "server-default" };
1949
+ const suggested = suggestTenantName(input.projectSlug, input.existing);
1950
+ if (input.existing.length === 1) return { kind: "use", tenant: input.existing[0] };
1951
+ if (!input.interactive) return { kind: "use", tenant: suggested };
1952
+ return { kind: "ask", existing: input.existing, suggested };
1953
+ }
1954
+ async function chooseTenantForCreate(teamId, projectSlug, opts) {
1955
+ if (opts.tenant) return opts.tenant.toLowerCase().replace(/[^a-z0-9]/g, "");
1956
+ if (!teamId) return void 0;
1957
+ let existing = [];
1958
+ try {
1959
+ const rows = await admin({
1960
+ method: "GET",
1961
+ path: `/teams/${encodeURIComponent(teamId)}/tenants`,
1962
+ summary: "List tenants to place the new proxy"
1963
+ });
1964
+ const list = Array.isArray(rows) ? rows : rows?.tenants ?? [];
1965
+ existing = list.map((t) => t?.tenant_name ?? t?.name).filter((n) => typeof n === "string" && n.length > 0);
1966
+ } catch {
1967
+ return void 0;
1968
+ }
1969
+ const decision = decideTenant({
1970
+ existing,
1971
+ projectSlug,
1972
+ tenant: opts.tenant,
1973
+ yes: opts.yes,
1974
+ json: opts.json,
1975
+ interactive: !opts.yes && !opts.json && !!process.stdin.isTTY
1976
+ });
1977
+ if (decision.kind === "server-default") return void 0;
1978
+ if (decision.kind === "use") {
1979
+ if (!opts.json && !existing.includes(decision.tenant)) {
1980
+ console.log(import_chalk8.default.dim(` Placing this proxy in a new tenant "${decision.tenant}" (pass --tenant to choose another).`));
1981
+ }
1982
+ return decision.tenant;
1983
+ }
1984
+ const { existing: choices, suggested } = decision;
1985
+ const { default: inquirer3 } = await import("inquirer");
1986
+ const { pick: pick2 } = await inquirer3.prompt([
1987
+ {
1988
+ type: "list",
1989
+ name: "pick",
1990
+ message: "Which tenant should this proxy's consumers live in?",
1991
+ choices: [
1992
+ { name: `${import_chalk8.default.green("\uFF0B")} New tenant "${suggested}" ${import_chalk8.default.dim("(its own portal, login and users)")}`, value: "\0new" },
1993
+ ...choices.map((t) => ({ name: `${t} ${import_chalk8.default.dim("(share its portal, login app and users)")}`, value: t }))
1994
+ ]
1995
+ }
1996
+ ]);
1997
+ return pick2 === "\0new" ? suggested : pick2;
1998
+ }
1999
+ function suggestTenantName(projectSlug, taken) {
2000
+ const base2 = (projectSlug || "tenant").toLowerCase().replace(/[^a-z0-9]/g, "").slice(0, 24) || "tenant";
2001
+ if (!taken.includes(base2)) return base2;
2002
+ for (let i = 2; i < 100; i++) {
2003
+ const candidate = `${base2}${i}`;
2004
+ if (!taken.includes(candidate)) return candidate;
2005
+ }
2006
+ return `${base2}${Math.random().toString(36).slice(2, 7)}`;
2007
+ }
2008
+
2009
+ // src/commands/create.ts
1939
2010
  var import_yaml = require("yaml");
1940
- var import_chalk10 = __toESM(require("chalk"));
2011
+ var import_chalk11 = __toESM(require("chalk"));
1941
2012
  var import_ora5 = __toESM(require("ora"));
1942
2013
  init_auth();
1943
2014
  init_api();
@@ -2000,7 +2071,7 @@ function stripTenantFromPortal(devPortal) {
2000
2071
  }
2001
2072
  }
2002
2073
  function fail(message) {
2003
- console.error(import_chalk10.default.red(`Error: ${message}`));
2074
+ console.error(import_chalk11.default.red(`Error: ${message}`));
2004
2075
  process.exit(1);
2005
2076
  }
2006
2077
  function buildTryItCurl(url, authType, apiKey) {
@@ -2015,11 +2086,11 @@ function printCurlExample(url, authType, apiKey, devPortal) {
2015
2086
  const curl = buildTryItCurl(url, authType, apiKey);
2016
2087
  console.log();
2017
2088
  if (curl) {
2018
- console.log(` ${import_chalk10.default.dim("Try it \u2014 copy/paste:")}`);
2019
- console.log(` ${import_chalk10.default.cyan(curl)}`);
2089
+ console.log(` ${import_chalk11.default.dim("Try it \u2014 copy/paste:")}`);
2090
+ console.log(` ${import_chalk11.default.cyan(curl)}`);
2020
2091
  } else if (authType === "oauth") {
2021
- console.log(` ${import_chalk10.default.dim("Try it:")} this proxy uses OAuth \u2014 sign in at ${import_chalk10.default.bold(devPortal ?? "the dev portal")} to get a token,`);
2022
- console.log(` ${import_chalk10.default.dim(`then call ${url} with`)} ${import_chalk10.default.cyan('-H "Authorization: Bearer <token>"')}`);
2092
+ console.log(` ${import_chalk11.default.dim("Try it:")} this proxy uses OAuth \u2014 sign in at ${import_chalk11.default.bold(devPortal ?? "the dev portal")} to get a token,`);
2093
+ console.log(` ${import_chalk11.default.dim(`then call ${url} with`)} ${import_chalk11.default.cyan('-H "Authorization: Bearer <token>"')}`);
2023
2094
  }
2024
2095
  }
2025
2096
  var VALID_AUTH = ["api_key", "none", "oauth"];
@@ -2049,7 +2120,7 @@ async function runCreate(opts = {}) {
2049
2120
  teamId = match.teamId;
2050
2121
  }
2051
2122
  }
2052
- if (!opts.json) console.log(import_chalk10.default.bold("\nCreate an API proxy\n"));
2123
+ if (!opts.json) console.log(import_chalk11.default.bold("\nCreate an API proxy\n"));
2053
2124
  let name = "";
2054
2125
  if (opts.name !== void 0) {
2055
2126
  name = normalizeName(opts.name);
@@ -2069,7 +2140,7 @@ async function runCreate(opts = {}) {
2069
2140
  }]);
2070
2141
  name = normalizeName(rawName);
2071
2142
  if (name.length < 3) {
2072
- console.log(import_chalk10.default.yellow(" Name must be at least 3 characters (letters and digits only).\n"));
2143
+ console.log(import_chalk11.default.yellow(" Name must be at least 3 characters (letters and digits only).\n"));
2073
2144
  continue;
2074
2145
  }
2075
2146
  const spinner2 = (0, import_ora5.default)("Checking availability...").start();
@@ -2077,15 +2148,15 @@ async function runCreate(opts = {}) {
2077
2148
  const check = await checkProxyName(name, teamId, opts.apiversion);
2078
2149
  spinner2.stop();
2079
2150
  if (!check.canUseProjectName || !check.canUseApiVersion) {
2080
- console.log(import_chalk10.default.yellow(` "${name}" is not available${check.message ? ` \u2014 ${check.message}` : ""}. Try another.
2151
+ console.log(import_chalk11.default.yellow(` "${name}" is not available${check.message ? ` \u2014 ${check.message}` : ""}. Try another.
2081
2152
  `));
2082
2153
  continue;
2083
2154
  }
2084
2155
  } catch {
2085
2156
  spinner2.stop();
2086
- console.log(import_chalk10.default.dim(" (could not verify availability; continuing)"));
2157
+ console.log(import_chalk11.default.dim(" (could not verify availability; continuing)"));
2087
2158
  }
2088
- console.log(`${import_chalk10.default.cyan("\u2192")} Your API will live at ${import_chalk10.default.bold(`https://${name}.abz.run`)}
2159
+ console.log(`${import_chalk11.default.cyan("\u2192")} Your API will live at ${import_chalk11.default.bold(`https://${name}.abz.run`)}
2089
2160
  `);
2090
2161
  break;
2091
2162
  }
@@ -2111,7 +2182,7 @@ async function runCreate(opts = {}) {
2111
2182
  message: "Target URL to forward requests to (e.g. https://httpbin.org):"
2112
2183
  }]);
2113
2184
  if (!isHttpUrl(url)) {
2114
- console.log(import_chalk10.default.yellow(" Enter a valid http(s) URL.\n"));
2185
+ console.log(import_chalk11.default.yellow(" Enter a valid http(s) URL.\n"));
2115
2186
  continue;
2116
2187
  }
2117
2188
  targetUrl = url.trim();
@@ -2122,7 +2193,7 @@ async function runCreate(opts = {}) {
2122
2193
  }
2123
2194
  if (interactive && !opts.yes) {
2124
2195
  const { default: inquirer3 } = await import("inquirer");
2125
- console.log(`${import_chalk10.default.cyan("\u2192")} Auth: ${import_chalk10.default.bold(auth)}${auth === "api_key" ? " \u2014 consumers send an X-API-Key header" : ""}`);
2196
+ console.log(`${import_chalk11.default.cyan("\u2192")} Auth: ${import_chalk11.default.bold(auth)}${auth === "api_key" ? " \u2014 consumers send an X-API-Key header" : ""}`);
2126
2197
  const { ok } = await inquirer3.prompt([{
2127
2198
  type: "confirm",
2128
2199
  name: "ok",
@@ -2130,10 +2201,15 @@ async function runCreate(opts = {}) {
2130
2201
  default: true
2131
2202
  }]);
2132
2203
  if (!ok) {
2133
- console.log(import_chalk10.default.yellow("Cancelled."));
2204
+ console.log(import_chalk11.default.yellow("Cancelled."));
2134
2205
  return;
2135
2206
  }
2136
2207
  }
2208
+ const chosenTenant = await chooseTenantForCreate(teamId, name, {
2209
+ tenant: opts.tenant,
2210
+ yes: opts.yes,
2211
+ json: opts.json
2212
+ });
2137
2213
  const spinner = !opts.json ? (0, import_ora5.default)("Creating proxy (tenant, keys, dev portal)...").start() : null;
2138
2214
  let result;
2139
2215
  try {
@@ -2142,10 +2218,10 @@ async function runCreate(opts = {}) {
2142
2218
  ...openapiContent ? { openapi: openapiContent } : { target_url: targetUrl },
2143
2219
  auth_type: auth,
2144
2220
  team_id: teamId,
2145
- ...opts.tenant ? { tenant: normalizeName(opts.tenant) } : {},
2221
+ ...chosenTenant ? { tenant: chosenTenant } : {},
2146
2222
  ...opts.apiversion ? { api_version: opts.apiversion } : {}
2147
2223
  });
2148
- spinner?.succeed(import_chalk10.default.green("Proxy created!"));
2224
+ spinner?.succeed(import_chalk11.default.green("Proxy created!"));
2149
2225
  } catch (err) {
2150
2226
  spinner?.fail("Failed to create proxy.");
2151
2227
  throw err;
@@ -2170,16 +2246,16 @@ async function runCreate(opts = {}) {
2170
2246
  return;
2171
2247
  }
2172
2248
  console.log();
2173
- console.log(` ${import_chalk10.default.dim("Proxy URL: ")} ${import_chalk10.default.bold(proxyUrl)}`);
2174
- if (devPortal) console.log(` ${import_chalk10.default.dim("Dev portal:")} ${import_chalk10.default.bold(devPortal)}`);
2249
+ console.log(` ${import_chalk11.default.dim("Proxy URL: ")} ${import_chalk11.default.bold(proxyUrl)}`);
2250
+ if (devPortal) console.log(` ${import_chalk11.default.dim("Dev portal:")} ${import_chalk11.default.bold(devPortal)}`);
2175
2251
  if (adminKey) {
2176
2252
  console.log();
2177
- console.log(` ${import_chalk10.default.dim("Consumer admin API key (dev):")}`);
2178
- console.log(` ${import_chalk10.default.bold.green(adminKey)}`);
2179
- console.log(import_chalk10.default.dim("\n Save this now \u2014 send it as the X-API-Key header. It may not be shown again."));
2253
+ console.log(` ${import_chalk11.default.dim("Consumer admin API key (dev):")}`);
2254
+ console.log(` ${import_chalk11.default.bold.green(adminKey)}`);
2255
+ console.log(import_chalk11.default.dim("\n Save this now \u2014 send it as the X-API-Key header. It may not be shown again."));
2180
2256
  const otherEnvs = Object.keys(keys).filter((e) => e !== "dev");
2181
2257
  if (otherEnvs.length) {
2182
- console.log(import_chalk10.default.dim(` (Separate keys were also created for: ${otherEnvs.join(", ")}.)`));
2258
+ console.log(import_chalk11.default.dim(` (Separate keys were also created for: ${otherEnvs.join(", ")}.)`));
2183
2259
  }
2184
2260
  }
2185
2261
  printCurlExample(proxyUrl, auth, adminKey, devPortal);
@@ -2195,8 +2271,8 @@ async function applyCreateToggles(name, opts) {
2195
2271
  async function runAnonymousCreate(opts) {
2196
2272
  const interactive = !!process.stdin.isTTY && !opts.json;
2197
2273
  if (!opts.json) {
2198
- console.log(import_chalk10.default.bold("\nCreate an API proxy"));
2199
- console.log(import_chalk10.default.dim("Not logged in \u2014 creating an anonymous proxy. You can claim it to your account within 30 days.\n"));
2274
+ console.log(import_chalk11.default.bold("\nCreate an API proxy"));
2275
+ console.log(import_chalk11.default.dim("Not logged in \u2014 creating an anonymous proxy. You can claim it to your account within 30 days.\n"));
2200
2276
  }
2201
2277
  let body = {};
2202
2278
  if (opts.config) {
@@ -2245,7 +2321,7 @@ async function runAnonymousCreate(opts) {
2245
2321
  message: "Target URL to forward requests to (e.g. https://httpbin.org):"
2246
2322
  }]);
2247
2323
  if (!isHttpUrl(url)) {
2248
- console.log(import_chalk10.default.yellow(" Enter a valid http(s) URL.\n"));
2324
+ console.log(import_chalk11.default.yellow(" Enter a valid http(s) URL.\n"));
2249
2325
  continue;
2250
2326
  }
2251
2327
  target = url.trim();
@@ -2286,7 +2362,7 @@ async function runAnonymousCreate(opts) {
2286
2362
  saveAnonCred2(result.cp_key, result.team_id, result.claim_code);
2287
2363
  }
2288
2364
  }
2289
- spinner?.succeed(import_chalk10.default.green("Proxy created!"));
2365
+ spinner?.succeed(import_chalk11.default.green("Proxy created!"));
2290
2366
  } catch (err) {
2291
2367
  spinner?.fail("Failed to create proxy.");
2292
2368
  throw err;
@@ -2309,36 +2385,36 @@ async function runAnonymousCreate(opts) {
2309
2385
  return;
2310
2386
  }
2311
2387
  console.log();
2312
- if (prodEndpoint) console.log(` ${import_chalk10.default.dim("Proxy URL: ")} ${import_chalk10.default.bold(prodEndpoint)}`);
2313
- if (result.portal) console.log(` ${import_chalk10.default.dim("Dev portal:")} ${import_chalk10.default.bold(result.portal)}`);
2388
+ if (prodEndpoint) console.log(` ${import_chalk11.default.dim("Proxy URL: ")} ${import_chalk11.default.bold(prodEndpoint)}`);
2389
+ if (result.portal) console.log(` ${import_chalk11.default.dim("Dev portal:")} ${import_chalk11.default.bold(result.portal)}`);
2314
2390
  if (apiKey) {
2315
2391
  console.log();
2316
- console.log(` ${import_chalk10.default.dim("API key:")}`);
2317
- console.log(` ${import_chalk10.default.bold.green(apiKey)}`);
2318
- console.log(import_chalk10.default.dim("\n Save this now \u2014 send it as the X-API-Key header. It may not be shown again."));
2392
+ console.log(` ${import_chalk11.default.dim("API key:")}`);
2393
+ console.log(` ${import_chalk11.default.bold.green(apiKey)}`);
2394
+ console.log(import_chalk11.default.dim("\n Save this now \u2014 send it as the X-API-Key header. It may not be shown again."));
2319
2395
  }
2320
2396
  if (prodEndpoint) printCurlExample(prodEndpoint, opts.auth || "api_key", apiKey, result.portal);
2321
2397
  const claimCode = result.claim_code || cred?.claim_code;
2322
2398
  if (claimCode) {
2323
2399
  console.log();
2324
- console.log(` ${import_chalk10.default.yellow("\u26A0 Anonymous \u2014 claim within 30 days or it expires.")} To claim these proxies:`);
2325
- console.log(` ${import_chalk10.default.cyan(`npx apiblaze login && npx apiblaze claim ${claimCode}`)}`);
2400
+ console.log(` ${import_chalk11.default.yellow("\u26A0 Anonymous \u2014 claim within 30 days or it expires.")} To claim these proxies:`);
2401
+ console.log(` ${import_chalk11.default.cyan(`npx apiblaze login && npx apiblaze claim ${claimCode}`)}`);
2326
2402
  } else if (result.claim_url) {
2327
2403
  console.log();
2328
- console.log(` ${import_chalk10.default.yellow("\u26A0 Anonymous proxy \u2014 claim it to your account within 30 days or it expires:")}`);
2329
- console.log(` ${import_chalk10.default.bold(result.claim_url)}`);
2404
+ console.log(` ${import_chalk11.default.yellow("\u26A0 Anonymous proxy \u2014 claim it to your account within 30 days or it expires:")}`);
2405
+ console.log(` ${import_chalk11.default.bold(result.claim_url)}`);
2330
2406
  }
2331
2407
  console.log();
2332
2408
  }
2333
2409
 
2334
2410
  // src/commands/claim.ts
2335
- var import_chalk11 = __toESM(require("chalk"));
2411
+ var import_chalk12 = __toESM(require("chalk"));
2336
2412
  init_auth();
2337
2413
  init_anon_cred();
2338
2414
  init_api();
2339
2415
  init_types();
2340
2416
  function fail2(message) {
2341
- console.error(import_chalk11.default.red(`Error: ${message}`));
2417
+ console.error(import_chalk12.default.red(`Error: ${message}`));
2342
2418
  process.exit(1);
2343
2419
  }
2344
2420
  async function runClaim(claimCodeArg, opts) {
@@ -2374,9 +2450,9 @@ async function runClaim(claimCodeArg, opts) {
2374
2450
  const c = typeof err.body === "object" && err.body ? err.body.error : void 0;
2375
2451
  if (c === "already_claimed" || c === "not_claimable") {
2376
2452
  if (fromLocal) clearAnonCred();
2377
- console.log(import_chalk11.default.yellow("\nThis workspace was already claimed (e.g. on dashboard.apiblaze.com)."));
2378
- if (fromLocal) console.log(import_chalk11.default.dim(" Cleared the local anonymous key."));
2379
- console.log(import_chalk11.default.dim(" Your proxies are safe under your account \u2014 manage them with `apiblaze login`."));
2453
+ console.log(import_chalk12.default.yellow("\nThis workspace was already claimed (e.g. on dashboard.apiblaze.com)."));
2454
+ if (fromLocal) console.log(import_chalk12.default.dim(" Cleared the local anonymous key."));
2455
+ console.log(import_chalk12.default.dim(" Your proxies are safe under your account \u2014 manage them with `apiblaze login`."));
2380
2456
  return;
2381
2457
  }
2382
2458
  if (c === "expired") {
@@ -2394,20 +2470,20 @@ async function runClaim(claimCodeArg, opts) {
2394
2470
  console.log(JSON.stringify(res, null, 2));
2395
2471
  return;
2396
2472
  }
2397
- console.log(import_chalk11.default.green("\n\u2714 Claimed your anonymous workspace into your account."));
2473
+ console.log(import_chalk12.default.green("\n\u2714 Claimed your anonymous workspace into your account."));
2398
2474
  if (res.merged) {
2399
- console.log(` Merged ${import_chalk11.default.bold(String(res.proxy_count ?? ""))} prox${res.proxy_count === 1 ? "y" : "ies"} into team ${import_chalk11.default.bold(res.team_id)}.`);
2475
+ console.log(` Merged ${import_chalk12.default.bold(String(res.proxy_count ?? ""))} prox${res.proxy_count === 1 ? "y" : "ies"} into team ${import_chalk12.default.bold(res.team_id)}.`);
2400
2476
  } else {
2401
2477
  const label3 = res.team_name ? `\u201C${res.team_name}\u201D` : res.team_id;
2402
- console.log(` It's now your team ${import_chalk11.default.bold(label3)}. Switch to it with ${import_chalk11.default.cyan(`apiblaze team ${res.team_id}`)}.`);
2403
- console.log(import_chalk11.default.dim(` (Tip: name it with --name, or --team <name> to merge into an existing team instead.)`));
2478
+ console.log(` It's now your team ${import_chalk12.default.bold(label3)}. Switch to it with ${import_chalk12.default.cyan(`apiblaze team ${res.team_id}`)}.`);
2479
+ console.log(import_chalk12.default.dim(` (Tip: name it with --name, or --team <name> to merge into an existing team instead.)`));
2404
2480
  }
2405
2481
  console.log(`
2406
- Manage it at ${import_chalk11.default.cyan("https://dashboard.apiblaze.com/dashboard")}`);
2482
+ Manage it at ${import_chalk12.default.cyan("https://dashboard.apiblaze.com/dashboard")}`);
2407
2483
  }
2408
2484
 
2409
2485
  // src/commands/logout.ts
2410
- var import_chalk12 = __toESM(require("chalk"));
2486
+ var import_chalk13 = __toESM(require("chalk"));
2411
2487
  init_auth();
2412
2488
 
2413
2489
  // src/lib/consumer-auth.ts
@@ -2539,7 +2615,7 @@ async function runLogout(opts = {}) {
2539
2615
  const creds = loadCredentials();
2540
2616
  const consumer2 = loadConsumer();
2541
2617
  if (!creds && !consumer2) {
2542
- console.log(import_chalk12.default.yellow("You were not logged in."));
2618
+ console.log(import_chalk13.default.yellow("You were not logged in."));
2543
2619
  return;
2544
2620
  }
2545
2621
  let target;
@@ -2566,16 +2642,16 @@ async function runLogout(opts = {}) {
2566
2642
  }
2567
2643
  if (target === "producer" || target === "all") {
2568
2644
  clearCredentials();
2569
- console.log(import_chalk12.default.green(`\u2714 Logged out of API Producer${creds?.githubHandle ? ` (${creds.githubHandle})` : ""}.`));
2645
+ console.log(import_chalk13.default.green(`\u2714 Logged out of API Producer${creds?.githubHandle ? ` (${creds.githubHandle})` : ""}.`));
2570
2646
  }
2571
2647
  if (target === "consumer" || target === "all") {
2572
2648
  clearConsumer();
2573
- console.log(import_chalk12.default.green(`\u2714 Logged out of API Consumer${consumer2?.tenant ? ` (${consumer2.tenant})` : ""}.`));
2649
+ console.log(import_chalk13.default.green(`\u2714 Logged out of API Consumer${consumer2?.tenant ? ` (${consumer2.tenant})` : ""}.`));
2574
2650
  }
2575
2651
  }
2576
2652
 
2577
2653
  // src/commands/flush.ts
2578
- var import_chalk13 = __toESM(require("chalk"));
2654
+ var import_chalk14 = __toESM(require("chalk"));
2579
2655
  var fs6 = __toESM(require("fs"));
2580
2656
  var path4 = __toESM(require("path"));
2581
2657
  init_auth();
@@ -2583,22 +2659,22 @@ async function runFlush(opts) {
2583
2659
  const dir = getApiblazeDir();
2584
2660
  const entries2 = fs6.existsSync(dir) ? fs6.readdirSync(dir) : [];
2585
2661
  if (!entries2.length) {
2586
- console.log(import_chalk13.default.dim("Nothing to flush \u2014 no local apiblaze config found."));
2662
+ console.log(import_chalk14.default.dim("Nothing to flush \u2014 no local apiblaze config found."));
2587
2663
  return;
2588
2664
  }
2589
- console.log(import_chalk13.default.yellow("This removes ALL local apiblaze state from this machine:"));
2590
- console.log(import_chalk13.default.dim(" \u2022 login credentials & anonymous-workspace keys"));
2591
- console.log(import_chalk13.default.dim(" \u2022 saved apichats \u2014 their DP API keys and transcripts"));
2592
- console.log(import_chalk13.default.dim(" \u2022 your BYO LLM key and any cached secrets"));
2593
- console.log(import_chalk13.default.dim(` (${entries2.length} item(s) in ${dir})`));
2594
- console.log(import_chalk13.default.dim(" It does NOT delete server-side proxies/keys \u2014 those GC or are revoked separately."));
2665
+ console.log(import_chalk14.default.yellow("This removes ALL local apiblaze state from this machine:"));
2666
+ console.log(import_chalk14.default.dim(" \u2022 login credentials & anonymous-workspace keys"));
2667
+ console.log(import_chalk14.default.dim(" \u2022 saved apichats \u2014 their DP API keys and transcripts"));
2668
+ console.log(import_chalk14.default.dim(" \u2022 your BYO LLM key and any cached secrets"));
2669
+ console.log(import_chalk14.default.dim(` (${entries2.length} item(s) in ${dir})`));
2670
+ console.log(import_chalk14.default.dim(" It does NOT delete server-side proxies/keys \u2014 those GC or are revoked separately."));
2595
2671
  if (!opts.yes) {
2596
2672
  const { default: inquirer3 } = await import("inquirer");
2597
2673
  const { ok } = await inquirer3.prompt([
2598
2674
  { type: "confirm", name: "ok", message: "Delete all local state?", default: false }
2599
2675
  ]);
2600
2676
  if (!ok) {
2601
- console.log(import_chalk13.default.dim("Cancelled \u2014 nothing removed."));
2677
+ console.log(import_chalk14.default.dim("Cancelled \u2014 nothing removed."));
2602
2678
  return;
2603
2679
  }
2604
2680
  }
@@ -2608,14 +2684,14 @@ async function runFlush(opts) {
2608
2684
  fs6.rmSync(path4.join(dir, e), { recursive: true, force: true });
2609
2685
  removed++;
2610
2686
  } catch (err) {
2611
- console.log(import_chalk13.default.red(` \u2717 could not remove ${e}: ${err instanceof Error ? err.message : "error"}`));
2687
+ console.log(import_chalk14.default.red(` \u2717 could not remove ${e}: ${err instanceof Error ? err.message : "error"}`));
2612
2688
  }
2613
2689
  }
2614
- console.log(`${import_chalk13.default.green("\u2714")} Flushed \u2014 removed ${removed} item(s). You're fully logged out and clean.`);
2690
+ console.log(`${import_chalk14.default.green("\u2714")} Flushed \u2014 removed ${removed} item(s). You're fully logged out and clean.`);
2615
2691
  }
2616
2692
 
2617
2693
  // src/commands/whoami.ts
2618
- var import_chalk14 = __toESM(require("chalk"));
2694
+ var import_chalk15 = __toESM(require("chalk"));
2619
2695
  init_auth();
2620
2696
  init_anon_cred();
2621
2697
  async function runWhoami(opts = {}) {
@@ -2638,43 +2714,43 @@ async function runWhoami(opts = {}) {
2638
2714
  }, null, 2));
2639
2715
  return;
2640
2716
  }
2641
- console.log(import_chalk14.default.bold("API Producer"));
2717
+ console.log(import_chalk15.default.bold("API Producer"));
2642
2718
  if (!creds) {
2643
- console.log(import_chalk14.default.dim(" Not logged in. Run `apiblaze login`."));
2719
+ console.log(import_chalk15.default.dim(" Not logged in. Run `apiblaze login`."));
2644
2720
  } else {
2645
2721
  const who = creds.githubHandle ?? creds.email ?? creds.apiblazeUserId ?? "unknown";
2646
- console.log(` ${import_chalk14.default.cyan("Signed in as")} ${import_chalk14.default.bold(who)}`);
2722
+ console.log(` ${import_chalk15.default.cyan("Signed in as")} ${import_chalk15.default.bold(who)}`);
2647
2723
  if (creds.email && creds.email !== who) console.log(` Email: ${creds.email}`);
2648
- if (creds.teamName || creds.teamId) console.log(` Team: ${import_chalk14.default.bold(creds.teamName ?? creds.teamId)}`);
2649
- if (creds.activeTenant) console.log(` Tenant scope: ${import_chalk14.default.bold(creds.activeTenant)} ${import_chalk14.default.dim("(clear: `apiblaze tenant use --clear`)")}`);
2650
- if (Date.now() >= creds.expiresAt) console.log(import_chalk14.default.yellow(" \u26A0 Session expired \u2014 run `apiblaze login`."));
2724
+ if (creds.teamName || creds.teamId) console.log(` Team: ${import_chalk15.default.bold(creds.teamName ?? creds.teamId)}`);
2725
+ if (creds.activeTenant) console.log(` Tenant scope: ${import_chalk15.default.bold(creds.activeTenant)} ${import_chalk15.default.dim("(clear: `apiblaze tenant use --clear`)")}`);
2726
+ if (Date.now() >= creds.expiresAt) console.log(import_chalk15.default.yellow(" \u26A0 Session expired \u2014 run `apiblaze login`."));
2651
2727
  }
2652
2728
  if (anon) {
2653
2729
  const masked = `${anon.cp_key.slice(0, 11)}\u2026${anon.cp_key.slice(-4)}`;
2654
- console.log(import_chalk14.default.bold("\nAnonymous workspace") + import_chalk14.default.dim(" (created without an account \u2014 unclaimed)"));
2655
- console.log(` Team: ${import_chalk14.default.bold(anon.team_id)}`);
2656
- console.log(` CP key: ${import_chalk14.default.bold(masked)} ${import_chalk14.default.dim("controls the proxies you created anonymously")}`);
2730
+ console.log(import_chalk15.default.bold("\nAnonymous workspace") + import_chalk15.default.dim(" (created without an account \u2014 unclaimed)"));
2731
+ console.log(` Team: ${import_chalk15.default.bold(anon.team_id)}`);
2732
+ console.log(` CP key: ${import_chalk15.default.bold(masked)} ${import_chalk15.default.dim("controls the proxies you created anonymously")}`);
2657
2733
  console.log(
2658
- import_chalk14.default.dim(` Keep it: ${import_chalk14.default.cyan("apiblaze login")} then ${import_chalk14.default.cyan("apiblaze claim")}`) + (anon.claim_code ? import_chalk14.default.dim(` \xB7 from another machine: ${import_chalk14.default.cyan(`apiblaze claim ${anon.claim_code}`)}`) : "")
2734
+ import_chalk15.default.dim(` Keep it: ${import_chalk15.default.cyan("apiblaze login")} then ${import_chalk15.default.cyan("apiblaze claim")}`) + (anon.claim_code ? import_chalk15.default.dim(` \xB7 from another machine: ${import_chalk15.default.cyan(`apiblaze claim ${anon.claim_code}`)}`) : "")
2659
2735
  );
2660
- if (creds) console.log(import_chalk14.default.dim(" (you're logged in \u2014 `apiblaze claim` folds this workspace into your account)"));
2736
+ if (creds) console.log(import_chalk15.default.dim(" (you're logged in \u2014 `apiblaze claim` folds this workspace into your account)"));
2661
2737
  }
2662
- console.log(import_chalk14.default.bold("\nAPI Consumer"));
2738
+ console.log(import_chalk15.default.bold("\nAPI Consumer"));
2663
2739
  if (!consumer2) {
2664
- console.log(import_chalk14.default.dim(" Not logged in. Run `apiblaze consumer login`."));
2740
+ console.log(import_chalk15.default.dim(" Not logged in. Run `apiblaze consumer login`."));
2665
2741
  } else {
2666
- console.log(` ${import_chalk14.default.cyan("Signed in as")} ${import_chalk14.default.bold(consumer2.email ?? consumer2.tenant)}`);
2667
- console.log(` Tenant: ${import_chalk14.default.bold(consumer2.tenant)}`);
2668
- if (Date.now() >= consumer2.expiresAt) console.log(import_chalk14.default.yellow(" \u26A0 Token expired \u2014 it will refresh on next use, or re-run `apiblaze consumer login`."));
2742
+ console.log(` ${import_chalk15.default.cyan("Signed in as")} ${import_chalk15.default.bold(consumer2.email ?? consumer2.tenant)}`);
2743
+ console.log(` Tenant: ${import_chalk15.default.bold(consumer2.tenant)}`);
2744
+ if (Date.now() >= consumer2.expiresAt) console.log(import_chalk15.default.yellow(" \u26A0 Token expired \u2014 it will refresh on next use, or re-run `apiblaze consumer login`."));
2669
2745
  }
2670
2746
  }
2671
2747
 
2672
2748
  // src/commands/team.ts
2673
- var import_chalk15 = __toESM(require("chalk"));
2749
+ var import_chalk16 = __toESM(require("chalk"));
2674
2750
  init_auth();
2675
2751
  init_api();
2676
2752
  function fail3(message) {
2677
- console.error(import_chalk15.default.red(`Error: ${message}`));
2753
+ console.error(import_chalk16.default.red(`Error: ${message}`));
2678
2754
  process.exit(1);
2679
2755
  }
2680
2756
  async function runTeam(arg) {
@@ -2696,7 +2772,7 @@ async function runTeam(arg) {
2696
2772
  }
2697
2773
  } else if (teams.length === 1) {
2698
2774
  chosen = teams[0];
2699
- console.log(`${import_chalk15.default.cyan("\u2192")} You only have one team: ${import_chalk15.default.bold(chosen.name)}`);
2775
+ console.log(`${import_chalk16.default.cyan("\u2192")} You only have one team: ${import_chalk16.default.bold(chosen.name)}`);
2700
2776
  } else if (process.stdin.isTTY) {
2701
2777
  const { default: inquirer3 } = await import("inquirer");
2702
2778
  const { picked } = await inquirer3.prompt([{
@@ -2711,48 +2787,48 @@ async function runTeam(arg) {
2711
2787
  fail3(`Specify a team: \`apiblaze team <name|id>\`. Available: ${teams.map((t) => t.name).join(", ")}.`);
2712
2788
  }
2713
2789
  saveCredentials({ ...creds, teamId: chosen.teamId, teamName: chosen.name });
2714
- console.log(import_chalk15.default.green(`
2715
- \u2714 Active team: ${import_chalk15.default.bold(chosen.name)}`));
2790
+ console.log(import_chalk16.default.green(`
2791
+ \u2714 Active team: ${import_chalk16.default.bold(chosen.name)}`));
2716
2792
  }
2717
2793
 
2718
2794
  // src/commands/authz.ts
2719
- var import_chalk18 = __toESM(require("chalk"));
2795
+ var import_chalk19 = __toESM(require("chalk"));
2720
2796
  init_auth();
2721
2797
  init_api();
2722
2798
 
2723
2799
  // src/lib/agent-chat.ts
2724
2800
  var import_readline = __toESM(require("readline"));
2725
- var import_chalk16 = __toESM(require("chalk"));
2801
+ var import_chalk17 = __toESM(require("chalk"));
2726
2802
  init_api();
2727
2803
  init_admin();
2728
2804
  async function runAgentChatRepl(opts) {
2729
2805
  const { title, subtitle, endpoint, buildBody, seedPrompt, summarizeProposal, commands } = opts;
2730
- console.log("\n" + import_chalk16.default.cyan.bold(title));
2731
- if (subtitle) console.log(import_chalk16.default.dim(subtitle));
2806
+ console.log("\n" + import_chalk17.default.cyan.bold(title));
2807
+ if (subtitle) console.log(import_chalk17.default.dim(subtitle));
2732
2808
  const messages = [];
2733
2809
  const ctx = { proposal: null, lastData: null, log: (s) => console.log(s) };
2734
2810
  const cmdByName = new Map(commands.map((c) => [c.name, c]));
2735
2811
  const footer = () => {
2736
2812
  const parts = [
2737
- import_chalk16.default.dim("type to chat/refine"),
2738
- ...commands.map((c) => import_chalk16.default.dim(`/${c.name} ${c.describe}`)),
2739
- import_chalk16.default.dim("/show"),
2740
- import_chalk16.default.dim("/exit when done"),
2741
- import_chalk16.default.dim("/drop discard changes")
2813
+ import_chalk17.default.dim("type to chat/refine"),
2814
+ ...commands.map((c) => import_chalk17.default.dim(`/${c.name} ${c.describe}`)),
2815
+ import_chalk17.default.dim("/show"),
2816
+ import_chalk17.default.dim("/exit when done"),
2817
+ import_chalk17.default.dim("/drop discard changes")
2742
2818
  ];
2743
- return " " + import_chalk16.default.dim("[ ") + parts.join(import_chalk16.default.dim(" \xB7 ")) + import_chalk16.default.dim(" ]");
2819
+ return " " + import_chalk17.default.dim("[ ") + parts.join(import_chalk17.default.dim(" \xB7 ")) + import_chalk17.default.dim(" ]");
2744
2820
  };
2745
2821
  async function turn(content) {
2746
2822
  messages.push({ role: "user", content });
2747
- process.stdout.write(import_chalk16.default.dim(" \u2026thinking\n"));
2823
+ process.stdout.write(import_chalk17.default.dim(" \u2026thinking\n"));
2748
2824
  const { status, data } = await agentCall(endpoint, "POST", { messages, ...buildBody(messages) });
2749
2825
  if (status === 402) {
2750
- console.log(import_chalk16.default.red(" Insufficient credits \u2014 top up to keep using the agents.\n"));
2826
+ console.log(import_chalk17.default.red(" Insufficient credits \u2014 top up to keep using the agents.\n"));
2751
2827
  messages.pop();
2752
2828
  return;
2753
2829
  }
2754
2830
  if (status >= 400 || !data) {
2755
- console.log(import_chalk16.default.red(` Error (${status}): ${(data && data.error) ?? "request failed"}
2831
+ console.log(import_chalk17.default.red(` Error (${status}): ${(data && data.error) ?? "request failed"}
2756
2832
  `));
2757
2833
  messages.pop();
2758
2834
  return;
@@ -2760,24 +2836,24 @@ async function runAgentChatRepl(opts) {
2760
2836
  ctx.lastData = data;
2761
2837
  const reply = data.reply ?? data.message ?? "(no reply)";
2762
2838
  messages.push({ role: "assistant", content: reply });
2763
- console.log("\n" + import_chalk16.default.cyan("agent \u203A ") + reply + "\n");
2839
+ console.log("\n" + import_chalk17.default.cyan("agent \u203A ") + reply + "\n");
2764
2840
  if (data.proposal) {
2765
2841
  ctx.proposal = data.proposal;
2766
2842
  const summary = summarizeProposal?.(data);
2767
- if (summary) console.log(import_chalk16.default.yellow(" " + summary));
2843
+ if (summary) console.log(import_chalk17.default.yellow(" " + summary));
2768
2844
  const applies = commands.filter((c) => c.needsProposal);
2769
2845
  const primary = applies[applies.length - 1];
2770
2846
  if (primary) {
2771
- console.log(import_chalk16.default.bold.green(" \u279C Next: type ") + import_chalk16.default.bold.cyan(`/${primary.name}`) + import_chalk16.default.bold.green(" to apply this, then ") + import_chalk16.default.bold.cyan("/exit") + import_chalk16.default.bold.green(" to leave."));
2847
+ console.log(import_chalk17.default.bold.green(" \u279C Next: type ") + import_chalk17.default.bold.cyan(`/${primary.name}`) + import_chalk17.default.bold.green(" to apply this, then ") + import_chalk17.default.bold.cyan("/exit") + import_chalk17.default.bold.green(" to leave."));
2772
2848
  const rest = applies.slice(0, -1).map((c) => `/${c.name} = ${c.describe}`).join(" \xB7 ");
2773
- console.log(import_chalk16.default.dim(` (or keep chatting to refine${rest ? ` \xB7 ${rest}` : ""} \xB7 /show = inspect)`));
2849
+ console.log(import_chalk17.default.dim(` (or keep chatting to refine${rest ? ` \xB7 ${rest}` : ""} \xB7 /show = inspect)`));
2774
2850
  }
2775
2851
  console.log();
2776
2852
  }
2777
2853
  const line = formatBilling(data.billing);
2778
2854
  if (line) {
2779
2855
  const llm2 = data.llm;
2780
- console.log(import_chalk16.default.dim(` ${line}${llm2?.model ? ` \xB7 ${llm2.model}` : ""}`));
2856
+ console.log(import_chalk17.default.dim(` ${line}${llm2?.model ? ` \xB7 ${llm2.model}` : ""}`));
2781
2857
  }
2782
2858
  }
2783
2859
  const rl = import_readline.default.createInterface({ input: process.stdin, output: process.stdout });
@@ -2785,31 +2861,31 @@ async function runAgentChatRepl(opts) {
2785
2861
  await turn(seedPrompt);
2786
2862
  for (; ; ) {
2787
2863
  console.log(footer());
2788
- const line = (await ask(import_chalk16.default.green("you \u203A "))).trim();
2864
+ const line = (await ask(import_chalk17.default.green("you \u203A "))).trim();
2789
2865
  if (!line) continue;
2790
2866
  const lower = line.toLowerCase();
2791
2867
  if (line === "/exit" || line === "/quit" || lower === "exit" || lower === "quit" || lower === "q") {
2792
- console.log(import_chalk16.default.dim(" Bye \u2014 anything you enabled or published stays in place.\n"));
2868
+ console.log(import_chalk17.default.dim(" Bye \u2014 anything you enabled or published stays in place.\n"));
2793
2869
  break;
2794
2870
  }
2795
2871
  if (line === "/drop") {
2796
- console.log(import_chalk16.default.dim(" Dropped the pending proposal \u2014 rules you already enabled/published are untouched.\n"));
2872
+ console.log(import_chalk17.default.dim(" Dropped the pending proposal \u2014 rules you already enabled/published are untouched.\n"));
2797
2873
  break;
2798
2874
  }
2799
2875
  if (line === "/show") {
2800
- if (!ctx.proposal) console.log(import_chalk16.default.dim(" No proposal yet \u2014 keep chatting until the agent proposes one.\n"));
2876
+ if (!ctx.proposal) console.log(import_chalk17.default.dim(" No proposal yet \u2014 keep chatting until the agent proposes one.\n"));
2801
2877
  else console.log("\n" + JSON.stringify(ctx.proposal, null, 2) + "\n");
2802
2878
  continue;
2803
2879
  }
2804
2880
  if (line.startsWith("/")) {
2805
2881
  const cmd = cmdByName.get(line.slice(1));
2806
2882
  if (!cmd) {
2807
- console.log(import_chalk16.default.red(` Unknown command "${line}". Try one of: ${commands.map((c) => "/" + c.name).join(", ")}, /show, /drop
2883
+ console.log(import_chalk17.default.red(` Unknown command "${line}". Try one of: ${commands.map((c) => "/" + c.name).join(", ")}, /show, /drop
2808
2884
  `));
2809
2885
  continue;
2810
2886
  }
2811
2887
  if (cmd.needsProposal && !ctx.proposal) {
2812
- console.log(import_chalk16.default.yellow(" No proposal yet \u2014 keep chatting until the agent generates one, then try again.\n"));
2888
+ console.log(import_chalk17.default.yellow(" No proposal yet \u2014 keep chatting until the agent generates one, then try again.\n"));
2813
2889
  continue;
2814
2890
  }
2815
2891
  await cmd.run(ctx);
@@ -2821,7 +2897,7 @@ async function runAgentChatRepl(opts) {
2821
2897
  }
2822
2898
 
2823
2899
  // src/lib/authz-apply.ts
2824
- var import_chalk17 = __toESM(require("chalk"));
2900
+ var import_chalk18 = __toESM(require("chalk"));
2825
2901
  init_api();
2826
2902
  async function gatherSampleIds(projectId, apiVersion, cap = 50) {
2827
2903
  try {
@@ -2846,10 +2922,10 @@ async function gatherSampleIds(projectId, apiVersion, cap = 50) {
2846
2922
  }
2847
2923
  function maybeWarnNoTraffic(total, projectArg) {
2848
2924
  if (total >= 3) return;
2849
- console.log(import_chalk17.default.yellow(total === 0 ? " \u26A0 No captured traffic for this API yet." : ` \u26A0 Only ${total} captured request(s) so far.`));
2850
- console.log(import_chalk17.default.dim(" The authorization agent designs much better models & rules from REAL requests"));
2851
- console.log(import_chalk17.default.dim(" (it sees who is allowed vs denied). Send some through your proxy first \u2014"));
2852
- console.log(import_chalk17.default.dim(` curl a few endpoints, or `) + import_chalk17.default.cyan("npx apiblaze dev") + import_chalk17.default.dim(` \u2014 then re-run.
2925
+ console.log(import_chalk18.default.yellow(total === 0 ? " \u26A0 No captured traffic for this API yet." : ` \u26A0 Only ${total} captured request(s) so far.`));
2926
+ console.log(import_chalk18.default.dim(" The authorization agent designs much better models & rules from REAL requests"));
2927
+ console.log(import_chalk18.default.dim(" (it sees who is allowed vs denied). Send some through your proxy first \u2014"));
2928
+ console.log(import_chalk18.default.dim(` curl a few endpoints, or `) + import_chalk18.default.cyan("npx apiblaze dev") + import_chalk18.default.dim(` \u2014 then re-run.
2853
2929
  `));
2854
2930
  }
2855
2931
  async function applyProposal(opts) {
@@ -2858,11 +2934,11 @@ async function applyProposal(opts) {
2858
2934
  {
2859
2935
  const m = await agentCall(`/projects/${projectId}/${apiVersion}/policies/model?tenantId=${encodeURIComponent(tenant2)}`, "POST", proposal.model);
2860
2936
  if (m.status === 404) {
2861
- log(import_chalk17.default.red(" Authorization store not provisioned yet. Open the dashboard Authorization tab for this project once (it auto-provisions the store), then re-run.\n"));
2937
+ log(import_chalk18.default.red(" Authorization store not provisioned yet. Open the dashboard Authorization tab for this project once (it auto-provisions the store), then re-run.\n"));
2862
2938
  return { ok: 0, fail: 0, enabled: false, storeMissing: true };
2863
2939
  }
2864
2940
  if (m.status >= 400) {
2865
- log(import_chalk17.default.red(` Model save failed (${m.status}): ${m.data?.error ?? ""}
2941
+ log(import_chalk18.default.red(` Model save failed (${m.status}): ${m.data?.error ?? ""}
2866
2942
  `));
2867
2943
  return { ok: 0, fail: 0, enabled: false };
2868
2944
  }
@@ -2891,7 +2967,7 @@ async function applyProposal(opts) {
2891
2967
  if (enable) {
2892
2968
  const e = await agentCall(`/projects/${projectId}/${apiVersion}`, "PATCH", { authorization: { enforce_authorization: true }, tenant: tenant2 });
2893
2969
  if (e.status >= 400) {
2894
- log(import_chalk17.default.red(` Enforced ${ok} route(s) but turning on the project-level switch failed (${e.status}). Toggle "Enforce Authorization" on in the dashboard.
2970
+ log(import_chalk18.default.red(` Enforced ${ok} route(s) but turning on the project-level switch failed (${e.status}). Toggle "Enforce Authorization" on in the dashboard.
2895
2971
  `));
2896
2972
  return { ok, fail: fail5, enabled: false };
2897
2973
  }
@@ -2917,10 +2993,10 @@ async function runAuthz(projectArg, apiVersionArg) {
2917
2993
  const r = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable, log: ctx.log });
2918
2994
  if (r.storeMissing) return;
2919
2995
  if (enable && r.enabled) {
2920
- ctx.log(import_chalk18.default.green(` \u2713 Enforcement ON \u2014 ${r.ok} route(s) + project switch on${r.fail ? `, ${r.fail} failed` : ""}.`));
2921
- ctx.log(import_chalk18.default.dim(" Done here? Type /exit to leave the chat (your rule stays on).\n"));
2996
+ ctx.log(import_chalk19.default.green(` \u2713 Enforcement ON \u2014 ${r.ok} route(s) + project switch on${r.fail ? `, ${r.fail} failed` : ""}.`));
2997
+ ctx.log(import_chalk19.default.dim(" Done here? Type /exit to leave the chat (your rule stays on).\n"));
2922
2998
  } else if (!enable) {
2923
- ctx.log(import_chalk18.default.green(` \u2713 Published (shadow): model + ${r.ok} route(s)${r.fail ? `, ${r.fail} failed` : ""}. Review, then /enable.
2999
+ ctx.log(import_chalk19.default.green(` \u2713 Published (shadow): model + ${r.ok} route(s)${r.fail ? `, ${r.fail} failed` : ""}. Review, then /enable.
2924
3000
  `));
2925
3001
  }
2926
3002
  }
@@ -2947,7 +3023,7 @@ async function runAuthz(projectArg, apiVersionArg) {
2947
3023
  }
2948
3024
 
2949
3025
  // src/commands/rule.ts
2950
- var import_chalk19 = __toESM(require("chalk"));
3026
+ var import_chalk20 = __toESM(require("chalk"));
2951
3027
  var import_ora6 = __toESM(require("ora"));
2952
3028
  init_auth();
2953
3029
  init_api();
@@ -2984,27 +3060,27 @@ async function runRule(ruleText, projectArg, opts) {
2984
3060
  const proposal = data?.proposal;
2985
3061
  if (!proposal || !Array.isArray(proposal.routes) || proposal.routes.length === 0) {
2986
3062
  spinner.fail("The agent couldn\u2019t turn that into a rule in one shot.");
2987
- if (data?.reply) console.log(import_chalk19.default.dim("\n " + String(data.reply).slice(0, 500) + "\n"));
2988
- console.log(import_chalk19.default.dim(" Try an interactive session for anything nuanced: ") + import_chalk19.default.cyan(`apiblaze agent authz ${projectArg}`));
3063
+ if (data?.reply) console.log(import_chalk20.default.dim("\n " + String(data.reply).slice(0, 500) + "\n"));
3064
+ console.log(import_chalk20.default.dim(" Try an interactive session for anything nuanced: ") + import_chalk20.default.cyan(`apiblaze agent authz ${projectArg}`));
2989
3065
  return;
2990
3066
  }
2991
3067
  spinner.succeed(`Rule designed \u2014 ${proposal.routes.length} route(s) affected.`);
2992
- if (data?.reply) console.log(import_chalk19.default.dim(" " + String(data.reply).slice(0, 240)));
3068
+ if (data?.reply) console.log(import_chalk20.default.dim(" " + String(data.reply).slice(0, 240)));
2993
3069
  const pub = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable: false });
2994
3070
  if (pub.storeMissing) return;
2995
- console.log(import_chalk19.default.green(` \u2713 Published in shadow mode \u2014 model + ${pub.ok} route(s)${pub.fail ? `, ${pub.fail} failed` : ""}.`));
3071
+ console.log(import_chalk20.default.green(` \u2713 Published in shadow mode \u2014 model + ${pub.ok} route(s)${pub.fail ? `, ${pub.fail} failed` : ""}.`));
2996
3072
  if (opts.enforce) {
2997
3073
  const enf = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable: true });
2998
3074
  if (enf.enabled) {
2999
- console.log(import_chalk19.default.green(` \u2713 Enforcement ON \u2014 ${enf.ok} route(s) + project switch on${enf.fail ? `, ${enf.fail} failed` : ""}.`));
3075
+ console.log(import_chalk20.default.green(` \u2713 Enforcement ON \u2014 ${enf.ok} route(s) + project switch on${enf.fail ? `, ${enf.fail} failed` : ""}.`));
3000
3076
  }
3001
3077
  } else {
3002
- console.log(import_chalk19.default.dim(` Review it (shadow logs), then enforce: `) + import_chalk19.default.cyan(`apiblaze rule "${rule}" ${projectArg} --enforce`));
3078
+ console.log(import_chalk20.default.dim(` Review it (shadow logs), then enforce: `) + import_chalk20.default.cyan(`apiblaze rule "${rule}" ${projectArg} --enforce`));
3003
3079
  }
3004
3080
  }
3005
3081
 
3006
3082
  // src/commands/openapi.ts
3007
- var import_chalk20 = __toESM(require("chalk"));
3083
+ var import_chalk21 = __toESM(require("chalk"));
3008
3084
  init_auth();
3009
3085
  init_api();
3010
3086
  async function runOpenapi(projectArg, apiVersionArg) {
@@ -3015,10 +3091,10 @@ async function runOpenapi(projectArg, apiVersionArg) {
3015
3091
  if (!match) throw new Error(`Project "${projectArg}" not found in your active team. Run \`apiblaze projects\`.`);
3016
3092
  const projectId = match.projectId;
3017
3093
  const apiVersion = apiVersionArg || match.apiVersion;
3018
- console.log(import_chalk20.default.dim("Gathering captured traffic samples\u2026"));
3094
+ console.log(import_chalk21.default.dim("Gathering captured traffic samples\u2026"));
3019
3095
  const routesRes = await agentCall(`/projects/${projectId}/${apiVersion}/samples/routes`, "GET");
3020
3096
  if (routesRes.status >= 400) {
3021
- console.log(import_chalk20.default.red(`Could not list traffic (${routesRes.status}): ${routesRes.data?.error ?? ""}`));
3097
+ console.log(import_chalk21.default.red(`Could not list traffic (${routesRes.status}): ${routesRes.data?.error ?? ""}`));
3022
3098
  return;
3023
3099
  }
3024
3100
  const routes = routesRes.data?.routes ?? (Array.isArray(routesRes.data) ? routesRes.data : []);
@@ -3031,25 +3107,25 @@ async function runOpenapi(projectArg, apiVersionArg) {
3031
3107
  }
3032
3108
  const sampleIds = [...ids];
3033
3109
  if (sampleIds.length === 0) {
3034
- console.log(import_chalk20.default.yellow("No captured traffic samples found. Hit the dev environment of this proxy to capture some traces, then retry."));
3110
+ console.log(import_chalk21.default.yellow("No captured traffic samples found. Hit the dev environment of this proxy to capture some traces, then retry."));
3035
3111
  return;
3036
3112
  }
3037
3113
  async function publish(ctx) {
3038
3114
  const patch = ctx.proposal.patch;
3039
3115
  if (!Array.isArray(patch) || patch.length === 0) {
3040
- ctx.log(import_chalk20.default.green(" Nothing to publish \u2014 the spec already covers the observed traffic.\n"));
3116
+ ctx.log(import_chalk21.default.green(" Nothing to publish \u2014 the spec already covers the observed traffic.\n"));
3041
3117
  return;
3042
3118
  }
3043
3119
  const specSource = ctx.lastData?.spec_source ?? "unknown";
3044
3120
  const endpoint = specSource === "github" ? "open-pr" : "publish-openapi";
3045
3121
  const pub = await agentCall(`/projects/${projectId}/${apiVersion}/samples/${endpoint}`, "POST", { patch, sample_ids_used: sampleIds });
3046
3122
  if (pub.status >= 400) {
3047
- ctx.log(import_chalk20.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
3123
+ ctx.log(import_chalk21.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
3048
3124
  `));
3049
3125
  return;
3050
3126
  }
3051
3127
  const prUrl = pub.data?.pr_url;
3052
- ctx.log(import_chalk20.default.green(prUrl ? ` \u2713 Pull request opened: ${prUrl}
3128
+ ctx.log(import_chalk21.default.green(prUrl ? ` \u2713 Pull request opened: ${prUrl}
3053
3129
  ` : " \u2713 Published updated OpenAPI spec.\n"));
3054
3130
  }
3055
3131
  await runAgentChatRepl({
@@ -3070,7 +3146,7 @@ async function runOpenapi(projectArg, apiVersionArg) {
3070
3146
  }
3071
3147
 
3072
3148
  // src/commands/mcp.ts
3073
- var import_chalk21 = __toESM(require("chalk"));
3149
+ var import_chalk22 = __toESM(require("chalk"));
3074
3150
  init_auth();
3075
3151
  init_api();
3076
3152
  async function runMcp(projectArg, apiVersionArg, opts) {
@@ -3087,11 +3163,11 @@ async function runMcp(projectArg, apiVersionArg, opts) {
3087
3163
  const spec2 = ctx.proposal;
3088
3164
  const pub = await agentCall(`/projects/${projectId}/${apiVersion}/mcp/spec`, "PUT", { environment, spec: spec2 });
3089
3165
  if (pub.status >= 400) {
3090
- ctx.log(import_chalk21.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
3166
+ ctx.log(import_chalk22.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
3091
3167
  `));
3092
3168
  return;
3093
3169
  }
3094
- ctx.log(import_chalk21.default.green(` \u2713 Published MCP server \u2014 ${mcpHost}.mcp.apiblaze.com/${apiVersion}/${environment}.
3170
+ ctx.log(import_chalk22.default.green(` \u2713 Published MCP server \u2014 ${mcpHost}.mcp.apiblaze.com/${apiVersion}/${environment}.
3095
3171
  `));
3096
3172
  }
3097
3173
  await runAgentChatRepl({
@@ -3113,7 +3189,7 @@ async function runMcp(projectArg, apiVersionArg, opts) {
3113
3189
  }
3114
3190
 
3115
3191
  // src/commands/delete.ts
3116
- var import_chalk22 = __toESM(require("chalk"));
3192
+ var import_chalk23 = __toESM(require("chalk"));
3117
3193
  var import_ora7 = __toESM(require("ora"));
3118
3194
  init_admin();
3119
3195
  init_resolve();
@@ -3139,10 +3215,10 @@ async function runDelete(project, version2, opts) {
3139
3215
  return;
3140
3216
  }
3141
3217
  } else {
3142
- console.log(`${import_chalk22.default.red.bold("Delete")} ${import_chalk22.default.bold(proj2.projectName)} ${import_chalk22.default.dim("v" + proj2.apiVersion)} ${import_chalk22.default.dim("(" + proj2.projectId + ")")}`);
3218
+ console.log(`${import_chalk23.default.red.bold("Delete")} ${import_chalk23.default.bold(proj2.projectName)} ${import_chalk23.default.dim("v" + proj2.apiVersion)} ${import_chalk23.default.dim("(" + proj2.projectId + ")")}`);
3143
3219
  if (impact && typeof impact === "object") {
3144
3220
  const counts = impact.counts ?? impact.impact ?? impact;
3145
- console.log(import_chalk22.default.dim(" This removes (cascade): ") + import_chalk22.default.yellow(JSON.stringify(counts)));
3221
+ console.log(import_chalk23.default.dim(" This removes (cascade): ") + import_chalk23.default.yellow(JSON.stringify(counts)));
3146
3222
  }
3147
3223
  if (!opts.yes) {
3148
3224
  const { default: inquirer3 } = await import("inquirer");
@@ -3150,7 +3226,7 @@ async function runDelete(project, version2, opts) {
3150
3226
  { type: "confirm", name: "confirm", message: `Permanently delete ${proj2.projectName} v${proj2.apiVersion}? This cannot be undone.`, default: false }
3151
3227
  ]);
3152
3228
  if (!confirm) {
3153
- console.log(import_chalk22.default.dim("Aborted."));
3229
+ console.log(import_chalk23.default.dim("Aborted."));
3154
3230
  return;
3155
3231
  }
3156
3232
  }
@@ -3171,7 +3247,7 @@ async function runDelete(project, version2, opts) {
3171
3247
  }
3172
3248
 
3173
3249
  // src/commands/export.ts
3174
- var import_chalk23 = __toESM(require("chalk"));
3250
+ var import_chalk24 = __toESM(require("chalk"));
3175
3251
  var import_fs3 = require("fs");
3176
3252
  init_admin();
3177
3253
  init_auth();
@@ -3190,7 +3266,7 @@ async function runExport(projectArg, versionArg, opts) {
3190
3266
  if (opts.noConsumers) q.set("include_consumers", "0");
3191
3267
  if (opts.keys) q.set("keys", opts.keys);
3192
3268
  const qs = q.toString() ? `?${q.toString()}` : "";
3193
- console.log(import_chalk23.default.dim(`Queuing ${target} export of ${projectId}@${version2}\u2026`));
3269
+ console.log(import_chalk24.default.dim(`Queuing ${target} export of ${projectId}@${version2}\u2026`));
3194
3270
  const job = await admin({
3195
3271
  path: `/projects/${projectId}/${version2}/export/${target}${qs}`,
3196
3272
  method: "GET",
@@ -3200,11 +3276,11 @@ async function runExport(projectArg, versionArg, opts) {
3200
3276
  const statusPath = `/projects/${projectId}/${version2}/export/jobs/${job.job_id}`;
3201
3277
  let status = "queued";
3202
3278
  const started = Date.now();
3203
- process.stdout.write(import_chalk23.default.dim("Building bundle"));
3279
+ process.stdout.write(import_chalk24.default.dim("Building bundle"));
3204
3280
  while (status !== "ready" && status !== "failed") {
3205
3281
  if (Date.now() - started > 10 * 6e4) throw new Error("Export timed out after 10 minutes.");
3206
3282
  await new Promise((r) => setTimeout(r, 3e3));
3207
- process.stdout.write(import_chalk23.default.dim("."));
3283
+ process.stdout.write(import_chalk24.default.dim("."));
3208
3284
  const st = await admin({ path: statusPath, method: "GET", summary: "poll export" });
3209
3285
  status = st?.status ?? "queued";
3210
3286
  if (status === "failed") {
@@ -3222,14 +3298,869 @@ async function runExport(projectArg, versionArg, opts) {
3222
3298
  if (!res.ok) throw new Error(`Download failed (${res.status}): ${await res.text().catch(() => "")}`);
3223
3299
  const buf = Buffer.from(await res.arrayBuffer());
3224
3300
  (0, import_fs3.writeFileSync)(outFile, buf);
3225
- console.log(import_chalk23.default.green(`\u2713 Saved ${outFile} (${(buf.length / 1024).toFixed(0)} KB)`));
3226
- if (job.decryption_key) console.log(import_chalk23.default.yellow(`Decryption key (shown once): ${job.decryption_key}`));
3227
- console.log(import_chalk23.default.dim("Read MIGRATION-REPORT.json inside the zip for the full fidelity ledger."));
3228
- if (target === "kong") console.log(import_chalk23.default.dim("Kong: unzip, then `cd kong && docker compose up` (see kong/README.md)."));
3301
+ console.log(import_chalk24.default.green(`\u2713 Saved ${outFile} (${(buf.length / 1024).toFixed(0)} KB)`));
3302
+ if (job.decryption_key) console.log(import_chalk24.default.yellow(`Decryption key (shown once): ${job.decryption_key}`));
3303
+ console.log(import_chalk24.default.dim("Read MIGRATION-REPORT.json inside the zip for the full fidelity ledger."));
3304
+ if (target === "kong") console.log(import_chalk24.default.dim("Kong: unzip, then `cd kong && docker compose up` (see kong/README.md)."));
3305
+ }
3306
+
3307
+ // src/commands/logs.ts
3308
+ var import_chalk26 = __toESM(require("chalk"));
3309
+ init_admin();
3310
+ init_auth();
3311
+ init_resolve();
3312
+
3313
+ // src/lib/log-view.ts
3314
+ var import_chalk25 = __toESM(require("chalk"));
3315
+ var readline2 = __toESM(require("readline"));
3316
+ function statusColor(status) {
3317
+ if (status < 300) return import_chalk25.default.green;
3318
+ if (status < 400) return import_chalk25.default.blue;
3319
+ if (status < 500) return import_chalk25.default.yellow;
3320
+ return import_chalk25.default.red;
3321
+ }
3322
+ function methodColor(method) {
3323
+ switch ((method || "").toUpperCase()) {
3324
+ case "GET":
3325
+ return import_chalk25.default.green;
3326
+ case "POST":
3327
+ return import_chalk25.default.blue;
3328
+ case "PUT":
3329
+ case "PATCH":
3330
+ return import_chalk25.default.yellow;
3331
+ case "DELETE":
3332
+ return import_chalk25.default.red;
3333
+ default:
3334
+ return import_chalk25.default.white;
3335
+ }
3336
+ }
3337
+ function clock(ts) {
3338
+ return new Date(ts).toLocaleTimeString(void 0, { hour12: false });
3339
+ }
3340
+ var ROUTE_W = 34;
3341
+ function routeCell(route) {
3342
+ const r = route || "\u2014";
3343
+ return (r.length > ROUTE_W ? `\u2026${r.slice(-(ROUTE_W - 1))}` : r).padEnd(ROUTE_W);
3344
+ }
3345
+ function formatRow(r) {
3346
+ const time = import_chalk25.default.dim(clock(r.ts));
3347
+ const method = methodColor(r.method)(String(r.method || "\u2014").padEnd(6));
3348
+ const route = routeCell(String(r.route || "\u2014"));
3349
+ const status = statusColor(r.status)(String(r.status ?? "\u2014").padStart(3));
3350
+ const ms = import_chalk25.default.dim(`${r.duration_ms}ms`.padStart(8));
3351
+ const step = r.error_step ? import_chalk25.default.dim(` ${r.error_step}`) : "";
3352
+ return `${time} ${method} ${route} ${status} ${ms}${step}`;
3353
+ }
3354
+ function printRow(r, json) {
3355
+ console.log(json ? JSON.stringify(r) : formatRow(r));
3356
+ }
3357
+ var WindowNotices = class {
3358
+ constructor() {
3359
+ this.saidUnavailable = false;
3360
+ this.saidGap = false;
3361
+ this.saidDropped = false;
3362
+ }
3363
+ note(res) {
3364
+ if (res.history_unavailable && !this.saidUnavailable) {
3365
+ this.saidUnavailable = true;
3366
+ console.error(import_chalk25.default.yellow("\u26A0 log history is unreachable right now \u2014 showing the live buffer only, older requests exist but cannot be read."));
3367
+ }
3368
+ if ((res.history_markers?.length ?? 0) > 0 && !this.saidGap) {
3369
+ this.saidGap = true;
3370
+ console.error(import_chalk25.default.yellow("\u26A0 this range includes a volume-ceiling gap \u2014 some rows were dropped at intake and are gone; counts are incomplete."));
3371
+ }
3372
+ if ((res.dropped_this_hour ?? 0) > 0 && !this.saidDropped) {
3373
+ this.saidDropped = true;
3374
+ console.error(import_chalk25.default.yellow(`\u26A0 volume ceiling \u2014 ${res.dropped_this_hour} rows dropped this hour; errors keep logging.`));
3375
+ }
3376
+ }
3377
+ };
3378
+ var MAX_RECONNECTS = 5;
3379
+ var PING_MS = Number(process.env.APIBLAZE_TAIL_PING_MS) || 3e4;
3380
+ var LIVENESS_MS = PING_MS * 2.5;
3381
+ var STABLE_MS = 3e4;
3382
+ var SEEN_CAP = 1e4;
3383
+ var TAIL_INSPECT_BUFFER = 500;
3384
+ var TAIL_INSPECT_CHOICES = 40;
3385
+ async function runTailSession(opts) {
3386
+ const { default: WebSocket2 } = await import("ws");
3387
+ guardStdoutPipe();
3388
+ let closed = false;
3389
+ let everConnected = false;
3390
+ let reconnects = 0;
3391
+ let openedAt = 0;
3392
+ let lastFailure = "";
3393
+ let pingTimer;
3394
+ let activeSocket;
3395
+ const seen = /* @__PURE__ */ new Set();
3396
+ const seenOrder = [];
3397
+ function remember(id) {
3398
+ seen.add(id);
3399
+ seenOrder.push(id);
3400
+ if (seenOrder.length > SEEN_CAP) seen.delete(seenOrder.shift());
3401
+ }
3402
+ const interactive = !opts.json && !!process.stdin.isTTY && !!process.stdout.isTTY;
3403
+ const recent = [];
3404
+ const held = [];
3405
+ let heldRowsDropped = 0;
3406
+ let heldNotesDropped = 0;
3407
+ let paused = false;
3408
+ let keysBound = false;
3409
+ function pushHeld(item) {
3410
+ if (held.length >= TAIL_INSPECT_BUFFER) {
3411
+ const victimIdx = held.findIndex((h) => h.kind === "row");
3412
+ if (victimIdx >= 0) {
3413
+ held.splice(victimIdx, 1);
3414
+ heldRowsDropped++;
3415
+ } else {
3416
+ held.shift();
3417
+ heldNotesDropped++;
3418
+ }
3419
+ }
3420
+ held.push(item);
3421
+ }
3422
+ function diag(msg) {
3423
+ if (paused) {
3424
+ pushHeld({ kind: "note", msg });
3425
+ return;
3426
+ }
3427
+ console.error(msg);
3428
+ }
3429
+ function flushHeld() {
3430
+ if (!held.length && !heldRowsDropped && !heldNotesDropped) return;
3431
+ const rows = held.filter((h) => h.kind === "row").length;
3432
+ const total = rows + heldRowsDropped;
3433
+ if (total) console.log(import_chalk25.default.dim(`\u2500\u2500\u2500 ${total} request${total === 1 ? "" : "s"} arrived while paused \u2500\u2500\u2500`));
3434
+ for (const h of held) {
3435
+ if (h.kind === "row") printRow(h.row, opts.json);
3436
+ else console.error(h.msg);
3437
+ }
3438
+ if (heldRowsDropped || heldNotesDropped) {
3439
+ console.log(import_chalk25.default.dim(`\u2500\u2500\u2500 ${heldRowsDropped} older one${heldRowsDropped === 1 ? "" : "s"} not shown (pause buffer full) \u2014 browse them with \`logs list\` \u2500\u2500\u2500`));
3440
+ }
3441
+ held.length = 0;
3442
+ heldRowsDropped = 0;
3443
+ heldNotesDropped = 0;
3444
+ }
3445
+ function shutdown() {
3446
+ closed = true;
3447
+ if (pingTimer) clearInterval(pingTimer);
3448
+ unbindKeys();
3449
+ try {
3450
+ activeSocket?.close();
3451
+ } catch {
3452
+ }
3453
+ if (!opts.json) console.log(import_chalk25.default.dim("\nStopped."));
3454
+ process.exit(0);
3455
+ }
3456
+ function onKeypress(_s, key) {
3457
+ if (key?.ctrl && key.name === "c") {
3458
+ shutdown();
3459
+ return;
3460
+ }
3461
+ if (key?.name === "return" || key?.name === "enter") void openInspector();
3462
+ }
3463
+ function bindKeys() {
3464
+ if (!interactive || keysBound || paused) return;
3465
+ keysBound = true;
3466
+ readline2.emitKeypressEvents(process.stdin);
3467
+ process.stdin.setRawMode(true);
3468
+ process.stdin.on("keypress", onKeypress);
3469
+ process.stdin.resume();
3470
+ }
3471
+ function unbindKeys() {
3472
+ if (!keysBound) return;
3473
+ keysBound = false;
3474
+ process.stdin.off("keypress", onKeypress);
3475
+ if (process.stdin.isTTY) process.stdin.setRawMode(false);
3476
+ process.stdin.pause();
3477
+ }
3478
+ async function openInspector() {
3479
+ if (paused) return;
3480
+ if (recent.length === 0) {
3481
+ console.log(import_chalk25.default.dim(" nothing captured yet \u2014 waiting for a request\u2026"));
3482
+ return;
3483
+ }
3484
+ paused = true;
3485
+ unbindKeys();
3486
+ try {
3487
+ const { default: inquirer3 } = await import("inquirer");
3488
+ console.log(import_chalk25.default.dim("\n\u2500\u2500\u2500 paused \xB7 still capturing in the background \u2500\u2500\u2500"));
3489
+ for (; ; ) {
3490
+ const choices = recent.slice(-TAIL_INSPECT_CHOICES).reverse().map((r) => ({ name: formatRow(r), value: r.request_id }));
3491
+ choices.push({ name: import_chalk25.default.dim("\u2039resume tail\u203A"), value: "__resume__" });
3492
+ const { picked } = await inquirer3.prompt([{
3493
+ type: "list",
3494
+ name: "picked",
3495
+ message: "Inspect which request?",
3496
+ choices,
3497
+ pageSize: 15
3498
+ }]);
3499
+ if (picked === "__resume__") break;
3500
+ const row = recent.find((r) => r.request_id === picked);
3501
+ if (row) printDetail(row, opts.detail);
3502
+ else console.log(import_chalk25.default.dim(" that request has scrolled out of the tail buffer \u2014 find it with `logs list`.\n"));
3503
+ }
3504
+ } finally {
3505
+ paused = false;
3506
+ flushHeld();
3507
+ console.log(import_chalk25.default.dim("\u2500\u2500\u2500 resumed \u2500\u2500\u2500"));
3508
+ bindKeys();
3509
+ }
3510
+ }
3511
+ process.on("SIGINT", shutdown);
3512
+ function scheduleReconnect() {
3513
+ if (closed) return;
3514
+ if (reconnects >= MAX_RECONNECTS) {
3515
+ paused = false;
3516
+ flushHeld();
3517
+ console.error(import_chalk25.default.red(`Connection lost \u2014 giving up after repeated reconnects${lastFailure ? ` (last error: ${lastFailure})` : ""}.`));
3518
+ process.exit(1);
3519
+ }
3520
+ const delay = Math.min(1e3 * 2 ** reconnects, 15e3);
3521
+ reconnects++;
3522
+ diag(import_chalk25.default.dim(`disconnected${lastFailure ? ` (${lastFailure})` : ""} \u2014 reconnecting in ${Math.round(delay / 1e3)}s\u2026`));
3523
+ setTimeout(() => {
3524
+ if (!closed) void connect();
3525
+ }, delay);
3526
+ }
3527
+ async function connect() {
3528
+ let url;
3529
+ try {
3530
+ url = await opts.mintTicket();
3531
+ } catch (err) {
3532
+ if (!everConnected) {
3533
+ console.error(import_chalk25.default.red(`Could not start tail: ${err.message}`));
3534
+ process.exit(1);
3535
+ }
3536
+ lastFailure = `ticket mint failed: ${err.message}`;
3537
+ scheduleReconnect();
3538
+ return;
3539
+ }
3540
+ let socket;
3541
+ try {
3542
+ socket = new WebSocket2(url);
3543
+ } catch (err) {
3544
+ lastFailure = `bad tail URL: ${err.message}`;
3545
+ if (!everConnected) {
3546
+ console.error(import_chalk25.default.red(`Could not start tail: ${lastFailure}`));
3547
+ process.exit(1);
3548
+ }
3549
+ scheduleReconnect();
3550
+ return;
3551
+ }
3552
+ activeSocket = socket;
3553
+ let lastInbound = Date.now();
3554
+ socket.on("open", () => {
3555
+ const isReconnect = everConnected;
3556
+ everConnected = true;
3557
+ openedAt = Date.now();
3558
+ lastInbound = Date.now();
3559
+ lastFailure = "";
3560
+ if (isReconnect) {
3561
+ diag(import_chalk25.default.dim("reconnected \u2014 requests during the gap were not replayed (browse them with `logs list`)."));
3562
+ } else {
3563
+ diag(import_chalk25.default.dim(interactive ? "[Enter] inspect a request \xB7 [Ctrl+C] stop\n" : "Ctrl+C to stop."));
3564
+ }
3565
+ bindKeys();
3566
+ pingTimer = setInterval(() => {
3567
+ if (Date.now() - lastInbound > LIVENESS_MS) {
3568
+ lastFailure = `no pong for ${Math.round(LIVENESS_MS / 1e3)}s \u2014 connection presumed dead`;
3569
+ try {
3570
+ socket.terminate();
3571
+ } catch {
3572
+ }
3573
+ return;
3574
+ }
3575
+ try {
3576
+ socket.send("ping");
3577
+ } catch {
3578
+ }
3579
+ }, PING_MS);
3580
+ });
3581
+ socket.on("message", (data) => {
3582
+ lastInbound = Date.now();
3583
+ let frame;
3584
+ try {
3585
+ frame = JSON.parse(String(data));
3586
+ } catch {
3587
+ return;
3588
+ }
3589
+ if (frame?.type === "ceiling") {
3590
+ diag(import_chalk25.default.yellow(
3591
+ `\u26A0 volume ceiling \u2014 ${Number(frame.dropped_this_hour) || 0} rows dropped this hour; errors keep streaming.`
3592
+ ));
3593
+ return;
3594
+ }
3595
+ if (!frame?.request_id || seen.has(frame.request_id)) return;
3596
+ remember(frame.request_id);
3597
+ if (opts.errorsOnly && Number(frame.status) < 400) return;
3598
+ recent.push(frame);
3599
+ if (recent.length > TAIL_INSPECT_BUFFER) recent.shift();
3600
+ if (paused) {
3601
+ pushHeld({ kind: "row", row: frame });
3602
+ return;
3603
+ }
3604
+ printRow(frame, opts.json);
3605
+ });
3606
+ socket.on("error", (err) => {
3607
+ lastFailure = err?.message || String(err);
3608
+ });
3609
+ socket.on("close", (code, reason) => {
3610
+ if (pingTimer) clearInterval(pingTimer);
3611
+ if (openedAt && Date.now() - openedAt >= STABLE_MS) reconnects = 0;
3612
+ openedAt = 0;
3613
+ const why = String(reason ?? "").trim();
3614
+ if (why) lastFailure = `socket closed: ${why} (${code})`;
3615
+ scheduleReconnect();
3616
+ });
3617
+ }
3618
+ await connect();
3619
+ }
3620
+ function localDayMs(ts) {
3621
+ const d = new Date(ts);
3622
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
3623
+ }
3624
+ function nextLocalDayMs(dayMs) {
3625
+ const d = new Date(dayMs);
3626
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1).getTime();
3627
+ }
3628
+ function dayKey(ts) {
3629
+ const d = new Date(ts);
3630
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
3631
+ }
3632
+ function dayLabel(dayMs, now) {
3633
+ const today = localDayMs(now);
3634
+ const n = new Date(now);
3635
+ const yesterday = new Date(n.getFullYear(), n.getMonth(), n.getDate() - 1).getTime();
3636
+ if (dayMs === today) return "Today";
3637
+ if (dayMs === yesterday) return "Yesterday";
3638
+ return new Date(dayMs).toLocaleDateString(void 0, { weekday: "short", month: "short", day: "numeric" });
3639
+ }
3640
+ function groupIntoDays(rows) {
3641
+ const byKey = /* @__PURE__ */ new Map();
3642
+ const order = [];
3643
+ for (const r of [...rows].sort((a, b) => b.ts - a.ts)) {
3644
+ const k = dayKey(r.ts);
3645
+ let b = byKey.get(k);
3646
+ if (!b) {
3647
+ b = { key: k, dayMs: localDayMs(r.ts), rows: [], errors: 0 };
3648
+ byKey.set(k, b);
3649
+ order.push(b);
3650
+ }
3651
+ b.rows.push(r);
3652
+ if (r.status >= 400) b.errors++;
3653
+ }
3654
+ return order;
3655
+ }
3656
+ var SCAN_LIMIT = 200;
3657
+ var PAGE_LIMIT = 50;
3658
+ var JSON_PAGE_LIMIT = 500;
3659
+ var MAX_EMPTY_HOPS = 100;
3660
+ async function fetchPage(fetchWindow3, params, notices) {
3661
+ let cursor = params.cursor;
3662
+ for (let hop = 0; ; hop++) {
3663
+ const res = await fetchWindow3({ ...params, cursor });
3664
+ notices.note(res);
3665
+ const rows = res.rows ?? [];
3666
+ if (rows.length > 0 || !res.next_cursor) {
3667
+ return { rows, nextCursor: res.next_cursor ?? void 0 };
3668
+ }
3669
+ if (hop >= MAX_EMPTY_HOPS) {
3670
+ console.error(import_chalk25.default.yellow("\u26A0 stopped after scanning a long empty span \u2014 older rows may still exist."));
3671
+ return { rows: [], nextCursor: res.next_cursor, fuseTripped: true };
3672
+ }
3673
+ if (hop === 0) console.error(import_chalk25.default.dim("searching older history\u2026"));
3674
+ cursor = res.next_cursor;
3675
+ }
3676
+ }
3677
+ var epipeGuarded = false;
3678
+ function guardStdoutPipe() {
3679
+ if (epipeGuarded) return;
3680
+ epipeGuarded = true;
3681
+ process.stdout.on("error", (err) => {
3682
+ if (err?.code === "EPIPE") process.exit(0);
3683
+ throw err;
3684
+ });
3685
+ }
3686
+ var PLAIN_MAX_ROWS = 200;
3687
+ async function runPlainList(opts, notices) {
3688
+ guardStdoutPipe();
3689
+ const rows = [];
3690
+ let cursor;
3691
+ let more = false;
3692
+ let fuseTripped = false;
3693
+ while (rows.length < PLAIN_MAX_ROWS) {
3694
+ const page = await fetchPage(opts.fetchWindow, {
3695
+ limit: Math.min(PAGE_LIMIT, PLAIN_MAX_ROWS - rows.length),
3696
+ errorsOnly: opts.errorsOnly,
3697
+ cursor
3698
+ }, notices);
3699
+ rows.push(...page.rows);
3700
+ if (page.fuseTripped) {
3701
+ more = true;
3702
+ fuseTripped = true;
3703
+ break;
3704
+ }
3705
+ if (!page.nextCursor) break;
3706
+ cursor = page.nextCursor;
3707
+ if (rows.length >= PLAIN_MAX_ROWS) {
3708
+ more = true;
3709
+ break;
3710
+ }
3711
+ }
3712
+ if (rows.length === 0) {
3713
+ console.log(import_chalk25.default.dim(fuseTripped ? "Nothing found in the scanned span \u2014 older requests may still exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
3714
+ return;
3715
+ }
3716
+ const now = Date.now();
3717
+ for (const d of groupIntoDays(rows)) {
3718
+ console.log(import_chalk25.default.bold(dayLabel(d.dayMs, now)));
3719
+ for (const r of d.rows) console.log(` ${formatRow(r)}`);
3720
+ console.log("");
3721
+ }
3722
+ const errs = rows.filter((r) => r.status >= 400).length;
3723
+ const tail = fuseTripped ? " \xB7 stopped early (long empty span) \u2014 older requests may still exist" : more ? " \xB7 showing the most recent \u2014 `--json` streams the rest" : "";
3724
+ console.log(import_chalk25.default.dim(
3725
+ `${rows.length} request${rows.length === 1 ? "" : "s"} \xB7 ${errs} error${errs === 1 ? "" : "s"}${tail}`
3726
+ ));
3727
+ }
3728
+ async function runHistoryBrowser(opts) {
3729
+ const notices = new WindowNotices();
3730
+ if (opts.json) {
3731
+ guardStdoutPipe();
3732
+ let cursor2;
3733
+ let any = false;
3734
+ for (; ; ) {
3735
+ const page = await fetchPage(opts.fetchWindow, {
3736
+ limit: JSON_PAGE_LIMIT,
3737
+ errorsOnly: opts.errorsOnly,
3738
+ cursor: cursor2
3739
+ }, notices);
3740
+ for (const r of page.rows) console.log(JSON.stringify(r));
3741
+ any = any || page.rows.length > 0;
3742
+ if (page.fuseTripped || !page.nextCursor) {
3743
+ if (!any && !page.fuseTripped) console.error(import_chalk25.default.dim(opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
3744
+ return;
3745
+ }
3746
+ cursor2 = page.nextCursor;
3747
+ }
3748
+ }
3749
+ if (opts.plain || !process.stdout.isTTY || !process.stdin.isTTY) {
3750
+ await runPlainList(opts, notices);
3751
+ return;
3752
+ }
3753
+ const { default: inquirer3 } = await import("inquirer");
3754
+ let scanRows = [];
3755
+ let scanCursor;
3756
+ {
3757
+ const first = await fetchPage(opts.fetchWindow, {
3758
+ limit: SCAN_LIMIT,
3759
+ errorsOnly: opts.errorsOnly
3760
+ }, notices);
3761
+ scanRows = first.rows;
3762
+ scanCursor = first.nextCursor;
3763
+ if (scanRows.length === 0) {
3764
+ console.log(import_chalk25.default.dim(first.fuseTripped ? "Nothing found in the scanned span \u2014 older rows may exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
3765
+ return;
3766
+ }
3767
+ }
3768
+ let day;
3769
+ let scanFloorUnknown = false;
3770
+ for (; ; ) {
3771
+ const days = groupIntoDays(scanRows);
3772
+ const now2 = Date.now();
3773
+ const oldestKey = days[days.length - 1]?.key;
3774
+ const choices = days.map((d) => ({
3775
+ name: `${dayLabel(d.dayMs, now2).padEnd(12)} ${String(d.rows.length).padStart(4)}${(scanCursor !== void 0 || scanFloorUnknown) && d.key === oldestKey ? "+" : ""} requests${d.errors ? import_chalk25.default.red(` ${d.errors} errors`) : ""}`,
3776
+ value: d.key
3777
+ }));
3778
+ if (scanCursor) choices.push({ name: import_chalk25.default.dim("\u2026 older days"), value: "__older__" });
3779
+ const { chosenDay } = await inquirer3.prompt([{
3780
+ type: "list",
3781
+ name: "chosenDay",
3782
+ message: "Which day?",
3783
+ choices,
3784
+ pageSize: 20
3785
+ }]);
3786
+ if (chosenDay === "__older__") {
3787
+ const more = await fetchPage(opts.fetchWindow, {
3788
+ limit: SCAN_LIMIT,
3789
+ errorsOnly: opts.errorsOnly,
3790
+ cursor: scanCursor
3791
+ }, notices);
3792
+ scanRows = scanRows.concat(more.rows);
3793
+ if (more.fuseTripped) {
3794
+ scanFloorUnknown = true;
3795
+ scanCursor = void 0;
3796
+ } else {
3797
+ scanCursor = more.nextCursor;
3798
+ if (more.rows.length === 0 && !scanCursor) console.log(import_chalk25.default.dim("That was everything \u2014 no older requests."));
3799
+ }
3800
+ continue;
3801
+ }
3802
+ day = days.find((d) => d.key === chosenDay);
3803
+ break;
3804
+ }
3805
+ const since = day.dayMs;
3806
+ const until = nextLocalDayMs(day.dayMs) - 1;
3807
+ const now = Date.now();
3808
+ let cursor;
3809
+ let pageRows = [];
3810
+ let moreCursor;
3811
+ for (; ; ) {
3812
+ const page = await fetchPage(opts.fetchWindow, {
3813
+ limit: PAGE_LIMIT,
3814
+ since,
3815
+ until,
3816
+ errorsOnly: opts.errorsOnly,
3817
+ cursor
3818
+ }, notices);
3819
+ if (page.rows.length === 0 && pageRows.length === 0) {
3820
+ console.log(import_chalk25.default.dim(page.fuseTripped ? "Stopped scanning this day (long empty span) \u2014 older rows in it may exist." : "No requests for this day."));
3821
+ return;
3822
+ }
3823
+ if (page.rows.length === 0) {
3824
+ console.log(import_chalk25.default.dim(page.fuseTripped ? "Stopped scanning further into this day (long empty span) \u2014 older rows in it may exist." : "That was everything for this day."));
3825
+ moreCursor = void 0;
3826
+ } else {
3827
+ pageRows = page.rows;
3828
+ moreCursor = page.fuseTripped ? void 0 : page.nextCursor;
3829
+ }
3830
+ console.log("");
3831
+ const choices = pageRows.map((r) => ({
3832
+ name: formatRow(r),
3833
+ value: r.request_id
3834
+ }));
3835
+ if (moreCursor) choices.push({ name: import_chalk25.default.dim("\u2026 load more"), value: "__more__" });
3836
+ choices.push({ name: import_chalk25.default.dim("quit"), value: "__quit__" });
3837
+ for (; ; ) {
3838
+ const { picked } = await inquirer3.prompt([{
3839
+ type: "list",
3840
+ name: "picked",
3841
+ message: `${dayLabel(day.dayMs, now)} \u2014 select a request for detail`,
3842
+ choices,
3843
+ pageSize: 20
3844
+ }]);
3845
+ if (picked === "__quit__") return;
3846
+ if (picked === "__more__") {
3847
+ cursor = moreCursor;
3848
+ break;
3849
+ }
3850
+ const row = pageRows.find((r) => r.request_id === picked);
3851
+ if (row) printDetail(row, opts.detail);
3852
+ }
3853
+ }
3854
+ }
3855
+ var NOISE_HEADER = /^(cf-|sec-ch-|sec-fetch-|x-forwarded-|x-real-ip$)/i;
3856
+ var HEADER_PRIORITY = [
3857
+ "authorization",
3858
+ "x-api-key",
3859
+ "content-type",
3860
+ "accept",
3861
+ "x-end-user-id",
3862
+ "user-agent",
3863
+ "host",
3864
+ "origin",
3865
+ "referer",
3866
+ "content-length",
3867
+ "cookie"
3868
+ ];
3869
+ var PANE_INDENT = " ".repeat(13);
3870
+ function wrapCells(items, width) {
3871
+ const cols = Math.max(40, width - PANE_INDENT.length);
3872
+ const lines = [];
3873
+ let line = "";
3874
+ for (const it of items) {
3875
+ if (line && line.length + 2 + it.length > cols) {
3876
+ lines.push(line);
3877
+ line = "";
3878
+ }
3879
+ line = line ? `${line} ${it}` : it;
3880
+ }
3881
+ if (line) lines.push(line);
3882
+ return lines.join(`
3883
+ ${PANE_INDENT}`);
3884
+ }
3885
+ function renderHeaders(h) {
3886
+ if (!h) return import_chalk25.default.dim("\u2014");
3887
+ const width = process.stdout.columns || 100;
3888
+ if (h.values) {
3889
+ const e = Object.entries(h.values);
3890
+ if (!e.length) return import_chalk25.default.dim("none");
3891
+ const rank = (k) => {
3892
+ const i = HEADER_PRIORITY.indexOf(k.toLowerCase());
3893
+ return i === -1 ? NOISE_HEADER.test(k) ? 999 : 500 : i;
3894
+ };
3895
+ return e.sort((a, b) => rank(a[0]) - rank(b[0])).map(([k, v]) => `${import_chalk25.default.dim(k + ":")} ${v}`).join(`
3896
+ ${PANE_INDENT}`);
3897
+ }
3898
+ if (!h.names?.length) return import_chalk25.default.dim("none");
3899
+ const names = [...h.names];
3900
+ const noise = names.filter((n) => NOISE_HEADER.test(n));
3901
+ const shown = names.filter((n) => !NOISE_HEADER.test(n)).sort((a, b) => {
3902
+ const ia = HEADER_PRIORITY.indexOf(a.toLowerCase());
3903
+ const ib = HEADER_PRIORITY.indexOf(b.toLowerCase());
3904
+ return (ia === -1 ? 500 : ia) - (ib === -1 ? 500 : ib) || a.localeCompare(b);
3905
+ });
3906
+ const body = shown.length ? wrapCells(shown, width) : import_chalk25.default.dim("(all forwarding headers)");
3907
+ const tail = noise.length ? `
3908
+ ${PANE_INDENT}${import_chalk25.default.dim(`+ ${noise.length} forwarding/client-hint header${noise.length === 1 ? "" : "s"} (cf-*, sec-*)`)}` : "";
3909
+ return `${body}${tail} ${import_chalk25.default.dim("(names only)")}`;
3910
+ }
3911
+ function renderBody(b) {
3912
+ if (!b) return import_chalk25.default.dim("\u2014");
3913
+ const meta = [b.content_type, b.size != null ? `${b.size}B` : null, b.truncated ? "truncated" : null].filter(Boolean).join(" \xB7 ");
3914
+ if (b.not_captured) return import_chalk25.default.dim(`not captured (${b.not_captured})${meta ? " \xB7 " + meta : ""}`);
3915
+ const isShape = b.value === void 0 && b.shape !== void 0;
3916
+ const content = b.value !== void 0 ? b.value : b.shape;
3917
+ if (content === null || content === void 0 || content === "" || content === "empty") {
3918
+ return import_chalk25.default.dim(`empty${meta ? " \xB7 " + meta : ""}`);
3919
+ }
3920
+ const text = typeof content === "string" ? content : JSON.stringify(content, null, 2);
3921
+ const head = isShape ? import_chalk25.default.dim("shape only (values not captured)\n ") : "";
3922
+ return head + text.split("\n").join("\n ");
3923
+ }
3924
+ function pane(title, tone, view, empty) {
3925
+ console.log(` ${tone(title)}`);
3926
+ if (empty !== void 0) {
3927
+ console.log(` ${import_chalk25.default.dim(empty)}`);
3928
+ return;
3929
+ }
3930
+ const v = view ?? {};
3931
+ if (v.url) console.log(` ${import_chalk25.default.dim("target")} ${v.url}`);
3932
+ if (v.status != null) {
3933
+ console.log(` ${import_chalk25.default.dim("status")} ${statusColor(v.status)(String(v.status))}${v.status_text ? import_chalk25.default.dim(" " + v.status_text) : ""}`);
3934
+ }
3935
+ if (v.raw_path) console.log(` ${import_chalk25.default.dim("path")} ${v.raw_path}`);
3936
+ if (v.query && Object.keys(v.query).length) {
3937
+ console.log(` ${import_chalk25.default.dim("query")} ${Object.entries(v.query).map(([k, q]) => `${k}=${q}`).join(" ")}`);
3938
+ }
3939
+ if (v.jwt !== void 0) console.log(` ${import_chalk25.default.dim("jwt")} ${JSON.stringify(v.jwt)}`);
3940
+ console.log(` ${import_chalk25.default.dim("headers")} ${renderHeaders(v.headers)}`);
3941
+ console.log(` ${import_chalk25.default.dim("body")} ${renderBody(v.body)}`);
3942
+ }
3943
+ function printDetail(r, mode = "producer") {
3944
+ const v = r.views;
3945
+ console.log("");
3946
+ console.log(import_chalk25.default.bold(`${r.method} ${r.route}`) + " " + statusColor(r.status)(String(r.status)) + import_chalk25.default.dim(` ${r.duration_ms}ms`));
3947
+ const cost = typeof r.cost_cents === "number" && r.cost_cents > 0 ? ` \xB7 ${r.cost_cents}\xA2` : "";
3948
+ console.log(import_chalk25.default.dim(` request_id ${r.request_id}${r.environment ? ` \xB7 env ${r.environment}` : ""}${r.consumer_id ? ` \xB7 consumer ${r.consumer_id}` : ""}${cost}`));
3949
+ console.log("");
3950
+ if (!v) {
3951
+ console.log(import_chalk25.default.dim(" No view detail captured for this request.\n"));
3952
+ return;
3953
+ }
3954
+ pane("Request (before) \u2014 client \u2192 APIblaze", import_chalk25.default.cyan, v.request);
3955
+ if (mode === "producer") {
3956
+ pane(
3957
+ "Request (after) \u2014 APIblaze \u2192 upstream",
3958
+ import_chalk25.default.cyan,
3959
+ v.forwarded_request,
3960
+ v.forwarded_request ? void 0 : "Request did not reach an upstream."
3961
+ );
3962
+ pane(
3963
+ "Response (before) \u2014 upstream \u2192 APIblaze",
3964
+ import_chalk25.default.magenta,
3965
+ v.upstream_response,
3966
+ v.upstream_response ? void 0 : "No upstream response."
3967
+ );
3968
+ }
3969
+ pane("Response (after) \u2014 APIblaze \u2192 client", import_chalk25.default.magenta, v.response);
3970
+ console.log("");
3971
+ }
3972
+
3973
+ // src/commands/logs.ts
3974
+ async function resolve(projectArg, versionArg, opts) {
3975
+ try {
3976
+ getAccessToken();
3977
+ } catch (err) {
3978
+ const consumerOnly = !loadCredentials() && !!loadConsumer();
3979
+ throw new Error(
3980
+ err.message + (consumerOnly ? "\nYou're signed in as an API Consumer. A proxy's full logs need a Producer login; for your own requests run `apiblaze consumer logs`." : "")
3981
+ );
3982
+ }
3983
+ const { teamId } = await resolveTeam(opts.team);
3984
+ const match = await resolveProject(teamId, projectArg, versionArg);
3985
+ const projectId = match.projectId;
3986
+ const version2 = versionArg || match.apiVersion;
3987
+ let tenant2 = opts.tenant;
3988
+ if (!tenant2) {
3989
+ const res = await admin({
3990
+ path: `/projects/${projectId}/${version2}/tenants`,
3991
+ method: "GET",
3992
+ summary: "list project tenants"
3993
+ });
3994
+ const tenants = res?.tenants ?? [];
3995
+ if (tenants.length === 0) {
3996
+ throw new Error(`No tenants attached to ${match.projectName}@${version2} \u2014 nothing to read logs for.`);
3997
+ } else if (tenants.length === 1) {
3998
+ tenant2 = tenants[0].tenant_name;
3999
+ } else if (opts.json || !process.stdin.isTTY) {
4000
+ throw new Error(`Project has ${tenants.length} tenants \u2014 pass --tenant <slug>. Attached: ${tenants.map((t) => t.tenant_name).join(", ")}`);
4001
+ } else {
4002
+ const { default: inquirer3 } = await import("inquirer");
4003
+ const ans = await inquirer3.prompt([{
4004
+ type: "list",
4005
+ name: "tenant",
4006
+ message: "Which tenant?",
4007
+ choices: tenants.map((t) => ({
4008
+ name: t.display_name ? `${t.display_name} (${t.tenant_name})` : t.tenant_name,
4009
+ value: t.tenant_name
4010
+ }))
4011
+ }]);
4012
+ tenant2 = ans.tenant;
4013
+ }
4014
+ }
4015
+ return { projectId, projectName: match.projectName, version: version2, tenant: tenant2 };
4016
+ }
4017
+ function otherPlaneHint() {
4018
+ if (loadConsumer()) console.log(import_chalk26.default.dim(" \u2039consumer view: apiblaze consumer logs\u203A"));
4019
+ }
4020
+ function fetchWindow(projectId, version2, tenant2) {
4021
+ return (params) => {
4022
+ const q = new URLSearchParams({ tenant: tenant2, limit: String(params.limit) });
4023
+ if (params.since !== void 0) q.set("since", String(params.since));
4024
+ if (params.until !== void 0) q.set("until", String(params.until));
4025
+ if (params.errorsOnly) q.set("errors_only", "true");
4026
+ if (params.cursor) q.set("cursor", params.cursor);
4027
+ return admin({
4028
+ path: `/projects/${projectId}/${version2}/logs/window?${q.toString()}`,
4029
+ method: "GET",
4030
+ summary: "read log window"
4031
+ });
4032
+ };
4033
+ }
4034
+ async function runLogsTail(projectArg, versionArg, opts) {
4035
+ const { projectId, projectName, version: version2, tenant: tenant2 } = await resolve(projectArg, versionArg, opts);
4036
+ if (!opts.json) {
4037
+ console.log(import_chalk26.default.bold("API Producer logs") + import_chalk26.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant2}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
4038
+ console.log(import_chalk26.default.dim("every caller's requests, with cost and upstream detail"));
4039
+ otherPlaneHint();
4040
+ }
4041
+ await runTailSession({
4042
+ mintTicket: async () => {
4043
+ const res = await admin({
4044
+ path: `/projects/${projectId}/${version2}/logs/tail-ticket?tenant=${encodeURIComponent(tenant2)}`,
4045
+ method: "POST",
4046
+ summary: "mint log tail ticket"
4047
+ });
4048
+ if (!res?.ws_url) throw new Error("No ws_url returned by tail-ticket");
4049
+ return res.ws_url;
4050
+ },
4051
+ errorsOnly: opts.errorsOnly,
4052
+ json: opts.json,
4053
+ detail: "producer"
4054
+ });
4055
+ }
4056
+ async function runLogsList(projectArg, versionArg, opts) {
4057
+ const { projectId, projectName, version: version2, tenant: tenant2 } = await resolve(projectArg, versionArg, opts);
4058
+ if (!opts.json) {
4059
+ console.log(import_chalk26.default.bold("API Producer logs") + import_chalk26.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant2}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
4060
+ console.log(import_chalk26.default.dim("every caller's requests, with cost and upstream detail"));
4061
+ otherPlaneHint();
4062
+ console.log("");
4063
+ }
4064
+ await runHistoryBrowser({
4065
+ fetchWindow: fetchWindow(projectId, version2, tenant2),
4066
+ errorsOnly: opts.errorsOnly,
4067
+ json: opts.json,
4068
+ plain: opts.plain,
4069
+ detail: "producer"
4070
+ });
4071
+ }
4072
+
4073
+ // src/commands/consumer-logs.ts
4074
+ var import_chalk27 = __toESM(require("chalk"));
4075
+ init_auth();
4076
+ var CONSUMER_LOGS_BASE = process.env.APIBLAZE_CONSUMER_LOGS_BASE || "https://logs.apiblaze.com/consumer";
4077
+ function requireConsumer() {
4078
+ const c = loadConsumer();
4079
+ if (!c) {
4080
+ console.error(import_chalk27.default.red("Not logged in as an API Consumer. Run `apiblaze consumer login` first."));
4081
+ if (loadCredentials()) {
4082
+ console.error(import_chalk27.default.dim("You're signed in as an API Producer \u2014 for a proxy's full logs run `apiblaze logs <project>`."));
4083
+ }
4084
+ process.exit(1);
4085
+ }
4086
+ return { creds: c };
4087
+ }
4088
+ async function consumerLogsFetch(session, suffix, init) {
4089
+ const fresh = await validConsumerToken(session.creds) ?? session.creds;
4090
+ session.creds = fresh;
4091
+ const res = await fetch(`${CONSUMER_LOGS_BASE}${suffix}`, {
4092
+ ...init,
4093
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${fresh.accessToken}`, ...init?.headers ?? {} }
4094
+ });
4095
+ let data = null;
4096
+ try {
4097
+ data = await res.json();
4098
+ } catch {
4099
+ }
4100
+ if (res.status === 404 || res.status === 405 || res.status === 501) {
4101
+ throw new Error("Consumer log access is not available on this tenant yet.");
4102
+ }
4103
+ if (res.status === 401) {
4104
+ throw new Error("Your consumer session was rejected \u2014 run `apiblaze consumer login` again.");
4105
+ }
4106
+ if (!res.ok) {
4107
+ const msg = data?.error ?? res.statusText;
4108
+ throw new Error(typeof msg === "string" ? msg : JSON.stringify(msg));
4109
+ }
4110
+ return data;
4111
+ }
4112
+ function otherPlaneHint2() {
4113
+ if (loadCredentials()) console.log(import_chalk27.default.dim(" \u2039producer view: apiblaze logs <project>\u203A"));
4114
+ }
4115
+ function fetchWindow2(session, project) {
4116
+ return (params) => {
4117
+ const q = new URLSearchParams({ limit: String(params.limit) });
4118
+ if (project) q.set("project", project);
4119
+ if (params.since !== void 0) q.set("since", String(params.since));
4120
+ if (params.until !== void 0) q.set("until", String(params.until));
4121
+ if (params.errorsOnly) q.set("errors_only", "true");
4122
+ if (params.cursor) q.set("cursor", params.cursor);
4123
+ return consumerLogsFetch(session, `/logs/window?${q.toString()}`);
4124
+ };
4125
+ }
4126
+ async function runConsumerLogsTail(opts) {
4127
+ const session = requireConsumer();
4128
+ if (!opts.json) {
4129
+ console.log(import_chalk27.default.bold("API Consumer logs") + import_chalk27.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
4130
+ console.log(import_chalk27.default.dim("cost and upstream details are producer-only and are not sent"));
4131
+ otherPlaneHint2();
4132
+ }
4133
+ await runTailSession({
4134
+ mintTicket: async () => {
4135
+ const q = opts.project ? `?project=${encodeURIComponent(opts.project)}` : "";
4136
+ const res = await consumerLogsFetch(session, `/logs/tail-ticket${q}`, { method: "POST" });
4137
+ if (!res?.ws_url) throw new Error("No ws_url returned by tail-ticket");
4138
+ return res.ws_url;
4139
+ },
4140
+ errorsOnly: opts.errorsOnly,
4141
+ json: opts.json,
4142
+ detail: "consumer"
4143
+ });
4144
+ }
4145
+ async function runConsumerLogsList(opts) {
4146
+ const session = requireConsumer();
4147
+ if (!opts.json) {
4148
+ console.log(import_chalk27.default.bold("API Consumer logs") + import_chalk27.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
4149
+ console.log(import_chalk27.default.dim("cost and upstream details are producer-only and are not sent"));
4150
+ otherPlaneHint2();
4151
+ console.log("");
4152
+ }
4153
+ await runHistoryBrowser({
4154
+ fetchWindow: fetchWindow2(session, opts.project),
4155
+ errorsOnly: opts.errorsOnly,
4156
+ json: opts.json,
4157
+ plain: opts.plain,
4158
+ detail: "consumer"
4159
+ });
3229
4160
  }
3230
4161
 
3231
4162
  // src/commands/config.ts
3232
- var import_chalk24 = __toESM(require("chalk"));
4163
+ var import_chalk28 = __toESM(require("chalk"));
3233
4164
  var import_ora8 = __toESM(require("ora"));
3234
4165
  init_admin();
3235
4166
  init_resolve();
@@ -3253,7 +4184,7 @@ async function patchConfig(project, opts, body, summary) {
3253
4184
  }
3254
4185
  async function runTargetSet(project, opts) {
3255
4186
  if (!opts.url) {
3256
- console.error(import_chalk24.default.red("--url is required."));
4187
+ console.error(import_chalk28.default.red("--url is required."));
3257
4188
  process.exit(1);
3258
4189
  }
3259
4190
  const body = opts.env ? { environments: { [opts.env]: { target: opts.url } } } : { target_url: opts.url };
@@ -3266,40 +4197,40 @@ async function runThrottleSet(project, opts) {
3266
4197
  if (opts.quota !== void 0) throttling.proxyQuota = Number(opts.quota);
3267
4198
  if (opts.period !== void 0) {
3268
4199
  if (!["daily", "weekly", "monthly"].includes(opts.period)) {
3269
- console.error(import_chalk24.default.red("--period must be daily, weekly, or monthly."));
4200
+ console.error(import_chalk28.default.red("--period must be daily, weekly, or monthly."));
3270
4201
  process.exit(1);
3271
4202
  }
3272
4203
  throttling.quotaPeriod = opts.period;
3273
4204
  }
3274
4205
  if (Object.keys(throttling).length === 0) {
3275
- console.error(import_chalk24.default.red("Nothing to set. Pass at least one of --rate, --end-user-rate, --quota, --period."));
4206
+ console.error(import_chalk28.default.red("Nothing to set. Pass at least one of --rate, --end-user-rate, --quota, --period."));
3276
4207
  process.exit(1);
3277
4208
  }
3278
4209
  await patchConfig(project, opts, { throttling }, `Update throttling ${JSON.stringify(throttling)}`);
3279
4210
  }
3280
4211
  async function runRename(project, opts) {
3281
4212
  if (!opts.displayName) {
3282
- console.error(import_chalk24.default.red("--display-name is required."));
4213
+ console.error(import_chalk28.default.red("--display-name is required."));
3283
4214
  process.exit(1);
3284
4215
  }
3285
4216
  await patchConfig(project, opts, { display_name: opts.displayName }, `Rename \u2192 "${opts.displayName}"`);
3286
4217
  }
3287
4218
 
3288
4219
  // src/commands/config-browse.ts
3289
- var import_chalk33 = __toESM(require("chalk"));
4220
+ var import_chalk37 = __toESM(require("chalk"));
3290
4221
  var import_ora16 = __toESM(require("ora"));
3291
4222
  init_admin();
3292
4223
  init_auth();
3293
4224
  init_resolve();
3294
4225
 
3295
4226
  // src/commands/domain.ts
3296
- var import_chalk25 = __toESM(require("chalk"));
4227
+ var import_chalk29 = __toESM(require("chalk"));
3297
4228
  var import_ora9 = __toESM(require("ora"));
3298
4229
  init_admin();
3299
4230
  init_resolve();
3300
4231
  async function runDomainAdd(project, opts) {
3301
4232
  if (!opts.domain) {
3302
- console.error(import_chalk25.default.red("--domain is required."));
4233
+ console.error(import_chalk29.default.red("--domain is required."));
3303
4234
  process.exit(1);
3304
4235
  }
3305
4236
  const { teamId } = await resolveTeam(opts.team);
@@ -3318,9 +4249,9 @@ async function runDomainAdd(project, opts) {
3318
4249
  console.log(JSON.stringify(out));
3319
4250
  return;
3320
4251
  }
3321
- if (out?.cnameRecord) console.log(` ${import_chalk25.default.cyan("CNAME")} ${out.cnameRecord.name ?? opts.domain} \u2192 ${out.cnameRecord.value ?? out.cnameRecord.target}`);
3322
- if (out?.dcv) console.log(` ${import_chalk25.default.cyan("TXT")} ${out.dcv.name} = ${out.dcv.value}`);
3323
- if (out?.id) console.log(import_chalk25.default.dim(` domain id: ${out.id}`));
4252
+ if (out?.cnameRecord) console.log(` ${import_chalk29.default.cyan("CNAME")} ${out.cnameRecord.name ?? opts.domain} \u2192 ${out.cnameRecord.value ?? out.cnameRecord.target}`);
4253
+ if (out?.dcv) console.log(` ${import_chalk29.default.cyan("TXT")} ${out.dcv.name} = ${out.dcv.value}`);
4254
+ if (out?.id) console.log(import_chalk29.default.dim(` domain id: ${out.id}`));
3324
4255
  } catch (err) {
3325
4256
  spinner.fail("Domain registration failed.");
3326
4257
  throw err;
@@ -3340,14 +4271,14 @@ async function runDomainList(project, opts) {
3340
4271
  return;
3341
4272
  }
3342
4273
  if (!domains.length) {
3343
- console.log(import_chalk25.default.yellow("No custom domains."));
4274
+ console.log(import_chalk29.default.yellow("No custom domains."));
3344
4275
  return;
3345
4276
  }
3346
- for (const d of domains) console.log(` ${import_chalk25.default.bold(d.hostname)} ${import_chalk25.default.dim(d.status ?? "")} ${import_chalk25.default.dim(d.id ?? "")}`);
4277
+ for (const d of domains) console.log(` ${import_chalk29.default.bold(d.hostname)} ${import_chalk29.default.dim(d.status ?? "")} ${import_chalk29.default.dim(d.id ?? "")}`);
3347
4278
  }
3348
4279
  async function runDomainStatus(project, opts) {
3349
4280
  if (!opts.id) {
3350
- console.error(import_chalk25.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
4281
+ console.error(import_chalk29.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
3351
4282
  process.exit(1);
3352
4283
  }
3353
4284
  const { teamId } = await resolveTeam(opts.team);
@@ -3357,11 +4288,11 @@ async function runDomainStatus(project, opts) {
3357
4288
  path: `/projects/${proj2.projectId}/domains/${encodeURIComponent(opts.id)}/status`,
3358
4289
  summary: `Check custom-domain status`
3359
4290
  });
3360
- console.log(opts.json ? JSON.stringify(out) : ` ${import_chalk25.default.bold(out?.hostname ?? opts.id)}: ${import_chalk25.default.cyan(out?.status ?? "unknown")}`);
4291
+ console.log(opts.json ? JSON.stringify(out) : ` ${import_chalk29.default.bold(out?.hostname ?? opts.id)}: ${import_chalk29.default.cyan(out?.status ?? "unknown")}`);
3361
4292
  }
3362
4293
  async function runDomainRemove(project, opts) {
3363
4294
  if (!opts.id) {
3364
- console.error(import_chalk25.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
4295
+ console.error(import_chalk29.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
3365
4296
  process.exit(1);
3366
4297
  }
3367
4298
  const { teamId } = await resolveTeam(opts.team);
@@ -3399,7 +4330,7 @@ async function runDomainSetBase(project, opts) {
3399
4330
  }
3400
4331
 
3401
4332
  // src/commands/tenant.ts
3402
- var import_chalk28 = __toESM(require("chalk"));
4333
+ var import_chalk32 = __toESM(require("chalk"));
3403
4334
  var import_ora12 = __toESM(require("ora"));
3404
4335
  init_admin();
3405
4336
  init_resolve();
@@ -3408,20 +4339,20 @@ init_tenant_pick();
3408
4339
  async function runTenantUse(query, opts) {
3409
4340
  const creds = loadCredentials();
3410
4341
  if (!creds) {
3411
- console.error(import_chalk28.default.red("Not logged in. Run `apiblaze login` first."));
4342
+ console.error(import_chalk32.default.red("Not logged in. Run `apiblaze login` first."));
3412
4343
  process.exit(1);
3413
4344
  }
3414
4345
  if (opts.clear) {
3415
4346
  delete creds.activeTenant;
3416
4347
  saveCredentials(creds);
3417
- console.log(import_chalk28.default.green("Tenant scope cleared."));
4348
+ console.log(import_chalk32.default.green("Tenant scope cleared."));
3418
4349
  return;
3419
4350
  }
3420
4351
  const { teamId } = await resolveTeam(opts.team);
3421
4352
  const slug = await pickTenant(teamId, { message: "Scope future commands to which tenant?", initialQuery: query });
3422
4353
  if (!slug) process.exit(1);
3423
4354
  saveCredentials({ ...creds, activeTenant: slug });
3424
- console.log(import_chalk28.default.green(`Tenant scope set to ${import_chalk28.default.bold(slug)}.`) + import_chalk28.default.dim(" (clear with `apiblaze tenant use --clear`)"));
4355
+ console.log(import_chalk32.default.green(`Tenant scope set to ${import_chalk32.default.bold(slug)}.`) + import_chalk32.default.dim(" (clear with `apiblaze tenant use --clear`)"));
3425
4356
  }
3426
4357
  async function runTenantList(opts) {
3427
4358
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -3438,22 +4369,22 @@ async function runTenantList(opts) {
3438
4369
  return;
3439
4370
  }
3440
4371
  if (!tenants.length) {
3441
- console.log(import_chalk28.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
4372
+ console.log(import_chalk32.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
3442
4373
  return;
3443
4374
  }
3444
4375
  for (const t of tenants) {
3445
4376
  const name = typeof t === "string" ? t : t.tenant_name;
3446
- const display = typeof t === "string" ? "" : import_chalk28.default.dim(` ${t.display_name ?? ""}`);
3447
- console.log(` ${import_chalk28.default.bold(name)}${display}`);
4377
+ const display = typeof t === "string" ? "" : import_chalk32.default.dim(` ${t.display_name ?? ""}`);
4378
+ console.log(` ${import_chalk32.default.bold(name)}${display}`);
3448
4379
  }
3449
4380
  const total = out?.total ?? tenants.length;
3450
4381
  if (total > tenants.length) {
3451
- console.log(import_chalk28.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
4382
+ console.log(import_chalk32.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
3452
4383
  }
3453
4384
  }
3454
4385
  async function runTenantCreate(opts) {
3455
4386
  if (!opts.name) {
3456
- console.error(import_chalk28.default.red("--name (display name) is required."));
4387
+ console.error(import_chalk32.default.red("--name (display name) is required."));
3457
4388
  process.exit(1);
3458
4389
  }
3459
4390
  const { teamId } = await resolveTeam(opts.team);
@@ -3465,7 +4396,7 @@ async function runTenantCreate(opts) {
3465
4396
  body: { display_name: opts.name, ...opts.slug ? { tenant_name: opts.slug } : {} },
3466
4397
  summary: `Create tenant "${opts.name}"`
3467
4398
  });
3468
- spinner.succeed(`Created tenant ${import_chalk28.default.bold(out?.tenant_name ?? opts.name)}.`);
4399
+ spinner.succeed(`Created tenant ${import_chalk32.default.bold(out?.tenant_name ?? opts.name)}.`);
3469
4400
  if (opts.json) console.log(JSON.stringify(out));
3470
4401
  } catch (err) {
3471
4402
  spinner.fail("Tenant create failed.");
@@ -3474,7 +4405,7 @@ async function runTenantCreate(opts) {
3474
4405
  }
3475
4406
  async function runTenantAttach(project, opts) {
3476
4407
  if (!opts.tenant) {
3477
- console.error(import_chalk28.default.red("--tenant <slug> is required."));
4408
+ console.error(import_chalk32.default.red("--tenant <slug> is required."));
3478
4409
  process.exit(1);
3479
4410
  }
3480
4411
  const { teamId } = await resolveTeam(opts.team);
@@ -3502,7 +4433,7 @@ async function runTenantDelete(slug, opts) {
3502
4433
  { type: "confirm", name: "confirm", message: `Permanently delete tenant "${slug}" and everything under it? This cannot be undone.`, default: false }
3503
4434
  ]);
3504
4435
  if (!confirm) {
3505
- console.log(import_chalk28.default.dim("Aborted."));
4436
+ console.log(import_chalk32.default.dim("Aborted."));
3506
4437
  return;
3507
4438
  }
3508
4439
  }
@@ -3521,7 +4452,7 @@ async function runTenantDelete(slug, opts) {
3521
4452
  }
3522
4453
  async function runTenantCors(opts) {
3523
4454
  if (!opts.tenant) {
3524
- console.error(import_chalk28.default.red("--tenant <slug> is required."));
4455
+ console.error(import_chalk32.default.red("--tenant <slug> is required."));
3525
4456
  process.exit(1);
3526
4457
  }
3527
4458
  const { teamId } = await resolveTeam(opts.team);
@@ -3543,7 +4474,7 @@ async function runTenantCors(opts) {
3543
4474
  }
3544
4475
 
3545
4476
  // src/commands/tenant-drill.ts
3546
- var import_chalk29 = __toESM(require("chalk"));
4477
+ var import_chalk33 = __toESM(require("chalk"));
3547
4478
  var import_ora13 = __toESM(require("ora"));
3548
4479
  var import_crypto = require("crypto");
3549
4480
  init_admin();
@@ -3574,15 +4505,15 @@ async function validScopedTenant(teamId, query) {
3574
4505
  const next = { ...creds };
3575
4506
  delete next.activeTenant;
3576
4507
  saveCredentials2(next);
3577
- console.log(import_chalk29.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
4508
+ console.log(import_chalk33.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
3578
4509
  return void 0;
3579
4510
  }
3580
4511
  async function tenantHome(teamId, tenant2) {
3581
4512
  const { default: inquirer3 } = await import("inquirer");
3582
4513
  const base2 = `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}`;
3583
- console.log(import_chalk29.default.bold(`
4514
+ console.log(import_chalk33.default.bold(`
3584
4515
  Tenant ${tenant2}`));
3585
- console.log(import_chalk29.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
4516
+ console.log(import_chalk33.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
3586
4517
  for (; ; ) {
3587
4518
  const spinner = (0, import_ora13.default)("Reading tenant state...").start();
3588
4519
  const [iam, cors, emails, issuers, opaque, clients] = await Promise.all([
@@ -3598,18 +4529,18 @@ Tenant ${tenant2}`));
3598
4529
  const nClients = Array.isArray(clients) ? clients.length : 0;
3599
4530
  const nOpaque = opaque?.opaque?.endpoint ? 1 : 0;
3600
4531
  const nLogin = nClients + nIssuers + nOpaque;
3601
- const onOff = (b) => b ? import_chalk29.default.green("on") : import_chalk29.default.dim("off");
4532
+ const onOff = (b) => b ? import_chalk33.default.green("on") : import_chalk33.default.dim("off");
3602
4533
  const { pick: pick2 } = await inquirer3.prompt([{
3603
4534
  type: "list",
3604
4535
  name: "pick",
3605
4536
  message: `Tenant ${tenant2}:`,
3606
4537
  pageSize: 12,
3607
4538
  choices: [
3608
- { name: `Login methods (${nLogin}) ${import_chalk29.default.dim("how your consumers sign in")}`, value: "login" },
3609
- { name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk29.default.dim(`identity & key management (iam.apiblaze.com)`)}`, value: "iam" },
3610
- { name: `Portal admins (${nEmails}) ${import_chalk29.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
3611
- new inquirer3.Separator(import_chalk29.default.dim(" Settings")),
3612
- { name: `CORS: ${cors?.cors ? import_chalk29.default.cyan(JSON.stringify(cors.cors)) : import_chalk29.default.dim("(unset)")} ${import_chalk29.default.dim("browser origins allowed to call this tenant")}`, value: "cors" },
4539
+ { name: `Login methods (${nLogin}) ${import_chalk33.default.dim("how your consumers sign in")}`, value: "login" },
4540
+ { name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk33.default.dim(`identity & key management (iam.apiblaze.com)`)}`, value: "iam" },
4541
+ { name: `Portal admins (${nEmails}) ${import_chalk33.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
4542
+ new inquirer3.Separator(import_chalk33.default.dim(" Settings")),
4543
+ { name: `CORS: ${cors?.cors ? import_chalk33.default.cyan(JSON.stringify(cors.cors)) : import_chalk33.default.dim("(unset)")} ${import_chalk33.default.dim("browser origins allowed to call this tenant")}`, value: "cors" },
3613
4544
  { name: "\u2190 Back", value: "back" }
3614
4545
  ]
3615
4546
  }]);
@@ -3622,7 +4553,7 @@ Tenant ${tenant2}`));
3622
4553
  case "iam": {
3623
4554
  const { v } = await inquirer3.prompt([{ type: "confirm", name: "v", message: "Enable Users & groups?", default: !!iam?.iam_enabled }]);
3624
4555
  await admin({ method: "PATCH", path: `${base2}/iam`, body: { enabled: v }, summary: `IAM enforcement \u2192 ${v ? "on" : "off"}` });
3625
- console.log(import_chalk29.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
4556
+ console.log(import_chalk33.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
3626
4557
  break;
3627
4558
  }
3628
4559
  case "cors": {
@@ -3635,11 +4566,11 @@ Tenant ${tenant2}`));
3635
4566
  if (v === "") break;
3636
4567
  const parsed = v === "null" ? null : safeJson(v);
3637
4568
  if (parsed === void 0) {
3638
- console.log(import_chalk29.default.yellow(" Not valid JSON \u2014 unchanged."));
4569
+ console.log(import_chalk33.default.yellow(" Not valid JSON \u2014 unchanged."));
3639
4570
  break;
3640
4571
  }
3641
4572
  await admin({ method: "PUT", path: `${base2}/cors`, body: { cors: parsed }, summary: "Set tenant CORS" });
3642
- console.log(import_chalk29.default.green(" CORS updated."));
4573
+ console.log(import_chalk33.default.green(" CORS updated."));
3643
4574
  break;
3644
4575
  }
3645
4576
  case "emails":
@@ -3663,15 +4594,15 @@ async function loginMethodsMenu(teamId, tenant2, base2) {
3663
4594
  const choices = [];
3664
4595
  for (const c of appClients) {
3665
4596
  const nP = (c.providers ?? []).length || c.providers_count || 0;
3666
- choices.push({ name: `${import_chalk29.default.cyan("APIblaze-hosted")} ${import_chalk29.default.bold(c.name ?? c.clientId)} ${import_chalk29.default.dim(`${c.clientId}${nP ? ` \xB7 ${nP} provider${nP === 1 ? "" : "s"}` : import_chalk29.default.yellow(" \xB7 needs a provider")}`)}`, value: { kind: "client", item: c } });
4597
+ choices.push({ name: `${import_chalk33.default.cyan("APIblaze-hosted")} ${import_chalk33.default.bold(c.name ?? c.clientId)} ${import_chalk33.default.dim(`${c.clientId}${nP ? ` \xB7 ${nP} provider${nP === 1 ? "" : "s"}` : import_chalk33.default.yellow(" \xB7 needs a provider")}`)}`, value: { kind: "client", item: c } });
3667
4598
  }
3668
4599
  for (const i of issuers) {
3669
- choices.push({ name: `${import_chalk29.default.cyan("Your own \u2014 JWT ")} ${import_chalk29.default.bold(i.iss)} ${import_chalk29.default.dim(`aud=${i.aud}`)}`, value: { kind: "issuer", item: i } });
4600
+ choices.push({ name: `${import_chalk33.default.cyan("Your own \u2014 JWT ")} ${import_chalk33.default.bold(i.iss)} ${import_chalk33.default.dim(`aud=${i.aud}`)}`, value: { kind: "issuer", item: i } });
3670
4601
  }
3671
4602
  if (opaque?.endpoint) {
3672
- choices.push({ name: `${import_chalk29.default.cyan("Your own \u2014 opaque")} ${import_chalk29.default.bold(opaque.endpoint)}`, value: { kind: "opaque", item: opaque } });
4603
+ choices.push({ name: `${import_chalk33.default.cyan("Your own \u2014 opaque")} ${import_chalk33.default.bold(opaque.endpoint)}`, value: { kind: "opaque", item: opaque } });
3673
4604
  }
3674
- if (!choices.length) console.log(import_chalk29.default.dim("\n No login methods yet \u2014 consumers cannot sign in until you add one."));
4605
+ if (!choices.length) console.log(import_chalk33.default.dim("\n No login methods yet \u2014 consumers cannot sign in until you add one."));
3675
4606
  const { pick: pick2 } = await inquirer3.prompt([{
3676
4607
  type: "list",
3677
4608
  name: "pick",
@@ -3711,9 +4642,9 @@ async function addLoginMethod(teamId, tenant2, base2) {
3711
4642
  message: "How do people log in?",
3712
4643
  pageSize: 8,
3713
4644
  choices: [
3714
- { name: `APIblaze hosted login page ${import_chalk29.default.dim("we host login; pick a provider (GitHub/Google/\u2026) \u2014 easiest")}`, value: "apiblaze" },
3715
- { name: `Your own hosted login \u2014 JWT ${import_chalk29.default.dim("your identity provider issues JWTs; we trust them")}`, value: "jwt" },
3716
- { name: `Your own login \u2014 opaque token ${import_chalk29.default.dim("we validate your opaque tokens via an introspection endpoint")}`, value: "opaque" },
4645
+ { name: `APIblaze hosted login page ${import_chalk33.default.dim("we host login; pick a provider (GitHub/Google/\u2026) \u2014 easiest")}`, value: "apiblaze" },
4646
+ { name: `Your own hosted login \u2014 JWT ${import_chalk33.default.dim("your identity provider issues JWTs; we trust them")}`, value: "jwt" },
4647
+ { name: `Your own login \u2014 opaque token ${import_chalk33.default.dim("we validate your opaque tokens via an introspection endpoint")}`, value: "opaque" },
3717
4648
  { name: "\u2190 Back", value: null }
3718
4649
  ]
3719
4650
  }]);
@@ -3737,8 +4668,8 @@ function safeJson(s) {
3737
4668
  async function emailsMenu(base2, emails) {
3738
4669
  const { default: inquirer3 } = await import("inquirer");
3739
4670
  console.log();
3740
- if (!emails.length) console.log(import_chalk29.default.dim(" No consumer-admin emails."));
3741
- for (const e of emails) console.log(` ${import_chalk29.default.bold(e.email ?? e)} ${import_chalk29.default.dim(e.status ?? "")}`);
4671
+ if (!emails.length) console.log(import_chalk33.default.dim(" No consumer-admin emails."));
4672
+ for (const e of emails) console.log(` ${import_chalk33.default.bold(e.email ?? e)} ${import_chalk33.default.dim(e.status ?? "")}`);
3742
4673
  const { act } = await inquirer3.prompt([{
3743
4674
  type: "list",
3744
4675
  name: "act",
@@ -3753,7 +4684,7 @@ async function emailsMenu(base2, emails) {
3753
4684
  if (act === "add") {
3754
4685
  const { email } = await inquirer3.prompt([{ type: "input", name: "email", message: "Email:", validate: (s) => /.+@.+\..+/.test(s) || "not an email" }]);
3755
4686
  await admin({ method: "POST", path: `${base2}/admin-emails`, body: { email }, summary: `Add consumer-admin ${email}` });
3756
- console.log(import_chalk29.default.green(` ${email} added.`));
4687
+ console.log(import_chalk33.default.green(` ${email} added.`));
3757
4688
  } else {
3758
4689
  const { e } = await inquirer3.prompt([{
3759
4690
  type: "list",
@@ -3763,7 +4694,7 @@ async function emailsMenu(base2, emails) {
3763
4694
  }]);
3764
4695
  if (!e) return;
3765
4696
  await admin({ method: "DELETE", path: `${base2}/admin-emails/${encodeURIComponent(e)}`, summary: `Remove consumer-admin ${e}` });
3766
- console.log(import_chalk29.default.green(` ${e} removed.`));
4697
+ console.log(import_chalk33.default.green(` ${e} removed.`));
3767
4698
  }
3768
4699
  }
3769
4700
  async function addIssuer(base2) {
@@ -3784,19 +4715,19 @@ async function addIssuer(base2) {
3784
4715
  body: { iss: a.iss.trim(), aud: a.aud.trim(), jwks_url: a.jwks.trim() || null, sub_semantics: a.sem, ...claim ? { claim_name: claim } : {} },
3785
4716
  summary: `Add external issuer ${a.iss.trim()}`
3786
4717
  });
3787
- console.log(import_chalk29.default.green(" JWT login method saved."));
4718
+ console.log(import_chalk33.default.green(" JWT login method saved."));
3788
4719
  }
3789
4720
  async function issuerHome(base2, issuer) {
3790
4721
  const { default: inquirer3 } = await import("inquirer");
3791
4722
  console.log(`
3792
- ${import_chalk29.default.bold(issuer.iss)} ${import_chalk29.default.dim(`aud=${issuer.aud} \xB7 ${issuer.sub_semantics ?? ""}`)}`);
4723
+ ${import_chalk33.default.bold(issuer.iss)} ${import_chalk33.default.dim(`aud=${issuer.aud} \xB7 ${issuer.sub_semantics ?? ""}`)}`);
3793
4724
  const { act } = await inquirer3.prompt([{
3794
4725
  type: "list",
3795
4726
  name: "act",
3796
4727
  message: "This JWT login method:",
3797
4728
  choices: [
3798
4729
  { name: "Replace it (re-enter details)", value: "edit" },
3799
- { name: import_chalk29.default.red("Delete it"), value: "rm" },
4730
+ { name: import_chalk33.default.red("Delete it"), value: "rm" },
3800
4731
  { name: "\u2190 Back", value: "back" }
3801
4732
  ]
3802
4733
  }]);
@@ -3812,7 +4743,7 @@ async function issuerHome(base2, issuer) {
3812
4743
  path: `${base2}/external-issuers?iss=${encodeURIComponent(issuer.iss)}&aud=${encodeURIComponent(issuer.aud)}`,
3813
4744
  summary: `Delete issuer ${issuer.iss}`
3814
4745
  });
3815
- console.log(import_chalk29.default.green(" Deleted."));
4746
+ console.log(import_chalk33.default.green(" Deleted."));
3816
4747
  }
3817
4748
  async function setOpaque(base2, cur) {
3818
4749
  const { default: inquirer3 } = await import("inquirer");
@@ -3821,19 +4752,19 @@ async function setOpaque(base2, cur) {
3821
4752
  { type: "list", name: "method", message: "HTTP method:", choices: ["GET", "POST"], default: cur?.method ?? "GET" }
3822
4753
  ]);
3823
4754
  await admin({ method: "PUT", path: `${base2}/opaque`, body: { opaque: { endpoint: a.endpoint, method: a.method } }, summary: "Set opaque validator" });
3824
- console.log(import_chalk29.default.green(" Opaque login method set."));
4755
+ console.log(import_chalk33.default.green(" Opaque login method set."));
3825
4756
  }
3826
4757
  async function opaqueHome(base2, cur) {
3827
4758
  const { default: inquirer3 } = await import("inquirer");
3828
4759
  console.log(`
3829
- ${import_chalk29.default.bold(cur.endpoint)} ${import_chalk29.default.dim(cur.method ?? "GET")}`);
4760
+ ${import_chalk33.default.bold(cur.endpoint)} ${import_chalk33.default.dim(cur.method ?? "GET")}`);
3830
4761
  const { act } = await inquirer3.prompt([{
3831
4762
  type: "list",
3832
4763
  name: "act",
3833
4764
  message: "This opaque login method:",
3834
4765
  choices: [
3835
4766
  { name: "Replace it", value: "edit" },
3836
- { name: import_chalk29.default.red("Delete it"), value: "rm" },
4767
+ { name: import_chalk33.default.red("Delete it"), value: "rm" },
3837
4768
  { name: "\u2190 Back", value: "back" }
3838
4769
  ]
3839
4770
  }]);
@@ -3843,7 +4774,7 @@ async function opaqueHome(base2, cur) {
3843
4774
  return;
3844
4775
  }
3845
4776
  await admin({ method: "PUT", path: `${base2}/opaque`, body: { opaque: null }, summary: "Clear opaque validator" });
3846
- console.log(import_chalk29.default.green(" Deleted."));
4777
+ console.log(import_chalk33.default.green(" Deleted."));
3847
4778
  }
3848
4779
  async function clientHome(base2, summary) {
3849
4780
  const { default: inquirer3 } = await import("inquirer");
@@ -3862,13 +4793,13 @@ async function clientHome(base2, summary) {
3862
4793
  message: `${c.name ?? id}:`,
3863
4794
  pageSize: 12,
3864
4795
  choices: [
3865
- { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk29.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
3866
- { name: `Callback URLs: ${cb.length ? import_chalk29.default.cyan(cb.join(", ")) : import_chalk29.default.dim("(none)")}`, value: "callbacks" },
3867
- { name: `Scopes: ${scopes.length ? import_chalk29.default.cyan(scopes.join(" ")) : import_chalk29.default.dim("(defaults)")}`, value: "scopes" },
4796
+ { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk33.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
4797
+ { name: `Callback URLs: ${cb.length ? import_chalk33.default.cyan(cb.join(", ")) : import_chalk33.default.dim("(none)")}`, value: "callbacks" },
4798
+ { name: `Scopes: ${scopes.length ? import_chalk33.default.cyan(scopes.join(" ")) : import_chalk33.default.dim("(defaults)")}`, value: "scopes" },
3868
4799
  { name: `Token expiries: access ${c.accessTokenExpiry ?? 3600}s \xB7 id ${c.idTokenExpiry ?? 3600}s \xB7 refresh ${c.refreshTokenExpiry ?? 2592e3}s`, value: "expiries" },
3869
4800
  { name: "Reveal client secret", value: "secret" },
3870
4801
  { name: "Rotate client secret", value: "rotate" },
3871
- { name: import_chalk29.default.red("Delete this app client"), value: "delete" },
4802
+ { name: import_chalk33.default.red("Delete this app client"), value: "delete" },
3872
4803
  { name: "\u2190 Back", value: "back" }
3873
4804
  ]
3874
4805
  }]);
@@ -3881,13 +4812,13 @@ async function clientHome(base2, summary) {
3881
4812
  case "callbacks": {
3882
4813
  const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Callback URLs (comma-separated):", default: cb.join(", ") }]);
3883
4814
  await admin({ method: "PATCH", path: cBase, body: { authorizedCallbackUrls: parseList(v) }, summary: "Update callback URLs" });
3884
- console.log(import_chalk29.default.green(" Callbacks updated."));
4815
+ console.log(import_chalk33.default.green(" Callbacks updated."));
3885
4816
  break;
3886
4817
  }
3887
4818
  case "scopes": {
3888
4819
  const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Scopes (space/comma-separated):", default: scopes.join(" ") }]);
3889
4820
  await admin({ method: "PATCH", path: cBase, body: { scopes: v.split(/[\s,]+/).filter(Boolean) }, summary: "Update scopes" });
3890
- console.log(import_chalk29.default.green(" Scopes updated."));
4821
+ console.log(import_chalk33.default.green(" Scopes updated."));
3891
4822
  break;
3892
4823
  }
3893
4824
  case "expiries": {
@@ -3902,14 +4833,14 @@ async function clientHome(base2, summary) {
3902
4833
  body: { accessTokenExpiry: Number(a.access), idTokenExpiry: Number(a.id), refreshTokenExpiry: Number(a.refresh) },
3903
4834
  summary: "Update token expiries"
3904
4835
  });
3905
- console.log(import_chalk29.default.green(" Expiries updated."));
4836
+ console.log(import_chalk33.default.green(" Expiries updated."));
3906
4837
  break;
3907
4838
  }
3908
4839
  case "secret": {
3909
4840
  const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: "Print the client secret to this terminal?", default: false }]);
3910
4841
  if (!sure) break;
3911
4842
  const s = await admin({ method: "GET", path: `${cBase}/secret`, summary: "Reveal client secret" });
3912
- console.log(` ${import_chalk29.default.bold("client_secret")}: ${import_chalk29.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
4843
+ console.log(` ${import_chalk33.default.bold("client_secret")}: ${import_chalk33.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3913
4844
  break;
3914
4845
  }
3915
4846
  case "rotate": {
@@ -3917,14 +4848,14 @@ async function clientHome(base2, summary) {
3917
4848
  if (!sure) break;
3918
4849
  const fresh = randomSecret();
3919
4850
  await admin({ method: "PATCH", path: cBase, body: { clientSecret: fresh }, summary: "Rotate client secret" });
3920
- console.log(` New ${import_chalk29.default.bold("client_secret")}: ${import_chalk29.default.green(fresh)} ${import_chalk29.default.dim("(store it now)")}`);
4851
+ console.log(` New ${import_chalk33.default.bold("client_secret")}: ${import_chalk33.default.green(fresh)} ${import_chalk33.default.dim("(store it now)")}`);
3921
4852
  break;
3922
4853
  }
3923
4854
  case "delete": {
3924
4855
  const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: `Delete app client "${c.name ?? id}"? Consumers logged in through it will lose access.`, default: false }]);
3925
4856
  if (!sure) break;
3926
4857
  await admin({ method: "DELETE", path: cBase, summary: `Delete app client ${id}` });
3927
- console.log(import_chalk29.default.green(" App client deleted."));
4858
+ console.log(import_chalk33.default.green(" App client deleted."));
3928
4859
  return;
3929
4860
  }
3930
4861
  }
@@ -3951,9 +4882,9 @@ async function providersMenu(cBase, clientLabel) {
3951
4882
  const providers = Array.isArray(raw) ? raw : [];
3952
4883
  console.log();
3953
4884
  for (const p of providers) {
3954
- console.log(` ${import_chalk29.default.bold(p.type)} ${import_chalk29.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
4885
+ console.log(` ${import_chalk33.default.bold(p.type)} ${import_chalk33.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
3955
4886
  }
3956
- if (!providers.length) console.log(import_chalk29.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
4887
+ if (!providers.length) console.log(import_chalk33.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
3957
4888
  const { act } = await inquirer3.prompt([{
3958
4889
  type: "list",
3959
4890
  name: "act",
@@ -4011,23 +4942,23 @@ async function providersMenu(cBase, clientLabel) {
4011
4942
  body.targetServerToken = routing;
4012
4943
  }
4013
4944
  await admin({ method: "POST", path: `${cBase}/providers`, body, summary: `Add ${type} login provider` });
4014
- console.log(import_chalk29.default.green(` ${type} provider added.`));
4945
+ console.log(import_chalk33.default.green(` ${type} provider added.`));
4015
4946
  } else {
4016
4947
  const { p } = await inquirer3.prompt([{
4017
4948
  type: "list",
4018
4949
  name: "p",
4019
4950
  message: act === "rm" ? "Remove which provider?" : "Reveal which secret?",
4020
- choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk29.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
4951
+ choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk33.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
4021
4952
  }]);
4022
4953
  if (!p) continue;
4023
4954
  if (act === "rm") {
4024
4955
  const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: `Remove the ${p.type} provider? Consumers using it can no longer sign in.`, default: false }]);
4025
4956
  if (!sure) continue;
4026
4957
  await admin({ method: "DELETE", path: `${cBase}/providers/${encodeURIComponent(p.id)}`, summary: `Remove ${p.type} provider` });
4027
- console.log(import_chalk29.default.green(` ${p.type} removed.`));
4958
+ console.log(import_chalk33.default.green(` ${p.type} removed.`));
4028
4959
  } else {
4029
4960
  const s = await admin({ method: "GET", path: `${cBase}/providers/${encodeURIComponent(p.id)}/secret`, summary: `Reveal ${p.type} provider secret` });
4030
- console.log(` ${import_chalk29.default.bold("client_secret")}: ${import_chalk29.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
4961
+ console.log(` ${import_chalk33.default.bold("client_secret")}: ${import_chalk33.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
4031
4962
  }
4032
4963
  }
4033
4964
  }
@@ -4035,7 +4966,7 @@ async function providersMenu(cBase, clientLabel) {
4035
4966
 
4036
4967
  // src/commands/spec.ts
4037
4968
  var fs7 = __toESM(require("fs"));
4038
- var import_chalk30 = __toESM(require("chalk"));
4969
+ var import_chalk34 = __toESM(require("chalk"));
4039
4970
  var import_ora14 = __toESM(require("ora"));
4040
4971
  init_admin();
4041
4972
  init_api();
@@ -4052,14 +4983,14 @@ async function runSpecGet(project, opts) {
4052
4983
  }
4053
4984
  async function runSpecSet(project, opts) {
4054
4985
  if (!opts.file) {
4055
- console.error(import_chalk30.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
4986
+ console.error(import_chalk34.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
4056
4987
  process.exit(1);
4057
4988
  }
4058
4989
  let specContent;
4059
4990
  try {
4060
4991
  specContent = fs7.readFileSync(opts.file, "utf-8");
4061
4992
  } catch {
4062
- console.error(import_chalk30.default.red(`Cannot read file: ${opts.file}`));
4993
+ console.error(import_chalk34.default.red(`Cannot read file: ${opts.file}`));
4063
4994
  process.exit(1);
4064
4995
  }
4065
4996
  const { teamId } = await resolveTeam(opts.team);
@@ -4088,23 +5019,23 @@ async function runSpecSet(project, opts) {
4088
5019
  function printSpecChangeReport(report, projectName) {
4089
5020
  const r = report.routes;
4090
5021
  if (r) {
4091
- for (const a of r.added) console.log(import_chalk30.default.green(` + ${a}`));
4092
- for (const d of r.removed) console.log(import_chalk30.default.red(` \u2212 ${d}`));
4093
- for (const rn of r.renamed ?? []) console.log(import_chalk30.default.yellow(` ~ ${rn.from} \u2192 ${rn.to}`));
4094
- for (const m of r.modified ?? []) console.log(import_chalk30.default.dim(` \xB1 ${m} (params/schema changed)`));
5022
+ for (const a of r.added) console.log(import_chalk34.default.green(` + ${a}`));
5023
+ for (const d of r.removed) console.log(import_chalk34.default.red(` \u2212 ${d}`));
5024
+ for (const rn of r.renamed ?? []) console.log(import_chalk34.default.yellow(` ~ ${rn.from} \u2192 ${rn.to}`));
5025
+ for (const m of r.modified ?? []) console.log(import_chalk34.default.dim(` \xB1 ${m} (params/schema changed)`));
4095
5026
  }
4096
- if (report.applied?.mcp_regenerated) console.log(import_chalk30.default.dim(" MCP catalogue regenerated."));
4097
- if (report.applied?.candidates_cleared) console.log(import_chalk30.default.dim(` ${report.applied.candidates_cleared} route candidate(s) now documented \u2014 cleared.`));
5027
+ if (report.applied?.mcp_regenerated) console.log(import_chalk34.default.dim(" MCP catalogue regenerated."));
5028
+ if (report.applied?.candidates_cleared) console.log(import_chalk34.default.dim(` ${report.applied.candidates_cleared} route candidate(s) now documented \u2014 cleared.`));
4098
5029
  for (const item of report.attention ?? []) {
4099
- console.log(import_chalk30.default.yellow(` \u26A0 ${item.detail}`));
5030
+ console.log(import_chalk34.default.yellow(` \u26A0 ${item.detail}`));
4100
5031
  if (item.suggestion?.carry_from && item.suggestion.carry_to) {
4101
- console.log(import_chalk30.default.dim(` Fix: apiblaze spec carry ${projectName} --method ${item.suggestion.method} --from "${item.suggestion.carry_from}" --to "${item.suggestion.carry_to}"`));
5032
+ console.log(import_chalk34.default.dim(` Fix: apiblaze spec carry ${projectName} --method ${item.suggestion.method} --from "${item.suggestion.carry_from}" --to "${item.suggestion.carry_to}"`));
4102
5033
  }
4103
5034
  }
4104
5035
  }
4105
5036
  async function runSpecCarry(project, opts) {
4106
5037
  if (!opts.method || !opts.from || !opts.to) {
4107
- console.error(import_chalk30.default.red("--method, --from and --to are required."));
5038
+ console.error(import_chalk34.default.red("--method, --from and --to are required."));
4108
5039
  process.exit(1);
4109
5040
  }
4110
5041
  const { teamId } = await resolveTeam(opts.team);
@@ -4126,7 +5057,7 @@ async function runSpecCarry(project, opts) {
4126
5057
  }
4127
5058
  async function runSpecDeleteRule(project, opts) {
4128
5059
  if (!opts.method || !opts.route) {
4129
- console.error(import_chalk30.default.red("--method and --route are required."));
5060
+ console.error(import_chalk34.default.red("--method and --route are required."));
4130
5061
  process.exit(1);
4131
5062
  }
4132
5063
  const { teamId } = await resolveTeam(opts.team);
@@ -4146,14 +5077,14 @@ async function runSpecDeleteRule(project, opts) {
4146
5077
  }
4147
5078
 
4148
5079
  // src/commands/agent.ts
4149
- var import_chalk32 = __toESM(require("chalk"));
5080
+ var import_chalk36 = __toESM(require("chalk"));
4150
5081
  var import_ora15 = __toESM(require("ora"));
4151
5082
  init_auth();
4152
5083
  init_admin();
4153
5084
  init_resolve();
4154
5085
 
4155
5086
  // src/lib/tools.ts
4156
- var import_chalk31 = __toESM(require("chalk"));
5087
+ var import_chalk35 = __toESM(require("chalk"));
4157
5088
  init_admin();
4158
5089
  init_api();
4159
5090
  init_resolve();
@@ -4173,15 +5104,15 @@ var TOOLS = [
4173
5104
  const key = keys.dev ?? Object.values(keys)[0];
4174
5105
  const url = `https://${a.name}.abz.run/${version2}/dev`;
4175
5106
  const tryIt = buildTryItCurl(url, auth, key);
4176
- const lines = [` ${import_chalk31.default.dim("Proxy URL:")} ${import_chalk31.default.bold(url)}`];
4177
- if (res.devPortal) lines.push(` ${import_chalk31.default.dim("Dev portal:")} ${res.devPortal}`);
5107
+ const lines = [` ${import_chalk35.default.dim("Proxy URL:")} ${import_chalk35.default.bold(url)}`];
5108
+ if (res.devPortal) lines.push(` ${import_chalk35.default.dim("Dev portal:")} ${res.devPortal}`);
4178
5109
  const envs = Object.keys(keys);
4179
5110
  if (envs.length) {
4180
- lines.push("", ` ${import_chalk31.default.bold("API keys")} ${import_chalk31.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
5111
+ lines.push("", ` ${import_chalk35.default.bold("API keys")} ${import_chalk35.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
4181
5112
  const w = Math.max(...envs.map((e) => e.length));
4182
- for (const env of envs) lines.push(` ${import_chalk31.default.cyan(env.padEnd(w))} ${import_chalk31.default.green(keys[env])}`);
5113
+ for (const env of envs) lines.push(` ${import_chalk35.default.cyan(env.padEnd(w))} ${import_chalk35.default.green(keys[env])}`);
4183
5114
  }
4184
- if (tryIt) lines.push("", ` ${import_chalk31.default.dim("Try it:")}`, ` ${import_chalk31.default.cyan(tryIt)}`);
5115
+ if (tryIt) lines.push("", ` ${import_chalk35.default.dim("Try it:")}`, ` ${import_chalk35.default.cyan(tryIt)}`);
4185
5116
  return { ...res, proxy_url: url, keys, ...tryIt ? { try_it: tryIt } : {}, display: lines.join("\n") };
4186
5117
  }
4187
5118
  },
@@ -4337,17 +5268,17 @@ function truncate(value, max = 1500) {
4337
5268
  }
4338
5269
  function printCost(resp) {
4339
5270
  const line = formatBilling(resp.billing);
4340
- if (line) console.log(import_chalk32.default.magenta(` ${line}`) + import_chalk32.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
5271
+ if (line) console.log(import_chalk36.default.magenta(` ${line}`) + import_chalk36.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
4341
5272
  }
4342
5273
  async function runAgent(opts) {
4343
5274
  requireAuth();
4344
5275
  const { teamId, teamName } = await resolveTeam(opts.team);
4345
5276
  const { default: inquirer3 } = await import("inquirer");
4346
- console.log(import_chalk32.default.bold("APIblaze agent") + import_chalk32.default.dim(` \xB7 team ${teamName ?? teamId}`));
4347
- console.log(import_chalk32.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
5277
+ console.log(import_chalk36.default.bold("APIblaze agent") + import_chalk36.default.dim(` \xB7 team ${teamName ?? teamId}`));
5278
+ console.log(import_chalk36.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
4348
5279
  const history = [];
4349
5280
  while (true) {
4350
- const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk32.default.cyan("you") + " \u203A" }]);
5281
+ const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk36.default.cyan("you") + " \u203A" }]);
4351
5282
  const text = (input ?? "").trim();
4352
5283
  if (!text) continue;
4353
5284
  if (["exit", "quit", ":q"].includes(text.toLowerCase())) break;
@@ -4361,14 +5292,14 @@ async function runAgent(opts) {
4361
5292
  } catch (err) {
4362
5293
  spinner.stop();
4363
5294
  if (err instanceof ApiError && err.status === 402) {
4364
- console.log(import_chalk32.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
5295
+ console.log(import_chalk36.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
4365
5296
  break;
4366
5297
  }
4367
5298
  throw err;
4368
5299
  }
4369
5300
  history.push({ role: "assistant", content: resp.raw });
4370
5301
  printCost(resp);
4371
- if (resp.reply) console.log(import_chalk32.default.green("agent") + " \u203A " + resp.reply);
5302
+ if (resp.reply) console.log(import_chalk36.default.green("agent") + " \u203A " + resp.reply);
4372
5303
  if (!resp.action) break;
4373
5304
  const tool = findTool(resp.action.tool);
4374
5305
  if (!tool) {
@@ -4393,11 +5324,11 @@ async function runAgent(opts) {
4393
5324
  }
4394
5325
  renderTrace();
4395
5326
  if (step === MAX_TOOL_STEPS - 1) {
4396
- console.log(import_chalk32.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
5327
+ console.log(import_chalk36.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
4397
5328
  }
4398
5329
  }
4399
5330
  }
4400
- console.log(import_chalk32.default.dim("\nBye."));
5331
+ console.log(import_chalk36.default.dim("\nBye."));
4401
5332
  }
4402
5333
 
4403
5334
  // src/commands/config-browse.ts
@@ -4539,6 +5470,53 @@ var SETTINGS = [
4539
5470
  desc: "Team-scoped tag grouping projects in the consumer portal",
4540
5471
  toPatch: (v) => ({ product_slug: v })
4541
5472
  },
5473
+ // Who funds AI chat here (specs/chat_funding.MD). A partial PATCH merges, so
5474
+ // setting one key never resurrects a switch the producer turned off.
5475
+ {
5476
+ key: "chat_sponsorship.enabled",
5477
+ label: "Pay for your users' AI chats",
5478
+ group: "Portal & MCP",
5479
+ type: "boolean",
5480
+ desc: "Every chat message costs money and your users can't pay for it here yet, so you cover it \u2014 for people who sign in, and for API keys you gave the use-premium permission. Off = everyone brings their own AI key, your own tools included",
5481
+ read: (cfg) => cfg.chat_sponsorship?.enabled !== false,
5482
+ toPatch: (v) => ({ chat_sponsorship: { enabled: v } })
5483
+ },
5484
+ {
5485
+ key: "chat_sponsorship.quota_enabled",
5486
+ label: "Limit AI chat per person per day",
5487
+ group: "Portal & MCP",
5488
+ type: "boolean",
5489
+ desc: "Give each person their own daily allowance, reset at midnight UTC. Off = your wallet running out is the only thing that stops it",
5490
+ read: (cfg) => cfg.chat_sponsorship?.quota_enabled !== false,
5491
+ toPatch: (v) => ({ chat_sponsorship: { quota_enabled: v } })
5492
+ },
5493
+ {
5494
+ key: "chat_sponsorship.cap_cents_per_day",
5495
+ label: "AI chat: cents per person per day",
5496
+ group: "Portal & MCP",
5497
+ type: "number",
5498
+ desc: "Most you'll spend on one person per day, in cents you're actually charged (not raw model price). 25 is roughly 25 short chats. Max 5000; 0 blocks everyone",
5499
+ read: (cfg) => cfg.chat_sponsorship?.cap_cents_per_day ?? 25,
5500
+ toPatch: (v) => ({ chat_sponsorship: { cap_cents_per_day: v } })
5501
+ },
5502
+ {
5503
+ key: "chat_sponsorship.max_chats_per_day",
5504
+ label: "AI chat: chats per person per day",
5505
+ group: "Portal & MCP",
5506
+ type: "number",
5507
+ desc: "Chats one person can have per day \u2014 counted even when a chat is cheap, so nobody runs thousands of tiny ones. Max 1000; 0 blocks everyone",
5508
+ read: (cfg) => cfg.chat_sponsorship?.max_chats_per_day ?? 25,
5509
+ toPatch: (v) => ({ chat_sponsorship: { max_chats_per_day: v } })
5510
+ },
5511
+ {
5512
+ key: "chat_sponsorship.max_chars_per_message",
5513
+ label: "AI chat: longest single message",
5514
+ group: "Portal & MCP",
5515
+ type: "number",
5516
+ desc: "2000 characters is about 300 words. Has its own limit because one very long message can cost more than a whole day of short ones. Max 64000",
5517
+ read: (cfg) => cfg.chat_sponsorship?.max_chars_per_message ?? 2e3,
5518
+ toPatch: (v) => ({ chat_sponsorship: { max_chars_per_message: v } })
5519
+ },
4542
5520
  // ── Advanced (specs/missing.md): all optional, default-off; null clears ────
4543
5521
  {
4544
5522
  key: "ip_access.mode",
@@ -4636,11 +5614,11 @@ function dig(blob, dotted) {
4636
5614
  }
4637
5615
  var readSetting = (s, cfg) => s.read ? s.read(cfg) : dig(cfg, s.key);
4638
5616
  function show(v) {
4639
- if (v === void 0) return import_chalk33.default.dim("(unset)");
4640
- if (v === null) return import_chalk33.default.dim("null");
4641
- if (typeof v === "object") return import_chalk33.default.cyan(JSON.stringify(v));
4642
- if (typeof v === "boolean") return v ? import_chalk33.default.green("on") : import_chalk33.default.red("off");
4643
- return import_chalk33.default.cyan(String(v));
5617
+ if (v === void 0) return import_chalk37.default.dim("(unset)");
5618
+ if (v === null) return import_chalk37.default.dim("null");
5619
+ if (typeof v === "object") return import_chalk37.default.cyan(JSON.stringify(v));
5620
+ if (typeof v === "boolean") return v ? import_chalk37.default.green("on") : import_chalk37.default.red("off");
5621
+ return import_chalk37.default.cyan(String(v));
4644
5622
  }
4645
5623
  function parseValue(raw) {
4646
5624
  if (raw === "true") return true;
@@ -4682,10 +5660,10 @@ async function patchSetting(proj2, s, value, cfg) {
4682
5660
  }
4683
5661
  }
4684
5662
  var loginFirst = (what) => {
4685
- console.log(import_chalk33.default.yellow(`
5663
+ console.log(import_chalk37.default.yellow(`
4686
5664
  Log in first to ${what}.`));
4687
- console.log(import_chalk33.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
4688
- console.log(import_chalk33.default.dim(" anonymously and want to bring it into your account.\n"));
5665
+ console.log(import_chalk37.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
5666
+ console.log(import_chalk37.default.dim(" anonymously and want to bring it into your account.\n"));
4689
5667
  };
4690
5668
  async function runConfig(project, key, value, opts) {
4691
5669
  const creds = loadCredentials();
@@ -4702,9 +5680,9 @@ async function runConfig(project, key, value, opts) {
4702
5680
  }
4703
5681
  const setting = SETTINGS.find((s) => s.key === key);
4704
5682
  if (!setting) {
4705
- console.error(import_chalk33.default.red(`Unknown setting "${key}".`));
4706
- console.error(import_chalk33.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
4707
- console.error(import_chalk33.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
5683
+ console.error(import_chalk37.default.red(`Unknown setting "${key}".`));
5684
+ console.error(import_chalk37.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
5685
+ console.error(import_chalk37.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
4708
5686
  process.exit(1);
4709
5687
  }
4710
5688
  if (value === void 0) {
@@ -4719,7 +5697,7 @@ async function pickProject(teamId) {
4719
5697
  const { getProjects: getProjects2 } = await Promise.resolve().then(() => (init_api(), api_exports));
4720
5698
  const projects = await getProjects2(teamId).catch(() => []);
4721
5699
  if (!projects.length) {
4722
- console.error(import_chalk33.default.red("No projects in this team. Create one: `npx apiblaze create`."));
5700
+ console.error(import_chalk37.default.red("No projects in this team. Create one: `npx apiblaze create`."));
4723
5701
  process.exit(1);
4724
5702
  }
4725
5703
  const { default: inquirer3 } = await import("inquirer");
@@ -4727,7 +5705,7 @@ async function pickProject(teamId) {
4727
5705
  type: "list",
4728
5706
  name: "picked",
4729
5707
  message: "Which project?",
4730
- choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk33.default.dim("v" + p.apiVersion)}`, value: p }))
5708
+ choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk37.default.dim("v" + p.apiVersion)}`, value: p }))
4731
5709
  }]);
4732
5710
  return { projectId: picked.projectId, projectName: picked.projectName, apiVersion: picked.apiVersion, teamId, tenant: picked.tenant };
4733
5711
  }
@@ -4738,25 +5716,25 @@ function printAll(proj2, cfg, json) {
4738
5716
  console.log(JSON.stringify(out, null, 2));
4739
5717
  return;
4740
5718
  }
4741
- console.log(import_chalk33.default.bold(`
5719
+ console.log(import_chalk37.default.bold(`
4742
5720
  ${proj2.projectName} v${proj2.apiVersion} \u2014 settings
4743
5721
  `));
4744
5722
  for (const group2 of SETTING_GROUPS) {
4745
- console.log(import_chalk33.default.bold(group2));
5723
+ console.log(import_chalk37.default.bold(group2));
4746
5724
  for (const s of SETTINGS.filter((x) => x.group === group2)) {
4747
- console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk33.default.dim(s.desc)}`);
5725
+ console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk37.default.dim(s.desc)}`);
4748
5726
  }
4749
5727
  console.log();
4750
5728
  }
4751
- console.log(import_chalk33.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
5729
+ console.log(import_chalk37.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
4752
5730
  }
4753
5731
  async function discoveryMenu(project) {
4754
5732
  const { default: inquirer3 } = await import("inquirer");
4755
- console.log(import_chalk33.default.bold(`
5733
+ console.log(import_chalk37.default.bold(`
4756
5734
  APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
4757
5735
  `));
4758
- console.log(import_chalk33.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
4759
- console.log(import_chalk33.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
5736
+ console.log(import_chalk37.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
5737
+ console.log(import_chalk37.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
4760
5738
  for (; ; ) {
4761
5739
  const { pick: pick2 } = await inquirer3.prompt([{
4762
5740
  type: "list",
@@ -4764,13 +5742,13 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
4764
5742
  message: "Explore:",
4765
5743
  pageSize: 20,
4766
5744
  choices: [
4767
- new inquirer3.Separator(import_chalk33.default.bold("\u2014 Settings \u2014")),
5745
+ new inquirer3.Separator(import_chalk37.default.bold("\u2014 Settings \u2014")),
4768
5746
  ...SETTING_GROUPS.map((g) => ({
4769
- name: `${g} ${import_chalk33.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
5747
+ name: `${g} ${import_chalk37.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
4770
5748
  value: { kind: "settings", g }
4771
5749
  })),
4772
- new inquirer3.Separator(import_chalk33.default.bold("\u2014 Features \u2014")),
4773
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk33.default.dim(f.desc)}`, value: { kind: "feature", f } })),
5750
+ new inquirer3.Separator(import_chalk37.default.bold("\u2014 Features \u2014")),
5751
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk37.default.dim(f.desc)}`, value: { kind: "feature", f } })),
4774
5752
  new inquirer3.Separator(),
4775
5753
  { name: "Exit", value: { kind: "exit" } }
4776
5754
  ]
@@ -4779,24 +5757,24 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
4779
5757
  if (pick2.kind === "settings") {
4780
5758
  console.log();
4781
5759
  for (const s of SETTINGS.filter((x) => x.group === pick2.g)) {
4782
- console.log(` ${import_chalk33.default.bold(s.label.padEnd(28))} ${import_chalk33.default.dim(s.desc)}`);
4783
- console.log(` ${import_chalk33.default.dim(" key: " + s.key)}`);
5760
+ console.log(` ${import_chalk37.default.bold(s.label.padEnd(28))} ${import_chalk37.default.dim(s.desc)}`);
5761
+ console.log(` ${import_chalk37.default.dim(" key: " + s.key)}`);
4784
5762
  }
4785
5763
  loginFirst("view or change these settings");
4786
5764
  } else {
4787
5765
  const f = pick2.f;
4788
5766
  console.log(`
4789
- ${import_chalk33.default.bold(f.label)} \u2014 ${f.desc}`);
5767
+ ${import_chalk37.default.bold(f.label)} \u2014 ${f.desc}`);
4790
5768
  loginFirst(`use ${f.label.toLowerCase()}`);
4791
5769
  }
4792
5770
  }
4793
5771
  }
4794
5772
  async function navigator(proj2, cfg, opts) {
4795
5773
  const { default: inquirer3 } = await import("inquirer");
4796
- console.log(import_chalk33.default.bold(`
5774
+ console.log(import_chalk37.default.bold(`
4797
5775
  ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
4798
5776
  `));
4799
- console.log(import_chalk33.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
5777
+ console.log(import_chalk37.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
4800
5778
  let blob = cfg;
4801
5779
  for (; ; ) {
4802
5780
  const { pick: pick2 } = await inquirer3.prompt([{
@@ -4805,10 +5783,10 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
4805
5783
  message: "Where to?",
4806
5784
  pageSize: 20,
4807
5785
  choices: [
4808
- new inquirer3.Separator(import_chalk33.default.bold("\u2014 Settings \u2014")),
5786
+ new inquirer3.Separator(import_chalk37.default.bold("\u2014 Settings \u2014")),
4809
5787
  ...SETTING_GROUPS.map((g) => ({ name: g, value: { kind: "settings", g } })),
4810
- new inquirer3.Separator(import_chalk33.default.bold("\u2014 Features \u2014")),
4811
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk33.default.dim(f.desc)}`, value: { kind: f.go } })),
5788
+ new inquirer3.Separator(import_chalk37.default.bold("\u2014 Features \u2014")),
5789
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk37.default.dim(f.desc)}`, value: { kind: f.go } })),
4812
5790
  new inquirer3.Separator(),
4813
5791
  { name: "Show all settings", value: { kind: "list" } },
4814
5792
  { name: "Exit", value: { kind: "exit" } }
@@ -4848,7 +5826,7 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
4848
5826
  }
4849
5827
  }
4850
5828
  } catch (err) {
4851
- console.error(import_chalk33.default.red(` ${err instanceof Error ? err.message : String(err)}`));
5829
+ console.error(import_chalk37.default.red(` ${err instanceof Error ? err.message : String(err)}`));
4852
5830
  }
4853
5831
  }
4854
5832
  }
@@ -4862,7 +5840,7 @@ async function settingsGroup(proj2, cfg, group2) {
4862
5840
  message: group2 + ":",
4863
5841
  pageSize: 16,
4864
5842
  choices: [
4865
- ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk33.default.dim(s2.desc)}`, value: s2 })),
5843
+ ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk37.default.dim(s2.desc)}`, value: s2 })),
4866
5844
  new inquirer3.Separator(),
4867
5845
  { name: "\u2190 Back", value: null }
4868
5846
  ]
@@ -4880,7 +5858,7 @@ async function settingsGroup(proj2, cfg, group2) {
4880
5858
  } else if (s.type === "number") {
4881
5859
  const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: `${s.label} (number):`, default: readSetting(s, cfg) }]);
4882
5860
  if (v === "" || Number.isNaN(Number(v))) {
4883
- console.log(import_chalk33.default.yellow(" Not a number \u2014 unchanged."));
5861
+ console.log(import_chalk37.default.yellow(" Not a number \u2014 unchanged."));
4884
5862
  continue;
4885
5863
  }
4886
5864
  value = Number(v);
@@ -4961,7 +5939,7 @@ async function buildCondition(phase) {
4961
5939
  const items = [];
4962
5940
  for (; ; ) {
4963
5941
  const a = await inquirer3.prompt([
4964
- { type: "input", name: "source", message: `Condition field ${import_chalk33.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
5942
+ { type: "input", name: "source", message: `Condition field ${import_chalk37.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
4965
5943
  { type: "list", name: "operator", message: "Operator:", choices: [
4966
5944
  "eq",
4967
5945
  "neq",
@@ -4992,7 +5970,7 @@ async function buildCondition(phase) {
4992
5970
  function showCondition(cond) {
4993
5971
  if (!Array.isArray(cond) || !cond.length) return "";
4994
5972
  const s = cond.map((c) => `${c.source} ${c.operator}${c.value !== void 0 ? ` "${c.value}"` : ""}${c.logicOp ? ` ${c.logicOp}` : ""}`).join(" ");
4995
- return import_chalk33.default.dim(` when ${s}`);
5973
+ return import_chalk37.default.dim(` when ${s}`);
4996
5974
  }
4997
5975
  async function transformsMenu(proj2) {
4998
5976
  const { default: inquirer3 } = await import("inquirer");
@@ -5001,12 +5979,12 @@ async function transformsMenu(proj2) {
5001
5979
  const out = await admin({ method: "GET", path: base2, summary: "List transform rules" });
5002
5980
  const rules = out?.rules ?? [];
5003
5981
  console.log();
5004
- if (!rules.length) console.log(import_chalk33.default.dim(" No transform rules yet."));
5982
+ if (!rules.length) console.log(import_chalk37.default.dim(" No transform rules yet."));
5005
5983
  for (const r of rules) {
5006
5984
  const a = r.action ?? {};
5007
5985
  const fns = [...a.source_fns ?? [], ...a.dest_fns ?? []].map((f) => f.fn);
5008
- const what = a.type === "hardcode" ? `${a.destination} = "${a.value}"` : a.type === "remove" ? `remove ${a.field}` : `${a.source} \u2192 ${a.destination}${a.lookup ? " (mapped)" : ""}${fns.length ? import_chalk33.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
5009
- console.log(` ${r.enabled ? import_chalk33.default.green("\u25CF") : import_chalk33.default.dim("\u25CB")} ${import_chalk33.default.bold(r.name)} ${import_chalk33.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
5986
+ const what = a.type === "hardcode" ? `${a.destination} = "${a.value}"` : a.type === "remove" ? `remove ${a.field}` : `${a.source} \u2192 ${a.destination}${a.lookup ? " (mapped)" : ""}${fns.length ? import_chalk37.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
5987
+ console.log(` ${r.enabled ? import_chalk37.default.green("\u25CF") : import_chalk37.default.dim("\u25CB")} ${import_chalk37.default.bold(r.name)} ${import_chalk37.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
5010
5988
  }
5011
5989
  const { act } = await inquirer3.prompt([{
5012
5990
  type: "list",
@@ -5018,7 +5996,7 @@ async function transformsMenu(proj2) {
5018
5996
  { name: "Enable/disable a rule", value: "toggle" },
5019
5997
  { name: "Delete a rule", value: "delete" }
5020
5998
  ] : [],
5021
- { name: import_chalk33.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
5999
+ { name: import_chalk37.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
5022
6000
  { name: "\u2190 Back", value: "back" }
5023
6001
  ]
5024
6002
  }]);
@@ -5031,11 +6009,11 @@ async function transformsMenu(proj2) {
5031
6009
  }]);
5032
6010
  const body = parseValue(raw);
5033
6011
  if (!body || typeof body !== "object" || Array.isArray(body)) {
5034
- console.log(import_chalk33.default.yellow(" Not a JSON object \u2014 skipped."));
6012
+ console.log(import_chalk37.default.yellow(" Not a JSON object \u2014 skipped."));
5035
6013
  continue;
5036
6014
  }
5037
6015
  await admin({ method: "POST", path: base2, body, summary: "Create transform rule (raw JSON)" });
5038
- console.log(import_chalk33.default.green(" Rule created."));
6016
+ console.log(import_chalk37.default.green(" Rule created."));
5039
6017
  continue;
5040
6018
  }
5041
6019
  if (act === "add") {
@@ -5051,7 +6029,7 @@ async function transformsMenu(proj2) {
5051
6029
  { name: "Remove a field", value: "remove" }
5052
6030
  ] }
5053
6031
  ]);
5054
- const fieldHint = import_chalk33.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
6032
+ const fieldHint = import_chalk37.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
5055
6033
  let action2;
5056
6034
  if (ans.kind === "hardcode") {
5057
6035
  const a = await inquirer3.prompt([
@@ -5098,16 +6076,16 @@ async function transformsMenu(proj2) {
5098
6076
  type: "list",
5099
6077
  name: "rule",
5100
6078
  message: act === "toggle" ? "Which rule?" : "Delete which rule?",
5101
- choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk33.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
6079
+ choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk37.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
5102
6080
  }]);
5103
6081
  if (!rule) continue;
5104
6082
  if (act === "toggle") {
5105
6083
  const flipped = { ...rule, enabled: rule.enabled === false };
5106
6084
  await admin({ method: "PUT", path: `${base2}/${rule.id}`, body: flipped, summary: `${flipped.enabled ? "Enable" : "Disable"} transform "${rule.name}"` });
5107
- console.log(import_chalk33.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
6085
+ console.log(import_chalk37.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
5108
6086
  } else {
5109
6087
  await admin({ method: "DELETE", path: `${base2}/${rule.id}`, summary: `Delete transform "${rule.name}"` });
5110
- console.log(import_chalk33.default.green(` ${rule.name} deleted.`));
6088
+ console.log(import_chalk37.default.green(` ${rule.name} deleted.`));
5111
6089
  }
5112
6090
  }
5113
6091
  }
@@ -5119,9 +6097,9 @@ async function mappingsMenu(proj2) {
5119
6097
  const out = await admin({ method: "GET", path: base2, summary: "List mapping tables" });
5120
6098
  const tables = out?.mappings ?? out?.tables ?? [];
5121
6099
  console.log();
5122
- if (!tables.length) console.log(import_chalk33.default.dim(" No mapping tables yet."));
6100
+ if (!tables.length) console.log(import_chalk37.default.dim(" No mapping tables yet."));
5123
6101
  for (const t of tables) {
5124
- console.log(` ${import_chalk33.default.bold(t.name)} ${import_chalk33.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
6102
+ console.log(` ${import_chalk37.default.bold(t.name)} ${import_chalk37.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
5125
6103
  }
5126
6104
  const { act } = await inquirer3.prompt([{
5127
6105
  type: "list",
@@ -5141,11 +6119,11 @@ async function mappingsMenu(proj2) {
5141
6119
  ]);
5142
6120
  const entries2 = parseValue(a.entries);
5143
6121
  if (!Array.isArray(entries2)) {
5144
- console.log(import_chalk33.default.yellow(" Entries must be a JSON array \u2014 not created."));
6122
+ console.log(import_chalk37.default.yellow(" Entries must be a JSON array \u2014 not created."));
5145
6123
  continue;
5146
6124
  }
5147
6125
  await admin({ method: "POST", path: base2, body: { name: a.name, entries: entries2 }, summary: `Create mapping table "${a.name}"` });
5148
- console.log(import_chalk33.default.green(` Table "${a.name}" created.`));
6126
+ console.log(import_chalk37.default.green(` Table "${a.name}" created.`));
5149
6127
  } else {
5150
6128
  const { table } = await inquirer3.prompt([{
5151
6129
  type: "list",
@@ -5155,7 +6133,7 @@ async function mappingsMenu(proj2) {
5155
6133
  }]);
5156
6134
  if (!table) continue;
5157
6135
  await admin({ method: "DELETE", path: `${base2}/${table.id}`, summary: `Delete mapping table "${table.name}"` });
5158
- console.log(import_chalk33.default.green(` ${table.name} deleted.`));
6136
+ console.log(import_chalk37.default.green(` ${table.name} deleted.`));
5159
6137
  }
5160
6138
  }
5161
6139
  }
@@ -5166,14 +6144,14 @@ async function tenantsMenu(proj2, opts) {
5166
6144
  const out = await admin({ method: "GET", path: base2, summary: "List attached tenants" });
5167
6145
  const tenants = out?.tenants ?? [];
5168
6146
  console.log();
5169
- if (!tenants.length) console.log(import_chalk33.default.dim(" No tenants attached (consumers use the default tenant)."));
5170
- for (const t of tenants) console.log(` ${import_chalk33.default.bold(t.tenant_name ?? t.name)} ${import_chalk33.default.dim(t.display_name ?? "")}`);
6147
+ if (!tenants.length) console.log(import_chalk37.default.dim(" No tenants attached (consumers use the default tenant)."));
6148
+ for (const t of tenants) console.log(` ${import_chalk37.default.bold(t.tenant_name ?? t.name)} ${import_chalk37.default.dim(t.display_name ?? "")}`);
5171
6149
  const { act } = await inquirer3.prompt([{
5172
6150
  type: "list",
5173
6151
  name: "act",
5174
6152
  message: "Tenants:",
5175
6153
  choices: [
5176
- { name: `Manage a tenant\u2026 ${import_chalk33.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
6154
+ { name: `Manage a tenant\u2026 ${import_chalk37.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
5177
6155
  { name: "Attach a tenant to this project", value: "attach" },
5178
6156
  ...tenants.length ? [{ name: "Detach a tenant from this project", value: "detach" }] : [],
5179
6157
  { name: "\u2190 Back", value: "back" }
@@ -5196,7 +6174,7 @@ async function tenantsMenu(proj2, opts) {
5196
6174
  }]);
5197
6175
  if (!t) continue;
5198
6176
  await admin({ method: "DELETE", path: `${base2}/${encodeURIComponent(t.tenant_name ?? t.name)}`, summary: `Detach tenant ${t.tenant_name ?? t.name}` });
5199
- console.log(import_chalk33.default.green(` Detached ${t.tenant_name ?? t.name}.`));
6177
+ console.log(import_chalk37.default.green(` Detached ${t.tenant_name ?? t.name}.`));
5200
6178
  }
5201
6179
  }
5202
6180
  }
@@ -5239,7 +6217,7 @@ async function specMenu(proj2, opts) {
5239
6217
  choices: [
5240
6218
  { name: "Print the stored spec", value: "get" },
5241
6219
  { name: "Refresh the spec from its source", value: "refresh" },
5242
- { name: import_chalk33.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
6220
+ { name: import_chalk37.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
5243
6221
  { name: "\u2190 Back", value: "back" }
5244
6222
  ]
5245
6223
  }]);
@@ -5247,7 +6225,7 @@ async function specMenu(proj2, opts) {
5247
6225
  if (act === "get") await runSpecGet(proj2.projectName, { team: opts.team, apiversion: proj2.apiVersion });
5248
6226
  else if (act === "refresh") {
5249
6227
  await admin({ method: "POST", path: `/projects/${proj2.projectId}/${proj2.apiVersion}/refresh-spec`, summary: "Refresh spec from source" });
5250
- console.log(import_chalk33.default.green(" Spec refresh triggered."));
6228
+ console.log(import_chalk37.default.green(" Spec refresh triggered."));
5251
6229
  } else await runOpenapi(proj2.projectName, proj2.apiVersion);
5252
6230
  }
5253
6231
  async function agentsMenu(proj2, opts) {
@@ -5272,7 +6250,7 @@ async function agentsMenu(proj2, opts) {
5272
6250
  }
5273
6251
 
5274
6252
  // src/commands/group.ts
5275
- var import_chalk34 = __toESM(require("chalk"));
6253
+ var import_chalk38 = __toESM(require("chalk"));
5276
6254
  var import_ora17 = __toESM(require("ora"));
5277
6255
  init_auth();
5278
6256
  init_admin();
@@ -5366,7 +6344,7 @@ async function userByRefOrCreate(t, ref) {
5366
6344
  if (!ref.includes("@")) throw e;
5367
6345
  const created = await t.call("/v1/admin/users", "POST", { email: ref.trim().toLowerCase() });
5368
6346
  if (!created?.abz_sub) throw e;
5369
- console.log(import_chalk34.default.dim(` ${ref} wasn't a user yet \u2014 created.`));
6347
+ console.log(import_chalk38.default.dim(` ${ref} wasn't a user yet \u2014 created.`));
5370
6348
  return { abz_sub: created.abz_sub, email: created.email ?? ref, display_name: null };
5371
6349
  }
5372
6350
  }
@@ -5374,11 +6352,11 @@ async function runGroupList(opts) {
5374
6352
  const t = await resolveTransport(opts);
5375
6353
  const groups = await listGroups(t);
5376
6354
  if (opts.json) return void console.log(JSON.stringify(groups));
5377
- if (!groups.length) return void console.log(import_chalk34.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
5378
- console.log(import_chalk34.default.dim(`Tenant ${t.tenant}:`));
6355
+ if (!groups.length) return void console.log(import_chalk38.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
6356
+ console.log(import_chalk38.default.dim(`Tenant ${t.tenant}:`));
5379
6357
  for (const g of groups) {
5380
- const sealed = g.name === "apiblaze_admins" ? import_chalk34.default.dim(" (admins \u2014 managed by allowlist)") : "";
5381
- console.log(` ${import_chalk34.default.bold(g.name)} ${import_chalk34.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
6358
+ const sealed = g.name === "apiblaze_admins" ? import_chalk38.default.dim(" (admins \u2014 managed by allowlist)") : "";
6359
+ console.log(` ${import_chalk38.default.bold(g.name)} ${import_chalk38.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
5382
6360
  }
5383
6361
  }
5384
6362
  async function runGroupCreate(name, opts) {
@@ -5406,7 +6384,7 @@ async function runGroupCreate(name, opts) {
5406
6384
  const spinner = (0, import_ora17.default)(`Creating group ${name}...`).start();
5407
6385
  try {
5408
6386
  await t.call("/v1/admin/groups", "POST", { name, admins: [adminSub] });
5409
- spinner.succeed(`Group ${import_chalk34.default.bold(name)} created in ${t.tenant}.`);
6387
+ spinner.succeed(`Group ${import_chalk38.default.bold(name)} created in ${t.tenant}.`);
5410
6388
  } catch (e) {
5411
6389
  spinner.fail("Create failed.");
5412
6390
  throw e;
@@ -5418,7 +6396,7 @@ async function runGroupDelete(name, opts) {
5418
6396
  const spinner = (0, import_ora17.default)(`Deleting group ${name}...`).start();
5419
6397
  try {
5420
6398
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}`, "DELETE");
5421
- spinner.succeed(`Group ${import_chalk34.default.bold(name)} deleted.`);
6399
+ spinner.succeed(`Group ${import_chalk38.default.bold(name)} deleted.`);
5422
6400
  } catch (e) {
5423
6401
  spinner.fail("Delete failed.");
5424
6402
  throw e;
@@ -5431,11 +6409,11 @@ async function runGroupMembers(name, opts) {
5431
6409
  const subs = await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/subgroups`);
5432
6410
  if (opts.json) return void console.log(JSON.stringify({ ...detail, subgroups: subs?.subgroups ?? [] }));
5433
6411
  const members = detail?.members ?? [];
5434
- console.log(import_chalk34.default.bold(`${g.name}`) + import_chalk34.default.dim(` (${t.tenant})`));
5435
- for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk34.default.cyan("group-admin") : import_chalk34.default.dim("member")}`);
5436
- if (!members.length) console.log(import_chalk34.default.dim(" no members"));
6412
+ console.log(import_chalk38.default.bold(`${g.name}`) + import_chalk38.default.dim(` (${t.tenant})`));
6413
+ for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk38.default.cyan("group-admin") : import_chalk38.default.dim("member")}`);
6414
+ if (!members.length) console.log(import_chalk38.default.dim(" no members"));
5437
6415
  const sg = subs?.subgroups ?? [];
5438
- if (sg.length) console.log(import_chalk34.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
6416
+ if (sg.length) console.log(import_chalk38.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
5439
6417
  }
5440
6418
  async function runGroupAddUser(userRef, groupName, opts) {
5441
6419
  const t = await resolveTransport(opts);
@@ -5445,7 +6423,7 @@ async function runGroupAddUser(userRef, groupName, opts) {
5445
6423
  const spinner = (0, import_ora17.default)(`Adding ${label2(u)} to ${g.name}...`).start();
5446
6424
  try {
5447
6425
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members`, "POST", { abz_sub: u.abz_sub, role });
5448
- spinner.succeed(`${import_chalk34.default.bold(label2(u))} added to ${import_chalk34.default.bold(g.name)} as ${role}.`);
6426
+ spinner.succeed(`${import_chalk38.default.bold(label2(u))} added to ${import_chalk38.default.bold(g.name)} as ${role}.`);
5449
6427
  } catch (e) {
5450
6428
  spinner.fail("Add failed.");
5451
6429
  throw e;
@@ -5457,7 +6435,7 @@ async function runGroupRemoveUser(userRef, groupName, opts) {
5457
6435
  const spinner = (0, import_ora17.default)(`Removing ${label2(u)} from ${g.name}...`).start();
5458
6436
  try {
5459
6437
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members/_?abz_sub=${encodeURIComponent(u.abz_sub)}`, "DELETE");
5460
- spinner.succeed(`${import_chalk34.default.bold(label2(u))} removed from ${import_chalk34.default.bold(g.name)}.`);
6438
+ spinner.succeed(`${import_chalk38.default.bold(label2(u))} removed from ${import_chalk38.default.bold(g.name)}.`);
5461
6439
  } catch (e) {
5462
6440
  spinner.fail("Remove failed.");
5463
6441
  throw e;
@@ -5469,7 +6447,7 @@ async function runGroupAddGroup(childName, parentName, opts) {
5469
6447
  const spinner = (0, import_ora17.default)(`Nesting ${child.name} under ${parent.name}...`).start();
5470
6448
  try {
5471
6449
  await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups`, "POST", { child_group_id: child.id });
5472
- spinner.succeed(`${import_chalk34.default.bold(child.name)} is now a subgroup of ${import_chalk34.default.bold(parent.name)}.`);
6450
+ spinner.succeed(`${import_chalk38.default.bold(child.name)} is now a subgroup of ${import_chalk38.default.bold(parent.name)}.`);
5473
6451
  } catch (e) {
5474
6452
  spinner.fail("Nest failed.");
5475
6453
  throw e;
@@ -5481,7 +6459,7 @@ async function runGroupRemoveGroup(childName, parentName, opts) {
5481
6459
  const spinner = (0, import_ora17.default)(`Un-nesting ${child.name} from ${parent.name}...`).start();
5482
6460
  try {
5483
6461
  await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups/${encodeURIComponent(child.id)}`, "DELETE");
5484
- spinner.succeed(`${import_chalk34.default.bold(child.name)} un-nested from ${import_chalk34.default.bold(parent.name)}.`);
6462
+ spinner.succeed(`${import_chalk38.default.bold(child.name)} un-nested from ${import_chalk38.default.bold(parent.name)}.`);
5485
6463
  } catch (e) {
5486
6464
  spinner.fail("Un-nest failed.");
5487
6465
  throw e;
@@ -5492,18 +6470,18 @@ async function runGroupUsers(opts) {
5492
6470
  const users = await listUsers(t);
5493
6471
  const observed = await t.call("/v1/admin/observed-identities").catch(() => ({ identities: [] }));
5494
6472
  if (opts.json) return void console.log(JSON.stringify({ users, observed: observed?.identities ?? [] }));
5495
- console.log(import_chalk34.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
5496
- for (const u of users) console.log(` ${label2(u)} ${import_chalk34.default.dim(u.abz_sub)}`);
5497
- if (!users.length) console.log(import_chalk34.default.dim(" no users yet"));
6473
+ console.log(import_chalk38.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
6474
+ for (const u of users) console.log(` ${label2(u)} ${import_chalk38.default.dim(u.abz_sub)}`);
6475
+ if (!users.length) console.log(import_chalk38.default.dim(" no users yet"));
5498
6476
  const fresh = (observed?.identities ?? []).filter((o) => !o.provisioned);
5499
6477
  if (fresh.length) {
5500
- console.log(import_chalk34.default.dim("Seen in traffic (not yet users):"));
5501
- for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk34.default.dim(o.source_label ?? "")}`);
6478
+ console.log(import_chalk38.default.dim("Seen in traffic (not yet users):"));
6479
+ for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk38.default.dim(o.source_label ?? "")}`);
5502
6480
  }
5503
6481
  }
5504
6482
 
5505
6483
  // src/commands/key.ts
5506
- var import_chalk35 = __toESM(require("chalk"));
6484
+ var import_chalk39 = __toESM(require("chalk"));
5507
6485
  var import_ora18 = __toESM(require("ora"));
5508
6486
  init_caller();
5509
6487
  async function runApikeysMenu(opts) {
@@ -5533,11 +6511,11 @@ async function runKeyList(opts) {
5533
6511
  return;
5534
6512
  }
5535
6513
  if (!keys.length) {
5536
- console.log(import_chalk35.default.yellow("No developer keys."));
6514
+ console.log(import_chalk39.default.yellow("No developer keys."));
5537
6515
  return;
5538
6516
  }
5539
6517
  for (const k of keys) {
5540
- console.log(` ${import_chalk35.default.bold(k.key_id ?? k.id)} ${import_chalk35.default.dim(k.description ?? "")} ${import_chalk35.default.dim(k.expires_at ?? "no expiry")}`);
6518
+ console.log(` ${import_chalk39.default.bold(k.key_id ?? k.id)} ${import_chalk39.default.dim(k.description ?? "")} ${import_chalk39.default.dim(k.expires_at ?? "no expiry")}`);
5541
6519
  }
5542
6520
  }
5543
6521
  async function runKeyMint(opts) {
@@ -5559,9 +6537,9 @@ async function runKeyMint(opts) {
5559
6537
  console.log(JSON.stringify(out));
5560
6538
  return;
5561
6539
  }
5562
- console.log(` ${import_chalk35.default.bold("key_id")}: ${out?.key_id}`);
5563
- console.log(` ${import_chalk35.default.bold("key")}: ${import_chalk35.default.green(out?.key)} ${import_chalk35.default.dim("(shown once \u2014 store it now)")}`);
5564
- if (out?.expires_at) console.log(` ${import_chalk35.default.dim("expires:")} ${out.expires_at}`);
6540
+ console.log(` ${import_chalk39.default.bold("key_id")}: ${out?.key_id}`);
6541
+ console.log(` ${import_chalk39.default.bold("key")}: ${import_chalk39.default.green(out?.key)} ${import_chalk39.default.dim("(shown once \u2014 store it now)")}`);
6542
+ if (out?.expires_at) console.log(` ${import_chalk39.default.dim("expires:")} ${out.expires_at}`);
5565
6543
  } catch (err) {
5566
6544
  spinner.fail("Mint failed.");
5567
6545
  throw err;
@@ -5588,7 +6566,7 @@ async function runKeyRevoke(keyId, opts) {
5588
6566
  init_iam();
5589
6567
 
5590
6568
  // src/commands/admins.ts
5591
- var import_chalk36 = __toESM(require("chalk"));
6569
+ var import_chalk40 = __toESM(require("chalk"));
5592
6570
  var import_ora19 = __toESM(require("ora"));
5593
6571
  init_caller();
5594
6572
  function requireTenant(opts) {
@@ -5616,13 +6594,13 @@ async function runAdminsList(opts) {
5616
6594
  return;
5617
6595
  }
5618
6596
  if (!admins2.length) {
5619
- console.log(import_chalk36.default.yellow(`No tenant admins for ${tenant2} yet.`));
6597
+ console.log(import_chalk40.default.yellow(`No tenant admins for ${tenant2} yet.`));
5620
6598
  return;
5621
6599
  }
5622
6600
  for (const a of admins2) {
5623
6601
  const email = typeof a === "string" ? a : a.email;
5624
6602
  const flags = [a.active === false ? "pending" : null, a.pinned ? "pinned" : null].filter(Boolean).join(", ");
5625
- console.log(` ${import_chalk36.default.bold(email)}${flags ? import_chalk36.default.dim(` (${flags})`) : ""}`);
6603
+ console.log(` ${import_chalk40.default.bold(email)}${flags ? import_chalk40.default.dim(` (${flags})`) : ""}`);
5626
6604
  }
5627
6605
  }
5628
6606
  async function runAdminsAdd(email, opts) {
@@ -5637,9 +6615,9 @@ async function runAdminsAdd(email, opts) {
5637
6615
  body: { email },
5638
6616
  summary: `Add ${email} to tenant ${tenant2} admins`
5639
6617
  });
5640
- spinner?.succeed(`${import_chalk36.default.bold(email)} is now a tenant admin of ${import_chalk36.default.bold(tenant2)}.`);
6618
+ spinner?.succeed(`${import_chalk40.default.bold(email)} is now a tenant admin of ${import_chalk40.default.bold(tenant2)}.`);
5641
6619
  if (opts.json) console.log(JSON.stringify(out ?? { ok: true }));
5642
- else console.log(import_chalk36.default.dim(" Reload the Users & Groups widget \u2014 access flips from \u201Cpending\u201D to ready."));
6620
+ else console.log(import_chalk40.default.dim(" Reload the Users & Groups widget \u2014 access flips from \u201Cpending\u201D to ready."));
5643
6621
  } catch (err) {
5644
6622
  spinner?.fail("Add failed.");
5645
6623
  throw err;
@@ -5656,7 +6634,7 @@ async function runAdminsRemove(email, opts) {
5656
6634
  path: `${base(teamId, tenant2)}/${encodeURIComponent(email)}`,
5657
6635
  summary: `Remove ${email} from tenant ${tenant2} admins`
5658
6636
  });
5659
- spinner?.succeed(`Removed ${import_chalk36.default.bold(email)} from the tenant admins of ${import_chalk36.default.bold(tenant2)}.`);
6637
+ spinner?.succeed(`Removed ${import_chalk40.default.bold(email)} from the tenant admins of ${import_chalk40.default.bold(tenant2)}.`);
5660
6638
  } catch (err) {
5661
6639
  spinner?.fail("Remove failed.");
5662
6640
  throw err;
@@ -5664,7 +6642,7 @@ async function runAdminsRemove(email, opts) {
5664
6642
  }
5665
6643
 
5666
6644
  // src/commands/preapprove.ts
5667
- var import_chalk37 = __toESM(require("chalk"));
6645
+ var import_chalk41 = __toESM(require("chalk"));
5668
6646
  var import_ora20 = __toESM(require("ora"));
5669
6647
 
5670
6648
  // src/lib/preapproval.ts
@@ -5729,14 +6707,14 @@ async function runPreapprove(who, opts) {
5729
6707
  const rules = await listPreapprovalRules(tenant2);
5730
6708
  if (opts.json) return void console.log(JSON.stringify(rules, null, 2));
5731
6709
  if (!rules.length) {
5732
- console.log(import_chalk37.default.dim(`No pre-approval rules in ${tenant2}. Anyone who signs in can access (unless access is restricted).`));
5733
- console.log(import_chalk37.default.dim(`Add one: apiblaze preapprove someone@acme.com`));
6710
+ console.log(import_chalk41.default.dim(`No pre-approval rules in ${tenant2}. Anyone who signs in can access (unless access is restricted).`));
6711
+ console.log(import_chalk41.default.dim(`Add one: apiblaze preapprove someone@acme.com`));
5734
6712
  return;
5735
6713
  }
5736
- console.log(import_chalk37.default.dim(`Pre-approved for ${import_chalk37.default.bold(tenant2)}:`));
6714
+ console.log(import_chalk41.default.dim(`Pre-approved for ${import_chalk41.default.bold(tenant2)}:`));
5737
6715
  for (const r of rules) {
5738
- const tag = r.kind === "domain" ? import_chalk37.default.cyan("@" + r.value + " (whole domain)") : r.value;
5739
- const grp = r.groups?.length ? import_chalk37.default.dim(` \u2192 groups: ${r.groups.join(", ")}`) : "";
6716
+ const tag = r.kind === "domain" ? import_chalk41.default.cyan("@" + r.value + " (whole domain)") : r.value;
6717
+ const grp = r.groups?.length ? import_chalk41.default.dim(` \u2192 groups: ${r.groups.join(", ")}`) : "";
5740
6718
  console.log(` ${tag}${grp}`);
5741
6719
  }
5742
6720
  return;
@@ -5747,17 +6725,17 @@ async function runPreapprove(who, opts) {
5747
6725
  if (opts.remove) {
5748
6726
  const spinner2 = (0, import_ora20.default)(`Removing ${who} from ${tenant2}\u2026`).start();
5749
6727
  const { removed, value } = await removePreapprovalRule(tenant2, who);
5750
- if (removed) spinner2.succeed(`${import_chalk37.default.bold(value)} is no longer pre-approved for ${tenant2}.`);
5751
- else spinner2.warn(`No pre-approval rule for ${import_chalk37.default.bold(value)} in ${tenant2} \u2014 nothing to remove.`);
6728
+ if (removed) spinner2.succeed(`${import_chalk41.default.bold(value)} is no longer pre-approved for ${tenant2}.`);
6729
+ else spinner2.warn(`No pre-approval rule for ${import_chalk41.default.bold(value)} in ${tenant2} \u2014 nothing to remove.`);
5752
6730
  return;
5753
6731
  }
5754
6732
  const spinner = (0, import_ora20.default)(`Pre-approving ${who} for ${tenant2}\u2026`).start();
5755
6733
  try {
5756
6734
  const { kind, value } = await addPreapprovalRule(tenant2, who, opts.group);
5757
6735
  const what = kind === "domain" ? `Anyone @${value}` : value;
5758
- spinner.succeed(`${import_chalk37.default.bold(what)} can now sign in to ${import_chalk37.default.bold(tenant2)}.`);
5759
- if (opts.group?.length) console.log(import_chalk37.default.dim(` They'll join group(s) ${opts.group.join(", ")} on first sign-in.`));
5760
- console.log(import_chalk37.default.dim(` See the full list: apiblaze preapprove --list`));
6736
+ spinner.succeed(`${import_chalk41.default.bold(what)} can now sign in to ${import_chalk41.default.bold(tenant2)}.`);
6737
+ if (opts.group?.length) console.log(import_chalk41.default.dim(` They'll join group(s) ${opts.group.join(", ")} on first sign-in.`));
6738
+ console.log(import_chalk41.default.dim(` See the full list: apiblaze preapprove --list`));
5761
6739
  } catch (err) {
5762
6740
  spinner.fail("Could not add the rule.");
5763
6741
  throw err;
@@ -5768,7 +6746,7 @@ async function runPreapprove(who, opts) {
5768
6746
  var fs9 = __toESM(require("fs"));
5769
6747
  var path6 = __toESM(require("path"));
5770
6748
  var crypto2 = __toESM(require("crypto"));
5771
- var import_chalk39 = __toESM(require("chalk"));
6749
+ var import_chalk43 = __toESM(require("chalk"));
5772
6750
  var import_ora21 = __toESM(require("ora"));
5773
6751
  var import_yaml2 = require("yaml");
5774
6752
  init_auth();
@@ -5779,7 +6757,7 @@ init_admin();
5779
6757
  // src/commands/llm.ts
5780
6758
  var fs8 = __toESM(require("fs"));
5781
6759
  var path5 = __toESM(require("path"));
5782
- var import_chalk38 = __toESM(require("chalk"));
6760
+ var import_chalk42 = __toESM(require("chalk"));
5783
6761
  var import_inquirer2 = __toESM(require("inquirer"));
5784
6762
  init_auth();
5785
6763
  var LLM_PATH = path5.join(getApiblazeDir(), "llm.json");
@@ -5823,27 +6801,27 @@ async function runLlmSetKey(keyArg, opts) {
5823
6801
  }
5824
6802
  const existing = loadLlmConfig();
5825
6803
  saveLlmConfig({ key, provider, model: opts.model ?? existing?.model });
5826
- console.log(`${import_chalk38.default.green("\u2713")} Saved ${import_chalk38.default.bold(provider)} key ${maskSecret(key)}`);
5827
- console.log(import_chalk38.default.gray(` Stored locally at ${LLM_PATH} (0600) \u2014 never sent to APIblaze except per chat turn.`));
5828
- if (opts.model) console.log(import_chalk38.default.gray(` Model: ${opts.model}`));
6804
+ console.log(`${import_chalk42.default.green("\u2713")} Saved ${import_chalk42.default.bold(provider)} key ${maskSecret(key)}`);
6805
+ console.log(import_chalk42.default.gray(` Stored locally at ${LLM_PATH} (0600) \u2014 never sent to APIblaze except per chat turn.`));
6806
+ if (opts.model) console.log(import_chalk42.default.gray(` Model: ${opts.model}`));
5829
6807
  }
5830
6808
  async function runLlmShow() {
5831
6809
  const cfg = loadLlmConfig();
5832
6810
  if (!cfg) {
5833
- console.log(import_chalk38.default.gray("No LLM key set. `apiblaze llm set-key sk-...` to add one (optional \u2014 chat works without it)."));
6811
+ console.log(import_chalk42.default.gray("No LLM key set. `apiblaze llm set-key sk-...` to add one (optional \u2014 chat works without it)."));
5834
6812
  return;
5835
6813
  }
5836
- console.log(`Provider: ${import_chalk38.default.bold(cfg.provider)}`);
6814
+ console.log(`Provider: ${import_chalk42.default.bold(cfg.provider)}`);
5837
6815
  console.log(`Key: ${maskSecret(cfg.key)}`);
5838
6816
  if (cfg.model) console.log(`Model: ${cfg.model}`);
5839
- console.log(import_chalk38.default.gray(`Stored at ${LLM_PATH}`));
6817
+ console.log(import_chalk42.default.gray(`Stored at ${LLM_PATH}`));
5840
6818
  }
5841
6819
  async function runLlmClearKey() {
5842
6820
  try {
5843
6821
  fs8.unlinkSync(LLM_PATH);
5844
- console.log(`${import_chalk38.default.green("\u2713")} Removed local LLM key.`);
6822
+ console.log(`${import_chalk42.default.green("\u2713")} Removed local LLM key.`);
5845
6823
  } catch {
5846
- console.log(import_chalk38.default.gray("No LLM key was set."));
6824
+ console.log(import_chalk42.default.gray("No LLM key was set."));
5847
6825
  }
5848
6826
  }
5849
6827
 
@@ -5851,9 +6829,9 @@ async function runLlmClearKey() {
5851
6829
  init_trace();
5852
6830
  init_types();
5853
6831
  function fail4(message, hint) {
5854
- console.error(import_chalk39.default.red(`
6832
+ console.error(import_chalk43.default.red(`
5855
6833
  Error: ${message}`));
5856
- if (hint) console.error(import_chalk39.default.dim(hint));
6834
+ if (hint) console.error(import_chalk43.default.dim(hint));
5857
6835
  process.exit(1);
5858
6836
  }
5859
6837
  function normalizeName2(raw) {
@@ -6001,7 +6979,7 @@ async function resolveTargetAuth(spec2, opts) {
6001
6979
  "Re-run with --force to provision anyway (configure target auth later with `apiblaze config`),\nor use an api_key / bearer / basic scheme."
6002
6980
  );
6003
6981
  }
6004
- if (sawOAuth) console.log(import_chalk39.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
6982
+ if (sawOAuth) console.log(import_chalk43.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
6005
6983
  return null;
6006
6984
  }
6007
6985
  if (candidates.length === 1 && !noneAllowed) return candidates[0];
@@ -6074,7 +7052,7 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
6074
7052
  const fresh = await validConsumerToken(existing);
6075
7053
  if (fresh) {
6076
7054
  if (fresh.accessToken !== existing.accessToken) saveConsumer({ ...fresh, resource });
6077
- console.log(import_chalk39.default.dim(` Using your consumer session on ${import_chalk39.default.bold(tenant2)}${fresh.email ? ` (${fresh.email})` : ""}.`));
7055
+ console.log(import_chalk43.default.dim(` Using your consumer session on ${import_chalk43.default.bold(tenant2)}${fresh.email ? ` (${fresh.email})` : ""}.`));
6078
7056
  return fresh;
6079
7057
  }
6080
7058
  }
@@ -6093,13 +7071,13 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
6093
7071
  );
6094
7072
  }
6095
7073
  const clientId = pick2.client_id ?? pick2.clientId;
6096
- console.log(`${import_chalk39.default.cyan("\u2192")} This proxy signs consumers in with OAuth \u2014 logging you in to ${import_chalk39.default.bold(tenant2)}...`);
7074
+ console.log(`${import_chalk43.default.cyan("\u2192")} This proxy signs consumers in with OAuth \u2014 logging you in to ${import_chalk43.default.bold(tenant2)}...`);
6097
7075
  const result = await deviceLogin(clientId, "openid email profile offline_access", ({ verificationUri, userCode }) => {
6098
7076
  console.log(`
6099
- Open: ${import_chalk39.default.underline(verificationUri)}`);
6100
- console.log(` Code: ${import_chalk39.default.bold(userCode)}
7077
+ Open: ${import_chalk43.default.underline(verificationUri)}`);
7078
+ console.log(` Code: ${import_chalk43.default.bold(userCode)}
6101
7079
  `);
6102
- console.log(import_chalk39.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
7080
+ console.log(import_chalk43.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
6103
7081
  }, resource);
6104
7082
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
6105
7083
  const creds = {
@@ -6115,7 +7093,7 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
6115
7093
  resource
6116
7094
  };
6117
7095
  saveConsumer(creds);
6118
- console.log(` ${import_chalk39.default.green("\u2714")} Signed in as${creds.email ? ` ${import_chalk39.default.bold(creds.email)}` : " a consumer"} on ${tenant2}.`);
7096
+ console.log(` ${import_chalk43.default.green("\u2714")} Signed in as${creds.email ? ` ${import_chalk43.default.bold(creds.email)}` : " a consumer"} on ${tenant2}.`);
6119
7097
  return creds;
6120
7098
  }
6121
7099
  async function cpPost(anon, path8, body, summary) {
@@ -6144,13 +7122,18 @@ async function provision(spec2, target, opts) {
6144
7122
  let name = opts.name ? base2 : `${base2}${salt()}`;
6145
7123
  const access = anon ? "open" : opts.access === "open" ? "open" : "invite";
6146
7124
  if (anon && opts.access === "invite") {
6147
- console.log(import_chalk39.default.dim(" Note: --access invite needs an account to pre-approve people. Staying open for this anonymous proxy \u2014 run `apiblaze login`, then `apiblaze apichat --access invite`."));
7125
+ console.log(import_chalk43.default.dim(" Note: --access invite needs an account to pre-approve people. Staying open for this anonymous proxy \u2014 run `apiblaze login`, then `apiblaze apichat --access invite`."));
6148
7126
  }
6149
7127
  const DUAL_AUTH = {
6150
7128
  mode: "authenticate",
6151
7129
  methods: ["api_key", "jwt"],
6152
7130
  ...access === "invite" ? { preapproved_users_only: true } : {}
6153
7131
  };
7132
+ const chosenTenant = loggedIn ? await chooseTenantForCreate(loadCredentials()?.teamId, name, {
7133
+ tenant: opts.tenant,
7134
+ yes: opts.yes,
7135
+ json: opts.json
7136
+ }) : void 0;
6154
7137
  const spinner = (0, import_ora21.default)("Provisioning an api_key proxy...").start();
6155
7138
  let result;
6156
7139
  for (let attempt = 0; attempt < 4; attempt++) {
@@ -6163,6 +7146,7 @@ async function provision(spec2, target, opts) {
6163
7146
  auth_type: "api_key",
6164
7147
  requests_auth: DUAL_AUTH,
6165
7148
  team_id: creds.teamId,
7149
+ ...chosenTenant ? { tenant: chosenTenant } : {},
6166
7150
  ...opts.apiversion ? { api_version: opts.apiversion } : {}
6167
7151
  });
6168
7152
  } else {
@@ -6237,7 +7221,7 @@ async function provision(spec2, target, opts) {
6237
7221
  try {
6238
7222
  await addPreapprovalRule(tenant2, email);
6239
7223
  } catch {
6240
- console.log(import_chalk39.default.dim(` (Could not auto-approve your email for sign-in \u2014 add it later: apiblaze preapprove ${email})`));
7224
+ console.log(import_chalk43.default.dim(` (Could not auto-approve your email for sign-in \u2014 add it later: apiblaze preapprove ${email})`));
6241
7225
  }
6242
7226
  }
6243
7227
  }
@@ -6281,7 +7265,7 @@ async function uploadSpec(p, specText, opts) {
6281
7265
  throw err;
6282
7266
  }
6283
7267
  if (out && out.reused === true) {
6284
- console.log(import_chalk39.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
7268
+ console.log(import_chalk43.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
6285
7269
  } else if (out && out.changed === true && out.previous_spec_hash) {
6286
7270
  const interactive = !!process.stdin.isTTY && !opts.yes;
6287
7271
  if (interactive) {
@@ -6289,7 +7273,7 @@ async function uploadSpec(p, specText, opts) {
6289
7273
  const { go } = await inquirer3.prompt([
6290
7274
  { type: "confirm", name: "go", message: "The spec changed since the last provision \u2014 re-publish the MCP catalogue?", default: true }
6291
7275
  ]);
6292
- if (!go) console.log(import_chalk39.default.dim(" Keeping the existing MCP catalogue."));
7276
+ if (!go) console.log(import_chalk43.default.dim(" Keeping the existing MCP catalogue."));
6293
7277
  }
6294
7278
  }
6295
7279
  }
@@ -6330,15 +7314,15 @@ var revealAuth = false;
6330
7314
  function renderToolEvents(events, cred) {
6331
7315
  for (const e of events ?? []) {
6332
7316
  const ok = typeof e.status === "number" ? e.status < 400 : String(e.status).toLowerCase() === "ok";
6333
- const mark = ok ? import_chalk39.default.green("\u2713") : import_chalk39.default.red("\u2717");
6334
- console.log(` ${mark} ${import_chalk39.default.cyan(e.name)} ${import_chalk39.default.dim(`(${e.status}, ${e.ms}ms)`)}`);
7317
+ const mark = ok ? import_chalk43.default.green("\u2713") : import_chalk43.default.red("\u2717");
7318
+ console.log(` ${mark} ${import_chalk43.default.cyan(e.name)} ${import_chalk43.default.dim(`(${e.status}, ${e.ms}ms)`)}`);
6335
7319
  if (isVerbose() && e.method && e.url) {
6336
- console.log(import_chalk39.default.dim(` curl -sS -X ${e.method} '${e.url}'${cred ? " \\" : ""}`));
7320
+ console.log(import_chalk43.default.dim(` curl -sS -X ${e.method} '${e.url}'${cred ? " \\" : ""}`));
6337
7321
  if (cred) {
6338
7322
  const shown = revealAuth ? cred.value : maskKey(cred.value);
6339
7323
  const keyLine = ` -H '${cred.header}: ${shown}'`;
6340
- const hint = revealAuth ? "" : import_chalk39.default.yellow(" \u2190 /showauth will reveal this");
6341
- console.log(import_chalk39.default.dim(keyLine) + hint);
7324
+ const hint = revealAuth ? "" : import_chalk43.default.yellow(" \u2190 /showauth will reveal this");
7325
+ console.log(import_chalk43.default.dim(keyLine) + hint);
6342
7326
  }
6343
7327
  }
6344
7328
  }
@@ -6359,20 +7343,20 @@ function renderToolResults(delta, events) {
6359
7343
  }
6360
7344
  })();
6361
7345
  const lines = pretty.split("\n");
6362
- console.log(import_chalk39.default.dim(" response:"));
7346
+ console.log(import_chalk43.default.dim(" response:"));
6363
7347
  for (const line of lines.slice(0, cap)) {
6364
- console.log(import_chalk39.default.dim(` ${line}`));
7348
+ console.log(import_chalk43.default.dim(` ${line}`));
6365
7349
  }
6366
- if (lines.length > cap) console.log(import_chalk39.default.dim(` \u2026${lines.length - cap} more lines`));
7350
+ if (lines.length > cap) console.log(import_chalk43.default.dim(` \u2026${lines.length - cap} more lines`));
6367
7351
  }
6368
7352
  }
6369
7353
  function billingLine(billing) {
6370
7354
  if (!billing || typeof billing.cents !== "number") return null;
6371
7355
  if (typeof billing.free_turns_remaining === "number") return null;
6372
7356
  const usd = (billing.cents / 100).toFixed(Math.abs(billing.cents - Math.round(billing.cents)) < 1e-9 ? 2 : 4);
6373
- let line = import_chalk39.default.magenta(` \u{1F4B3} $${usd}`) + import_chalk39.default.dim(billing.model ? ` \xB7 ${billing.model}` : "");
7357
+ let line = import_chalk43.default.magenta(` \u{1F4B3} $${usd}`) + import_chalk43.default.dim(billing.model ? ` \xB7 ${billing.model}` : "");
6374
7358
  if (typeof billing.credits_remaining === "number") {
6375
- line += import_chalk39.default.dim(` \xB7 balance $${(billing.credits_remaining / 100).toFixed(2)}`);
7359
+ line += import_chalk43.default.dim(` \xB7 balance $${(billing.credits_remaining / 100).toFixed(2)}`);
6376
7360
  }
6377
7361
  return line;
6378
7362
  }
@@ -6380,21 +7364,21 @@ function freeBudgetWarning(billing, anon) {
6380
7364
  if (!anon || !billing) return null;
6381
7365
  if (typeof billing.free_turns_remaining === "number") {
6382
7366
  const left2 = billing.free_turns_remaining;
6383
- if (left2 <= 0) return import_chalk39.default.yellow(" Free chats used up \u2014 `npx apiblaze login` (free) to keep going.");
6384
- return import_chalk39.default.dim(` ${left2} free chat${left2 === 1 ? "" : "s"} left \xB7 /login to get more`);
7367
+ if (left2 <= 0) return import_chalk43.default.yellow(" Free chats used up \u2014 `npx apiblaze login` (free) to keep going.");
7368
+ return import_chalk43.default.dim(` ${left2} free chat${left2 === 1 ? "" : "s"} left \xB7 /login to get more`);
6385
7369
  }
6386
7370
  if (typeof billing.free_remaining_cents !== "number") return null;
6387
7371
  const perTurn = Math.max(billing.cents || 0, 0.02);
6388
7372
  const left = Math.floor(billing.free_remaining_cents / perTurn);
6389
7373
  if (left > 8) return null;
6390
- if (left <= 0) return import_chalk39.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
6391
- return import_chalk39.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
7374
+ if (left <= 0) return import_chalk43.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
7375
+ return import_chalk43.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
6392
7376
  }
6393
7377
  function printAssistant(delta) {
6394
7378
  for (let i = delta.length - 1; i >= 0; i--) {
6395
7379
  const m = delta[i];
6396
7380
  if (m && m.role === "assistant" && typeof m.content === "string" && m.content.trim()) {
6397
- console.log("\n" + import_chalk39.default.green("assistant \u203A ") + m.content + "\n");
7381
+ console.log("\n" + import_chalk43.default.green("assistant \u203A ") + m.content + "\n");
6398
7382
  return;
6399
7383
  }
6400
7384
  }
@@ -6420,7 +7404,7 @@ async function replTurn(p, messages, userText) {
6420
7404
  });
6421
7405
  } catch (err) {
6422
7406
  spinner.fail("Network error.");
6423
- console.log(import_chalk39.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
7407
+ console.log(import_chalk43.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
6424
7408
  return;
6425
7409
  }
6426
7410
  let data = null;
@@ -6440,9 +7424,9 @@ async function replTurn(p, messages, userText) {
6440
7424
  if (res.status === 401) {
6441
7425
  const reason = data && (data.error || data.message) || null;
6442
7426
  const usingKey = !p.consumerAuth;
6443
- console.log(import_chalk39.default.red(` The proxy rejected the request (401)${reason ? `: ${reason}` : "."}`));
7427
+ console.log(import_chalk43.default.red(` The proxy rejected the request (401)${reason ? `: ${reason}` : "."}`));
6444
7428
  console.log(
6445
- import_chalk39.default.dim(
7429
+ import_chalk43.default.dim(
6446
7430
  usingKey ? " Sent an API key. If the key was revoked, re-run `apiblaze apichat` to re-provision." : " Sent your consumer OAuth token. Re-run `apiblaze apichat` to sign in again."
6447
7431
  )
6448
7432
  );
@@ -6450,7 +7434,7 @@ async function replTurn(p, messages, userText) {
6450
7434
  }
6451
7435
  if (!res.ok || !data) {
6452
7436
  const err = data && data.error || `HTTP ${res.status}`;
6453
- console.log(import_chalk39.default.red(` Chat error: ${err}`));
7437
+ console.log(import_chalk43.default.red(` Chat error: ${err}`));
6454
7438
  return;
6455
7439
  }
6456
7440
  if (Array.isArray(data.delta)) {
@@ -6471,25 +7455,25 @@ async function replTurn(p, messages, userText) {
6471
7455
  if (warn) console.log(warn);
6472
7456
  if (!data.continue) return;
6473
7457
  }
6474
- console.log(import_chalk39.default.dim(" (stopped after several tool rounds \u2014 ask again to continue)"));
7458
+ console.log(import_chalk43.default.dim(" (stopped after several tool rounds \u2014 ask again to continue)"));
6475
7459
  }
6476
7460
  function renderUpsell(p, upsell) {
6477
7461
  const loggedIn = !!loadCredentials();
6478
7462
  if (upsell.reason === "CAPPED" && !loggedIn) {
6479
- console.log("\n" + import_chalk39.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
6480
- console.log(import_chalk39.default.dim(" (or `/login` right here \u2014 your chat is preserved \u2014 or `apiblaze llm set-key` for your own model key.)"));
7463
+ console.log("\n" + import_chalk43.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
7464
+ console.log(import_chalk43.default.dim(" (or `/login` right here \u2014 your chat is preserved \u2014 or `apiblaze llm set-key` for your own model key.)"));
6481
7465
  console.log();
6482
7466
  return;
6483
7467
  }
6484
- console.log("\n" + import_chalk39.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
6485
- if (upsell.reason === "INSUFFICIENT" || upsell.reason === "BREAKER" || upsell.reason === "CAPPED" || upsell.reason === "PAUSED") {
7468
+ console.log("\n" + import_chalk43.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
7469
+ if (upsell.reason === "INSUFFICIENT" || upsell.reason === "BREAKER" || upsell.reason === "CAPPED" || upsell.reason === "QUOTA" || upsell.reason === "PROXY_CAP" || upsell.reason === "PAUSED" || upsell.reason === "BYO_REQUIRED") {
6486
7470
  if (!loggedIn) {
6487
- console.log(import_chalk39.default.dim(" Options: `/login` for more free chats and requests, or `apiblaze llm set-key` to bring your own model key."));
7471
+ console.log(import_chalk43.default.dim(" Options: `/login` for more free chats and requests, or `apiblaze llm set-key` to bring your own model key."));
6488
7472
  } else {
6489
- console.log(import_chalk39.default.dim(" Options: top up your wallet, or `apiblaze llm set-key` to bring your own model key (bypasses platform limits)."));
7473
+ console.log(import_chalk43.default.dim(" Options: top up your wallet, or `apiblaze llm set-key` to bring your own model key (bypasses platform limits)."));
6490
7474
  }
6491
7475
  } else if (upsell.reason === "INFLIGHT") {
6492
- console.log(import_chalk39.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
7476
+ console.log(import_chalk43.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
6493
7477
  }
6494
7478
  console.log();
6495
7479
  }
@@ -6582,9 +7566,9 @@ async function openServerProxy(project) {
6582
7566
  let consumerAuth = false;
6583
7567
  if (acceptsApiKey) {
6584
7568
  if (!dpKey) {
6585
- console.log(import_chalk39.default.dim(` Minting an API key for tenant ${import_chalk39.default.bold(tenant2)} to query project ${import_chalk39.default.bold(project.projectName)}\u2026`));
7569
+ console.log(import_chalk43.default.dim(` Minting an API key for tenant ${import_chalk43.default.bold(tenant2)} to query project ${import_chalk43.default.bold(project.projectName)}\u2026`));
6586
7570
  dpKey = await mintDurableProxyKey(project.teamId, tenant2);
6587
- console.log(` ${import_chalk39.default.green("\u2714")} API key: ${import_chalk39.default.dim(maskKey(dpKey))}`);
7571
+ console.log(` ${import_chalk43.default.green("\u2714")} API key: ${import_chalk43.default.dim(maskKey(dpKey))}`);
6588
7572
  }
6589
7573
  } else {
6590
7574
  consumerAuth = true;
@@ -6613,9 +7597,9 @@ async function openServerProxy(project) {
6613
7597
  const spec2 = raw && (raw.spec ?? raw);
6614
7598
  spinner.stop();
6615
7599
  if (!spec2 || !(spec2.paths || spec2.openapi)) {
6616
- console.log(import_chalk39.default.yellow(" This proxy has no OpenAPI spec yet \u2014 chat will have no tools. Build one with `apiblaze agent openapi`."));
7600
+ console.log(import_chalk43.default.yellow(" This proxy has no OpenAPI spec yet \u2014 chat will have no tools. Build one with `apiblaze agent openapi`."));
6617
7601
  } else {
6618
- console.log(import_chalk39.default.dim(" Using the proxy's existing MCP catalogue (`apiblaze mcp` to rebuild it)."));
7602
+ console.log(import_chalk43.default.dim(" Using the proxy's existing MCP catalogue (`apiblaze mcp` to rebuild it)."));
6619
7603
  }
6620
7604
  } catch (err) {
6621
7605
  spinner.fail("Could not open the proxy.");
@@ -6671,7 +7655,7 @@ async function noArgsMenu(opts) {
6671
7655
  const me = loadCredentials()?.apiblazeUserId;
6672
7656
  const saved = loadApichats().filter((a) => a.anon ? true : a.ownerUserId !== void 0 && a.ownerUserId === me);
6673
7657
  const choices = saved.map((a) => ({
6674
- name: `Chat with ${import_chalk39.default.bold(a.name)} ${import_chalk39.default.dim(`(${a.target})${a.messages && a.messages.length ? ` \xB7 ${a.messages.length} msgs` : ""}`)}`,
7658
+ name: `Chat with ${import_chalk43.default.bold(a.name)} ${import_chalk43.default.dim(`(${a.target})${a.messages && a.messages.length ? ` \xB7 ${a.messages.length} msgs` : ""}`)}`,
6675
7659
  value: { type: "existing", a }
6676
7660
  }));
6677
7661
  const creds = loadCredentials();
@@ -6681,14 +7665,14 @@ async function noArgsMenu(opts) {
6681
7665
  const proxies = (await getProjects(creds.teamId)).filter((pr) => !savedIds.has(pr.projectId));
6682
7666
  for (const pr of proxies) {
6683
7667
  choices.push({
6684
- name: `Chat with ${import_chalk39.default.bold(pr.projectName)} ${import_chalk39.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
7668
+ name: `Chat with ${import_chalk43.default.bold(pr.projectName)} ${import_chalk43.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
6685
7669
  value: { type: "server", project: pr }
6686
7670
  });
6687
7671
  }
6688
7672
  } catch {
6689
7673
  }
6690
7674
  }
6691
- choices.push({ name: import_chalk39.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
7675
+ choices.push({ name: import_chalk43.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
6692
7676
  const { pick: pick2 } = await inquirer3.prompt([
6693
7677
  { type: "list", name: "pick", message: "What would you like to do?", choices }
6694
7678
  ]);
@@ -6791,36 +7775,36 @@ async function noArgsMenu(opts) {
6791
7775
  async function runRepl(p, initialMessages) {
6792
7776
  const { default: inquirer3 } = await import("inquirer");
6793
7777
  const messages = initialMessages && initialMessages.length ? initialMessages.slice() : [];
6794
- console.log("\n" + import_chalk39.default.cyan.bold("Chat with your API") + import_chalk39.default.dim(` \xB7 ${p.mcpHost}`));
6795
- if (messages.length) console.log(import_chalk39.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
7778
+ console.log("\n" + import_chalk43.default.cyan.bold("Chat with your API") + import_chalk43.default.dim(` \xB7 ${p.mcpHost}`));
7779
+ if (messages.length) console.log(import_chalk43.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
6796
7780
  const llm2 = loadLlmConfig();
6797
7781
  console.log(
6798
- import_chalk39.default.dim(
7782
+ import_chalk43.default.dim(
6799
7783
  llm2 ? `Using your local ${llm2.provider} key for the model. Type a question, or /exit. /login /claim manage your workspace.` : "Ask a question in plain English. /exit to quit \xB7 /login for more free chats \xB7 /claim to keep this workspace \xB7 `apiblaze llm set-key` for BYO models."
6800
7784
  )
6801
7785
  );
6802
7786
  for (; ; ) {
6803
- const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk39.default.green("you \u203A") }]);
7787
+ const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk43.default.green("you \u203A") }]);
6804
7788
  const text = (input ?? "").trim();
6805
7789
  if (!text) continue;
6806
7790
  if (["/exit", "/quit", "exit", "quit", ":q"].includes(text.toLowerCase())) break;
6807
7791
  if (text === "/login") {
6808
7792
  try {
6809
7793
  await runLogin();
6810
- console.log(import_chalk39.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
7794
+ console.log(import_chalk43.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
6811
7795
  } catch (err) {
6812
- console.log(import_chalk39.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
7796
+ console.log(import_chalk43.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
6813
7797
  }
6814
7798
  continue;
6815
7799
  }
6816
7800
  if (text === "/claim") {
6817
7801
  const justLoggedIn = !loadCredentials();
6818
7802
  if (justLoggedIn) {
6819
- console.log(import_chalk39.default.dim(" Logging in to claim your workspace\u2026"));
7803
+ console.log(import_chalk43.default.dim(" Logging in to claim your workspace\u2026"));
6820
7804
  try {
6821
7805
  await runLogin();
6822
7806
  } catch (err) {
6823
- console.log(import_chalk39.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
7807
+ console.log(import_chalk43.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
6824
7808
  continue;
6825
7809
  }
6826
7810
  if (!loadCredentials()) continue;
@@ -6831,30 +7815,30 @@ async function runRepl(p, initialMessages) {
6831
7815
  p.mcpHost = p.mcpHost.replace(".mcp.tryabz.run", ".mcp.abz.run");
6832
7816
  p.anon = false;
6833
7817
  claimApichat(p, loadCredentials()?.apiblazeUserId);
6834
- console.log(import_chalk39.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
7818
+ console.log(import_chalk43.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
6835
7819
  }
6836
7820
  } catch (err) {
6837
- console.log(import_chalk39.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
7821
+ console.log(import_chalk43.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
6838
7822
  }
6839
7823
  continue;
6840
7824
  }
6841
7825
  if (text === "/showauth") {
6842
7826
  revealAuth = !revealAuth;
6843
- console.log(import_chalk39.default.dim(revealAuth ? " The real API key will be shown in the next call's curl. /showauth again to re-mask." : " API key re-masked."));
7827
+ console.log(import_chalk43.default.dim(revealAuth ? " The real API key will be shown in the next call's curl. /showauth again to re-mask." : " API key re-masked."));
6844
7828
  continue;
6845
7829
  }
6846
7830
  if (text.startsWith("/")) {
6847
- console.log(import_chalk39.default.dim(" Commands: /login /claim /showauth /exit"));
7831
+ console.log(import_chalk43.default.dim(" Commands: /login /claim /showauth /exit"));
6848
7832
  continue;
6849
7833
  }
6850
7834
  await replTurn(p, messages, text);
6851
7835
  saveTranscript(p, messages);
6852
7836
  }
6853
- console.log(import_chalk39.default.dim("\nBye."));
7837
+ console.log(import_chalk43.default.dim("\nBye."));
6854
7838
  }
6855
7839
  async function runApichat(opts) {
6856
7840
  setVerbose(opts.verbose !== false);
6857
- console.log(import_chalk39.default.bold("\napichat \u2014 turn any API into a chat\n"));
7841
+ console.log(import_chalk43.default.bold("\napichat \u2014 turn any API into a chat\n"));
6858
7842
  if (!opts.openapispec && !opts.target) {
6859
7843
  if (!process.stdin.isTTY) {
6860
7844
  fail4("No spec source. Pass --openapispec <file|url> or --target <url>.", GENERATOR_HINT);
@@ -6867,7 +7851,7 @@ async function runApichat(opts) {
6867
7851
  }
6868
7852
  const { spec: spec2, sourceUrl } = await loadSpec(opts);
6869
7853
  const target = resolveTarget(spec2, opts, sourceUrl);
6870
- console.log(` ${import_chalk39.default.dim("Target:")} ${import_chalk39.default.bold(target)}`);
7854
+ console.log(` ${import_chalk43.default.dim("Target:")} ${import_chalk43.default.bold(target)}`);
6871
7855
  const auth = await resolveTargetAuth(spec2, opts);
6872
7856
  if (auth && !process.stdin.isTTY && !opts.targetAuthEnv) {
6873
7857
  fail4(
@@ -6876,7 +7860,7 @@ async function runApichat(opts) {
6876
7860
  );
6877
7861
  }
6878
7862
  const p = await provision(spec2, target, opts);
6879
- console.log(` ${import_chalk39.default.dim("Proxy: ")} ${import_chalk39.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
7863
+ console.log(` ${import_chalk43.default.dim("Proxy: ")} ${import_chalk43.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
6880
7864
  upsertApichat({
6881
7865
  name: p.projectId,
6882
7866
  target,
@@ -6896,30 +7880,30 @@ async function runApichat(opts) {
6896
7880
  const secret = await captureTargetSecret(auth, opts);
6897
7881
  if (secret) await writeTargetAuth(p, auth, secret);
6898
7882
  } else {
6899
- console.log(import_chalk39.default.dim(" Target auth: none required."));
7883
+ console.log(import_chalk43.default.dim(" Target auth: none required."));
6900
7884
  }
6901
7885
  const specText = JSON.stringify(spec2);
6902
7886
  await uploadSpec(p, specText, opts);
6903
7887
  const mcpUrl = await publishMcp(p, spec2);
6904
7888
  console.log();
6905
- if (p.proxyUrl) console.log(` ${import_chalk39.default.green("\u2713")} proxy ${import_chalk39.default.bold(p.proxyUrl)}`);
7889
+ if (p.proxyUrl) console.log(` ${import_chalk43.default.green("\u2713")} proxy ${import_chalk43.default.bold(p.proxyUrl)}`);
6906
7890
  if (mcpUrl) {
6907
- console.log(` ${import_chalk39.default.green("\u2713")} mcp ${import_chalk39.default.bold(mcpUrl)}`);
7891
+ console.log(` ${import_chalk43.default.green("\u2713")} mcp ${import_chalk43.default.bold(mcpUrl)}`);
6908
7892
  if (p.access === "invite") {
6909
- console.log(import_chalk39.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: invite \u2014 only you + emails you pre-approve"));
6910
- console.log(import_chalk39.default.dim(` Let others in: apiblaze preapprove someone@company.com${p.tenant ? ` --tenant ${p.tenant}` : ""} (or re-run with --access open)`));
7893
+ console.log(import_chalk43.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: invite \u2014 only you + emails you pre-approve"));
7894
+ console.log(import_chalk43.default.dim(` Let others in: apiblaze preapprove someone@company.com${p.tenant ? ` --tenant ${p.tenant}` : ""} (or re-run with --access open)`));
6911
7895
  } else {
6912
- console.log(import_chalk39.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: open \u2014 anyone who signs in can call this API"));
7896
+ console.log(import_chalk43.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: open \u2014 anyone who signs in can call this API"));
6913
7897
  }
6914
7898
  }
6915
7899
  if (p.anon) {
6916
- console.log(import_chalk39.default.dim("\n Anonymous workspace \u2014 /claim inside the chat to log in and keep it beyond 30 days."));
7900
+ console.log(import_chalk43.default.dim("\n Anonymous workspace \u2014 /claim inside the chat to log in and keep it beyond 30 days."));
6917
7901
  }
6918
7902
  await runRepl(p);
6919
7903
  }
6920
7904
 
6921
7905
  // src/commands/consumer.ts
6922
- var import_chalk40 = __toESM(require("chalk"));
7906
+ var import_chalk44 = __toESM(require("chalk"));
6923
7907
  var import_ora22 = __toESM(require("ora"));
6924
7908
  init_admin();
6925
7909
  init_resolve();
@@ -6938,10 +7922,10 @@ async function consumerFetch(creds, suffix, init) {
6938
7922
  }
6939
7923
  return { status: res.status, data, creds: fresh };
6940
7924
  }
6941
- function requireConsumer() {
7925
+ function requireConsumer2() {
6942
7926
  const c = loadConsumer();
6943
7927
  if (!c) {
6944
- console.error(import_chalk40.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
7928
+ console.error(import_chalk44.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
6945
7929
  process.exit(1);
6946
7930
  }
6947
7931
  return c;
@@ -6952,7 +7936,7 @@ async function runConsumerLogin(opts) {
6952
7936
  let clientId = opts.client;
6953
7937
  if (clientId) {
6954
7938
  if (!tenant2) {
6955
- console.error(import_chalk40.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
7939
+ console.error(import_chalk44.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
6956
7940
  process.exit(1);
6957
7941
  }
6958
7942
  } else {
@@ -6970,19 +7954,19 @@ async function runConsumerLogin(opts) {
6970
7954
  const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
6971
7955
  const pick2 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
6972
7956
  if (!pick2) {
6973
- console.error(import_chalk40.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
7957
+ console.error(import_chalk44.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
6974
7958
  process.exit(1);
6975
7959
  }
6976
7960
  clientId = pick2.client_id ?? pick2.clientId;
6977
7961
  }
6978
7962
  const portalResource = `https://${tenant2}.portal.apiblaze.com/1.0.0`;
6979
- console.log(`${import_chalk40.default.cyan("\u2192")} Logging in to ${import_chalk40.default.bold(tenant2)} as a consumer...`);
7963
+ console.log(`${import_chalk44.default.cyan("\u2192")} Logging in to ${import_chalk44.default.bold(tenant2)} as a consumer...`);
6980
7964
  const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
6981
7965
  console.log(`
6982
- Open: ${import_chalk40.default.underline(verificationUri)}`);
6983
- console.log(` Code: ${import_chalk40.default.bold(userCode)}
7966
+ Open: ${import_chalk44.default.underline(verificationUri)}`);
7967
+ console.log(` Code: ${import_chalk44.default.bold(userCode)}
6984
7968
  `);
6985
- console.log(import_chalk40.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
7969
+ console.log(import_chalk44.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
6986
7970
  }, portalResource);
6987
7971
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
6988
7972
  const creds = {
@@ -6997,10 +7981,10 @@ async function runConsumerLogin(opts) {
6997
7981
  obtainedAt: Date.now()
6998
7982
  };
6999
7983
  saveConsumer(creds);
7000
- console.log(import_chalk40.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
7984
+ console.log(import_chalk44.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
7001
7985
  }
7002
7986
  async function runConsumerTokens(opts) {
7003
- const creds = requireConsumer();
7987
+ const creds = requireConsumer2();
7004
7988
  const fresh = await validConsumerToken(creds) ?? creds;
7005
7989
  const exp = (t) => {
7006
7990
  const p = t ? decodeJwt2(t) : null;
@@ -7010,29 +7994,29 @@ async function runConsumerTokens(opts) {
7010
7994
  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));
7011
7995
  return;
7012
7996
  }
7013
- console.log(`${import_chalk40.default.cyan("Consumer")} ${import_chalk40.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk40.default.bold(fresh.tenant)}
7997
+ console.log(`${import_chalk44.default.cyan("Consumer")} ${import_chalk44.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk44.default.bold(fresh.tenant)}
7014
7998
  `);
7015
- console.log(`${import_chalk40.default.bold("access_token")} ${import_chalk40.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
7999
+ console.log(`${import_chalk44.default.bold("access_token")} ${import_chalk44.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
7016
8000
  ${fresh.accessToken}
7017
8001
  `);
7018
- if (fresh.idToken) console.log(`${import_chalk40.default.bold("id_token")} ${import_chalk40.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
8002
+ if (fresh.idToken) console.log(`${import_chalk44.default.bold("id_token")} ${import_chalk44.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
7019
8003
  ${fresh.idToken}
7020
8004
  `);
7021
- if (fresh.refreshToken) console.log(`${import_chalk40.default.bold("refresh_token")}
8005
+ if (fresh.refreshToken) console.log(`${import_chalk44.default.bold("refresh_token")}
7022
8006
  ${fresh.refreshToken}
7023
8007
  `);
7024
- console.log(import_chalk40.default.dim("These are your own tokens \u2014 keep them secret."));
8008
+ console.log(import_chalk44.default.dim("These are your own tokens \u2014 keep them secret."));
7025
8009
  }
7026
8010
  async function runConsumerApikeys(opts) {
7027
- const creds = requireConsumer();
8011
+ const creds = requireConsumer2();
7028
8012
  const { default: inquirer3 } = await import("inquirer");
7029
8013
  const spinner = (0, import_ora22.default)("Loading your API keys...").start();
7030
8014
  const list = await consumerFetch(creds, "/apikeys");
7031
8015
  const revealed = await consumerFetch(list.creds, "/apikeys/reveal").catch(() => ({ status: 0, data: null, creds: list.creds }));
7032
8016
  spinner.stop();
7033
8017
  if (list.status >= 400) {
7034
- console.error(import_chalk40.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
7035
- if (list.status === 401) console.error(import_chalk40.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
8018
+ console.error(import_chalk44.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
8019
+ if (list.status === 401) console.error(import_chalk44.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
7036
8020
  process.exit(1);
7037
8021
  }
7038
8022
  const keys = list.data?.keys ?? [];
@@ -7040,16 +8024,16 @@ async function runConsumerApikeys(opts) {
7040
8024
  if (opts.json) {
7041
8025
  console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
7042
8026
  } else if (!keys.length) {
7043
- console.log(import_chalk40.default.yellow("No API keys yet."));
8027
+ console.log(import_chalk44.default.yellow("No API keys yet."));
7044
8028
  } else {
7045
8029
  for (const k of keys) {
7046
8030
  const clear = revealMap[k.environment]?.key;
7047
- const shown = clear ? import_chalk40.default.green(clear) : import_chalk40.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
7048
- const exp = k.expires_at ? import_chalk40.default.dim(`exp ${k.expires_at}`) : import_chalk40.default.dim("no expiry");
7049
- console.log(` ${import_chalk40.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk40.default.dim(k.description ?? "")}`);
8031
+ const shown = clear ? import_chalk44.default.green(clear) : import_chalk44.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
8032
+ const exp = k.expires_at ? import_chalk44.default.dim(`exp ${k.expires_at}`) : import_chalk44.default.dim("no expiry");
8033
+ console.log(` ${import_chalk44.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk44.default.dim(k.description ?? "")}`);
7050
8034
  }
7051
8035
  if (Object.keys(revealMap).length === 0 && keys.some((k) => !k.expires_at)) {
7052
- console.log(import_chalk40.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
8036
+ console.log(import_chalk44.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
7053
8037
  }
7054
8038
  }
7055
8039
  if (opts.json) return;
@@ -7071,12 +8055,12 @@ async function runConsumerApikeys(opts) {
7071
8055
  }
7072
8056
  s2.succeed("Key created.");
7073
8057
  const key = created.data?.key ?? created.data?.fullKey;
7074
- if (key) console.log(` ${import_chalk40.default.green(key)} ${import_chalk40.default.dim("(shown once \u2014 store it now)")}`);
7075
- else console.log(import_chalk40.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
8058
+ if (key) console.log(` ${import_chalk44.default.green(key)} ${import_chalk44.default.dim("(shown once \u2014 store it now)")}`);
8059
+ else console.log(import_chalk44.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
7076
8060
  }
7077
8061
 
7078
8062
  // src/commands/sidecar.ts
7079
- var import_chalk41 = __toESM(require("chalk"));
8063
+ var import_chalk45 = __toESM(require("chalk"));
7080
8064
  var import_ora23 = __toESM(require("ora"));
7081
8065
  var fs10 = __toESM(require("fs"));
7082
8066
  var path7 = __toESM(require("path"));
@@ -7119,7 +8103,7 @@ function upsertEnvLocal(root, token) {
7119
8103
  }
7120
8104
  function installSidecarPackage(root) {
7121
8105
  if (fs10.existsSync(path7.join(root, "node_modules", "apiblaze", "package.json"))) {
7122
- console.log(` ${import_chalk41.default.green("\u2713")} apiblaze package already installed`);
8106
+ console.log(` ${import_chalk45.default.green("\u2713")} apiblaze package already installed`);
7123
8107
  return;
7124
8108
  }
7125
8109
  const has = (f) => fs10.existsSync(path7.join(root, f));
@@ -7130,7 +8114,7 @@ function installSidecarPackage(root) {
7130
8114
  execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
7131
8115
  spinner.succeed("Installed apiblaze (the sidecar runtime).");
7132
8116
  } catch {
7133
- spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk41.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk41.default.cyan("npm run dev")}.`);
8117
+ spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk45.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk45.default.cyan("npm run dev")}.`);
7134
8118
  }
7135
8119
  }
7136
8120
  function readEnvKey(root) {
@@ -7281,29 +8265,29 @@ async function runAnonymousInit(root, router, opts) {
7281
8265
  if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
7282
8266
  const envState = upsertEnvLocal(root, out.token);
7283
8267
  ensureGitignored(root);
7284
- console.log(` ${import_chalk41.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
7285
- console.log(` ${import_chalk41.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
8268
+ console.log(` ${import_chalk45.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
8269
+ console.log(` ${import_chalk45.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
7286
8270
  installSidecarPackage(root);
7287
8271
  let inspectorPath = null;
7288
8272
  if (!opts.noInspector) {
7289
8273
  inspectorPath = generateInspector(root, router);
7290
- if (inspectorPath) console.log(` ${import_chalk41.default.green("\u2713")} inspector at ${inspectorPath}`);
8274
+ if (inspectorPath) console.log(` ${import_chalk45.default.green("\u2713")} inspector at ${inspectorPath}`);
7291
8275
  }
7292
8276
  console.log("");
7293
- console.log(import_chalk41.default.bold("Done (no account needed). What happens next:"));
7294
- console.log(` 1. ${import_chalk41.default.cyan("npm run dev")} and use your app.`);
8277
+ console.log(import_chalk45.default.bold("Done (no account needed). What happens next:"));
8278
+ console.log(` 1. ${import_chalk45.default.cyan("npm run dev")} and use your app.`);
7295
8279
  console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
7296
- console.log(` ${import_chalk41.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
8280
+ console.log(` ${import_chalk45.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
7297
8281
  console.log("");
7298
- console.log(import_chalk41.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
7299
- console.log(` ${import_chalk41.default.cyan("apiblaze login")} then ${import_chalk41.default.cyan("apiblaze claim")} ${import_chalk41.default.dim("(no code needed here)")}`);
7300
- console.log(import_chalk41.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
8282
+ console.log(import_chalk45.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
8283
+ console.log(` ${import_chalk45.default.cyan("apiblaze login")} then ${import_chalk45.default.cyan("apiblaze claim")} ${import_chalk45.default.dim("(no code needed here)")}`);
8284
+ console.log(import_chalk45.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
7301
8285
  }
7302
8286
  async function runSidecar(opts) {
7303
8287
  const root = path7.resolve(opts.dir ?? process.cwd());
7304
8288
  const detected = detectNextProject(root);
7305
8289
  if (!detected.found) {
7306
- console.log(import_chalk41.default.yellow(`No Next.js project detected in ${root}.`));
8290
+ console.log(import_chalk45.default.yellow(`No Next.js project detected in ${root}.`));
7307
8291
  console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
7308
8292
  return;
7309
8293
  }
@@ -7314,10 +8298,10 @@ async function runSidecar(opts) {
7314
8298
  if (!loadCredentials()) {
7315
8299
  upsertEnvLocal(root, readEnvKey(root));
7316
8300
  ensureGitignored(root);
7317
- console.log(` ${import_chalk41.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
7318
- console.log(` ${import_chalk41.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
8301
+ console.log(` ${import_chalk45.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
8302
+ console.log(` ${import_chalk45.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
7319
8303
  installSidecarPackage(root);
7320
- console.log(import_chalk41.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
8304
+ console.log(import_chalk45.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
7321
8305
  return;
7322
8306
  }
7323
8307
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -7340,38 +8324,38 @@ async function runSidecar(opts) {
7340
8324
  throw err;
7341
8325
  }
7342
8326
  } else {
7343
- console.log(import_chalk41.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
8327
+ console.log(import_chalk45.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
7344
8328
  }
7345
8329
  const envState = upsertEnvLocal(root, token);
7346
8330
  ensureGitignored(root);
7347
- console.log(` ${import_chalk41.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
8331
+ console.log(` ${import_chalk45.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
7348
8332
  const wireState = wireInstrumentation(root);
7349
- console.log(` ${import_chalk41.default.green("\u2713")} instrumentation.ts ${wireState}`);
8333
+ console.log(` ${import_chalk45.default.green("\u2713")} instrumentation.ts ${wireState}`);
7350
8334
  installSidecarPackage(root);
7351
8335
  let inspectorPath = null;
7352
8336
  if (!opts.noInspector) {
7353
8337
  inspectorPath = generateInspector(root, detected.router);
7354
- if (inspectorPath) console.log(` ${import_chalk41.default.green("\u2713")} inspector at ${inspectorPath}`);
8338
+ if (inspectorPath) console.log(` ${import_chalk45.default.green("\u2713")} inspector at ${inspectorPath}`);
7355
8339
  }
7356
8340
  console.log("");
7357
- console.log(import_chalk41.default.bold("Done. What happens next:"));
7358
- console.log(` 1. ${import_chalk41.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
7359
- console.log(` 2. The origins your app calls appear as ${import_chalk41.default.bold("candidates")} \u2014 list them: ${import_chalk41.default.cyan("apiblaze sidecar")}`);
7360
- console.log(` 3. Approve the ones to route: ${import_chalk41.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
8341
+ console.log(import_chalk45.default.bold("Done. What happens next:"));
8342
+ console.log(` 1. ${import_chalk45.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
8343
+ console.log(` 2. The origins your app calls appear as ${import_chalk45.default.bold("candidates")} \u2014 list them: ${import_chalk45.default.cyan("apiblaze sidecar")}`);
8344
+ console.log(` 3. Approve the ones to route: ${import_chalk45.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
7361
8345
  console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
7362
- if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk41.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path7.dirname(inspectorPath)} before shipping)`);
7363
- if (switchingTeam) console.log(import_chalk41.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
8346
+ if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk45.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path7.dirname(inspectorPath)} before shipping)`);
8347
+ if (switchingTeam) console.log(import_chalk45.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
7364
8348
  console.log("");
7365
- console.log(import_chalk41.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
7366
- console.log(import_chalk41.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
7367
- console.log(import_chalk41.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
8349
+ console.log(import_chalk45.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
8350
+ console.log(import_chalk45.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
8351
+ console.log(import_chalk45.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
7368
8352
  console.log("");
7369
- console.log(import_chalk41.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
7370
- console.log(import_chalk41.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
8353
+ console.log(import_chalk45.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
8354
+ console.log(import_chalk45.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
7371
8355
  }
7372
8356
 
7373
8357
  // src/commands/origins.ts
7374
- var import_chalk42 = __toESM(require("chalk"));
8358
+ var import_chalk46 = __toESM(require("chalk"));
7375
8359
  var import_ora24 = __toESM(require("ora"));
7376
8360
  init_admin();
7377
8361
  init_resolve();
@@ -7382,7 +8366,7 @@ async function runOriginsList(opts) {
7382
8366
  if (!loadCredentials()) {
7383
8367
  const cred = loadAnonCred();
7384
8368
  if (!cred) {
7385
- console.log(import_chalk42.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
8369
+ console.log(import_chalk46.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
7386
8370
  return;
7387
8371
  }
7388
8372
  out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
@@ -7400,27 +8384,27 @@ async function runOriginsList(opts) {
7400
8384
  }
7401
8385
  const routed = out.routed ?? [];
7402
8386
  const candidates = out.candidates ?? [];
7403
- console.log(import_chalk42.default.bold(`
8387
+ console.log(import_chalk46.default.bold(`
7404
8388
  Routed through APIblaze (${routed.length})`));
7405
- if (!routed.length) console.log(import_chalk42.default.dim(" none yet"));
7406
- for (const r of routed) console.log(` ${import_chalk42.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk42.default.dim(`\u2192 ${r.project_id}`)}`);
7407
- console.log(import_chalk42.default.bold(`
8389
+ if (!routed.length) console.log(import_chalk46.default.dim(" none yet"));
8390
+ for (const r of routed) console.log(` ${import_chalk46.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk46.default.dim(`\u2192 ${r.project_id}`)}`);
8391
+ console.log(import_chalk46.default.bold(`
7408
8392
  Candidates \u2014 going direct, not yet approved (${candidates.length})`));
7409
- if (!candidates.length) console.log(import_chalk42.default.dim(" none \u2014 run your app to discover the origins it calls"));
8393
+ if (!candidates.length) console.log(import_chalk46.default.dim(" none \u2014 run your app to discover the origins it calls"));
7410
8394
  for (const c of candidates) {
7411
- console.log(` ${import_chalk42.default.yellow("\u25CB")} ${c.origin} ${import_chalk42.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
8395
+ console.log(` ${import_chalk46.default.yellow("\u25CB")} ${c.origin} ${import_chalk46.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
7412
8396
  }
7413
8397
  if (candidates.length) {
7414
- console.log(import_chalk42.default.dim(`
8398
+ console.log(import_chalk46.default.dim(`
7415
8399
  Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
7416
- console.log(import_chalk42.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
8400
+ console.log(import_chalk46.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
7417
8401
  }
7418
8402
  }
7419
8403
  async function runOriginsApprove(origin, opts) {
7420
8404
  if (!loadCredentials()) {
7421
8405
  const cred = loadAnonCred();
7422
8406
  if (!cred) {
7423
- console.error(import_chalk42.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
8407
+ console.error(import_chalk46.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
7424
8408
  process.exit(1);
7425
8409
  }
7426
8410
  const spinner2 = (0, import_ora24.default)(`Approving ${origin} (anonymous)...`).start();
@@ -7473,7 +8457,7 @@ async function runOriginsRemove(origin, opts) {
7473
8457
  }
7474
8458
 
7475
8459
  // src/commands/op.ts
7476
- var import_chalk43 = __toESM(require("chalk"));
8460
+ var import_chalk47 = __toESM(require("chalk"));
7477
8461
  init_auth();
7478
8462
  init_trace();
7479
8463
  init_types();
@@ -7506,82 +8490,82 @@ function printResidue(report, applied) {
7506
8490
  const up = report?.upstash ?? {};
7507
8491
  const fga = report?.fga ?? {};
7508
8492
  const ghosts = report?.ghosts ?? {};
7509
- console.log(import_chalk43.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
7510
- console.log(import_chalk43.default.bold("\n Upstash"));
8493
+ console.log(import_chalk47.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
8494
+ console.log(import_chalk47.default.bold("\n Upstash"));
7511
8495
  const orphans = up.orphans ?? [];
7512
- if (orphans.length === 0) console.log(import_chalk43.default.green(" no orphaned keys"));
7513
- for (const o of orphans) console.log(` ${import_chalk43.default.yellow(o.key)} ${import_chalk43.default.dim(`\u2014 ${o.reason}`)}`);
7514
- console.log(import_chalk43.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
8496
+ if (orphans.length === 0) console.log(import_chalk47.default.green(" no orphaned keys"));
8497
+ for (const o of orphans) console.log(` ${import_chalk47.default.yellow(o.key)} ${import_chalk47.default.dim(`\u2014 ${o.reason}`)}`);
8498
+ console.log(import_chalk47.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
7515
8499
  if (up.anon_wallet_detail) {
7516
8500
  const d = up.anon_wallet_detail;
7517
- console.log(import_chalk43.default.dim(` anon wallets: ${d.count} ($${(d.total_cents / 100).toFixed(2)}), ${d.no_ttl} with NO TTL${d.no_ttl ? " \u26A0" : " (all self-expire)"}`));
8501
+ console.log(import_chalk47.default.dim(` anon wallets: ${d.count} ($${(d.total_cents / 100).toFixed(2)}), ${d.no_ttl} with NO TTL${d.no_ttl ? " \u26A0" : " (all self-expire)"}`));
7518
8502
  }
7519
8503
  if (up.keyspace_census) {
7520
8504
  const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
7521
- console.log(import_chalk43.default.dim(` keyspace: ${census}`));
8505
+ console.log(import_chalk47.default.dim(` keyspace: ${census}`));
7522
8506
  }
7523
- if (up.unknown?.length) console.log(import_chalk43.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
7524
- if (applied) console.log(` ${import_chalk43.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
7525
- for (const e of up.errors ?? []) console.log(import_chalk43.default.red(` error: ${e}`));
7526
- console.log(import_chalk43.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
8507
+ if (up.unknown?.length) console.log(import_chalk47.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
8508
+ if (applied) console.log(` ${import_chalk47.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
8509
+ for (const e of up.errors ?? []) console.log(import_chalk47.default.red(` error: ${e}`));
8510
+ console.log(import_chalk47.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
7527
8511
  if (applied) {
7528
8512
  const swept = fga?.swept ?? [];
7529
- if (swept.length === 0) console.log(import_chalk43.default.green(" no orphaned stores"));
8513
+ if (swept.length === 0) console.log(import_chalk47.default.green(" no orphaned stores"));
7530
8514
  for (const s of swept) {
7531
8515
  console.log(
7532
- ` ${import_chalk43.default.yellow(s.store_id)} ${import_chalk43.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
8516
+ ` ${import_chalk47.default.yellow(s.store_id)} ${import_chalk47.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
7533
8517
  );
7534
8518
  }
7535
- if (fga?.remaining) console.log(import_chalk43.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
8519
+ if (fga?.remaining) console.log(import_chalk47.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
7536
8520
  const st = fga?.side_tables;
7537
- if (st) console.log(import_chalk43.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})` : ""}`));
8521
+ if (st) console.log(import_chalk47.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})` : ""}`));
7538
8522
  } else {
7539
8523
  const fgaOrphans = fga?.orphans ?? [];
7540
- if (fgaOrphans.length === 0) console.log(import_chalk43.default.green(" no orphaned stores"));
8524
+ if (fgaOrphans.length === 0) console.log(import_chalk47.default.green(" no orphaned stores"));
7541
8525
  for (const s of fgaOrphans) {
7542
8526
  const src = s.in_openfga ? "live in OpenFGA" : "Neon tuples only";
7543
- console.log(` ${import_chalk43.default.yellow(s.store_id)} ${import_chalk43.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
8527
+ console.log(` ${import_chalk47.default.yellow(s.store_id)} ${import_chalk47.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
7544
8528
  }
7545
- console.log(import_chalk43.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
8529
+ console.log(import_chalk47.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
7546
8530
  const st = fga?.side_tables;
7547
- if (st) console.log(import_chalk43.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`));
8531
+ if (st) console.log(import_chalk47.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`));
7548
8532
  }
7549
- for (const e of fga?.errors ?? []) console.log(import_chalk43.default.red(` error: ${e}`));
7550
- console.log(import_chalk43.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
8533
+ for (const e of fga?.errors ?? []) console.log(import_chalk47.default.red(` error: ${e}`));
8534
+ console.log(import_chalk47.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
7551
8535
  if (applied) {
7552
- if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk43.default.green(" no ghost tuples"));
7553
- else console.log(` ${import_chalk43.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk43.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
8536
+ if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk47.default.green(" no ghost tuples"));
8537
+ else console.log(` ${import_chalk47.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk47.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
7554
8538
  } else {
7555
8539
  const n = ghosts?.ghost_count ?? 0;
7556
- if (n === 0) console.log(import_chalk43.default.green(` no ghost tuples ${import_chalk43.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
8540
+ if (n === 0) console.log(import_chalk47.default.green(` no ghost tuples ${import_chalk47.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
7557
8541
  else {
7558
- console.log(import_chalk43.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
8542
+ console.log(import_chalk47.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
7559
8543
  for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
7560
- console.log(import_chalk43.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
8544
+ console.log(import_chalk47.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
7561
8545
  }
7562
- if (n > 20) console.log(import_chalk43.default.dim(` \u2026 and ${n - 20} more`));
8546
+ if (n > 20) console.log(import_chalk47.default.dim(` \u2026 and ${n - 20} more`));
7563
8547
  }
7564
8548
  }
7565
- for (const e of ghosts?.errors ?? []) console.log(import_chalk43.default.red(` error: ${e}`));
8549
+ for (const e of ghosts?.errors ?? []) console.log(import_chalk47.default.red(` error: ${e}`));
7566
8550
  console.log();
7567
8551
  }
7568
8552
  async function runOp(sub, opts = {}) {
7569
8553
  if (!loadCredentials()) {
7570
- console.log(import_chalk43.default.dim("Not logged in. Run `apiblaze login`."));
8554
+ console.log(import_chalk47.default.dim("Not logged in. Run `apiblaze login`."));
7571
8555
  return;
7572
8556
  }
7573
8557
  if (!isOperatorLogin()) {
7574
- console.log(import_chalk43.default.dim("`apiblaze op` is only available to platform operators."));
8558
+ console.log(import_chalk47.default.dim("`apiblaze op` is only available to platform operators."));
7575
8559
  return;
7576
8560
  }
7577
8561
  switch (sub) {
7578
8562
  case void 0:
7579
8563
  case "menu": {
7580
- console.log(import_chalk43.default.bold("\nOperator menu"));
7581
- console.log(` ${import_chalk43.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
7582
- console.log(` ${import_chalk43.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk43.default.dim("-y to skip")})`);
7583
- console.log(` ${import_chalk43.default.cyan("apiblaze op credits")} list credit wallets`);
7584
- console.log(import_chalk43.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
8564
+ console.log(import_chalk47.default.bold("\nOperator menu"));
8565
+ console.log(` ${import_chalk47.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
8566
+ console.log(` ${import_chalk47.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk47.default.dim("-y to skip")})`);
8567
+ console.log(` ${import_chalk47.default.cyan("apiblaze op credits")} list credit wallets`);
8568
+ console.log(import_chalk47.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
7585
8569
  `));
7586
8570
  return;
7587
8571
  }
@@ -7600,17 +8584,17 @@ async function runOp(sub, opts = {}) {
7600
8584
  const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
7601
8585
  printResidue(report, false);
7602
8586
  if (nUp + nFga + nGhost + nSide === 0) {
7603
- console.log(import_chalk43.default.green("Nothing to sweep."));
8587
+ console.log(import_chalk47.default.green("Nothing to sweep."));
7604
8588
  return;
7605
8589
  }
7606
8590
  if (!opts.yes) {
7607
- const readline2 = await import("readline/promises");
7608
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
8591
+ const readline3 = await import("readline/promises");
8592
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
7609
8593
  const answer = await rl.question(
7610
- import_chalk43.default.red(`Delete ${nUp} Upstash key(s) + ${nFga} OpenFGA store(s) + ${nGhost} ghost tuple(s) + ${nSide} Neon side-table row(s)? Type 'sweep' to confirm: `)
8594
+ import_chalk47.default.red(`Delete ${nUp} Upstash key(s) + ${nFga} OpenFGA store(s) + ${nGhost} ghost tuple(s) + ${nSide} Neon side-table row(s)? Type 'sweep' to confirm: `)
7611
8595
  );
7612
8596
  rl.close();
7613
- if (answer.trim() !== "sweep") return void console.log(import_chalk43.default.dim("Aborted."));
8597
+ if (answer.trim() !== "sweep") return void console.log(import_chalk47.default.dim("Aborted."));
7614
8598
  }
7615
8599
  const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
7616
8600
  if (opts.json) return void console.log(JSON.stringify(result, null, 2));
@@ -7621,15 +8605,15 @@ async function runOp(sub, opts = {}) {
7621
8605
  const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list credit wallets" });
7622
8606
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
7623
8607
  const accounts = data?.accounts ?? [];
7624
- if (accounts.length === 0) return void console.log(import_chalk43.default.dim("No credit wallets."));
8608
+ if (accounts.length === 0) return void console.log(import_chalk47.default.dim("No credit wallets."));
7625
8609
  for (const a of accounts) {
7626
8610
  const bal = typeof a.balance_cents === "number" ? `$${(a.balance_cents / 100).toFixed(2)}` : "?";
7627
- console.log(` ${import_chalk43.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk43.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk43.default.dim(" \u2014 anon") : ""}`);
8611
+ console.log(` ${import_chalk47.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk47.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk47.default.dim(" \u2014 anon") : ""}`);
7628
8612
  }
7629
8613
  return;
7630
8614
  }
7631
8615
  default:
7632
- console.log(import_chalk43.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
8616
+ console.log(import_chalk47.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
7633
8617
  }
7634
8618
  }
7635
8619
 
@@ -7675,7 +8659,7 @@ agent.command("authz").description("Chat to design and turn on access rules for
7675
8659
  program.command("rule").description("Author an object-level access rule in plain English, in one shot (billed per turn)").argument("<rule>", 'The rule in plain English, e.g. "users see only their own rows"').argument("<project>", "Project name or id").option("--enforce", "Turn enforcement on immediately (default: shadow-publish only)").option("--apiversion <version>", "API version (defaults to the project's)").action(action((rule, project, opts) => runRule(rule, project, opts)));
7676
8660
  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)));
7677
8661
  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)));
7678
- program.command("apichat").description("Turn any API into a chat: point at an OpenAPI spec and start asking questions (no login needed)").option("--openapi <file|url>", "OpenAPI/Swagger spec to build from (JSON or YAML; file path or URL)").option("--openapispec <file|url>", "Alias for --openapi").option("--target <url>", "Upstream base URL (overrides servers[0].url; enables spec discovery when --openapi is omitted)").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("--no-verbose", "Hide the per-turn proxy curl trace (shown by default for apichat)").action(action((opts) => runApichat({ ...opts, openapispec: opts.openapispec ?? opts.openapi })));
8662
+ program.command("apichat").description("Turn any API into a chat: point at an OpenAPI spec and start asking questions (no login needed)").option("--openapi <file|url>", "OpenAPI/Swagger spec to build from (JSON or YAML; file path or URL)").option("--openapispec <file|url>", "Alias for --openapi").option("--target <url>", "Upstream base URL (overrides servers[0].url; enables spec discovery when --openapi is omitted)").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("--no-verbose", "Hide the per-turn proxy curl trace (shown by default for apichat)").action(action((opts) => runApichat({ ...opts, openapispec: opts.openapispec ?? opts.openapi })));
7679
8663
  var llm = program.command("llm").description("Manage a local LLM provider key for chat (optional \u2014 lifts model quality, bills your key)");
7680
8664
  llm.command("set-key").description("Store an LLM provider key locally (OpenRouter/Anthropic/DeepSeek/OpenAI)").argument("[key]", "The API key (omit to enter it hidden at a prompt)").option("--model <id>", "Model id to use with this key (e.g. anthropic/claude-haiku-4.5)").action(action((key, opts) => runLlmSetKey(key, opts)));
7681
8665
  llm.command("show").description("Show the locally stored LLM key (masked)").action(action(() => runLlmShow()));
@@ -7684,15 +8668,15 @@ var runSetup = (opts) => runSidecar({ team: opts.team, dir: opts.dir, yes: opts.
7684
8668
  var withSetupOptions = (cmd) => cmd.option("--team <id|name>", "Team to set up under (defaults to your active team)").option("--dir <path>", "Project directory (defaults to cwd)").option("--no-inspector", "Skip generating the dev-only /abz-inspector page").option("--rotate", "Mint a fresh invoke key even if one already exists").option("--new-session", "Start a fresh anonymous session (logged-out only)").option("-y, --yes", "Skip prompts");
7685
8669
  withSetupOptions(program.command("init").description("Set up the APIblaze sidecar in a Next.js app (shortcut for `apiblaze sidecar setup`)")).action(action((opts) => runSetup(opts)));
7686
8670
  var sidecar = program.command("sidecar").description("The APIblaze sidecar \u2014 set it up, then approve which origins route through APIblaze").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Machine-readable output").action(action((opts) => runOriginsList(opts)));
7687
- withSetupOptions(sidecar.command("setup").description("Wire a Next.js app to route its external fetches through APIblaze")).action(action((opts) => runSetup(opts)));
7688
- sidecar.command("approve").description("Route an origin through APIblaze (creates its proxy)").argument("<origin>", "Origin, e.g. api.stripe.com").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Machine-readable output").action(action((origin, opts) => runOriginsApprove(origin, opts)));
7689
- sidecar.command("deny").description("Dismiss a candidate origin so it stops being suggested").argument("<origin>", "Origin, e.g. sentry.io").option("--team <id|name>", "Team (defaults to active team)").action(action((origin, opts) => runOriginsDeny(origin, opts)));
7690
- sidecar.command("remove").description("Un-route an approved origin (deletes its proxy; the app goes direct again)").argument("<origin>", "Origin, e.g. api.stripe.com").option("--team <id|name>", "Team (defaults to active team)").action(action((origin, opts) => runOriginsRemove(origin, opts)));
8671
+ withSetupOptions(sidecar.command("setup").description("Wire a Next.js app to route its external fetches through APIblaze")).action(action((opts, cmd) => runSetup({ ...cmd.parent?.opts(), ...opts })));
8672
+ sidecar.command("approve").description("Route an origin through APIblaze (creates its proxy)").argument("<origin>", "Origin, e.g. api.stripe.com").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Machine-readable output").action(action((origin, opts, cmd) => runOriginsApprove(origin, { ...cmd.parent?.opts(), ...opts })));
8673
+ sidecar.command("deny").description("Dismiss a candidate origin so it stops being suggested").argument("<origin>", "Origin, e.g. sentry.io").option("--team <id|name>", "Team (defaults to active team)").action(action((origin, opts, cmd) => runOriginsDeny(origin, { ...cmd.parent?.opts(), ...opts })));
8674
+ sidecar.command("remove").description("Un-route an approved origin (deletes its proxy; the app goes direct again)").argument("<origin>", "Origin, e.g. api.stripe.com").option("--team <id|name>", "Team (defaults to active team)").action(action((origin, opts, cmd) => runOriginsRemove(origin, { ...cmd.parent?.opts(), ...opts })));
7691
8675
  program.command("dev").description("Put your localhost behind a public URL (dev tunnel)").argument("[port]", "Local port to tunnel (positional; overrides --port)").option("-p, --port <number>", "Local port to tunnel", "3000").option("--project <nameOrId>", "Tunnel this specific project (skips the picker \u2014 for scripts)").option("-y, --yes", "Skip confirmation prompts (non-interactive)").option("-o, --capture-file <path>", "Stream full request/response traffic to a file (JSON lines)").option("--new-session", "Logged-out only: start a fresh anonymous workspace instead of reusing this machine's (each run = a throwaway proxy)").action(async (port, opts) => {
7692
8676
  try {
7693
8677
  const resolved = parseInt(port ?? opts.port, 10);
7694
8678
  if (Number.isNaN(resolved)) {
7695
- console.error(import_chalk44.default.red(`Invalid port: ${port ?? opts.port}`));
8679
+ console.error(import_chalk48.default.red(`Invalid port: ${port ?? opts.port}`));
7696
8680
  process.exit(1);
7697
8681
  }
7698
8682
  await runDev({ port: resolved, project: opts.project, yes: opts.yes, captureFile: opts.captureFile, newSession: opts.newSession });
@@ -7705,6 +8689,8 @@ var consumer = program.command("consumer").description("Act as a consumer of you
7705
8689
  consumer.command("login").description("Log in to a tenant's portal as a consumer (device flow)").option("--team <id|name>", "Team whose tenants to choose from (producer mode)").option("--tenant <slug>", "Tenant to log in to (skips the picker)").option("--client <clientId>", "App client id \u2014 for standalone login without a producer session").action(action((opts) => runConsumerLogin(opts)));
7706
8690
  consumer.command("tokens").description("Show the logged-in consumer access / refresh / id tokens").option("--json", "Output machine-readable JSON").action(action((opts) => runConsumerTokens(opts)));
7707
8691
  consumer.command("apikeys").description("List your consumer API keys (reveals expiring ones), then offer to create one").option("--json", "Output machine-readable JSON").action(action((opts) => runConsumerApikeys(opts)));
8692
+ var consumerLogs = consumer.command("logs").description("API Consumer view \u2014 stream YOUR OWN requests on this tenant live (see `consumer logs list` for past days)").option("--project <name>", "Only this project (when the tenant serves several)").option("--errors-only", "Only show 4xx/5xx responses").option("--json", "Emit raw NDJSON rows (pipe into jq)").action(action((opts) => runConsumerLogsTail(opts)));
8693
+ consumerLogs.command("list").description("API Consumer view \u2014 browse YOUR OWN past requests by day, then open one for detail").option("--project <name>", "Only this project (when the tenant serves several)").option("--errors-only", "Only show 4xx/5xx responses").option("--json", "Emit ALL matching rows as NDJSON, newest first (non-interactive)").option("--plain", "Print day-grouped rows instead of prompting (automatic when piped)").action(action((_o, cmd) => runConsumerLogsList(cmd.optsWithGlobals())));
7708
8694
  program.command("flush").description("Wipe ALL local state (login, workspace keys, apichats, DP keys, secrets)").option("-y, --yes", "Skip the confirmation prompt").action(runFlush);
7709
8695
  program.command("logout").description("Sign out (asks whether to drop the Producer or Consumer login)").option("--producer", "Log out of the API Producer identity").option("--consumer", "Log out of the API Consumer identity").option("--all", "Log out of both").action(action((opts) => runLogout(opts)));
7710
8696
  program.command("whoami").description("Show who you are \u2014 both API Producer and API Consumer").option("--json", "Output machine-readable JSON").action(async (opts) => {
@@ -7741,6 +8727,8 @@ program.command("projects").description("List the projects in your team").action
7741
8727
  });
7742
8728
  program.command("delete").description("Delete a proxy and everything under it (asks first)").argument("<project>", "Project name or id (see `apiblaze projects`)").argument("[version]", "API version (defaults to the first match)").option("--team <id|name>", "Team the project is in (defaults to active team)").option("-y, --yes", "Skip the confirmation prompt").option("--json", "Output machine-readable JSON").action(action((project, version2, opts) => runDelete(project, version2, opts)));
7743
8729
  program.command("export").description("Export config and data for migration out of APIblaze (Kong, ...)").argument("<project>", "Project name or id (see `apiblaze projects`)").argument("[version]", "API version (defaults to the first match)").option("--kong", "Produce a runnable Kong OSS bundle (decK config + plugins + docker-compose)").option("--data", "Plain data export (default)").option("--secrets", "Include decrypted producer-supplied secrets (member role; audit-logged)").option("--keys <mode>", "API-key export: hashes (default, consumers keep keys) | mint | none").option("--no-consumers", "Skip the end-user lane (users, groups, keys)").option("-o, --out <file>", "Output zip path").option("--team <id|name>", "Team the project is in (defaults to active team)").action(action((project, version2, opts) => runExport(project, version2, { ...opts, noConsumers: opts.consumers === false })));
8730
+ var logs = program.command("logs").description("API Producer view \u2014 stream this proxy's requests from EVERY caller live (see `apiblaze logs list` to browse past days)").argument("<project>", "Project name or id (see `apiblaze projects`)").argument("[version]", "API version (defaults to the first match)").option("--tenant <slug>", "Tenant to tail (auto when one is attached; prompted otherwise)").option("--errors-only", "Only show 4xx/5xx responses").option("--json", "Emit raw NDJSON rows (pipe into jq)").option("--team <id|name>", "Team the project is in (defaults to active team)").action(action((project, version2, opts) => runLogsTail(project, version2, opts)));
8731
+ logs.command("list").description("API Producer view \u2014 browse EVERY caller's past requests by day, then open one to see its 4 views").argument("<project>", "Project name or id").argument("[version]", "API version (defaults to the first match)").option("--tenant <slug>", "Tenant to read (auto when one is attached; prompted otherwise)").option("--errors-only", "Only show 4xx/5xx responses").option("--json", "Emit ALL matching rows as NDJSON, newest first (non-interactive)").option("--plain", "Print day-grouped rows instead of prompting (automatic when piped)").option("--team <id|name>", "Team the project is in (defaults to active team)").action(action((project, version2, _o, cmd) => runLogsList(project, version2, cmd.optsWithGlobals())));
7744
8732
  program.command("config").description("Browse and change every proxy setting & feature (interactive; git-config-style get/set)").argument("[project]", "Project name or id (omit to pick interactively)").argument("[key]", "Setting key, e.g. throttling.proxyQuota (omit for the menu)").argument("[value]", "New value (omit to read the current value)").option("--list", "Print every setting and its current value").option("--team <id|name>", "Team the project is in").option("--apiversion <version>", "API version (defaults to the first match)").option("--json", "Machine-readable output (with --list or a key read)").action(action((project, key, value, opts) => runConfig(project, key, value, opts)));
7745
8733
  program.command("target").description("Change where a proxy forwards requests").argument("<project>", "Project name or id").requiredOption("--url <url>", "Target URL to forward to").option("--env <env>", "Environment to scope the target to (e.g. prod, dev)").option("--team <id|name>", "Team the project is in").option("--apiversion <version>", "API version (defaults to the first match)").option("--json", "Output machine-readable JSON").action(action((project, opts) => runTargetSet(project, opts)));
7746
8734
  program.command("throttle").description("Set rate limits and quotas for a proxy").argument("<project>", "Project name or id").option("--rate <n>", "User rate limit (requests/sec)").option("--end-user-rate <n>", "Per-end-user rate limit (requests/sec)").option("--quota <n>", "Proxy quota (requests/period)").option("--period <p>", "Quota period: daily | weekly | monthly").option("--team <id|name>", "Team the project is in").option("--apiversion <version>", "API version").option("--json", "Output machine-readable JSON").action(action((project, opts) => runThrottleSet(project, opts)));
@@ -7792,10 +8780,11 @@ spec.command("delete-rule").description("Delete the saved rules for a route (e.g
7792
8780
  var HELP_GROUPS = [
7793
8781
  { title: "Chat", commands: ["apichat", "agent"] },
7794
8782
  { title: "Setup", commands: ["login", "create", "init", "sidecar", "dev", "claim", "team", "whoami", "logout"] },
7795
- { title: "Control plane commands", commands: ["config", "projects", "tenant", "group", "admins", "iam", "identified", "preapprove", "rule", "domain", "delete", "target", "throttle", "rename", "spec", "export"] },
8783
+ { title: "Control plane commands", commands: ["config", "projects", "logs", "tenant", "group", "admins", "iam", "identified", "preapprove", "rule", "domain", "delete", "target", "throttle", "rename", "spec", "export"] },
7796
8784
  { title: "Data plane commands", commands: [
7797
8785
  { parent: "consumer", sub: "login" },
7798
- { parent: "consumer", sub: "apikeys" }
8786
+ { parent: "consumer", sub: "apikeys" },
8787
+ { parent: "consumer", sub: "logs" }
7799
8788
  ] }
7800
8789
  ];
7801
8790
  var helpLabel = (e) => typeof e === "string" ? e : `${e.parent} ${e.sub}`;
@@ -7811,7 +8800,7 @@ function groupedCommandHelp() {
7811
8800
  const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
7812
8801
  return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
7813
8802
  }).filter(Boolean).join("\n");
7814
- return `${import_chalk44.default.bold(g.title)}
8803
+ return `${import_chalk48.default.bold(g.title)}
7815
8804
  ${rows}`;
7816
8805
  }).join("\n\n");
7817
8806
  }
@@ -7846,14 +8835,14 @@ async function recoverStaleTeam() {
7846
8835
  const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
7847
8836
  const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
7848
8837
  if (!linked) {
7849
- console.error(import_chalk44.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
8838
+ console.error(import_chalk48.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
7850
8839
  return;
7851
8840
  }
7852
8841
  if (linked.teamId === creds.teamId) return;
7853
8842
  const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
7854
8843
  delete next.activeTenant;
7855
8844
  saveCredentials(next);
7856
- console.error(import_chalk44.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk44.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
8845
+ console.error(import_chalk48.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk48.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
7857
8846
  } catch {
7858
8847
  }
7859
8848
  }
@@ -7861,16 +8850,16 @@ async function printError(err) {
7861
8850
  if (err instanceof ApiError) {
7862
8851
  const data = err.body;
7863
8852
  const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
7864
- console.error(import_chalk44.default.red(`
8853
+ console.error(import_chalk48.default.red(`
7865
8854
  API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
7866
8855
  if (err.status === 403 || err.status === 404) {
7867
8856
  await recoverStaleTeam();
7868
8857
  }
7869
8858
  } else if (err instanceof Error) {
7870
- console.error(import_chalk44.default.red(`
8859
+ console.error(import_chalk48.default.red(`
7871
8860
  Error: ${err.message}`));
7872
8861
  } else {
7873
- console.error(import_chalk44.default.red("\nUnknown error"));
8862
+ console.error(import_chalk48.default.red("\nUnknown error"));
7874
8863
  }
7875
8864
  }
7876
8865
  program.parse(process.argv);