apiblaze 0.15.2 → 0.17.0

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 +575 -430
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -457,6 +457,140 @@ var init_admin = __esm({
457
457
  }
458
458
  });
459
459
 
460
+ // src/lib/tenant-create.ts
461
+ var tenant_create_exports = {};
462
+ __export(tenant_create_exports, {
463
+ addApiblazeHostedLogin: () => addApiblazeHostedLogin,
464
+ createTenantInteractive: () => createTenantInteractive
465
+ });
466
+ async function createTenantRow(teamId) {
467
+ const { default: inquirer2 } = await import("inquirer");
468
+ for (; ; ) {
469
+ const { name } = await inquirer2.prompt([{
470
+ type: "input",
471
+ name: "name",
472
+ message: `Tenant name ${import_chalk22.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
473
+ validate: (s) => /^[a-z0-9]+$/.test(s.trim()) ? true : "lowercase letters and numbers only"
474
+ }]);
475
+ const slug = name.trim();
476
+ try {
477
+ const out = await admin({
478
+ method: "POST",
479
+ path: `/teams/${encodeURIComponent(teamId)}/tenants`,
480
+ body: { tenant_name: slug, display_name: slug },
481
+ summary: `Create tenant "${slug}"`
482
+ });
483
+ return out?.tenant_name ?? out?.tenant?.tenant_name ?? slug;
484
+ } catch (err) {
485
+ const msg = err instanceof Error ? err.message : String(err);
486
+ if (/taken|unique|exists|reserved|conflict/i.test(msg)) {
487
+ console.log(import_chalk22.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
488
+ continue;
489
+ }
490
+ throw err;
491
+ }
492
+ }
493
+ }
494
+ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
495
+ const { default: inquirer2 } = await import("inquirer");
496
+ const base = `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}`;
497
+ const { provider } = await inquirer2.prompt([{
498
+ type: "list",
499
+ name: "provider",
500
+ message: "Which login provider?",
501
+ pageSize: 10,
502
+ choices: [
503
+ ...PROVIDERS.map((p) => ({ name: p.label, value: p.id })),
504
+ ...opts.allowSkip ? [new inquirer2.Separator(), { name: import_chalk22.default.dim("Skip for now \u2014 set up a login method later"), value: null }] : []
505
+ ]
506
+ }]);
507
+ if (!provider) {
508
+ console.log(import_chalk22.default.dim(" No login method yet \u2014 add one later under Login methods."));
509
+ return false;
510
+ }
511
+ const opt = PROVIDERS.find((p) => p.id === provider);
512
+ let providerBody;
513
+ if (!opt.own) {
514
+ providerBody = { type: "github", managed: true };
515
+ } else {
516
+ const a = await inquirer2.prompt([
517
+ { type: "input", name: "clientId", message: `${opt.label} OAuth client id:`, validate: (s) => !!s.trim() || "required" },
518
+ { type: "password", name: "clientSecret", mask: "*", message: `${opt.label} OAuth client secret:`, validate: (s) => s.length >= 6 && s.length <= 200 || "6\u2013200 chars" },
519
+ ...provider === "auth0" || provider === "other" ? [{ type: "input", name: "domain", message: "Issuer / domain (e.g. your-tenant.auth0.com):" }] : []
520
+ ]);
521
+ providerBody = {
522
+ type: provider,
523
+ clientId: a.clientId.trim(),
524
+ clientSecret: a.clientSecret,
525
+ ...a.domain?.trim() ? { domain: a.domain.trim() } : {},
526
+ scopes: (DEFAULT_SCOPES[provider] ?? "openid email profile").split(/\s+/).filter(Boolean)
527
+ };
528
+ }
529
+ const { advanced } = await inquirer2.prompt([{ type: "confirm", name: "advanced", message: "Configure advanced settings (callback URLs, scopes)?", default: false }]);
530
+ const clientBody = { name: `${tenant2}-login` };
531
+ if (advanced) {
532
+ const a = await inquirer2.prompt([
533
+ { type: "input", name: "callbacks", message: "Callback URLs (comma-separated, empty = none):" },
534
+ { type: "input", name: "scopes", message: `Provider scopes:`, default: (providerBody.scopes ?? []).join(" ") }
535
+ ]);
536
+ if (a.callbacks.trim()) clientBody.authorizedCallbackUrls = a.callbacks.split(/\s*,\s*/).map((s) => s.trim()).filter(Boolean);
537
+ if (a.scopes.trim() && opt.own) providerBody.scopes = a.scopes.split(/\s+/).filter(Boolean);
538
+ }
539
+ const spinner = (0, import_ora8.default)("Setting up login...").start();
540
+ try {
541
+ const client = await admin({ method: "POST", path: `${base}/app-clients`, body: clientBody, summary: `Create login for ${tenant2}` });
542
+ const clientId = client?.clientId ?? client?.client_id;
543
+ await admin({ method: "POST", path: `${base}/app-clients/${encodeURIComponent(clientId)}/providers`, body: providerBody, summary: `Add ${provider} provider` });
544
+ spinner.succeed(opt.own ? `${opt.label} login is ready.` : "APIblaze-hosted GitHub login is ready.");
545
+ return true;
546
+ } catch (err) {
547
+ spinner.fail("Login setup failed.");
548
+ throw err;
549
+ }
550
+ }
551
+ async function createTenantInteractive(teamId) {
552
+ const { default: inquirer2 } = await import("inquirer");
553
+ const tenant2 = await createTenantRow(teamId);
554
+ console.log(import_chalk22.default.green(` Tenant ${import_chalk22.default.bold(tenant2)} created.`));
555
+ const { users } = await inquirer2.prompt([{
556
+ type: "confirm",
557
+ name: "users",
558
+ default: false,
559
+ message: `Enable Users & groups? ${import_chalk22.default.dim(`(identity/key management at ${tenant2}.iam.apiblaze.com)`)}`
560
+ }]);
561
+ if (users) {
562
+ await admin({ method: "PATCH", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/iam`, body: { enabled: true }, summary: "Enable Users & groups" }).catch(() => {
563
+ });
564
+ console.log(import_chalk22.default.green(" Users & groups enabled."));
565
+ }
566
+ await addApiblazeHostedLogin(teamId, tenant2, { allowSkip: true });
567
+ return tenant2;
568
+ }
569
+ var import_chalk22, import_ora8, PROVIDERS, DEFAULT_SCOPES;
570
+ var init_tenant_create = __esm({
571
+ "src/lib/tenant-create.ts"() {
572
+ "use strict";
573
+ import_chalk22 = __toESM(require("chalk"));
574
+ import_ora8 = __toESM(require("ora"));
575
+ init_admin();
576
+ PROVIDERS = [
577
+ { id: "apiblaze", label: "APIblaze (via GitHub) \u2014 zero setup, recommended", own: false },
578
+ { id: "google", label: "Google", own: true },
579
+ { id: "github", label: "GitHub", own: true },
580
+ { id: "microsoft", label: "Microsoft", own: true },
581
+ { id: "facebook", label: "Facebook", own: true },
582
+ { id: "auth0", label: "Auth0", own: true },
583
+ { id: "other", label: "Custom (any OIDC provider)", own: true }
584
+ ];
585
+ DEFAULT_SCOPES = {
586
+ google: "openid email profile",
587
+ microsoft: "openid email profile",
588
+ github: "read:user user:email",
589
+ facebook: "public_profile email"
590
+ };
591
+ }
592
+ });
593
+
460
594
  // src/lib/tenant-pick.ts
461
595
  var tenant_pick_exports = {};
462
596
  __export(tenant_pick_exports, {
@@ -475,10 +609,10 @@ async function fetchPage(teamId, q) {
475
609
  }
476
610
  function label(t, defaultTenant, active) {
477
611
  const tags = [
478
- t.tenant_name === active ? import_chalk22.default.cyan("active scope") : "",
479
- t.tenant_name === defaultTenant ? import_chalk22.default.dim("team default") : ""
612
+ t.tenant_name === active ? import_chalk23.default.cyan("active scope") : "",
613
+ t.tenant_name === defaultTenant ? import_chalk23.default.dim("team default") : ""
480
614
  ].filter(Boolean).join(", ");
481
- const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk22.default.dim(` ${t.display_name}`) : "";
615
+ const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk23.default.dim(` ${t.display_name}`) : "";
482
616
  return `${t.tenant_name}${disp}${tags ? ` (${tags})` : ""}`;
483
617
  }
484
618
  async function pickTenant(teamId, opts = {}) {
@@ -486,14 +620,14 @@ async function pickTenant(teamId, opts = {}) {
486
620
  const active = loadCredentials()?.activeTenant;
487
621
  let q = opts.initialQuery ?? "";
488
622
  for (; ; ) {
489
- const spinner = (0, import_ora8.default)(q ? `Searching tenants for "${q}"...` : "Loading tenants...").start();
623
+ const spinner = (0, import_ora9.default)(q ? `Searching tenants for "${q}"...` : "Loading tenants...").start();
490
624
  const page = await fetchPage(teamId, q).finally(() => spinner.stop());
491
625
  if (!page.total && !q) {
492
626
  if (opts.allowCreate) {
493
627
  const { make } = await inquirer2.prompt([{ type: "confirm", name: "make", message: "No tenants yet \u2014 create one?", default: true }]);
494
628
  if (make) return await createTenantInline(teamId);
495
629
  }
496
- console.error(import_chalk22.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
630
+ console.error(import_chalk23.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
497
631
  return null;
498
632
  }
499
633
  const truncated = page.total > page.rows.length;
@@ -502,7 +636,7 @@ async function pickTenant(teamId, opts = {}) {
502
636
  value: t.tenant_name
503
637
  }));
504
638
  if (truncated || q) {
505
- choices.push(new inquirer2.Separator(import_chalk22.default.dim(
639
+ choices.push(new inquirer2.Separator(import_chalk23.default.dim(
506
640
  truncated ? `showing ${page.rows.length} of ${page.total}${q ? ` matching "${q}"` : ""} \u2014 search to narrow` : `matches for "${q}"`
507
641
  )));
508
642
  choices.push({ name: `\u{1F50D} Search${q ? " again" : ""}\u2026`, value: "\0search" });
@@ -533,41 +667,15 @@ async function pickTenant(teamId, opts = {}) {
533
667
  }
534
668
  }
535
669
  async function createTenantInline(teamId) {
536
- const { default: inquirer2 } = await import("inquirer");
537
- for (; ; ) {
538
- const { name } = await inquirer2.prompt([{
539
- type: "input",
540
- name: "name",
541
- message: `Tenant name ${import_chalk22.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
542
- validate: (s) => /^[a-z0-9]+$/.test(s.trim()) ? true : "lowercase letters and numbers only"
543
- }]);
544
- const slugInput = name.trim();
545
- try {
546
- const out = await admin({
547
- method: "POST",
548
- path: `/teams/${encodeURIComponent(teamId)}/tenants`,
549
- body: { tenant_name: slugInput, display_name: slugInput },
550
- summary: `Create tenant "${slugInput}"`
551
- });
552
- const slug = out?.tenant_name ?? out?.tenant?.tenant_name ?? slugInput;
553
- console.log(import_chalk22.default.green(` Tenant ${import_chalk22.default.bold(slug)} created.`));
554
- return slug;
555
- } catch (err) {
556
- const msg = err instanceof Error ? err.message : String(err);
557
- if (/taken|unique|exists|reserved|conflict/i.test(msg)) {
558
- console.log(import_chalk22.default.yellow(` "${slugInput}" is not available (tenant names are global): ${msg}`));
559
- continue;
560
- }
561
- throw err;
562
- }
563
- }
670
+ const { createTenantInteractive: createTenantInteractive2 } = await Promise.resolve().then(() => (init_tenant_create(), tenant_create_exports));
671
+ return createTenantInteractive2(teamId);
564
672
  }
565
- var import_chalk22, import_ora8, PAGE;
673
+ var import_chalk23, import_ora9, PAGE;
566
674
  var init_tenant_pick = __esm({
567
675
  "src/lib/tenant-pick.ts"() {
568
676
  "use strict";
569
- import_chalk22 = __toESM(require("chalk"));
570
- import_ora8 = __toESM(require("ora"));
677
+ import_chalk23 = __toESM(require("chalk"));
678
+ import_ora9 = __toESM(require("ora"));
571
679
  init_admin();
572
680
  init_auth();
573
681
  PAGE = 15;
@@ -576,10 +684,10 @@ var init_tenant_pick = __esm({
576
684
 
577
685
  // src/index.ts
578
686
  var import_commander = require("commander");
579
- var import_chalk34 = __toESM(require("chalk"));
687
+ var import_chalk35 = __toESM(require("chalk"));
580
688
 
581
689
  // package.json
582
- var version = "0.15.2";
690
+ var version = "0.17.0";
583
691
 
584
692
  // src/index.ts
585
693
  init_types();
@@ -2652,8 +2760,8 @@ async function runRename(project, opts) {
2652
2760
  }
2653
2761
 
2654
2762
  // src/commands/config-browse.ts
2655
- var import_chalk28 = __toESM(require("chalk"));
2656
- var import_ora13 = __toESM(require("ora"));
2763
+ var import_chalk29 = __toESM(require("chalk"));
2764
+ var import_ora14 = __toESM(require("ora"));
2657
2765
  init_admin();
2658
2766
  init_auth();
2659
2767
 
@@ -2763,28 +2871,28 @@ async function runDomainSetBase(project, opts) {
2763
2871
  }
2764
2872
 
2765
2873
  // src/commands/tenant.ts
2766
- var import_chalk23 = __toESM(require("chalk"));
2767
- var import_ora9 = __toESM(require("ora"));
2874
+ var import_chalk24 = __toESM(require("chalk"));
2875
+ var import_ora10 = __toESM(require("ora"));
2768
2876
  init_admin();
2769
2877
  init_auth();
2770
2878
  init_tenant_pick();
2771
2879
  async function runTenantUse(query, opts) {
2772
2880
  const creds = loadCredentials();
2773
2881
  if (!creds) {
2774
- console.error(import_chalk23.default.red("Not logged in. Run `apiblaze login` first."));
2882
+ console.error(import_chalk24.default.red("Not logged in. Run `apiblaze login` first."));
2775
2883
  process.exit(1);
2776
2884
  }
2777
2885
  if (opts.clear) {
2778
2886
  delete creds.activeTenant;
2779
2887
  saveCredentials(creds);
2780
- console.log(import_chalk23.default.green("Tenant scope cleared."));
2888
+ console.log(import_chalk24.default.green("Tenant scope cleared."));
2781
2889
  return;
2782
2890
  }
2783
2891
  const { teamId } = await resolveTeam(opts.team);
2784
2892
  const slug = await pickTenant(teamId, { message: "Scope future commands to which tenant?", initialQuery: query });
2785
2893
  if (!slug) process.exit(1);
2786
2894
  saveCredentials({ ...creds, activeTenant: slug });
2787
- console.log(import_chalk23.default.green(`Tenant scope set to ${import_chalk23.default.bold(slug)}.`) + import_chalk23.default.dim(" (clear with `apiblaze tenant use --clear`)"));
2895
+ console.log(import_chalk24.default.green(`Tenant scope set to ${import_chalk24.default.bold(slug)}.`) + import_chalk24.default.dim(" (clear with `apiblaze tenant use --clear`)"));
2788
2896
  }
2789
2897
  async function runTenantList(opts) {
2790
2898
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -2801,26 +2909,26 @@ async function runTenantList(opts) {
2801
2909
  return;
2802
2910
  }
2803
2911
  if (!tenants.length) {
2804
- console.log(import_chalk23.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
2912
+ console.log(import_chalk24.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
2805
2913
  return;
2806
2914
  }
2807
2915
  for (const t of tenants) {
2808
2916
  const name = typeof t === "string" ? t : t.tenant_name;
2809
- const display = typeof t === "string" ? "" : import_chalk23.default.dim(` ${t.display_name ?? ""}`);
2810
- console.log(` ${import_chalk23.default.bold(name)}${display}`);
2917
+ const display = typeof t === "string" ? "" : import_chalk24.default.dim(` ${t.display_name ?? ""}`);
2918
+ console.log(` ${import_chalk24.default.bold(name)}${display}`);
2811
2919
  }
2812
2920
  const total = out?.total ?? tenants.length;
2813
2921
  if (total > tenants.length) {
2814
- console.log(import_chalk23.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
2922
+ console.log(import_chalk24.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
2815
2923
  }
2816
2924
  }
2817
2925
  async function runTenantCreate(opts) {
2818
2926
  if (!opts.name) {
2819
- console.error(import_chalk23.default.red("--name (display name) is required."));
2927
+ console.error(import_chalk24.default.red("--name (display name) is required."));
2820
2928
  process.exit(1);
2821
2929
  }
2822
2930
  const { teamId } = await resolveTeam(opts.team);
2823
- const spinner = (0, import_ora9.default)("Creating tenant...").start();
2931
+ const spinner = (0, import_ora10.default)("Creating tenant...").start();
2824
2932
  try {
2825
2933
  const out = await admin({
2826
2934
  method: "POST",
@@ -2828,7 +2936,7 @@ async function runTenantCreate(opts) {
2828
2936
  body: { display_name: opts.name, ...opts.slug ? { tenant_name: opts.slug } : {} },
2829
2937
  summary: `Create tenant "${opts.name}"`
2830
2938
  });
2831
- spinner.succeed(`Created tenant ${import_chalk23.default.bold(out?.tenant_name ?? opts.name)}.`);
2939
+ spinner.succeed(`Created tenant ${import_chalk24.default.bold(out?.tenant_name ?? opts.name)}.`);
2832
2940
  if (opts.json) console.log(JSON.stringify(out));
2833
2941
  } catch (err) {
2834
2942
  spinner.fail("Tenant create failed.");
@@ -2837,12 +2945,12 @@ async function runTenantCreate(opts) {
2837
2945
  }
2838
2946
  async function runTenantAttach(project, opts) {
2839
2947
  if (!opts.tenant) {
2840
- console.error(import_chalk23.default.red("--tenant <slug> is required."));
2948
+ console.error(import_chalk24.default.red("--tenant <slug> is required."));
2841
2949
  process.exit(1);
2842
2950
  }
2843
2951
  const { teamId } = await resolveTeam(opts.team);
2844
2952
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
2845
- const spinner = (0, import_ora9.default)("Attaching tenant...").start();
2953
+ const spinner = (0, import_ora10.default)("Attaching tenant...").start();
2846
2954
  try {
2847
2955
  const out = await admin({
2848
2956
  method: "POST",
@@ -2865,11 +2973,11 @@ async function runTenantDelete(slug, opts) {
2865
2973
  { type: "confirm", name: "confirm", message: `Permanently delete tenant "${slug}" and everything under it? This cannot be undone.`, default: false }
2866
2974
  ]);
2867
2975
  if (!confirm) {
2868
- console.log(import_chalk23.default.dim("Aborted."));
2976
+ console.log(import_chalk24.default.dim("Aborted."));
2869
2977
  return;
2870
2978
  }
2871
2979
  }
2872
- const spinner = (0, import_ora9.default)("Deleting tenant...").start();
2980
+ const spinner = (0, import_ora10.default)("Deleting tenant...").start();
2873
2981
  try {
2874
2982
  await admin({
2875
2983
  method: "DELETE",
@@ -2884,13 +2992,13 @@ async function runTenantDelete(slug, opts) {
2884
2992
  }
2885
2993
  async function runTenantCors(opts) {
2886
2994
  if (!opts.tenant) {
2887
- console.error(import_chalk23.default.red("--tenant <slug> is required."));
2995
+ console.error(import_chalk24.default.red("--tenant <slug> is required."));
2888
2996
  process.exit(1);
2889
2997
  }
2890
2998
  const { teamId } = await resolveTeam(opts.team);
2891
2999
  const origins = (opts.origins ?? "").split(",").map((s) => s.trim()).filter(Boolean);
2892
3000
  const cors = origins.length ? { allowed_origins: origins } : null;
2893
- const spinner = (0, import_ora9.default)("Updating CORS...").start();
3001
+ const spinner = (0, import_ora10.default)("Updating CORS...").start();
2894
3002
  try {
2895
3003
  await admin({
2896
3004
  method: "PUT",
@@ -2906,8 +3014,8 @@ async function runTenantCors(opts) {
2906
3014
  }
2907
3015
 
2908
3016
  // src/commands/tenant-drill.ts
2909
- var import_chalk24 = __toESM(require("chalk"));
2910
- var import_ora10 = __toESM(require("ora"));
3017
+ var import_chalk25 = __toESM(require("chalk"));
3018
+ var import_ora11 = __toESM(require("ora"));
2911
3019
  var import_crypto = require("crypto");
2912
3020
  init_admin();
2913
3021
  init_auth();
@@ -2936,17 +3044,17 @@ async function validScopedTenant(teamId, query) {
2936
3044
  const next = { ...creds };
2937
3045
  delete next.activeTenant;
2938
3046
  saveCredentials2(next);
2939
- console.log(import_chalk24.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
3047
+ console.log(import_chalk25.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
2940
3048
  return void 0;
2941
3049
  }
2942
3050
  async function tenantHome(teamId, tenant2) {
2943
3051
  const { default: inquirer2 } = await import("inquirer");
2944
3052
  const base = `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}`;
2945
- console.log(import_chalk24.default.bold(`
3053
+ console.log(import_chalk25.default.bold(`
2946
3054
  Tenant ${tenant2}`));
2947
- console.log(import_chalk24.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
3055
+ console.log(import_chalk25.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
2948
3056
  for (; ; ) {
2949
- const spinner = (0, import_ora10.default)("Reading tenant state...").start();
3057
+ const spinner = (0, import_ora11.default)("Reading tenant state...").start();
2950
3058
  const [iam, cors, emails, issuers, opaque, clients] = await Promise.all([
2951
3059
  admin({ method: "GET", path: `${base}/iam`, summary: "Read IAM toggle" }).catch(() => null),
2952
3060
  admin({ method: "GET", path: `${base}/cors`, summary: "Read tenant CORS" }).catch(() => null),
@@ -2958,32 +3066,33 @@ Tenant ${tenant2}`));
2958
3066
  const nEmails = (emails?.admin_emails ?? []).length;
2959
3067
  const nIssuers = (issuers?.external_issuers ?? []).length;
2960
3068
  const nClients = Array.isArray(clients) ? clients.length : 0;
2961
- const onOff = (b) => b ? import_chalk24.default.green("on") : import_chalk24.default.dim("off");
3069
+ const nOpaque = opaque?.opaque?.endpoint ? 1 : 0;
3070
+ const nLogin = nClients + nIssuers + nOpaque;
3071
+ const onOff = (b) => b ? import_chalk25.default.green("on") : import_chalk25.default.dim("off");
2962
3072
  const { pick: pick2 } = await inquirer2.prompt([{
2963
3073
  type: "list",
2964
3074
  name: "pick",
2965
3075
  message: `Tenant ${tenant2}:`,
2966
3076
  pageSize: 12,
2967
3077
  choices: [
2968
- { name: `App clients (${nClients}) ${import_chalk24.default.dim("OAuth clients your consumers log in through \u2014 providers live inside")}`, value: "clients" },
2969
- { name: `IAM enforcement: ${onOff(iam?.iam_enabled)} ${import_chalk24.default.dim("key/identity enforcement for this tenant")}`, value: "iam" },
2970
- { name: `CORS override: ${cors?.cors ? import_chalk24.default.cyan(JSON.stringify(cors.cors)) : import_chalk24.default.dim("(unset)")}`, value: "cors" },
2971
- { name: `Consumer-admin emails (${nEmails}) ${import_chalk24.default.dim("who may administer the tenant portal")}`, value: "emails" },
2972
- { name: `External JWT issuers (${nIssuers}) ${import_chalk24.default.dim("bring-your-own auth: trust tokens you already mint")}`, value: "issuers" },
2973
- { name: `Opaque-token validator: ${opaque?.opaque?.endpoint ? import_chalk24.default.cyan(opaque.opaque.endpoint) : import_chalk24.default.dim("(unset)")}`, value: "opaque" },
3078
+ { name: `Login methods (${nLogin}) ${import_chalk25.default.dim("how your consumers sign in")}`, value: "login" },
3079
+ { name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk25.default.dim(`identity & key management (${tenant2}.iam.apiblaze.com)`)}`, value: "iam" },
3080
+ { name: `Portal admins (${nEmails}) ${import_chalk25.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
3081
+ new inquirer2.Separator(import_chalk25.default.dim(" Settings")),
3082
+ { name: `CORS: ${cors?.cors ? import_chalk25.default.cyan(JSON.stringify(cors.cors)) : import_chalk25.default.dim("(unset)")} ${import_chalk25.default.dim("browser origins allowed to call this tenant")}`, value: "cors" },
2974
3083
  { name: "\u2190 Back", value: "back" }
2975
3084
  ]
2976
3085
  }]);
2977
3086
  switch (pick2) {
2978
3087
  case "back":
2979
3088
  return;
2980
- case "clients":
2981
- await clientsMenu(teamId, tenant2, base);
3089
+ case "login":
3090
+ await loginMethodsMenu(teamId, tenant2, base);
2982
3091
  break;
2983
3092
  case "iam": {
2984
- const { v } = await inquirer2.prompt([{ type: "confirm", name: "v", message: "Enable IAM enforcement?", default: !!iam?.iam_enabled }]);
3093
+ const { v } = await inquirer2.prompt([{ type: "confirm", name: "v", message: "Enable Users & groups?", default: !!iam?.iam_enabled }]);
2985
3094
  await admin({ method: "PATCH", path: `${base}/iam`, body: { enabled: v }, summary: `IAM enforcement \u2192 ${v ? "on" : "off"}` });
2986
- console.log(import_chalk24.default.green(` IAM enforcement ${v ? "enabled" : "disabled"}.`));
3095
+ console.log(import_chalk25.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
2987
3096
  break;
2988
3097
  }
2989
3098
  case "cors": {
@@ -2996,48 +3105,98 @@ Tenant ${tenant2}`));
2996
3105
  if (v === "") break;
2997
3106
  const parsed = v === "null" ? null : safeJson(v);
2998
3107
  if (parsed === void 0) {
2999
- console.log(import_chalk24.default.yellow(" Not valid JSON \u2014 unchanged."));
3108
+ console.log(import_chalk25.default.yellow(" Not valid JSON \u2014 unchanged."));
3000
3109
  break;
3001
3110
  }
3002
3111
  await admin({ method: "PUT", path: `${base}/cors`, body: { cors: parsed }, summary: "Set tenant CORS" });
3003
- console.log(import_chalk24.default.green(" CORS updated."));
3112
+ console.log(import_chalk25.default.green(" CORS updated."));
3004
3113
  break;
3005
3114
  }
3006
3115
  case "emails":
3007
3116
  await emailsMenu(base, emails?.admin_emails ?? []);
3008
3117
  break;
3009
- case "issuers":
3010
- await issuersMenu(base, issuers?.external_issuers ?? []);
3011
- break;
3012
- case "opaque": {
3013
- const cur = opaque?.opaque;
3014
- const { mode } = await inquirer2.prompt([{
3015
- type: "list",
3016
- name: "mode",
3017
- message: "Opaque-token validator:",
3018
- choices: [
3019
- { name: cur ? "Replace it" : "Set one up", value: "set" },
3020
- ...cur ? [{ name: "Clear it", value: "clear" }] : [],
3021
- { name: "\u2190 Back", value: "back" }
3022
- ]
3023
- }]);
3024
- if (mode === "back") break;
3025
- if (mode === "clear") {
3026
- await admin({ method: "PUT", path: `${base}/opaque`, body: { opaque: null }, summary: "Clear opaque validator" });
3027
- console.log(import_chalk24.default.green(" Cleared."));
3028
- break;
3029
- }
3030
- const a = await inquirer2.prompt([
3031
- { type: "input", name: "endpoint", message: "Introspection endpoint (https):", default: cur?.endpoint, validate: (s) => s.startsWith("https://") || "must be https" },
3032
- { type: "list", name: "method", message: "HTTP method:", choices: ["GET", "POST"], default: cur?.method ?? "GET" }
3033
- ]);
3034
- await admin({ method: "PUT", path: `${base}/opaque`, body: { opaque: { endpoint: a.endpoint, method: a.method } }, summary: "Set opaque validator" });
3035
- console.log(import_chalk24.default.green(" Opaque validator set."));
3036
- break;
3037
- }
3038
3118
  }
3039
3119
  }
3040
3120
  }
3121
+ async function loginMethodsMenu(teamId, tenant2, base) {
3122
+ const { default: inquirer2 } = await import("inquirer");
3123
+ for (; ; ) {
3124
+ const spinner = (0, import_ora11.default)("Loading login methods...").start();
3125
+ const [rawClients, rawIssuers, rawOpaque] = await Promise.all([
3126
+ admin({ method: "GET", path: `${base}/app-clients`, summary: "List APIblaze-hosted logins" }).catch(() => []),
3127
+ admin({ method: "GET", path: `${base}/external-issuers`, summary: "List your-own-JWT logins" }).catch(() => null),
3128
+ admin({ method: "GET", path: `${base}/opaque`, summary: "Read opaque login" }).catch(() => null)
3129
+ ]).finally(() => spinner.stop());
3130
+ const appClients = Array.isArray(rawClients) ? rawClients : [];
3131
+ const issuers = rawIssuers?.external_issuers ?? [];
3132
+ const opaque = rawOpaque?.opaque ?? null;
3133
+ const choices = [];
3134
+ for (const c of appClients) {
3135
+ const nP = (c.providers ?? []).length || c.providers_count || 0;
3136
+ choices.push({ name: `${import_chalk25.default.cyan("APIblaze-hosted")} ${import_chalk25.default.bold(c.name ?? c.clientId)} ${import_chalk25.default.dim(`${c.clientId}${nP ? ` \xB7 ${nP} provider${nP === 1 ? "" : "s"}` : import_chalk25.default.yellow(" \xB7 needs a provider")}`)}`, value: { kind: "client", item: c } });
3137
+ }
3138
+ for (const i of issuers) {
3139
+ choices.push({ name: `${import_chalk25.default.cyan("Your own \u2014 JWT ")} ${import_chalk25.default.bold(i.iss)} ${import_chalk25.default.dim(`aud=${i.aud}`)}`, value: { kind: "issuer", item: i } });
3140
+ }
3141
+ if (opaque?.endpoint) {
3142
+ choices.push({ name: `${import_chalk25.default.cyan("Your own \u2014 opaque")} ${import_chalk25.default.bold(opaque.endpoint)}`, value: { kind: "opaque", item: opaque } });
3143
+ }
3144
+ if (!choices.length) console.log(import_chalk25.default.dim("\n No login methods yet \u2014 consumers cannot sign in until you add one."));
3145
+ const { pick: pick2 } = await inquirer2.prompt([{
3146
+ type: "list",
3147
+ name: "pick",
3148
+ message: `Login methods for ${tenant2}:`,
3149
+ pageSize: 15,
3150
+ choices: [
3151
+ ...choices,
3152
+ new inquirer2.Separator(),
3153
+ { name: "\uFF0B Add a login method\u2026", value: { kind: "add" } },
3154
+ { name: "\u2190 Back", value: { kind: "back" } }
3155
+ ]
3156
+ }]);
3157
+ if (pick2.kind === "back") return;
3158
+ if (pick2.kind === "add") {
3159
+ await addLoginMethod(teamId, tenant2, base);
3160
+ continue;
3161
+ }
3162
+ if (pick2.kind === "client") {
3163
+ await clientHome(base, pick2.item);
3164
+ continue;
3165
+ }
3166
+ if (pick2.kind === "issuer") {
3167
+ await issuerHome(base, pick2.item);
3168
+ continue;
3169
+ }
3170
+ if (pick2.kind === "opaque") {
3171
+ await opaqueHome(base, pick2.item);
3172
+ continue;
3173
+ }
3174
+ }
3175
+ }
3176
+ async function addLoginMethod(teamId, tenant2, base) {
3177
+ const { default: inquirer2 } = await import("inquirer");
3178
+ const { kind } = await inquirer2.prompt([{
3179
+ type: "list",
3180
+ name: "kind",
3181
+ message: "How do people log in?",
3182
+ pageSize: 8,
3183
+ choices: [
3184
+ { name: `APIblaze hosted login page ${import_chalk25.default.dim("we host login; pick a provider (GitHub/Google/\u2026) \u2014 easiest")}`, value: "apiblaze" },
3185
+ { name: `Your own hosted login \u2014 JWT ${import_chalk25.default.dim("your identity provider issues JWTs; we trust them")}`, value: "jwt" },
3186
+ { name: `Your own login \u2014 opaque token ${import_chalk25.default.dim("we validate your opaque tokens via an introspection endpoint")}`, value: "opaque" },
3187
+ { name: "\u2190 Back", value: null }
3188
+ ]
3189
+ }]);
3190
+ if (!kind) return;
3191
+ if (kind === "apiblaze") {
3192
+ const { addApiblazeHostedLogin: addApiblazeHostedLogin2 } = await Promise.resolve().then(() => (init_tenant_create(), tenant_create_exports));
3193
+ await addApiblazeHostedLogin2(teamId, tenant2);
3194
+ } else if (kind === "jwt") {
3195
+ await addIssuer(base);
3196
+ } else {
3197
+ await setOpaque(base, null);
3198
+ }
3199
+ }
3041
3200
  function safeJson(s) {
3042
3201
  try {
3043
3202
  return JSON.parse(s);
@@ -3048,8 +3207,8 @@ function safeJson(s) {
3048
3207
  async function emailsMenu(base, emails) {
3049
3208
  const { default: inquirer2 } = await import("inquirer");
3050
3209
  console.log();
3051
- if (!emails.length) console.log(import_chalk24.default.dim(" No consumer-admin emails."));
3052
- for (const e of emails) console.log(` ${import_chalk24.default.bold(e.email ?? e)} ${import_chalk24.default.dim(e.status ?? "")}`);
3210
+ if (!emails.length) console.log(import_chalk25.default.dim(" No consumer-admin emails."));
3211
+ for (const e of emails) console.log(` ${import_chalk25.default.bold(e.email ?? e)} ${import_chalk25.default.dim(e.status ?? "")}`);
3053
3212
  const { act } = await inquirer2.prompt([{
3054
3213
  type: "list",
3055
3214
  name: "act",
@@ -3064,7 +3223,7 @@ async function emailsMenu(base, emails) {
3064
3223
  if (act === "add") {
3065
3224
  const { email } = await inquirer2.prompt([{ type: "input", name: "email", message: "Email:", validate: (s) => /.+@.+\..+/.test(s) || "not an email" }]);
3066
3225
  await admin({ method: "POST", path: `${base}/admin-emails`, body: { email }, summary: `Add consumer-admin ${email}` });
3067
- console.log(import_chalk24.default.green(` ${email} added.`));
3226
+ console.log(import_chalk25.default.green(` ${email} added.`));
3068
3227
  } else {
3069
3228
  const { e } = await inquirer2.prompt([{
3070
3229
  type: "list",
@@ -3074,108 +3233,94 @@ async function emailsMenu(base, emails) {
3074
3233
  }]);
3075
3234
  if (!e) return;
3076
3235
  await admin({ method: "DELETE", path: `${base}/admin-emails/${encodeURIComponent(e)}`, summary: `Remove consumer-admin ${e}` });
3077
- console.log(import_chalk24.default.green(` ${e} removed.`));
3236
+ console.log(import_chalk25.default.green(` ${e} removed.`));
3078
3237
  }
3079
3238
  }
3080
- async function issuersMenu(base, issuers) {
3239
+ async function addIssuer(base) {
3081
3240
  const { default: inquirer2 } = await import("inquirer");
3082
- console.log();
3083
- if (!issuers.length) console.log(import_chalk24.default.dim(" No external issuers \u2014 consumers use APIblaze-issued tokens."));
3084
- for (const i of issuers) console.log(` ${import_chalk24.default.bold(i.iss)} aud=${i.aud} ${import_chalk24.default.dim(i.sub_semantics ?? "")}`);
3241
+ const a = await inquirer2.prompt([
3242
+ { type: "input", name: "iss", message: "Issuer URL (iss):", validate: (s) => !!s.trim() || "required" },
3243
+ { type: "input", name: "aud", message: "Audience (aud):", validate: (s) => !!s.trim() || "required" },
3244
+ { type: "input", name: "jwks", message: "JWKS URL (empty = derive from issuer):" },
3245
+ { type: "list", name: "sem", message: "Where is the end-user id?", choices: [
3246
+ { name: "The token sub IS the end user (tenant-owned)", value: "tenant_owned" },
3247
+ { name: "Extract it from a claim\u2026", value: "extract_from_claim" }
3248
+ ] }
3249
+ ]);
3250
+ const claim = a.sem === "extract_from_claim" ? (await inquirer2.prompt([{ type: "input", name: "c", message: "Claim name:", validate: (s) => !!s.trim() || "required" }])).c : void 0;
3251
+ await admin({
3252
+ method: "POST",
3253
+ path: `${base}/external-issuers`,
3254
+ body: { iss: a.iss.trim(), aud: a.aud.trim(), jwks_url: a.jwks.trim() || null, sub_semantics: a.sem, ...claim ? { claim_name: claim } : {} },
3255
+ summary: `Add external issuer ${a.iss.trim()}`
3256
+ });
3257
+ console.log(import_chalk25.default.green(" JWT login method saved."));
3258
+ }
3259
+ async function issuerHome(base, issuer) {
3260
+ const { default: inquirer2 } = await import("inquirer");
3261
+ console.log(`
3262
+ ${import_chalk25.default.bold(issuer.iss)} ${import_chalk25.default.dim(`aud=${issuer.aud} \xB7 ${issuer.sub_semantics ?? ""}`)}`);
3085
3263
  const { act } = await inquirer2.prompt([{
3086
3264
  type: "list",
3087
3265
  name: "act",
3088
- message: "External JWT issuers:",
3266
+ message: "This JWT login method:",
3089
3267
  choices: [
3090
- { name: "Add / replace one issuer", value: "add" },
3091
- ...issuers.length ? [{ name: "Delete an issuer", value: "rm" }] : [],
3268
+ { name: "Replace it (re-enter details)", value: "edit" },
3269
+ { name: import_chalk25.default.red("Delete it"), value: "rm" },
3092
3270
  { name: "\u2190 Back", value: "back" }
3093
3271
  ]
3094
3272
  }]);
3095
3273
  if (act === "back") return;
3096
- if (act === "add") {
3097
- const a = await inquirer2.prompt([
3098
- { type: "input", name: "iss", message: "Issuer URL (iss):", validate: (s) => !!s.trim() || "required" },
3099
- { type: "input", name: "aud", message: "Audience (aud):", validate: (s) => !!s.trim() || "required" },
3100
- { type: "input", name: "jwks", message: "JWKS URL (empty = derive from issuer):" },
3101
- { type: "list", name: "sem", message: "Where is the end-user id?", choices: [
3102
- { name: "The token sub IS the end user (tenant-owned)", value: "tenant_owned" },
3103
- { name: "Extract it from a claim\u2026", value: "extract_from_claim" }
3104
- ] }
3105
- ]);
3106
- const claim = a.sem === "extract_from_claim" ? (await inquirer2.prompt([{ type: "input", name: "c", message: "Claim name:", validate: (s) => !!s.trim() || "required" }])).c : void 0;
3107
- await admin({
3108
- method: "POST",
3109
- path: `${base}/external-issuers`,
3110
- body: { iss: a.iss.trim(), aud: a.aud.trim(), jwks_url: a.jwks.trim() || null, sub_semantics: a.sem, ...claim ? { claim_name: claim } : {} },
3111
- summary: `Add external issuer ${a.iss.trim()}`
3112
- });
3113
- console.log(import_chalk24.default.green(" Issuer saved."));
3114
- } else {
3115
- const { i } = await inquirer2.prompt([{
3116
- type: "list",
3117
- name: "i",
3118
- message: "Delete which issuer?",
3119
- choices: [...issuers.map((x) => ({ name: `${x.iss} (aud=${x.aud})`, value: x })), { name: "\u2190 Back", value: null }]
3120
- }]);
3121
- if (!i) return;
3122
- await admin({
3123
- method: "DELETE",
3124
- path: `${base}/external-issuers?iss=${encodeURIComponent(i.iss)}&aud=${encodeURIComponent(i.aud)}`,
3125
- summary: `Delete issuer ${i.iss}`
3126
- });
3127
- console.log(import_chalk24.default.green(" Issuer deleted."));
3274
+ if (act === "edit") {
3275
+ await addIssuer(base);
3276
+ return;
3128
3277
  }
3278
+ const { sure } = await inquirer2.prompt([{ type: "confirm", name: "sure", message: `Delete the JWT login method for ${issuer.iss}? Consumers using it can no longer sign in.`, default: false }]);
3279
+ if (!sure) return;
3280
+ await admin({
3281
+ method: "DELETE",
3282
+ path: `${base}/external-issuers?iss=${encodeURIComponent(issuer.iss)}&aud=${encodeURIComponent(issuer.aud)}`,
3283
+ summary: `Delete issuer ${issuer.iss}`
3284
+ });
3285
+ console.log(import_chalk25.default.green(" Deleted."));
3129
3286
  }
3130
- async function clientsMenu(teamId, tenant2, base) {
3287
+ async function setOpaque(base, cur) {
3131
3288
  const { default: inquirer2 } = await import("inquirer");
3132
- for (; ; ) {
3133
- const spinner = (0, import_ora10.default)("Loading app clients...").start();
3134
- const raw = await admin({ method: "GET", path: `${base}/app-clients`, summary: "List app clients" }).catch(() => []);
3135
- spinner.stop();
3136
- const clients = Array.isArray(raw) ? raw : [];
3137
- const { pick: pick2 } = await inquirer2.prompt([{
3138
- type: "list",
3139
- name: "pick",
3140
- message: `App clients of ${tenant2}:`,
3141
- pageSize: 15,
3142
- choices: [
3143
- ...clients.map((c) => ({
3144
- name: `${import_chalk24.default.bold(c.name ?? c.clientId)} ${import_chalk24.default.dim(`${c.clientId}${c.projectName ? ` \xB7 ${c.projectName}` : ""}`)}`,
3145
- value: c
3146
- })),
3147
- ...clients.length ? [] : [new inquirer2.Separator(import_chalk24.default.dim(" no app clients yet"))],
3148
- { name: "\uFF0B Create an app client\u2026", value: " create" },
3149
- { name: "\u2190 Back", value: " back" }
3150
- ]
3151
- }]);
3152
- if (pick2 === " back") return;
3153
- if (pick2 === " create") {
3154
- const a = await inquirer2.prompt([
3155
- { type: "input", name: "name", message: "Client name:", validate: (s) => !!s.trim() || "required" },
3156
- { type: "input", name: "callbacks", message: "Callback URLs (comma-separated, empty = none):" }
3157
- ]);
3158
- const created = await admin({
3159
- method: "POST",
3160
- path: `${base}/app-clients`,
3161
- body: {
3162
- name: a.name.trim(),
3163
- ...a.callbacks.trim() ? { authorizedCallbackUrls: parseList(a.callbacks) } : {}
3164
- },
3165
- summary: `Create app client "${a.name.trim()}"`
3166
- });
3167
- console.log(import_chalk24.default.green(` App client created${created?.clientId ? ` (${created.clientId})` : ""}.`));
3168
- continue;
3169
- }
3170
- await clientHome(base, pick2);
3289
+ const a = await inquirer2.prompt([
3290
+ { type: "input", name: "endpoint", message: "Introspection endpoint (https):", default: cur?.endpoint, validate: (s) => s.startsWith("https://") || "must be https" },
3291
+ { type: "list", name: "method", message: "HTTP method:", choices: ["GET", "POST"], default: cur?.method ?? "GET" }
3292
+ ]);
3293
+ await admin({ method: "PUT", path: `${base}/opaque`, body: { opaque: { endpoint: a.endpoint, method: a.method } }, summary: "Set opaque validator" });
3294
+ console.log(import_chalk25.default.green(" Opaque login method set."));
3295
+ }
3296
+ async function opaqueHome(base, cur) {
3297
+ const { default: inquirer2 } = await import("inquirer");
3298
+ console.log(`
3299
+ ${import_chalk25.default.bold(cur.endpoint)} ${import_chalk25.default.dim(cur.method ?? "GET")}`);
3300
+ const { act } = await inquirer2.prompt([{
3301
+ type: "list",
3302
+ name: "act",
3303
+ message: "This opaque login method:",
3304
+ choices: [
3305
+ { name: "Replace it", value: "edit" },
3306
+ { name: import_chalk25.default.red("Delete it"), value: "rm" },
3307
+ { name: "\u2190 Back", value: "back" }
3308
+ ]
3309
+ }]);
3310
+ if (act === "back") return;
3311
+ if (act === "edit") {
3312
+ await setOpaque(base, cur);
3313
+ return;
3171
3314
  }
3315
+ await admin({ method: "PUT", path: `${base}/opaque`, body: { opaque: null }, summary: "Clear opaque validator" });
3316
+ console.log(import_chalk25.default.green(" Deleted."));
3172
3317
  }
3173
3318
  async function clientHome(base, summary) {
3174
3319
  const { default: inquirer2 } = await import("inquirer");
3175
3320
  const id = summary.clientId ?? summary.client_id;
3176
3321
  const cBase = `${base}/app-clients/${encodeURIComponent(id)}`;
3177
3322
  for (; ; ) {
3178
- const spinner = (0, import_ora10.default)("Reading app client...").start();
3323
+ const spinner = (0, import_ora11.default)("Reading app client...").start();
3179
3324
  const c = await admin({ method: "GET", path: cBase, summary: `Read app client ${id}` }).catch(() => summary);
3180
3325
  spinner.stop();
3181
3326
  const cb = c.authorizedCallbackUrls ?? c.authorized_callback_urls ?? [];
@@ -3187,13 +3332,13 @@ async function clientHome(base, summary) {
3187
3332
  message: `${c.name ?? id}:`,
3188
3333
  pageSize: 12,
3189
3334
  choices: [
3190
- { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk24.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
3191
- { name: `Callback URLs: ${cb.length ? import_chalk24.default.cyan(cb.join(", ")) : import_chalk24.default.dim("(none)")}`, value: "callbacks" },
3192
- { name: `Scopes: ${scopes.length ? import_chalk24.default.cyan(scopes.join(" ")) : import_chalk24.default.dim("(defaults)")}`, value: "scopes" },
3335
+ { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk25.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
3336
+ { name: `Callback URLs: ${cb.length ? import_chalk25.default.cyan(cb.join(", ")) : import_chalk25.default.dim("(none)")}`, value: "callbacks" },
3337
+ { name: `Scopes: ${scopes.length ? import_chalk25.default.cyan(scopes.join(" ")) : import_chalk25.default.dim("(defaults)")}`, value: "scopes" },
3193
3338
  { name: `Token expiries: access ${c.accessTokenExpiry ?? 3600}s \xB7 id ${c.idTokenExpiry ?? 3600}s \xB7 refresh ${c.refreshTokenExpiry ?? 2592e3}s`, value: "expiries" },
3194
3339
  { name: "Reveal client secret", value: "secret" },
3195
3340
  { name: "Rotate client secret", value: "rotate" },
3196
- { name: import_chalk24.default.red("Delete this app client"), value: "delete" },
3341
+ { name: import_chalk25.default.red("Delete this app client"), value: "delete" },
3197
3342
  { name: "\u2190 Back", value: "back" }
3198
3343
  ]
3199
3344
  }]);
@@ -3206,13 +3351,13 @@ async function clientHome(base, summary) {
3206
3351
  case "callbacks": {
3207
3352
  const { v } = await inquirer2.prompt([{ type: "input", name: "v", message: "Callback URLs (comma-separated):", default: cb.join(", ") }]);
3208
3353
  await admin({ method: "PATCH", path: cBase, body: { authorizedCallbackUrls: parseList(v) }, summary: "Update callback URLs" });
3209
- console.log(import_chalk24.default.green(" Callbacks updated."));
3354
+ console.log(import_chalk25.default.green(" Callbacks updated."));
3210
3355
  break;
3211
3356
  }
3212
3357
  case "scopes": {
3213
3358
  const { v } = await inquirer2.prompt([{ type: "input", name: "v", message: "Scopes (space/comma-separated):", default: scopes.join(" ") }]);
3214
3359
  await admin({ method: "PATCH", path: cBase, body: { scopes: v.split(/[\s,]+/).filter(Boolean) }, summary: "Update scopes" });
3215
- console.log(import_chalk24.default.green(" Scopes updated."));
3360
+ console.log(import_chalk25.default.green(" Scopes updated."));
3216
3361
  break;
3217
3362
  }
3218
3363
  case "expiries": {
@@ -3227,14 +3372,14 @@ async function clientHome(base, summary) {
3227
3372
  body: { accessTokenExpiry: Number(a.access), idTokenExpiry: Number(a.id), refreshTokenExpiry: Number(a.refresh) },
3228
3373
  summary: "Update token expiries"
3229
3374
  });
3230
- console.log(import_chalk24.default.green(" Expiries updated."));
3375
+ console.log(import_chalk25.default.green(" Expiries updated."));
3231
3376
  break;
3232
3377
  }
3233
3378
  case "secret": {
3234
3379
  const { sure } = await inquirer2.prompt([{ type: "confirm", name: "sure", message: "Print the client secret to this terminal?", default: false }]);
3235
3380
  if (!sure) break;
3236
3381
  const s = await admin({ method: "GET", path: `${cBase}/secret`, summary: "Reveal client secret" });
3237
- console.log(` ${import_chalk24.default.bold("client_secret")}: ${import_chalk24.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3382
+ console.log(` ${import_chalk25.default.bold("client_secret")}: ${import_chalk25.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3238
3383
  break;
3239
3384
  }
3240
3385
  case "rotate": {
@@ -3242,14 +3387,14 @@ async function clientHome(base, summary) {
3242
3387
  if (!sure) break;
3243
3388
  const fresh = randomSecret();
3244
3389
  await admin({ method: "PATCH", path: cBase, body: { clientSecret: fresh }, summary: "Rotate client secret" });
3245
- console.log(` New ${import_chalk24.default.bold("client_secret")}: ${import_chalk24.default.green(fresh)} ${import_chalk24.default.dim("(store it now)")}`);
3390
+ console.log(` New ${import_chalk25.default.bold("client_secret")}: ${import_chalk25.default.green(fresh)} ${import_chalk25.default.dim("(store it now)")}`);
3246
3391
  break;
3247
3392
  }
3248
3393
  case "delete": {
3249
3394
  const { sure } = await inquirer2.prompt([{ type: "confirm", name: "sure", message: `Delete app client "${c.name ?? id}"? Consumers logged in through it will lose access.`, default: false }]);
3250
3395
  if (!sure) break;
3251
3396
  await admin({ method: "DELETE", path: cBase, summary: `Delete app client ${id}` });
3252
- console.log(import_chalk24.default.green(" App client deleted."));
3397
+ console.log(import_chalk25.default.green(" App client deleted."));
3253
3398
  return;
3254
3399
  }
3255
3400
  }
@@ -3261,7 +3406,7 @@ function randomSecret() {
3261
3406
  return Buffer.from(bytes).toString("base64url");
3262
3407
  }
3263
3408
  var PROVIDER_TYPES = ["google", "github", "microsoft", "facebook", "auth0", "other"];
3264
- var DEFAULT_SCOPES = {
3409
+ var DEFAULT_SCOPES2 = {
3265
3410
  google: "openid email profile",
3266
3411
  microsoft: "openid email profile",
3267
3412
  github: "read:user user:email",
@@ -3270,19 +3415,19 @@ var DEFAULT_SCOPES = {
3270
3415
  async function providersMenu(cBase, clientLabel) {
3271
3416
  const { default: inquirer2 } = await import("inquirer");
3272
3417
  for (; ; ) {
3273
- const spinner = (0, import_ora10.default)("Loading providers...").start();
3418
+ const spinner = (0, import_ora11.default)("Loading providers...").start();
3274
3419
  const raw = await admin({ method: "GET", path: `${cBase}/providers`, summary: "List login providers" }).catch(() => []);
3275
3420
  spinner.stop();
3276
3421
  const providers = Array.isArray(raw) ? raw : [];
3277
3422
  console.log();
3278
3423
  for (const p of providers) {
3279
- console.log(` ${import_chalk24.default.bold(p.type)} ${import_chalk24.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
3424
+ console.log(` ${import_chalk25.default.bold(p.type)} ${import_chalk25.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
3280
3425
  }
3281
- if (!providers.length) console.log(import_chalk24.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
3426
+ if (!providers.length) console.log(import_chalk25.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
3282
3427
  const { act } = await inquirer2.prompt([{
3283
3428
  type: "list",
3284
3429
  name: "act",
3285
- message: `Login providers of ${clientLabel}:`,
3430
+ message: `Sign-in providers for ${clientLabel}:`,
3286
3431
  choices: [
3287
3432
  { name: "\uFF0B Add a provider", value: "add" },
3288
3433
  ...providers.length ? [
@@ -3310,7 +3455,7 @@ async function providersMenu(cBase, clientLabel) {
3310
3455
  { type: "input", name: "clientId", message: `${type} OAuth client id:`, validate: (s) => !!s.trim() || "required" },
3311
3456
  { type: "password", name: "clientSecret", mask: "*", message: `${type} OAuth client secret:`, validate: (s) => s.length >= 6 && s.length <= 200 || "6\u2013200 chars" },
3312
3457
  ...type === "auth0" || type === "other" ? [{ type: "input", name: "domain", message: "Issuer / domain (e.g. your-tenant.auth0.com):" }] : [],
3313
- { type: "input", name: "scopes", message: "Scopes:", default: DEFAULT_SCOPES[type] ?? "" }
3458
+ { type: "input", name: "scopes", message: "Scopes:", default: DEFAULT_SCOPES2[type] ?? "" }
3314
3459
  ]);
3315
3460
  body = {
3316
3461
  type,
@@ -3336,23 +3481,23 @@ async function providersMenu(cBase, clientLabel) {
3336
3481
  body.targetServerToken = routing;
3337
3482
  }
3338
3483
  await admin({ method: "POST", path: `${cBase}/providers`, body, summary: `Add ${type} login provider` });
3339
- console.log(import_chalk24.default.green(` ${type} provider added.`));
3484
+ console.log(import_chalk25.default.green(` ${type} provider added.`));
3340
3485
  } else {
3341
3486
  const { p } = await inquirer2.prompt([{
3342
3487
  type: "list",
3343
3488
  name: "p",
3344
3489
  message: act === "rm" ? "Remove which provider?" : "Reveal which secret?",
3345
- choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk24.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
3490
+ choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk25.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
3346
3491
  }]);
3347
3492
  if (!p) continue;
3348
3493
  if (act === "rm") {
3349
3494
  const { sure } = await inquirer2.prompt([{ type: "confirm", name: "sure", message: `Remove the ${p.type} provider? Consumers using it can no longer sign in.`, default: false }]);
3350
3495
  if (!sure) continue;
3351
3496
  await admin({ method: "DELETE", path: `${cBase}/providers/${encodeURIComponent(p.id)}`, summary: `Remove ${p.type} provider` });
3352
- console.log(import_chalk24.default.green(` ${p.type} removed.`));
3497
+ console.log(import_chalk25.default.green(` ${p.type} removed.`));
3353
3498
  } else {
3354
3499
  const s = await admin({ method: "GET", path: `${cBase}/providers/${encodeURIComponent(p.id)}/secret`, summary: `Reveal ${p.type} provider secret` });
3355
- console.log(` ${import_chalk24.default.bold("client_secret")}: ${import_chalk24.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3500
+ console.log(` ${import_chalk25.default.bold("client_secret")}: ${import_chalk25.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3356
3501
  }
3357
3502
  }
3358
3503
  }
@@ -3360,8 +3505,8 @@ async function providersMenu(cBase, clientLabel) {
3360
3505
 
3361
3506
  // src/commands/spec.ts
3362
3507
  var fs6 = __toESM(require("fs"));
3363
- var import_chalk25 = __toESM(require("chalk"));
3364
- var import_ora11 = __toESM(require("ora"));
3508
+ var import_chalk26 = __toESM(require("chalk"));
3509
+ var import_ora12 = __toESM(require("ora"));
3365
3510
  init_admin();
3366
3511
  async function runSpecGet(project, opts) {
3367
3512
  const { teamId } = await resolveTeam(opts.team);
@@ -3375,19 +3520,19 @@ async function runSpecGet(project, opts) {
3375
3520
  }
3376
3521
  async function runSpecSet(project, opts) {
3377
3522
  if (!opts.file) {
3378
- console.error(import_chalk25.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
3523
+ console.error(import_chalk26.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
3379
3524
  process.exit(1);
3380
3525
  }
3381
3526
  let specContent;
3382
3527
  try {
3383
3528
  specContent = fs6.readFileSync(opts.file, "utf-8");
3384
3529
  } catch {
3385
- console.error(import_chalk25.default.red(`Cannot read file: ${opts.file}`));
3530
+ console.error(import_chalk26.default.red(`Cannot read file: ${opts.file}`));
3386
3531
  process.exit(1);
3387
3532
  }
3388
3533
  const { teamId } = await resolveTeam(opts.team);
3389
3534
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
3390
- const spinner = (0, import_ora11.default)("Uploading spec...").start();
3535
+ const spinner = (0, import_ora12.default)("Uploading spec...").start();
3391
3536
  try {
3392
3537
  const out = await admin({
3393
3538
  method: "POST",
@@ -3404,12 +3549,12 @@ async function runSpecSet(project, opts) {
3404
3549
  }
3405
3550
 
3406
3551
  // src/commands/agent.ts
3407
- var import_chalk27 = __toESM(require("chalk"));
3408
- var import_ora12 = __toESM(require("ora"));
3552
+ var import_chalk28 = __toESM(require("chalk"));
3553
+ var import_ora13 = __toESM(require("ora"));
3409
3554
  init_auth();
3410
3555
 
3411
3556
  // src/lib/tools.ts
3412
- var import_chalk26 = __toESM(require("chalk"));
3557
+ var import_chalk27 = __toESM(require("chalk"));
3413
3558
  init_admin();
3414
3559
  init_api();
3415
3560
  async function proj(teamId, name, version2) {
@@ -3428,15 +3573,15 @@ var TOOLS = [
3428
3573
  const key = keys.dev ?? Object.values(keys)[0];
3429
3574
  const url = `https://${a.name}.abz.run/${version2}/dev`;
3430
3575
  const tryIt = buildTryItCurl(url, auth, key);
3431
- const lines = [` ${import_chalk26.default.dim("Proxy URL:")} ${import_chalk26.default.bold(url)}`];
3432
- if (res.devPortal) lines.push(` ${import_chalk26.default.dim("Dev portal:")} ${res.devPortal}`);
3576
+ const lines = [` ${import_chalk27.default.dim("Proxy URL:")} ${import_chalk27.default.bold(url)}`];
3577
+ if (res.devPortal) lines.push(` ${import_chalk27.default.dim("Dev portal:")} ${res.devPortal}`);
3433
3578
  const envs = Object.keys(keys);
3434
3579
  if (envs.length) {
3435
- lines.push("", ` ${import_chalk26.default.bold("API keys")} ${import_chalk26.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
3580
+ lines.push("", ` ${import_chalk27.default.bold("API keys")} ${import_chalk27.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
3436
3581
  const w = Math.max(...envs.map((e) => e.length));
3437
- for (const env of envs) lines.push(` ${import_chalk26.default.cyan(env.padEnd(w))} ${import_chalk26.default.green(keys[env])}`);
3582
+ for (const env of envs) lines.push(` ${import_chalk27.default.cyan(env.padEnd(w))} ${import_chalk27.default.green(keys[env])}`);
3438
3583
  }
3439
- if (tryIt) lines.push("", ` ${import_chalk26.default.dim("Try it:")}`, ` ${import_chalk26.default.cyan(tryIt)}`);
3584
+ if (tryIt) lines.push("", ` ${import_chalk27.default.dim("Try it:")}`, ` ${import_chalk27.default.cyan(tryIt)}`);
3440
3585
  return { ...res, proxy_url: url, keys, ...tryIt ? { try_it: tryIt } : {}, display: lines.join("\n") };
3441
3586
  }
3442
3587
  },
@@ -3592,23 +3737,23 @@ function truncate(value, max = 1500) {
3592
3737
  }
3593
3738
  function printCost(llm) {
3594
3739
  const usd = llm.cost > 0 ? `$${llm.cost.toFixed(4)}` : "<$0.0001";
3595
- console.log(import_chalk27.default.magenta(` \u{1F4B3} ${usd}`) + import_chalk27.default.dim(` (${llm.model}, ${llm.total_tokens} tok)`));
3740
+ console.log(import_chalk28.default.magenta(` \u{1F4B3} ${usd}`) + import_chalk28.default.dim(` (${llm.model}, ${llm.total_tokens} tok)`));
3596
3741
  }
3597
3742
  async function runAgent(opts) {
3598
3743
  requireAuth();
3599
3744
  const { teamId, teamName } = await resolveTeam(opts.team);
3600
3745
  const { default: inquirer2 } = await import("inquirer");
3601
- console.log(import_chalk27.default.bold("APIblaze agent") + import_chalk27.default.dim(` \xB7 team ${teamName ?? teamId}`));
3602
- console.log(import_chalk27.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
3746
+ console.log(import_chalk28.default.bold("APIblaze agent") + import_chalk28.default.dim(` \xB7 team ${teamName ?? teamId}`));
3747
+ console.log(import_chalk28.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
3603
3748
  const history = [];
3604
3749
  while (true) {
3605
- const { input } = await inquirer2.prompt([{ type: "input", name: "input", message: import_chalk27.default.cyan("you") + " \u203A" }]);
3750
+ const { input } = await inquirer2.prompt([{ type: "input", name: "input", message: import_chalk28.default.cyan("you") + " \u203A" }]);
3606
3751
  const text = (input ?? "").trim();
3607
3752
  if (!text) continue;
3608
3753
  if (["exit", "quit", ":q"].includes(text.toLowerCase())) break;
3609
3754
  history.push({ role: "user", content: text });
3610
3755
  for (let step = 0; step < MAX_TOOL_STEPS; step++) {
3611
- const spinner = (0, import_ora12.default)({ text: "thinking...", color: "magenta" }).start();
3756
+ const spinner = (0, import_ora13.default)({ text: "thinking...", color: "magenta" }).start();
3612
3757
  let resp;
3613
3758
  try {
3614
3759
  resp = await callAgent(history, teamId);
@@ -3616,21 +3761,21 @@ async function runAgent(opts) {
3616
3761
  } catch (err) {
3617
3762
  spinner.stop();
3618
3763
  if (err instanceof ApiError && err.status === 402) {
3619
- console.log(import_chalk27.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
3764
+ console.log(import_chalk28.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
3620
3765
  break;
3621
3766
  }
3622
3767
  throw err;
3623
3768
  }
3624
3769
  history.push({ role: "assistant", content: resp.raw });
3625
3770
  printCost(resp.llm);
3626
- if (resp.reply) console.log(import_chalk27.default.green("agent") + " \u203A " + resp.reply);
3771
+ if (resp.reply) console.log(import_chalk28.default.green("agent") + " \u203A " + resp.reply);
3627
3772
  if (!resp.action) break;
3628
3773
  const tool = findTool(resp.action.tool);
3629
3774
  if (!tool) {
3630
3775
  history.push({ role: "user", content: `TOOL_RESULT ${resp.action.tool}: error \u2014 unknown tool` });
3631
3776
  continue;
3632
3777
  }
3633
- const runSpinner = (0, import_ora12.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
3778
+ const runSpinner = (0, import_ora13.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
3634
3779
  try {
3635
3780
  const result = await tool.run(resp.action.args, { teamId });
3636
3781
  runSpinner.succeed(`${tool.name} \u2713`);
@@ -3648,11 +3793,11 @@ async function runAgent(opts) {
3648
3793
  }
3649
3794
  renderTrace();
3650
3795
  if (step === MAX_TOOL_STEPS - 1) {
3651
- console.log(import_chalk27.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
3796
+ console.log(import_chalk28.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
3652
3797
  }
3653
3798
  }
3654
3799
  }
3655
- console.log(import_chalk27.default.dim("\nBye."));
3800
+ console.log(import_chalk28.default.dim("\nBye."));
3656
3801
  }
3657
3802
 
3658
3803
  // src/commands/config-browse.ts
@@ -3815,11 +3960,11 @@ function dig(blob, dotted) {
3815
3960
  }
3816
3961
  var readSetting = (s, cfg) => s.read ? s.read(cfg) : dig(cfg, s.key);
3817
3962
  function show(v) {
3818
- if (v === void 0) return import_chalk28.default.dim("(unset)");
3819
- if (v === null) return import_chalk28.default.dim("null");
3820
- if (typeof v === "object") return import_chalk28.default.cyan(JSON.stringify(v));
3821
- if (typeof v === "boolean") return v ? import_chalk28.default.green("on") : import_chalk28.default.red("off");
3822
- return import_chalk28.default.cyan(String(v));
3963
+ if (v === void 0) return import_chalk29.default.dim("(unset)");
3964
+ if (v === null) return import_chalk29.default.dim("null");
3965
+ if (typeof v === "object") return import_chalk29.default.cyan(JSON.stringify(v));
3966
+ if (typeof v === "boolean") return v ? import_chalk29.default.green("on") : import_chalk29.default.red("off");
3967
+ return import_chalk29.default.cyan(String(v));
3823
3968
  }
3824
3969
  function parseValue(raw) {
3825
3970
  if (raw === "true") return true;
@@ -3846,7 +3991,7 @@ async function fetchConfigBlob(proj2) {
3846
3991
  }
3847
3992
  async function patchSetting(proj2, s, value, cfg) {
3848
3993
  const body = s.toPatch(value, cfg);
3849
- const spinner = (0, import_ora13.default)(`Set ${s.key}...`).start();
3994
+ const spinner = (0, import_ora14.default)(`Set ${s.key}...`).start();
3850
3995
  try {
3851
3996
  await admin({
3852
3997
  method: "PATCH",
@@ -3861,10 +4006,10 @@ async function patchSetting(proj2, s, value, cfg) {
3861
4006
  }
3862
4007
  }
3863
4008
  var loginFirst = (what) => {
3864
- console.log(import_chalk28.default.yellow(`
4009
+ console.log(import_chalk29.default.yellow(`
3865
4010
  Log in first to ${what}.`));
3866
- console.log(import_chalk28.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
3867
- console.log(import_chalk28.default.dim(" anonymously and want to bring it into your account.\n"));
4011
+ console.log(import_chalk29.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
4012
+ console.log(import_chalk29.default.dim(" anonymously and want to bring it into your account.\n"));
3868
4013
  };
3869
4014
  async function runConfig(project, key, value, opts) {
3870
4015
  const creds = loadCredentials();
@@ -3881,9 +4026,9 @@ async function runConfig(project, key, value, opts) {
3881
4026
  }
3882
4027
  const setting = SETTINGS.find((s) => s.key === key);
3883
4028
  if (!setting) {
3884
- console.error(import_chalk28.default.red(`Unknown setting "${key}".`));
3885
- console.error(import_chalk28.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
3886
- console.error(import_chalk28.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
4029
+ console.error(import_chalk29.default.red(`Unknown setting "${key}".`));
4030
+ console.error(import_chalk29.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
4031
+ console.error(import_chalk29.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
3887
4032
  process.exit(1);
3888
4033
  }
3889
4034
  if (value === void 0) {
@@ -3898,7 +4043,7 @@ async function pickProject(teamId) {
3898
4043
  const { getProjects: getProjects2 } = await Promise.resolve().then(() => (init_api(), api_exports));
3899
4044
  const projects = await getProjects2(teamId).catch(() => []);
3900
4045
  if (!projects.length) {
3901
- console.error(import_chalk28.default.red("No projects in this team. Create one: `npx apiblaze create`."));
4046
+ console.error(import_chalk29.default.red("No projects in this team. Create one: `npx apiblaze create`."));
3902
4047
  process.exit(1);
3903
4048
  }
3904
4049
  const { default: inquirer2 } = await import("inquirer");
@@ -3906,7 +4051,7 @@ async function pickProject(teamId) {
3906
4051
  type: "list",
3907
4052
  name: "picked",
3908
4053
  message: "Which project?",
3909
- choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk28.default.dim("v" + p.apiVersion)}`, value: p }))
4054
+ choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk29.default.dim("v" + p.apiVersion)}`, value: p }))
3910
4055
  }]);
3911
4056
  return { projectId: picked.projectId, projectName: picked.projectName, apiVersion: picked.apiVersion, teamId, tenant: picked.tenant };
3912
4057
  }
@@ -3917,25 +4062,25 @@ function printAll(proj2, cfg, json) {
3917
4062
  console.log(JSON.stringify(out, null, 2));
3918
4063
  return;
3919
4064
  }
3920
- console.log(import_chalk28.default.bold(`
4065
+ console.log(import_chalk29.default.bold(`
3921
4066
  ${proj2.projectName} v${proj2.apiVersion} \u2014 settings
3922
4067
  `));
3923
4068
  for (const group of SETTING_GROUPS) {
3924
- console.log(import_chalk28.default.bold(group));
4069
+ console.log(import_chalk29.default.bold(group));
3925
4070
  for (const s of SETTINGS.filter((x) => x.group === group)) {
3926
- console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk28.default.dim(s.desc)}`);
4071
+ console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk29.default.dim(s.desc)}`);
3927
4072
  }
3928
4073
  console.log();
3929
4074
  }
3930
- console.log(import_chalk28.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
4075
+ console.log(import_chalk29.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
3931
4076
  }
3932
4077
  async function discoveryMenu(project) {
3933
4078
  const { default: inquirer2 } = await import("inquirer");
3934
- console.log(import_chalk28.default.bold(`
4079
+ console.log(import_chalk29.default.bold(`
3935
4080
  APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
3936
4081
  `));
3937
- console.log(import_chalk28.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
3938
- console.log(import_chalk28.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
4082
+ console.log(import_chalk29.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
4083
+ console.log(import_chalk29.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
3939
4084
  for (; ; ) {
3940
4085
  const { pick: pick2 } = await inquirer2.prompt([{
3941
4086
  type: "list",
@@ -3943,13 +4088,13 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
3943
4088
  message: "Explore:",
3944
4089
  pageSize: 20,
3945
4090
  choices: [
3946
- new inquirer2.Separator(import_chalk28.default.bold("\u2014 Settings \u2014")),
4091
+ new inquirer2.Separator(import_chalk29.default.bold("\u2014 Settings \u2014")),
3947
4092
  ...SETTING_GROUPS.map((g) => ({
3948
- name: `${g} ${import_chalk28.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
4093
+ name: `${g} ${import_chalk29.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
3949
4094
  value: { kind: "settings", g }
3950
4095
  })),
3951
- new inquirer2.Separator(import_chalk28.default.bold("\u2014 Features \u2014")),
3952
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk28.default.dim(f.desc)}`, value: { kind: "feature", f } })),
4096
+ new inquirer2.Separator(import_chalk29.default.bold("\u2014 Features \u2014")),
4097
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk29.default.dim(f.desc)}`, value: { kind: "feature", f } })),
3953
4098
  new inquirer2.Separator(),
3954
4099
  { name: "Exit", value: { kind: "exit" } }
3955
4100
  ]
@@ -3958,24 +4103,24 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
3958
4103
  if (pick2.kind === "settings") {
3959
4104
  console.log();
3960
4105
  for (const s of SETTINGS.filter((x) => x.group === pick2.g)) {
3961
- console.log(` ${import_chalk28.default.bold(s.label.padEnd(28))} ${import_chalk28.default.dim(s.desc)}`);
3962
- console.log(` ${import_chalk28.default.dim(" key: " + s.key)}`);
4106
+ console.log(` ${import_chalk29.default.bold(s.label.padEnd(28))} ${import_chalk29.default.dim(s.desc)}`);
4107
+ console.log(` ${import_chalk29.default.dim(" key: " + s.key)}`);
3963
4108
  }
3964
4109
  loginFirst("view or change these settings");
3965
4110
  } else {
3966
4111
  const f = pick2.f;
3967
4112
  console.log(`
3968
- ${import_chalk28.default.bold(f.label)} \u2014 ${f.desc}`);
4113
+ ${import_chalk29.default.bold(f.label)} \u2014 ${f.desc}`);
3969
4114
  loginFirst(`use ${f.label.toLowerCase()}`);
3970
4115
  }
3971
4116
  }
3972
4117
  }
3973
4118
  async function navigator(proj2, cfg, opts) {
3974
4119
  const { default: inquirer2 } = await import("inquirer");
3975
- console.log(import_chalk28.default.bold(`
4120
+ console.log(import_chalk29.default.bold(`
3976
4121
  ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
3977
4122
  `));
3978
- console.log(import_chalk28.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
4123
+ console.log(import_chalk29.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
3979
4124
  let blob = cfg;
3980
4125
  for (; ; ) {
3981
4126
  const { pick: pick2 } = await inquirer2.prompt([{
@@ -3984,10 +4129,10 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
3984
4129
  message: "Where to?",
3985
4130
  pageSize: 20,
3986
4131
  choices: [
3987
- new inquirer2.Separator(import_chalk28.default.bold("\u2014 Settings \u2014")),
4132
+ new inquirer2.Separator(import_chalk29.default.bold("\u2014 Settings \u2014")),
3988
4133
  ...SETTING_GROUPS.map((g) => ({ name: g, value: { kind: "settings", g } })),
3989
- new inquirer2.Separator(import_chalk28.default.bold("\u2014 Features \u2014")),
3990
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk28.default.dim(f.desc)}`, value: { kind: f.go } })),
4134
+ new inquirer2.Separator(import_chalk29.default.bold("\u2014 Features \u2014")),
4135
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk29.default.dim(f.desc)}`, value: { kind: f.go } })),
3991
4136
  new inquirer2.Separator(),
3992
4137
  { name: "Show all settings", value: { kind: "list" } },
3993
4138
  { name: "Exit", value: { kind: "exit" } }
@@ -4027,7 +4172,7 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
4027
4172
  }
4028
4173
  }
4029
4174
  } catch (err) {
4030
- console.error(import_chalk28.default.red(` ${err instanceof Error ? err.message : String(err)}`));
4175
+ console.error(import_chalk29.default.red(` ${err instanceof Error ? err.message : String(err)}`));
4031
4176
  }
4032
4177
  }
4033
4178
  }
@@ -4041,7 +4186,7 @@ async function settingsGroup(proj2, cfg, group) {
4041
4186
  message: group + ":",
4042
4187
  pageSize: 16,
4043
4188
  choices: [
4044
- ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk28.default.dim(s2.desc)}`, value: s2 })),
4189
+ ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk29.default.dim(s2.desc)}`, value: s2 })),
4045
4190
  new inquirer2.Separator(),
4046
4191
  { name: "\u2190 Back", value: null }
4047
4192
  ]
@@ -4059,7 +4204,7 @@ async function settingsGroup(proj2, cfg, group) {
4059
4204
  } else if (s.type === "number") {
4060
4205
  const { v } = await inquirer2.prompt([{ type: "input", name: "v", message: `${s.label} (number):`, default: readSetting(s, cfg) }]);
4061
4206
  if (v === "" || Number.isNaN(Number(v))) {
4062
- console.log(import_chalk28.default.yellow(" Not a number \u2014 unchanged."));
4207
+ console.log(import_chalk29.default.yellow(" Not a number \u2014 unchanged."));
4063
4208
  continue;
4064
4209
  }
4065
4210
  value = Number(v);
@@ -4140,7 +4285,7 @@ async function buildCondition(phase) {
4140
4285
  const items = [];
4141
4286
  for (; ; ) {
4142
4287
  const a = await inquirer2.prompt([
4143
- { type: "input", name: "source", message: `Condition field ${import_chalk28.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
4288
+ { type: "input", name: "source", message: `Condition field ${import_chalk29.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
4144
4289
  { type: "list", name: "operator", message: "Operator:", choices: [
4145
4290
  "eq",
4146
4291
  "neq",
@@ -4171,7 +4316,7 @@ async function buildCondition(phase) {
4171
4316
  function showCondition(cond) {
4172
4317
  if (!Array.isArray(cond) || !cond.length) return "";
4173
4318
  const s = cond.map((c) => `${c.source} ${c.operator}${c.value !== void 0 ? ` "${c.value}"` : ""}${c.logicOp ? ` ${c.logicOp}` : ""}`).join(" ");
4174
- return import_chalk28.default.dim(` when ${s}`);
4319
+ return import_chalk29.default.dim(` when ${s}`);
4175
4320
  }
4176
4321
  async function transformsMenu(proj2) {
4177
4322
  const { default: inquirer2 } = await import("inquirer");
@@ -4180,12 +4325,12 @@ async function transformsMenu(proj2) {
4180
4325
  const out = await admin({ method: "GET", path: base, summary: "List transform rules" });
4181
4326
  const rules = out?.rules ?? [];
4182
4327
  console.log();
4183
- if (!rules.length) console.log(import_chalk28.default.dim(" No transform rules yet."));
4328
+ if (!rules.length) console.log(import_chalk29.default.dim(" No transform rules yet."));
4184
4329
  for (const r of rules) {
4185
4330
  const a = r.action ?? {};
4186
4331
  const fns = [...a.source_fns ?? [], ...a.dest_fns ?? []].map((f) => f.fn);
4187
- 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_chalk28.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
4188
- console.log(` ${r.enabled ? import_chalk28.default.green("\u25CF") : import_chalk28.default.dim("\u25CB")} ${import_chalk28.default.bold(r.name)} ${import_chalk28.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
4332
+ 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_chalk29.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
4333
+ console.log(` ${r.enabled ? import_chalk29.default.green("\u25CF") : import_chalk29.default.dim("\u25CB")} ${import_chalk29.default.bold(r.name)} ${import_chalk29.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
4189
4334
  }
4190
4335
  const { act } = await inquirer2.prompt([{
4191
4336
  type: "list",
@@ -4197,7 +4342,7 @@ async function transformsMenu(proj2) {
4197
4342
  { name: "Enable/disable a rule", value: "toggle" },
4198
4343
  { name: "Delete a rule", value: "delete" }
4199
4344
  ] : [],
4200
- { name: import_chalk28.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
4345
+ { name: import_chalk29.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
4201
4346
  { name: "\u2190 Back", value: "back" }
4202
4347
  ]
4203
4348
  }]);
@@ -4210,11 +4355,11 @@ async function transformsMenu(proj2) {
4210
4355
  }]);
4211
4356
  const body = parseValue(raw);
4212
4357
  if (!body || typeof body !== "object" || Array.isArray(body)) {
4213
- console.log(import_chalk28.default.yellow(" Not a JSON object \u2014 skipped."));
4358
+ console.log(import_chalk29.default.yellow(" Not a JSON object \u2014 skipped."));
4214
4359
  continue;
4215
4360
  }
4216
4361
  await admin({ method: "POST", path: base, body, summary: "Create transform rule (raw JSON)" });
4217
- console.log(import_chalk28.default.green(" Rule created."));
4362
+ console.log(import_chalk29.default.green(" Rule created."));
4218
4363
  continue;
4219
4364
  }
4220
4365
  if (act === "add") {
@@ -4230,7 +4375,7 @@ async function transformsMenu(proj2) {
4230
4375
  { name: "Remove a field", value: "remove" }
4231
4376
  ] }
4232
4377
  ]);
4233
- const fieldHint = import_chalk28.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
4378
+ const fieldHint = import_chalk29.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
4234
4379
  let action2;
4235
4380
  if (ans.kind === "hardcode") {
4236
4381
  const a = await inquirer2.prompt([
@@ -4261,7 +4406,7 @@ async function transformsMenu(proj2) {
4261
4406
  };
4262
4407
  }
4263
4408
  const condition = await buildCondition(ans.phase);
4264
- const spinner = (0, import_ora13.default)("Creating rule...").start();
4409
+ const spinner = (0, import_ora14.default)("Creating rule...").start();
4265
4410
  try {
4266
4411
  await admin({
4267
4412
  method: "POST",
@@ -4279,16 +4424,16 @@ async function transformsMenu(proj2) {
4279
4424
  type: "list",
4280
4425
  name: "rule",
4281
4426
  message: act === "toggle" ? "Which rule?" : "Delete which rule?",
4282
- choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk28.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
4427
+ choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk29.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
4283
4428
  }]);
4284
4429
  if (!rule) continue;
4285
4430
  if (act === "toggle") {
4286
4431
  const flipped = { ...rule, enabled: rule.enabled === false };
4287
4432
  await admin({ method: "PUT", path: `${base}/${rule.id}`, body: flipped, summary: `${flipped.enabled ? "Enable" : "Disable"} transform "${rule.name}"` });
4288
- console.log(import_chalk28.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
4433
+ console.log(import_chalk29.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
4289
4434
  } else {
4290
4435
  await admin({ method: "DELETE", path: `${base}/${rule.id}`, summary: `Delete transform "${rule.name}"` });
4291
- console.log(import_chalk28.default.green(` ${rule.name} deleted.`));
4436
+ console.log(import_chalk29.default.green(` ${rule.name} deleted.`));
4292
4437
  }
4293
4438
  }
4294
4439
  }
@@ -4300,9 +4445,9 @@ async function mappingsMenu(proj2) {
4300
4445
  const out = await admin({ method: "GET", path: base, summary: "List mapping tables" });
4301
4446
  const tables = out?.mappings ?? out?.tables ?? [];
4302
4447
  console.log();
4303
- if (!tables.length) console.log(import_chalk28.default.dim(" No mapping tables yet."));
4448
+ if (!tables.length) console.log(import_chalk29.default.dim(" No mapping tables yet."));
4304
4449
  for (const t of tables) {
4305
- console.log(` ${import_chalk28.default.bold(t.name)} ${import_chalk28.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
4450
+ console.log(` ${import_chalk29.default.bold(t.name)} ${import_chalk29.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
4306
4451
  }
4307
4452
  const { act } = await inquirer2.prompt([{
4308
4453
  type: "list",
@@ -4322,11 +4467,11 @@ async function mappingsMenu(proj2) {
4322
4467
  ]);
4323
4468
  const entries2 = parseValue(a.entries);
4324
4469
  if (!Array.isArray(entries2)) {
4325
- console.log(import_chalk28.default.yellow(" Entries must be a JSON array \u2014 not created."));
4470
+ console.log(import_chalk29.default.yellow(" Entries must be a JSON array \u2014 not created."));
4326
4471
  continue;
4327
4472
  }
4328
4473
  await admin({ method: "POST", path: base, body: { name: a.name, entries: entries2 }, summary: `Create mapping table "${a.name}"` });
4329
- console.log(import_chalk28.default.green(` Table "${a.name}" created.`));
4474
+ console.log(import_chalk29.default.green(` Table "${a.name}" created.`));
4330
4475
  } else {
4331
4476
  const { table } = await inquirer2.prompt([{
4332
4477
  type: "list",
@@ -4336,7 +4481,7 @@ async function mappingsMenu(proj2) {
4336
4481
  }]);
4337
4482
  if (!table) continue;
4338
4483
  await admin({ method: "DELETE", path: `${base}/${table.id}`, summary: `Delete mapping table "${table.name}"` });
4339
- console.log(import_chalk28.default.green(` ${table.name} deleted.`));
4484
+ console.log(import_chalk29.default.green(` ${table.name} deleted.`));
4340
4485
  }
4341
4486
  }
4342
4487
  }
@@ -4347,14 +4492,14 @@ async function tenantsMenu(proj2, opts) {
4347
4492
  const out = await admin({ method: "GET", path: base, summary: "List attached tenants" });
4348
4493
  const tenants = out?.tenants ?? [];
4349
4494
  console.log();
4350
- if (!tenants.length) console.log(import_chalk28.default.dim(" No tenants attached (consumers use the default tenant)."));
4351
- for (const t of tenants) console.log(` ${import_chalk28.default.bold(t.tenant_name ?? t.name)} ${import_chalk28.default.dim(t.display_name ?? "")}`);
4495
+ if (!tenants.length) console.log(import_chalk29.default.dim(" No tenants attached (consumers use the default tenant)."));
4496
+ for (const t of tenants) console.log(` ${import_chalk29.default.bold(t.tenant_name ?? t.name)} ${import_chalk29.default.dim(t.display_name ?? "")}`);
4352
4497
  const { act } = await inquirer2.prompt([{
4353
4498
  type: "list",
4354
4499
  name: "act",
4355
4500
  message: "Tenants:",
4356
4501
  choices: [
4357
- { name: `Manage a tenant\u2026 ${import_chalk28.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
4502
+ { name: `Manage a tenant\u2026 ${import_chalk29.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
4358
4503
  { name: "Attach a tenant to this project", value: "attach" },
4359
4504
  ...tenants.length ? [{ name: "Detach a tenant from this project", value: "detach" }] : [],
4360
4505
  { name: "\u2190 Back", value: "back" }
@@ -4377,7 +4522,7 @@ async function tenantsMenu(proj2, opts) {
4377
4522
  }]);
4378
4523
  if (!t) continue;
4379
4524
  await admin({ method: "DELETE", path: `${base}/${encodeURIComponent(t.tenant_name ?? t.name)}`, summary: `Detach tenant ${t.tenant_name ?? t.name}` });
4380
- console.log(import_chalk28.default.green(` Detached ${t.tenant_name ?? t.name}.`));
4525
+ console.log(import_chalk29.default.green(` Detached ${t.tenant_name ?? t.name}.`));
4381
4526
  }
4382
4527
  }
4383
4528
  }
@@ -4420,7 +4565,7 @@ async function specMenu(proj2, opts) {
4420
4565
  choices: [
4421
4566
  { name: "Print the stored spec", value: "get" },
4422
4567
  { name: "Refresh the spec from its source", value: "refresh" },
4423
- { name: import_chalk28.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
4568
+ { name: import_chalk29.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
4424
4569
  { name: "\u2190 Back", value: "back" }
4425
4570
  ]
4426
4571
  }]);
@@ -4428,7 +4573,7 @@ async function specMenu(proj2, opts) {
4428
4573
  if (act === "get") await runSpecGet(proj2.projectName, { team: opts.team, apiversion: proj2.apiVersion });
4429
4574
  else if (act === "refresh") {
4430
4575
  await admin({ method: "POST", path: `/projects/${proj2.projectId}/${proj2.apiVersion}/refresh-spec`, summary: "Refresh spec from source" });
4431
- console.log(import_chalk28.default.green(" Spec refresh triggered."));
4576
+ console.log(import_chalk29.default.green(" Spec refresh triggered."));
4432
4577
  } else await runOpenapi(proj2.projectName, proj2.apiVersion);
4433
4578
  }
4434
4579
  async function agentsMenu(proj2, opts) {
@@ -4453,8 +4598,8 @@ async function agentsMenu(proj2, opts) {
4453
4598
  }
4454
4599
 
4455
4600
  // src/commands/key.ts
4456
- var import_chalk29 = __toESM(require("chalk"));
4457
- var import_ora14 = __toESM(require("ora"));
4601
+ var import_chalk30 = __toESM(require("chalk"));
4602
+ var import_ora15 = __toESM(require("ora"));
4458
4603
  init_admin();
4459
4604
  async function runApikeysMenu(opts) {
4460
4605
  await runKeyList(opts);
@@ -4482,11 +4627,11 @@ async function runKeyList(opts) {
4482
4627
  return;
4483
4628
  }
4484
4629
  if (!keys.length) {
4485
- console.log(import_chalk29.default.yellow("No developer keys."));
4630
+ console.log(import_chalk30.default.yellow("No developer keys."));
4486
4631
  return;
4487
4632
  }
4488
4633
  for (const k of keys) {
4489
- console.log(` ${import_chalk29.default.bold(k.key_id ?? k.id)} ${import_chalk29.default.dim(k.description ?? "")} ${import_chalk29.default.dim(k.expires_at ?? "no expiry")}`);
4634
+ console.log(` ${import_chalk30.default.bold(k.key_id ?? k.id)} ${import_chalk30.default.dim(k.description ?? "")} ${import_chalk30.default.dim(k.expires_at ?? "no expiry")}`);
4490
4635
  }
4491
4636
  }
4492
4637
  async function runKeyMint(opts) {
@@ -4494,7 +4639,7 @@ async function runKeyMint(opts) {
4494
4639
  const body = { role: "consumer-admin" };
4495
4640
  if (opts.desc) body.description = opts.desc;
4496
4641
  if (opts.expiresDays) body.expires_in_seconds = Number(opts.expiresDays) * 24 * 60 * 60;
4497
- const spinner = (0, import_ora14.default)("Minting key...").start();
4642
+ const spinner = (0, import_ora15.default)("Minting key...").start();
4498
4643
  try {
4499
4644
  const out = await admin({
4500
4645
  method: "POST",
@@ -4507,9 +4652,9 @@ async function runKeyMint(opts) {
4507
4652
  console.log(JSON.stringify(out));
4508
4653
  return;
4509
4654
  }
4510
- console.log(` ${import_chalk29.default.bold("key_id")}: ${out?.key_id}`);
4511
- console.log(` ${import_chalk29.default.bold("key")}: ${import_chalk29.default.green(out?.key)} ${import_chalk29.default.dim("(shown once \u2014 store it now)")}`);
4512
- if (out?.expires_at) console.log(` ${import_chalk29.default.dim("expires:")} ${out.expires_at}`);
4655
+ console.log(` ${import_chalk30.default.bold("key_id")}: ${out?.key_id}`);
4656
+ console.log(` ${import_chalk30.default.bold("key")}: ${import_chalk30.default.green(out?.key)} ${import_chalk30.default.dim("(shown once \u2014 store it now)")}`);
4657
+ if (out?.expires_at) console.log(` ${import_chalk30.default.dim("expires:")} ${out.expires_at}`);
4513
4658
  } catch (err) {
4514
4659
  spinner.fail("Mint failed.");
4515
4660
  throw err;
@@ -4517,7 +4662,7 @@ async function runKeyMint(opts) {
4517
4662
  }
4518
4663
  async function runKeyRevoke(keyId, opts) {
4519
4664
  const { teamId } = await resolveTeam(opts.team);
4520
- const spinner = (0, import_ora14.default)("Revoking key...").start();
4665
+ const spinner = (0, import_ora15.default)("Revoking key...").start();
4521
4666
  try {
4522
4667
  await admin({
4523
4668
  method: "DELETE",
@@ -4532,8 +4677,8 @@ async function runKeyRevoke(keyId, opts) {
4532
4677
  }
4533
4678
 
4534
4679
  // src/commands/consumer.ts
4535
- var import_chalk30 = __toESM(require("chalk"));
4536
- var import_ora15 = __toESM(require("ora"));
4680
+ var import_chalk31 = __toESM(require("chalk"));
4681
+ var import_ora16 = __toESM(require("ora"));
4537
4682
  init_admin();
4538
4683
  var DEFAULT_SCOPE = "openid email profile offline_access";
4539
4684
  var APIKEYS_BASE = process.env.APIBLAZE_APIKEYS_BASE || "https://apikeys.apiblaze.com";
@@ -4553,7 +4698,7 @@ async function consumerFetch(creds, suffix, init) {
4553
4698
  function requireConsumer() {
4554
4699
  const c = loadConsumer();
4555
4700
  if (!c) {
4556
- console.error(import_chalk30.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
4701
+ console.error(import_chalk31.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
4557
4702
  process.exit(1);
4558
4703
  }
4559
4704
  return c;
@@ -4564,7 +4709,7 @@ async function runConsumerLogin(opts) {
4564
4709
  let clientId = opts.client;
4565
4710
  if (clientId) {
4566
4711
  if (!tenant2) {
4567
- console.error(import_chalk30.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
4712
+ console.error(import_chalk31.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
4568
4713
  process.exit(1);
4569
4714
  }
4570
4715
  } else {
@@ -4576,25 +4721,25 @@ async function runConsumerLogin(opts) {
4576
4721
  if (!picked) process.exit(1);
4577
4722
  tenant2 = picked;
4578
4723
  }
4579
- const s2 = (0, import_ora15.default)("Finding the login app...").start();
4724
+ const s2 = (0, import_ora16.default)("Finding the login app...").start();
4580
4725
  const clients = await admin({ method: "GET", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/app-clients`, summary: `List app clients for ${tenant2}` }).catch(() => []);
4581
4726
  s2.stop();
4582
4727
  const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
4583
4728
  const pick2 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
4584
4729
  if (!pick2) {
4585
- console.error(import_chalk30.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
4730
+ console.error(import_chalk31.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
4586
4731
  process.exit(1);
4587
4732
  }
4588
4733
  clientId = pick2.client_id ?? pick2.clientId;
4589
4734
  }
4590
4735
  const portalResource = `https://${tenant2}.portal.apiblaze.com/1.0.0`;
4591
- console.log(`${import_chalk30.default.cyan("\u2192")} Logging in to ${import_chalk30.default.bold(tenant2)} as a consumer...`);
4736
+ console.log(`${import_chalk31.default.cyan("\u2192")} Logging in to ${import_chalk31.default.bold(tenant2)} as a consumer...`);
4592
4737
  const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
4593
4738
  console.log(`
4594
- Open: ${import_chalk30.default.underline(verificationUri)}`);
4595
- console.log(` Code: ${import_chalk30.default.bold(userCode)}
4739
+ Open: ${import_chalk31.default.underline(verificationUri)}`);
4740
+ console.log(` Code: ${import_chalk31.default.bold(userCode)}
4596
4741
  `);
4597
- console.log(import_chalk30.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
4742
+ console.log(import_chalk31.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
4598
4743
  }, portalResource);
4599
4744
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
4600
4745
  const creds = {
@@ -4609,7 +4754,7 @@ async function runConsumerLogin(opts) {
4609
4754
  obtainedAt: Date.now()
4610
4755
  };
4611
4756
  saveConsumer(creds);
4612
- console.log(import_chalk30.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
4757
+ console.log(import_chalk31.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
4613
4758
  }
4614
4759
  async function runConsumerTokens(opts) {
4615
4760
  const creds = requireConsumer();
@@ -4622,29 +4767,29 @@ async function runConsumerTokens(opts) {
4622
4767
  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));
4623
4768
  return;
4624
4769
  }
4625
- console.log(`${import_chalk30.default.cyan("Consumer")} ${import_chalk30.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk30.default.bold(fresh.tenant)}
4770
+ console.log(`${import_chalk31.default.cyan("Consumer")} ${import_chalk31.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk31.default.bold(fresh.tenant)}
4626
4771
  `);
4627
- console.log(`${import_chalk30.default.bold("access_token")} ${import_chalk30.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
4772
+ console.log(`${import_chalk31.default.bold("access_token")} ${import_chalk31.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
4628
4773
  ${fresh.accessToken}
4629
4774
  `);
4630
- if (fresh.idToken) console.log(`${import_chalk30.default.bold("id_token")} ${import_chalk30.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
4775
+ if (fresh.idToken) console.log(`${import_chalk31.default.bold("id_token")} ${import_chalk31.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
4631
4776
  ${fresh.idToken}
4632
4777
  `);
4633
- if (fresh.refreshToken) console.log(`${import_chalk30.default.bold("refresh_token")}
4778
+ if (fresh.refreshToken) console.log(`${import_chalk31.default.bold("refresh_token")}
4634
4779
  ${fresh.refreshToken}
4635
4780
  `);
4636
- console.log(import_chalk30.default.dim("These are your own tokens \u2014 keep them secret."));
4781
+ console.log(import_chalk31.default.dim("These are your own tokens \u2014 keep them secret."));
4637
4782
  }
4638
4783
  async function runConsumerApikeys(opts) {
4639
4784
  const creds = requireConsumer();
4640
4785
  const { default: inquirer2 } = await import("inquirer");
4641
- const spinner = (0, import_ora15.default)("Loading your API keys...").start();
4786
+ const spinner = (0, import_ora16.default)("Loading your API keys...").start();
4642
4787
  const list = await consumerFetch(creds, "/apikeys");
4643
4788
  const revealed = await consumerFetch(list.creds, "/apikeys/reveal").catch(() => ({ status: 0, data: null, creds: list.creds }));
4644
4789
  spinner.stop();
4645
4790
  if (list.status >= 400) {
4646
- console.error(import_chalk30.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
4647
- if (list.status === 401) console.error(import_chalk30.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
4791
+ console.error(import_chalk31.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
4792
+ if (list.status === 401) console.error(import_chalk31.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
4648
4793
  process.exit(1);
4649
4794
  }
4650
4795
  const keys = list.data?.keys ?? [];
@@ -4652,16 +4797,16 @@ async function runConsumerApikeys(opts) {
4652
4797
  if (opts.json) {
4653
4798
  console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
4654
4799
  } else if (!keys.length) {
4655
- console.log(import_chalk30.default.yellow("No API keys yet."));
4800
+ console.log(import_chalk31.default.yellow("No API keys yet."));
4656
4801
  } else {
4657
4802
  for (const k of keys) {
4658
4803
  const clear = revealMap[k.environment]?.key;
4659
- const shown = clear ? import_chalk30.default.green(clear) : import_chalk30.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
4660
- const exp = k.expires_at ? import_chalk30.default.dim(`exp ${k.expires_at}`) : import_chalk30.default.dim("no expiry");
4661
- console.log(` ${import_chalk30.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk30.default.dim(k.description ?? "")}`);
4804
+ const shown = clear ? import_chalk31.default.green(clear) : import_chalk31.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
4805
+ const exp = k.expires_at ? import_chalk31.default.dim(`exp ${k.expires_at}`) : import_chalk31.default.dim("no expiry");
4806
+ console.log(` ${import_chalk31.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk31.default.dim(k.description ?? "")}`);
4662
4807
  }
4663
4808
  if (Object.keys(revealMap).length === 0 && keys.some((k) => !k.expires_at)) {
4664
- console.log(import_chalk30.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
4809
+ console.log(import_chalk31.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
4665
4810
  }
4666
4811
  }
4667
4812
  if (opts.json) return;
@@ -4675,7 +4820,7 @@ async function runConsumerApikeys(opts) {
4675
4820
  const body = { environment: answers.environment };
4676
4821
  if (answers.description) body.description = answers.description;
4677
4822
  if (answers.expiresDays) body.expires_in_seconds = Number(answers.expiresDays) * 86400;
4678
- const s2 = (0, import_ora15.default)("Creating key...").start();
4823
+ const s2 = (0, import_ora16.default)("Creating key...").start();
4679
4824
  const created = await consumerFetch(list.creds, "/apikeys", { method: "POST", body: JSON.stringify(body) });
4680
4825
  if (created.status >= 400) {
4681
4826
  s2.fail(`Create failed (${created.status}): ${created.data?.error ?? ""}`);
@@ -4683,13 +4828,13 @@ async function runConsumerApikeys(opts) {
4683
4828
  }
4684
4829
  s2.succeed("Key created.");
4685
4830
  const key = created.data?.key ?? created.data?.fullKey;
4686
- if (key) console.log(` ${import_chalk30.default.green(key)} ${import_chalk30.default.dim("(shown once \u2014 store it now)")}`);
4687
- else console.log(import_chalk30.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
4831
+ if (key) console.log(` ${import_chalk31.default.green(key)} ${import_chalk31.default.dim("(shown once \u2014 store it now)")}`);
4832
+ else console.log(import_chalk31.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
4688
4833
  }
4689
4834
 
4690
4835
  // src/commands/sidecar.ts
4691
- var import_chalk31 = __toESM(require("chalk"));
4692
- var import_ora16 = __toESM(require("ora"));
4836
+ var import_chalk32 = __toESM(require("chalk"));
4837
+ var import_ora17 = __toESM(require("ora"));
4693
4838
  var fs7 = __toESM(require("fs"));
4694
4839
  var path4 = __toESM(require("path"));
4695
4840
  init_admin();
@@ -4730,18 +4875,18 @@ function upsertEnvLocal(root, token) {
4730
4875
  }
4731
4876
  function installSidecarPackage(root) {
4732
4877
  if (fs7.existsSync(path4.join(root, "node_modules", "apiblaze", "package.json"))) {
4733
- console.log(` ${import_chalk31.default.green("\u2713")} apiblaze package already installed`);
4878
+ console.log(` ${import_chalk32.default.green("\u2713")} apiblaze package already installed`);
4734
4879
  return;
4735
4880
  }
4736
4881
  const has = (f) => fs7.existsSync(path4.join(root, f));
4737
4882
  const pm = has("bun.lockb") || has("bun.lock") ? { cmd: "bun", add: "add" } : has("pnpm-lock.yaml") ? { cmd: "pnpm", add: "add" } : has("yarn.lock") ? { cmd: "yarn", add: "add" } : { cmd: "npm", add: "install" };
4738
- const spinner = (0, import_ora16.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
4883
+ const spinner = (0, import_ora17.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
4739
4884
  try {
4740
4885
  const { execSync } = require("child_process");
4741
4886
  execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
4742
4887
  spinner.succeed("Installed apiblaze (the sidecar runtime).");
4743
4888
  } catch {
4744
- spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk31.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk31.default.cyan("npm run dev")}.`);
4889
+ spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk32.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk32.default.cyan("npm run dev")}.`);
4745
4890
  }
4746
4891
  }
4747
4892
  function readEnvKey(root) {
@@ -4880,7 +5025,7 @@ async function runAnonymousInit(root, router, opts) {
4880
5025
  const { sidecarInitAnonymous: sidecarInitAnonymous2 } = await Promise.resolve().then(() => (init_api(), api_exports));
4881
5026
  const { saveAnonCred: saveAnonCred2, clearAnonCred: clearAnonCred2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
4882
5027
  if (opts.newSession) clearAnonCred2();
4883
- const spinner = (0, import_ora16.default)("Setting up a sidecar (no login needed)...").start();
5028
+ const spinner = (0, import_ora17.default)("Setting up a sidecar (no login needed)...").start();
4884
5029
  let out;
4885
5030
  try {
4886
5031
  out = await sidecarInitAnonymous2();
@@ -4892,29 +5037,29 @@ async function runAnonymousInit(root, router, opts) {
4892
5037
  if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
4893
5038
  const envState = upsertEnvLocal(root, out.token);
4894
5039
  ensureGitignored(root);
4895
- console.log(` ${import_chalk31.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
4896
- console.log(` ${import_chalk31.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
5040
+ console.log(` ${import_chalk32.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
5041
+ console.log(` ${import_chalk32.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
4897
5042
  installSidecarPackage(root);
4898
5043
  let inspectorPath = null;
4899
5044
  if (!opts.noInspector) {
4900
5045
  inspectorPath = generateInspector(root, router);
4901
- if (inspectorPath) console.log(` ${import_chalk31.default.green("\u2713")} inspector at ${inspectorPath}`);
5046
+ if (inspectorPath) console.log(` ${import_chalk32.default.green("\u2713")} inspector at ${inspectorPath}`);
4902
5047
  }
4903
5048
  console.log("");
4904
- console.log(import_chalk31.default.bold("Done (no account needed). What happens next:"));
4905
- console.log(` 1. ${import_chalk31.default.cyan("npm run dev")} and use your app.`);
5049
+ console.log(import_chalk32.default.bold("Done (no account needed). What happens next:"));
5050
+ console.log(` 1. ${import_chalk32.default.cyan("npm run dev")} and use your app.`);
4906
5051
  console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
4907
- console.log(` ${import_chalk31.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
5052
+ console.log(` ${import_chalk32.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
4908
5053
  console.log("");
4909
- console.log(import_chalk31.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
4910
- console.log(` ${import_chalk31.default.cyan("apiblaze login")} then ${import_chalk31.default.cyan("apiblaze claim")} ${import_chalk31.default.dim("(no code needed here)")}`);
4911
- console.log(import_chalk31.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
5054
+ console.log(import_chalk32.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
5055
+ console.log(` ${import_chalk32.default.cyan("apiblaze login")} then ${import_chalk32.default.cyan("apiblaze claim")} ${import_chalk32.default.dim("(no code needed here)")}`);
5056
+ console.log(import_chalk32.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
4912
5057
  }
4913
5058
  async function runSidecar(opts) {
4914
5059
  const root = path4.resolve(opts.dir ?? process.cwd());
4915
5060
  const detected = detectNextProject(root);
4916
5061
  if (!detected.found) {
4917
- console.log(import_chalk31.default.yellow(`No Next.js project detected in ${root}.`));
5062
+ console.log(import_chalk32.default.yellow(`No Next.js project detected in ${root}.`));
4918
5063
  console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
4919
5064
  return;
4920
5065
  }
@@ -4925,10 +5070,10 @@ async function runSidecar(opts) {
4925
5070
  if (!loadCredentials()) {
4926
5071
  upsertEnvLocal(root, readEnvKey(root));
4927
5072
  ensureGitignored(root);
4928
- console.log(` ${import_chalk31.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
4929
- console.log(` ${import_chalk31.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
5073
+ console.log(` ${import_chalk32.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
5074
+ console.log(` ${import_chalk32.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
4930
5075
  installSidecarPackage(root);
4931
- console.log(import_chalk31.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
5076
+ console.log(import_chalk32.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
4932
5077
  return;
4933
5078
  }
4934
5079
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -4937,7 +5082,7 @@ async function runSidecar(opts) {
4937
5082
  const mustMint = !existingKey || opts.rotate || switchingTeam;
4938
5083
  let token = existingKey ?? "";
4939
5084
  if (mustMint) {
4940
- const spinner = (0, import_ora16.default)(existingKey ? "Re-establishing the sidecar (minting a fresh invoke key)..." : "Setting up the sidecar (tenant + non-expiring invoke key)...").start();
5085
+ const spinner = (0, import_ora17.default)(existingKey ? "Re-establishing the sidecar (minting a fresh invoke key)..." : "Setting up the sidecar (tenant + non-expiring invoke key)...").start();
4941
5086
  try {
4942
5087
  const out = await admin({
4943
5088
  method: "POST",
@@ -4951,39 +5096,39 @@ async function runSidecar(opts) {
4951
5096
  throw err;
4952
5097
  }
4953
5098
  } else {
4954
- console.log(import_chalk31.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
5099
+ console.log(import_chalk32.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
4955
5100
  }
4956
5101
  const envState = upsertEnvLocal(root, token);
4957
5102
  ensureGitignored(root);
4958
- console.log(` ${import_chalk31.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
5103
+ console.log(` ${import_chalk32.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
4959
5104
  const wireState = wireInstrumentation(root);
4960
- console.log(` ${import_chalk31.default.green("\u2713")} instrumentation.ts ${wireState}`);
5105
+ console.log(` ${import_chalk32.default.green("\u2713")} instrumentation.ts ${wireState}`);
4961
5106
  installSidecarPackage(root);
4962
5107
  let inspectorPath = null;
4963
5108
  if (!opts.noInspector) {
4964
5109
  inspectorPath = generateInspector(root, detected.router);
4965
- if (inspectorPath) console.log(` ${import_chalk31.default.green("\u2713")} inspector at ${inspectorPath}`);
5110
+ if (inspectorPath) console.log(` ${import_chalk32.default.green("\u2713")} inspector at ${inspectorPath}`);
4966
5111
  }
4967
5112
  console.log("");
4968
- console.log(import_chalk31.default.bold("Done. What happens next:"));
4969
- console.log(` 1. ${import_chalk31.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
4970
- console.log(` 2. The origins your app calls appear as ${import_chalk31.default.bold("candidates")} \u2014 list them: ${import_chalk31.default.cyan("apiblaze sidecar")}`);
4971
- console.log(` 3. Approve the ones to route: ${import_chalk31.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
5113
+ console.log(import_chalk32.default.bold("Done. What happens next:"));
5114
+ console.log(` 1. ${import_chalk32.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
5115
+ console.log(` 2. The origins your app calls appear as ${import_chalk32.default.bold("candidates")} \u2014 list them: ${import_chalk32.default.cyan("apiblaze sidecar")}`);
5116
+ console.log(` 3. Approve the ones to route: ${import_chalk32.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
4972
5117
  console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
4973
- if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk31.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path4.dirname(inspectorPath)} before shipping)`);
4974
- if (switchingTeam) console.log(import_chalk31.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
5118
+ if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk32.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path4.dirname(inspectorPath)} before shipping)`);
5119
+ if (switchingTeam) console.log(import_chalk32.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
4975
5120
  console.log("");
4976
- console.log(import_chalk31.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
4977
- console.log(import_chalk31.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
4978
- console.log(import_chalk31.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
5121
+ console.log(import_chalk32.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
5122
+ console.log(import_chalk32.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
5123
+ console.log(import_chalk32.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
4979
5124
  console.log("");
4980
- console.log(import_chalk31.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
4981
- console.log(import_chalk31.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
5125
+ console.log(import_chalk32.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
5126
+ console.log(import_chalk32.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
4982
5127
  }
4983
5128
 
4984
5129
  // src/commands/origins.ts
4985
- var import_chalk32 = __toESM(require("chalk"));
4986
- var import_ora17 = __toESM(require("ora"));
5130
+ var import_chalk33 = __toESM(require("chalk"));
5131
+ var import_ora18 = __toESM(require("ora"));
4987
5132
  init_admin();
4988
5133
  init_auth();
4989
5134
  init_anon_cred();
@@ -4992,7 +5137,7 @@ async function runOriginsList(opts) {
4992
5137
  if (!loadCredentials()) {
4993
5138
  const cred = loadAnonCred();
4994
5139
  if (!cred) {
4995
- console.log(import_chalk32.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
5140
+ console.log(import_chalk33.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
4996
5141
  return;
4997
5142
  }
4998
5143
  out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
@@ -5010,30 +5155,30 @@ async function runOriginsList(opts) {
5010
5155
  }
5011
5156
  const routed = out.routed ?? [];
5012
5157
  const candidates = out.candidates ?? [];
5013
- console.log(import_chalk32.default.bold(`
5158
+ console.log(import_chalk33.default.bold(`
5014
5159
  Routed through APIblaze (${routed.length})`));
5015
- if (!routed.length) console.log(import_chalk32.default.dim(" none yet"));
5016
- for (const r of routed) console.log(` ${import_chalk32.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk32.default.dim(`\u2192 ${r.project_id}`)}`);
5017
- console.log(import_chalk32.default.bold(`
5160
+ if (!routed.length) console.log(import_chalk33.default.dim(" none yet"));
5161
+ for (const r of routed) console.log(` ${import_chalk33.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk33.default.dim(`\u2192 ${r.project_id}`)}`);
5162
+ console.log(import_chalk33.default.bold(`
5018
5163
  Candidates \u2014 going direct, not yet approved (${candidates.length})`));
5019
- if (!candidates.length) console.log(import_chalk32.default.dim(" none \u2014 run your app to discover the origins it calls"));
5164
+ if (!candidates.length) console.log(import_chalk33.default.dim(" none \u2014 run your app to discover the origins it calls"));
5020
5165
  for (const c of candidates) {
5021
- console.log(` ${import_chalk32.default.yellow("\u25CB")} ${c.origin} ${import_chalk32.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
5166
+ console.log(` ${import_chalk33.default.yellow("\u25CB")} ${c.origin} ${import_chalk33.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
5022
5167
  }
5023
5168
  if (candidates.length) {
5024
- console.log(import_chalk32.default.dim(`
5169
+ console.log(import_chalk33.default.dim(`
5025
5170
  Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
5026
- console.log(import_chalk32.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
5171
+ console.log(import_chalk33.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
5027
5172
  }
5028
5173
  }
5029
5174
  async function runOriginsApprove(origin, opts) {
5030
5175
  if (!loadCredentials()) {
5031
5176
  const cred = loadAnonCred();
5032
5177
  if (!cred) {
5033
- console.error(import_chalk32.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
5178
+ console.error(import_chalk33.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
5034
5179
  process.exit(1);
5035
5180
  }
5036
- const spinner2 = (0, import_ora17.default)(`Approving ${origin} (anonymous)...`).start();
5181
+ const spinner2 = (0, import_ora18.default)(`Approving ${origin} (anonymous)...`).start();
5037
5182
  try {
5038
5183
  const out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/approve`, { method: "POST", body: JSON.stringify({ origin }) });
5039
5184
  spinner2.succeed(`Approved ${origin} \u2192 proxy ${out.project_id}. Routing within ~5 min.`);
@@ -5044,7 +5189,7 @@ async function runOriginsApprove(origin, opts) {
5044
5189
  return;
5045
5190
  }
5046
5191
  const { teamId } = await resolveTeam(opts.team);
5047
- const spinner = (0, import_ora17.default)(`Approving ${origin}...`).start();
5192
+ const spinner = (0, import_ora18.default)(`Approving ${origin}...`).start();
5048
5193
  try {
5049
5194
  const out = await admin({
5050
5195
  method: "POST",
@@ -5061,7 +5206,7 @@ async function runOriginsApprove(origin, opts) {
5061
5206
  }
5062
5207
  async function runOriginsDeny(origin, opts) {
5063
5208
  const { teamId } = await resolveTeam(opts.team);
5064
- const spinner = (0, import_ora17.default)(`Dismissing ${origin}...`).start();
5209
+ const spinner = (0, import_ora18.default)(`Dismissing ${origin}...`).start();
5065
5210
  try {
5066
5211
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/dismiss`, body: { origin }, summary: `Dismiss sidecar origin ${origin}` });
5067
5212
  spinner.succeed(`Dismissed ${origin}. It won't be suggested again.`);
@@ -5072,7 +5217,7 @@ async function runOriginsDeny(origin, opts) {
5072
5217
  }
5073
5218
  async function runOriginsRemove(origin, opts) {
5074
5219
  const { teamId } = await resolveTeam(opts.team);
5075
- const spinner = (0, import_ora17.default)(`Removing the proxy for ${origin}...`).start();
5220
+ const spinner = (0, import_ora18.default)(`Removing the proxy for ${origin}...`).start();
5076
5221
  try {
5077
5222
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/remove`, body: { origin }, summary: `Un-route sidecar origin ${origin}` });
5078
5223
  spinner.succeed(`Removed ${origin}. Your app will stop routing it (goes direct) within ~5 min.`);
@@ -5083,7 +5228,7 @@ async function runOriginsRemove(origin, opts) {
5083
5228
  }
5084
5229
 
5085
5230
  // src/commands/op.ts
5086
- var import_chalk33 = __toESM(require("chalk"));
5231
+ var import_chalk34 = __toESM(require("chalk"));
5087
5232
  init_auth();
5088
5233
  init_trace();
5089
5234
  init_types();
@@ -5116,82 +5261,82 @@ function printResidue(report, applied) {
5116
5261
  const up = report?.upstash ?? {};
5117
5262
  const fga = report?.fga ?? {};
5118
5263
  const ghosts = report?.ghosts ?? {};
5119
- console.log(import_chalk33.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
5120
- console.log(import_chalk33.default.bold("\n Upstash"));
5264
+ console.log(import_chalk34.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
5265
+ console.log(import_chalk34.default.bold("\n Upstash"));
5121
5266
  const orphans = up.orphans ?? [];
5122
- if (orphans.length === 0) console.log(import_chalk33.default.green(" no orphaned keys"));
5123
- for (const o of orphans) console.log(` ${import_chalk33.default.yellow(o.key)} ${import_chalk33.default.dim(`\u2014 ${o.reason}`)}`);
5124
- console.log(import_chalk33.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
5267
+ if (orphans.length === 0) console.log(import_chalk34.default.green(" no orphaned keys"));
5268
+ for (const o of orphans) console.log(` ${import_chalk34.default.yellow(o.key)} ${import_chalk34.default.dim(`\u2014 ${o.reason}`)}`);
5269
+ console.log(import_chalk34.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
5125
5270
  if (up.anon_wallet_detail) {
5126
5271
  const d = up.anon_wallet_detail;
5127
- console.log(import_chalk33.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)"}`));
5272
+ console.log(import_chalk34.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)"}`));
5128
5273
  }
5129
5274
  if (up.keyspace_census) {
5130
5275
  const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
5131
- console.log(import_chalk33.default.dim(` keyspace: ${census}`));
5276
+ console.log(import_chalk34.default.dim(` keyspace: ${census}`));
5132
5277
  }
5133
- if (up.unknown?.length) console.log(import_chalk33.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
5134
- if (applied) console.log(` ${import_chalk33.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
5135
- for (const e of up.errors ?? []) console.log(import_chalk33.default.red(` error: ${e}`));
5136
- console.log(import_chalk33.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
5278
+ if (up.unknown?.length) console.log(import_chalk34.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
5279
+ if (applied) console.log(` ${import_chalk34.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
5280
+ for (const e of up.errors ?? []) console.log(import_chalk34.default.red(` error: ${e}`));
5281
+ console.log(import_chalk34.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
5137
5282
  if (applied) {
5138
5283
  const swept = fga?.swept ?? [];
5139
- if (swept.length === 0) console.log(import_chalk33.default.green(" no orphaned stores"));
5284
+ if (swept.length === 0) console.log(import_chalk34.default.green(" no orphaned stores"));
5140
5285
  for (const s of swept) {
5141
5286
  console.log(
5142
- ` ${import_chalk33.default.yellow(s.store_id)} ${import_chalk33.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
5287
+ ` ${import_chalk34.default.yellow(s.store_id)} ${import_chalk34.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
5143
5288
  );
5144
5289
  }
5145
- if (fga?.remaining) console.log(import_chalk33.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
5290
+ if (fga?.remaining) console.log(import_chalk34.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
5146
5291
  const st = fga?.side_tables;
5147
- if (st) console.log(import_chalk33.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})` : ""}`));
5292
+ if (st) console.log(import_chalk34.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})` : ""}`));
5148
5293
  } else {
5149
5294
  const fgaOrphans = fga?.orphans ?? [];
5150
- if (fgaOrphans.length === 0) console.log(import_chalk33.default.green(" no orphaned stores"));
5295
+ if (fgaOrphans.length === 0) console.log(import_chalk34.default.green(" no orphaned stores"));
5151
5296
  for (const s of fgaOrphans) {
5152
5297
  const src = s.in_openfga ? "live in OpenFGA" : "Neon tuples only";
5153
- console.log(` ${import_chalk33.default.yellow(s.store_id)} ${import_chalk33.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
5298
+ console.log(` ${import_chalk34.default.yellow(s.store_id)} ${import_chalk34.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
5154
5299
  }
5155
- console.log(import_chalk33.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
5300
+ console.log(import_chalk34.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
5156
5301
  const st = fga?.side_tables;
5157
- if (st) console.log(import_chalk33.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`));
5302
+ if (st) console.log(import_chalk34.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`));
5158
5303
  }
5159
- for (const e of fga?.errors ?? []) console.log(import_chalk33.default.red(` error: ${e}`));
5160
- console.log(import_chalk33.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
5304
+ for (const e of fga?.errors ?? []) console.log(import_chalk34.default.red(` error: ${e}`));
5305
+ console.log(import_chalk34.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
5161
5306
  if (applied) {
5162
- if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk33.default.green(" no ghost tuples"));
5163
- else console.log(` ${import_chalk33.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk33.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
5307
+ if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk34.default.green(" no ghost tuples"));
5308
+ else console.log(` ${import_chalk34.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk34.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
5164
5309
  } else {
5165
5310
  const n = ghosts?.ghost_count ?? 0;
5166
- if (n === 0) console.log(import_chalk33.default.green(` no ghost tuples ${import_chalk33.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
5311
+ if (n === 0) console.log(import_chalk34.default.green(` no ghost tuples ${import_chalk34.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
5167
5312
  else {
5168
- console.log(import_chalk33.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
5313
+ console.log(import_chalk34.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
5169
5314
  for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
5170
- console.log(import_chalk33.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
5315
+ console.log(import_chalk34.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
5171
5316
  }
5172
- if (n > 20) console.log(import_chalk33.default.dim(` \u2026 and ${n - 20} more`));
5317
+ if (n > 20) console.log(import_chalk34.default.dim(` \u2026 and ${n - 20} more`));
5173
5318
  }
5174
5319
  }
5175
- for (const e of ghosts?.errors ?? []) console.log(import_chalk33.default.red(` error: ${e}`));
5320
+ for (const e of ghosts?.errors ?? []) console.log(import_chalk34.default.red(` error: ${e}`));
5176
5321
  console.log();
5177
5322
  }
5178
5323
  async function runOp(sub, opts = {}) {
5179
5324
  if (!loadCredentials()) {
5180
- console.log(import_chalk33.default.dim("Not logged in. Run `apiblaze login`."));
5325
+ console.log(import_chalk34.default.dim("Not logged in. Run `apiblaze login`."));
5181
5326
  return;
5182
5327
  }
5183
5328
  if (!isOperatorLogin()) {
5184
- console.log(import_chalk33.default.dim("`apiblaze op` is only available to platform operators."));
5329
+ console.log(import_chalk34.default.dim("`apiblaze op` is only available to platform operators."));
5185
5330
  return;
5186
5331
  }
5187
5332
  switch (sub) {
5188
5333
  case void 0:
5189
5334
  case "menu": {
5190
- console.log(import_chalk33.default.bold("\nOperator menu"));
5191
- console.log(` ${import_chalk33.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
5192
- console.log(` ${import_chalk33.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk33.default.dim("-y to skip")})`);
5193
- console.log(` ${import_chalk33.default.cyan("apiblaze op credits")} list credit wallets`);
5194
- console.log(import_chalk33.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
5335
+ console.log(import_chalk34.default.bold("\nOperator menu"));
5336
+ console.log(` ${import_chalk34.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
5337
+ console.log(` ${import_chalk34.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk34.default.dim("-y to skip")})`);
5338
+ console.log(` ${import_chalk34.default.cyan("apiblaze op credits")} list credit wallets`);
5339
+ console.log(import_chalk34.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
5195
5340
  `));
5196
5341
  return;
5197
5342
  }
@@ -5210,17 +5355,17 @@ async function runOp(sub, opts = {}) {
5210
5355
  const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
5211
5356
  printResidue(report, false);
5212
5357
  if (nUp + nFga + nGhost + nSide === 0) {
5213
- console.log(import_chalk33.default.green("Nothing to sweep."));
5358
+ console.log(import_chalk34.default.green("Nothing to sweep."));
5214
5359
  return;
5215
5360
  }
5216
5361
  if (!opts.yes) {
5217
5362
  const readline2 = await import("readline/promises");
5218
5363
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
5219
5364
  const answer = await rl.question(
5220
- import_chalk33.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: `)
5365
+ import_chalk34.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: `)
5221
5366
  );
5222
5367
  rl.close();
5223
- if (answer.trim() !== "sweep") return void console.log(import_chalk33.default.dim("Aborted."));
5368
+ if (answer.trim() !== "sweep") return void console.log(import_chalk34.default.dim("Aborted."));
5224
5369
  }
5225
5370
  const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
5226
5371
  if (opts.json) return void console.log(JSON.stringify(result, null, 2));
@@ -5231,15 +5376,15 @@ async function runOp(sub, opts = {}) {
5231
5376
  const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list credit wallets" });
5232
5377
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
5233
5378
  const accounts = data?.accounts ?? [];
5234
- if (accounts.length === 0) return void console.log(import_chalk33.default.dim("No credit wallets."));
5379
+ if (accounts.length === 0) return void console.log(import_chalk34.default.dim("No credit wallets."));
5235
5380
  for (const a of accounts) {
5236
5381
  const bal = typeof a.balance_cents === "number" ? `$${(a.balance_cents / 100).toFixed(2)}` : "?";
5237
- console.log(` ${import_chalk33.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk33.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk33.default.dim(" \u2014 anon") : ""}`);
5382
+ console.log(` ${import_chalk34.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk34.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk34.default.dim(" \u2014 anon") : ""}`);
5238
5383
  }
5239
5384
  return;
5240
5385
  }
5241
5386
  default:
5242
- console.log(import_chalk33.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
5387
+ console.log(import_chalk34.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
5243
5388
  }
5244
5389
  }
5245
5390
 
@@ -5296,7 +5441,7 @@ program.command("dev").description("Put your localhost behind a public URL (dev
5296
5441
  try {
5297
5442
  const resolved = parseInt(port ?? opts.port, 10);
5298
5443
  if (Number.isNaN(resolved)) {
5299
- console.error(import_chalk34.default.red(`Invalid port: ${port ?? opts.port}`));
5444
+ console.error(import_chalk35.default.red(`Invalid port: ${port ?? opts.port}`));
5300
5445
  process.exit(1);
5301
5446
  }
5302
5447
  await runDev({ port: resolved, captureFile: opts.captureFile });
@@ -5394,7 +5539,7 @@ function groupedCommandHelp() {
5394
5539
  const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
5395
5540
  return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
5396
5541
  }).filter(Boolean).join("\n");
5397
- return `${import_chalk34.default.bold(g.title)}
5542
+ return `${import_chalk35.default.bold(g.title)}
5398
5543
  ${rows}`;
5399
5544
  }).join("\n\n");
5400
5545
  }
@@ -5427,14 +5572,14 @@ async function recoverStaleTeam() {
5427
5572
  const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
5428
5573
  const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
5429
5574
  if (!linked) {
5430
- console.error(import_chalk34.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
5575
+ console.error(import_chalk35.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
5431
5576
  return;
5432
5577
  }
5433
5578
  if (linked.teamId === creds.teamId) return;
5434
5579
  const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
5435
5580
  delete next.activeTenant;
5436
5581
  saveCredentials(next);
5437
- console.error(import_chalk34.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk34.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
5582
+ console.error(import_chalk35.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk35.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
5438
5583
  } catch {
5439
5584
  }
5440
5585
  }
@@ -5442,16 +5587,16 @@ async function printError(err) {
5442
5587
  if (err instanceof ApiError) {
5443
5588
  const data = err.body;
5444
5589
  const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
5445
- console.error(import_chalk34.default.red(`
5590
+ console.error(import_chalk35.default.red(`
5446
5591
  API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
5447
5592
  if (err.status === 403 || err.status === 404) {
5448
5593
  await recoverStaleTeam();
5449
5594
  }
5450
5595
  } else if (err instanceof Error) {
5451
- console.error(import_chalk34.default.red(`
5596
+ console.error(import_chalk35.default.red(`
5452
5597
  Error: ${err.message}`));
5453
5598
  } else {
5454
- console.error(import_chalk34.default.red("\nUnknown error"));
5599
+ console.error(import_chalk35.default.red("\nUnknown error"));
5455
5600
  }
5456
5601
  }
5457
5602
  program.parse(process.argv);