apiblaze 0.15.1 → 0.16.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 +440 -345
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -457,6 +457,139 @@ 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
+ createTenantInteractive: () => createTenantInteractive
464
+ });
465
+ async function createTenantRow(teamId) {
466
+ const { default: inquirer2 } = await import("inquirer");
467
+ for (; ; ) {
468
+ const { name } = await inquirer2.prompt([{
469
+ type: "input",
470
+ name: "name",
471
+ message: `Tenant name ${import_chalk22.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
472
+ validate: (s) => /^[a-z0-9]+$/.test(s.trim()) ? true : "lowercase letters and numbers only"
473
+ }]);
474
+ const slug = name.trim();
475
+ try {
476
+ const out = await admin({
477
+ method: "POST",
478
+ path: `/teams/${encodeURIComponent(teamId)}/tenants`,
479
+ body: { tenant_name: slug, display_name: slug },
480
+ summary: `Create tenant "${slug}"`
481
+ });
482
+ return out?.tenant_name ?? out?.tenant?.tenant_name ?? slug;
483
+ } catch (err) {
484
+ const msg = err instanceof Error ? err.message : String(err);
485
+ if (/taken|unique|exists|reserved|conflict/i.test(msg)) {
486
+ console.log(import_chalk22.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
487
+ continue;
488
+ }
489
+ throw err;
490
+ }
491
+ }
492
+ }
493
+ async function setUpLogin(teamId, tenant2) {
494
+ const { default: inquirer2 } = await import("inquirer");
495
+ const base = `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}`;
496
+ const { provider } = await inquirer2.prompt([{
497
+ type: "list",
498
+ name: "provider",
499
+ message: "How do people log in?",
500
+ pageSize: 10,
501
+ choices: [
502
+ ...PROVIDERS.map((p) => ({ name: p.label, value: p.id })),
503
+ new inquirer2.Separator(),
504
+ { 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;
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
+ } catch (err) {
546
+ spinner.fail("Login setup failed (the tenant was still created).");
547
+ throw err;
548
+ }
549
+ }
550
+ async function createTenantInteractive(teamId) {
551
+ const { default: inquirer2 } = await import("inquirer");
552
+ const tenant2 = await createTenantRow(teamId);
553
+ console.log(import_chalk22.default.green(` Tenant ${import_chalk22.default.bold(tenant2)} created.`));
554
+ const { users } = await inquirer2.prompt([{
555
+ type: "confirm",
556
+ name: "users",
557
+ default: false,
558
+ message: `Enable Users & groups? ${import_chalk22.default.dim(`(identity/key management at ${tenant2}.iam.apiblaze.com)`)}`
559
+ }]);
560
+ if (users) {
561
+ await admin({ method: "PATCH", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/iam`, body: { enabled: true }, summary: "Enable Users & groups" }).catch(() => {
562
+ });
563
+ console.log(import_chalk22.default.green(" Users & groups enabled."));
564
+ }
565
+ await setUpLogin(teamId, tenant2);
566
+ return tenant2;
567
+ }
568
+ var import_chalk22, import_ora8, PROVIDERS, DEFAULT_SCOPES;
569
+ var init_tenant_create = __esm({
570
+ "src/lib/tenant-create.ts"() {
571
+ "use strict";
572
+ import_chalk22 = __toESM(require("chalk"));
573
+ import_ora8 = __toESM(require("ora"));
574
+ init_admin();
575
+ PROVIDERS = [
576
+ { id: "apiblaze", label: "APIblaze (via GitHub) \u2014 zero setup, recommended", own: false },
577
+ { id: "google", label: "Google", own: true },
578
+ { id: "github", label: "GitHub", own: true },
579
+ { id: "microsoft", label: "Microsoft", own: true },
580
+ { id: "facebook", label: "Facebook", own: true },
581
+ { id: "auth0", label: "Auth0", own: true },
582
+ { id: "other", label: "Custom (any OIDC provider)", own: true }
583
+ ];
584
+ DEFAULT_SCOPES = {
585
+ google: "openid email profile",
586
+ microsoft: "openid email profile",
587
+ github: "read:user user:email",
588
+ facebook: "public_profile email"
589
+ };
590
+ }
591
+ });
592
+
460
593
  // src/lib/tenant-pick.ts
461
594
  var tenant_pick_exports = {};
462
595
  __export(tenant_pick_exports, {
@@ -475,10 +608,10 @@ async function fetchPage(teamId, q) {
475
608
  }
476
609
  function label(t, defaultTenant, active) {
477
610
  const tags = [
478
- t.tenant_name === active ? import_chalk22.default.cyan("active scope") : "",
479
- t.tenant_name === defaultTenant ? import_chalk22.default.dim("team default") : ""
611
+ t.tenant_name === active ? import_chalk23.default.cyan("active scope") : "",
612
+ t.tenant_name === defaultTenant ? import_chalk23.default.dim("team default") : ""
480
613
  ].filter(Boolean).join(", ");
481
- const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk22.default.dim(` ${t.display_name}`) : "";
614
+ const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk23.default.dim(` ${t.display_name}`) : "";
482
615
  return `${t.tenant_name}${disp}${tags ? ` (${tags})` : ""}`;
483
616
  }
484
617
  async function pickTenant(teamId, opts = {}) {
@@ -486,14 +619,14 @@ async function pickTenant(teamId, opts = {}) {
486
619
  const active = loadCredentials()?.activeTenant;
487
620
  let q = opts.initialQuery ?? "";
488
621
  for (; ; ) {
489
- const spinner = (0, import_ora8.default)(q ? `Searching tenants for "${q}"...` : "Loading tenants...").start();
622
+ const spinner = (0, import_ora9.default)(q ? `Searching tenants for "${q}"...` : "Loading tenants...").start();
490
623
  const page = await fetchPage(teamId, q).finally(() => spinner.stop());
491
624
  if (!page.total && !q) {
492
625
  if (opts.allowCreate) {
493
626
  const { make } = await inquirer2.prompt([{ type: "confirm", name: "make", message: "No tenants yet \u2014 create one?", default: true }]);
494
627
  if (make) return await createTenantInline(teamId);
495
628
  }
496
- console.error(import_chalk22.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
629
+ console.error(import_chalk23.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
497
630
  return null;
498
631
  }
499
632
  const truncated = page.total > page.rows.length;
@@ -502,7 +635,7 @@ async function pickTenant(teamId, opts = {}) {
502
635
  value: t.tenant_name
503
636
  }));
504
637
  if (truncated || q) {
505
- choices.push(new inquirer2.Separator(import_chalk22.default.dim(
638
+ choices.push(new inquirer2.Separator(import_chalk23.default.dim(
506
639
  truncated ? `showing ${page.rows.length} of ${page.total}${q ? ` matching "${q}"` : ""} \u2014 search to narrow` : `matches for "${q}"`
507
640
  )));
508
641
  choices.push({ name: `\u{1F50D} Search${q ? " again" : ""}\u2026`, value: "\0search" });
@@ -533,41 +666,15 @@ async function pickTenant(teamId, opts = {}) {
533
666
  }
534
667
  }
535
668
  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
- }
669
+ const { createTenantInteractive: createTenantInteractive2 } = await Promise.resolve().then(() => (init_tenant_create(), tenant_create_exports));
670
+ return createTenantInteractive2(teamId);
564
671
  }
565
- var import_chalk22, import_ora8, PAGE;
672
+ var import_chalk23, import_ora9, PAGE;
566
673
  var init_tenant_pick = __esm({
567
674
  "src/lib/tenant-pick.ts"() {
568
675
  "use strict";
569
- import_chalk22 = __toESM(require("chalk"));
570
- import_ora8 = __toESM(require("ora"));
676
+ import_chalk23 = __toESM(require("chalk"));
677
+ import_ora9 = __toESM(require("ora"));
571
678
  init_admin();
572
679
  init_auth();
573
680
  PAGE = 15;
@@ -576,10 +683,10 @@ var init_tenant_pick = __esm({
576
683
 
577
684
  // src/index.ts
578
685
  var import_commander = require("commander");
579
- var import_chalk34 = __toESM(require("chalk"));
686
+ var import_chalk35 = __toESM(require("chalk"));
580
687
 
581
688
  // package.json
582
- var version = "0.15.1";
689
+ var version = "0.16.0";
583
690
 
584
691
  // src/index.ts
585
692
  init_types();
@@ -2652,8 +2759,8 @@ async function runRename(project, opts) {
2652
2759
  }
2653
2760
 
2654
2761
  // src/commands/config-browse.ts
2655
- var import_chalk28 = __toESM(require("chalk"));
2656
- var import_ora13 = __toESM(require("ora"));
2762
+ var import_chalk29 = __toESM(require("chalk"));
2763
+ var import_ora14 = __toESM(require("ora"));
2657
2764
  init_admin();
2658
2765
  init_auth();
2659
2766
 
@@ -2763,28 +2870,28 @@ async function runDomainSetBase(project, opts) {
2763
2870
  }
2764
2871
 
2765
2872
  // src/commands/tenant.ts
2766
- var import_chalk23 = __toESM(require("chalk"));
2767
- var import_ora9 = __toESM(require("ora"));
2873
+ var import_chalk24 = __toESM(require("chalk"));
2874
+ var import_ora10 = __toESM(require("ora"));
2768
2875
  init_admin();
2769
2876
  init_auth();
2770
2877
  init_tenant_pick();
2771
2878
  async function runTenantUse(query, opts) {
2772
2879
  const creds = loadCredentials();
2773
2880
  if (!creds) {
2774
- console.error(import_chalk23.default.red("Not logged in. Run `apiblaze login` first."));
2881
+ console.error(import_chalk24.default.red("Not logged in. Run `apiblaze login` first."));
2775
2882
  process.exit(1);
2776
2883
  }
2777
2884
  if (opts.clear) {
2778
2885
  delete creds.activeTenant;
2779
2886
  saveCredentials(creds);
2780
- console.log(import_chalk23.default.green("Tenant scope cleared."));
2887
+ console.log(import_chalk24.default.green("Tenant scope cleared."));
2781
2888
  return;
2782
2889
  }
2783
2890
  const { teamId } = await resolveTeam(opts.team);
2784
2891
  const slug = await pickTenant(teamId, { message: "Scope future commands to which tenant?", initialQuery: query });
2785
2892
  if (!slug) process.exit(1);
2786
2893
  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`)"));
2894
+ 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
2895
  }
2789
2896
  async function runTenantList(opts) {
2790
2897
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -2801,26 +2908,26 @@ async function runTenantList(opts) {
2801
2908
  return;
2802
2909
  }
2803
2910
  if (!tenants.length) {
2804
- console.log(import_chalk23.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
2911
+ console.log(import_chalk24.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
2805
2912
  return;
2806
2913
  }
2807
2914
  for (const t of tenants) {
2808
2915
  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}`);
2916
+ const display = typeof t === "string" ? "" : import_chalk24.default.dim(` ${t.display_name ?? ""}`);
2917
+ console.log(` ${import_chalk24.default.bold(name)}${display}`);
2811
2918
  }
2812
2919
  const total = out?.total ?? tenants.length;
2813
2920
  if (total > tenants.length) {
2814
- console.log(import_chalk23.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
2921
+ console.log(import_chalk24.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
2815
2922
  }
2816
2923
  }
2817
2924
  async function runTenantCreate(opts) {
2818
2925
  if (!opts.name) {
2819
- console.error(import_chalk23.default.red("--name (display name) is required."));
2926
+ console.error(import_chalk24.default.red("--name (display name) is required."));
2820
2927
  process.exit(1);
2821
2928
  }
2822
2929
  const { teamId } = await resolveTeam(opts.team);
2823
- const spinner = (0, import_ora9.default)("Creating tenant...").start();
2930
+ const spinner = (0, import_ora10.default)("Creating tenant...").start();
2824
2931
  try {
2825
2932
  const out = await admin({
2826
2933
  method: "POST",
@@ -2828,7 +2935,7 @@ async function runTenantCreate(opts) {
2828
2935
  body: { display_name: opts.name, ...opts.slug ? { tenant_name: opts.slug } : {} },
2829
2936
  summary: `Create tenant "${opts.name}"`
2830
2937
  });
2831
- spinner.succeed(`Created tenant ${import_chalk23.default.bold(out?.tenant_name ?? opts.name)}.`);
2938
+ spinner.succeed(`Created tenant ${import_chalk24.default.bold(out?.tenant_name ?? opts.name)}.`);
2832
2939
  if (opts.json) console.log(JSON.stringify(out));
2833
2940
  } catch (err) {
2834
2941
  spinner.fail("Tenant create failed.");
@@ -2837,12 +2944,12 @@ async function runTenantCreate(opts) {
2837
2944
  }
2838
2945
  async function runTenantAttach(project, opts) {
2839
2946
  if (!opts.tenant) {
2840
- console.error(import_chalk23.default.red("--tenant <slug> is required."));
2947
+ console.error(import_chalk24.default.red("--tenant <slug> is required."));
2841
2948
  process.exit(1);
2842
2949
  }
2843
2950
  const { teamId } = await resolveTeam(opts.team);
2844
2951
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
2845
- const spinner = (0, import_ora9.default)("Attaching tenant...").start();
2952
+ const spinner = (0, import_ora10.default)("Attaching tenant...").start();
2846
2953
  try {
2847
2954
  const out = await admin({
2848
2955
  method: "POST",
@@ -2865,11 +2972,11 @@ async function runTenantDelete(slug, opts) {
2865
2972
  { type: "confirm", name: "confirm", message: `Permanently delete tenant "${slug}" and everything under it? This cannot be undone.`, default: false }
2866
2973
  ]);
2867
2974
  if (!confirm) {
2868
- console.log(import_chalk23.default.dim("Aborted."));
2975
+ console.log(import_chalk24.default.dim("Aborted."));
2869
2976
  return;
2870
2977
  }
2871
2978
  }
2872
- const spinner = (0, import_ora9.default)("Deleting tenant...").start();
2979
+ const spinner = (0, import_ora10.default)("Deleting tenant...").start();
2873
2980
  try {
2874
2981
  await admin({
2875
2982
  method: "DELETE",
@@ -2884,13 +2991,13 @@ async function runTenantDelete(slug, opts) {
2884
2991
  }
2885
2992
  async function runTenantCors(opts) {
2886
2993
  if (!opts.tenant) {
2887
- console.error(import_chalk23.default.red("--tenant <slug> is required."));
2994
+ console.error(import_chalk24.default.red("--tenant <slug> is required."));
2888
2995
  process.exit(1);
2889
2996
  }
2890
2997
  const { teamId } = await resolveTeam(opts.team);
2891
2998
  const origins = (opts.origins ?? "").split(",").map((s) => s.trim()).filter(Boolean);
2892
2999
  const cors = origins.length ? { allowed_origins: origins } : null;
2893
- const spinner = (0, import_ora9.default)("Updating CORS...").start();
3000
+ const spinner = (0, import_ora10.default)("Updating CORS...").start();
2894
3001
  try {
2895
3002
  await admin({
2896
3003
  method: "PUT",
@@ -2906,13 +3013,12 @@ async function runTenantCors(opts) {
2906
3013
  }
2907
3014
 
2908
3015
  // src/commands/tenant-drill.ts
2909
- var import_chalk24 = __toESM(require("chalk"));
2910
- var import_ora10 = __toESM(require("ora"));
3016
+ var import_chalk25 = __toESM(require("chalk"));
3017
+ var import_ora11 = __toESM(require("ora"));
2911
3018
  var import_crypto = require("crypto");
2912
3019
  init_admin();
2913
3020
  init_auth();
2914
3021
  init_tenant_pick();
2915
- init_api();
2916
3022
  var trailingComma = /\s*,\s*/;
2917
3023
  var parseList = (s) => s.split(trailingComma).map((x) => x.trim()).filter(Boolean);
2918
3024
  async function runTenantManage(query, opts) {
@@ -2937,17 +3043,17 @@ async function validScopedTenant(teamId, query) {
2937
3043
  const next = { ...creds };
2938
3044
  delete next.activeTenant;
2939
3045
  saveCredentials2(next);
2940
- console.log(import_chalk24.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
3046
+ console.log(import_chalk25.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
2941
3047
  return void 0;
2942
3048
  }
2943
3049
  async function tenantHome(teamId, tenant2) {
2944
3050
  const { default: inquirer2 } = await import("inquirer");
2945
3051
  const base = `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}`;
2946
- console.log(import_chalk24.default.bold(`
3052
+ console.log(import_chalk25.default.bold(`
2947
3053
  Tenant ${tenant2}`));
2948
- console.log(import_chalk24.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
3054
+ console.log(import_chalk25.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
2949
3055
  for (; ; ) {
2950
- const spinner = (0, import_ora10.default)("Reading tenant state...").start();
3056
+ const spinner = (0, import_ora11.default)("Reading tenant state...").start();
2951
3057
  const [iam, cors, emails, issuers, opaque, clients] = await Promise.all([
2952
3058
  admin({ method: "GET", path: `${base}/iam`, summary: "Read IAM toggle" }).catch(() => null),
2953
3059
  admin({ method: "GET", path: `${base}/cors`, summary: "Read tenant CORS" }).catch(() => null),
@@ -2959,19 +3065,20 @@ Tenant ${tenant2}`));
2959
3065
  const nEmails = (emails?.admin_emails ?? []).length;
2960
3066
  const nIssuers = (issuers?.external_issuers ?? []).length;
2961
3067
  const nClients = Array.isArray(clients) ? clients.length : 0;
2962
- const onOff = (b) => b ? import_chalk24.default.green("on") : import_chalk24.default.dim("off");
3068
+ const onOff = (b) => b ? import_chalk25.default.green("on") : import_chalk25.default.dim("off");
2963
3069
  const { pick: pick2 } = await inquirer2.prompt([{
2964
3070
  type: "list",
2965
3071
  name: "pick",
2966
3072
  message: `Tenant ${tenant2}:`,
2967
3073
  pageSize: 12,
2968
3074
  choices: [
2969
- { name: `App clients (${nClients}) ${import_chalk24.default.dim("OAuth clients your consumers log in through \u2014 providers live inside")}`, value: "clients" },
2970
- { name: `IAM enforcement: ${onOff(iam?.iam_enabled)} ${import_chalk24.default.dim("key/identity enforcement for this tenant")}`, value: "iam" },
2971
- { name: `CORS override: ${cors?.cors ? import_chalk24.default.cyan(JSON.stringify(cors.cors)) : import_chalk24.default.dim("(unset)")}`, value: "cors" },
2972
- { name: `Consumer-admin emails (${nEmails}) ${import_chalk24.default.dim("who may administer the tenant portal")}`, value: "emails" },
2973
- { name: `External JWT issuers (${nIssuers}) ${import_chalk24.default.dim("bring-your-own auth: trust tokens you already mint")}`, value: "issuers" },
2974
- { name: `Opaque-token validator: ${opaque?.opaque?.endpoint ? import_chalk24.default.cyan(opaque.opaque.endpoint) : import_chalk24.default.dim("(unset)")}`, value: "opaque" },
3075
+ { name: `Login methods (${nClients}) ${import_chalk25.default.dim("how your consumers sign in \u2014 providers live inside")}`, value: "clients" },
3076
+ { name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk25.default.dim(`identity & key management (${tenant2}.iam.apiblaze.com)`)}`, value: "iam" },
3077
+ { name: `Your own hosted login \u2014 JWT (${nIssuers}) ${import_chalk25.default.dim("trust tokens your own identity provider issues")}`, value: "issuers" },
3078
+ { name: `Portal admins (${nEmails}) ${import_chalk25.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
3079
+ new inquirer2.Separator(import_chalk25.default.dim(" Settings")),
3080
+ { 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" },
3081
+ { name: `Opaque-token login (advanced): ${opaque?.opaque?.endpoint ? import_chalk25.default.cyan(opaque.opaque.endpoint) : import_chalk25.default.dim("(unset)")}`, value: "opaque" },
2975
3082
  { name: "\u2190 Back", value: "back" }
2976
3083
  ]
2977
3084
  }]);
@@ -2982,9 +3089,9 @@ Tenant ${tenant2}`));
2982
3089
  await clientsMenu(teamId, tenant2, base);
2983
3090
  break;
2984
3091
  case "iam": {
2985
- const { v } = await inquirer2.prompt([{ type: "confirm", name: "v", message: "Enable IAM enforcement?", default: !!iam?.iam_enabled }]);
3092
+ const { v } = await inquirer2.prompt([{ type: "confirm", name: "v", message: "Enable Users & groups?", default: !!iam?.iam_enabled }]);
2986
3093
  await admin({ method: "PATCH", path: `${base}/iam`, body: { enabled: v }, summary: `IAM enforcement \u2192 ${v ? "on" : "off"}` });
2987
- console.log(import_chalk24.default.green(` IAM enforcement ${v ? "enabled" : "disabled"}.`));
3094
+ console.log(import_chalk25.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
2988
3095
  break;
2989
3096
  }
2990
3097
  case "cors": {
@@ -2997,11 +3104,11 @@ Tenant ${tenant2}`));
2997
3104
  if (v === "") break;
2998
3105
  const parsed = v === "null" ? null : safeJson(v);
2999
3106
  if (parsed === void 0) {
3000
- console.log(import_chalk24.default.yellow(" Not valid JSON \u2014 unchanged."));
3107
+ console.log(import_chalk25.default.yellow(" Not valid JSON \u2014 unchanged."));
3001
3108
  break;
3002
3109
  }
3003
3110
  await admin({ method: "PUT", path: `${base}/cors`, body: { cors: parsed }, summary: "Set tenant CORS" });
3004
- console.log(import_chalk24.default.green(" CORS updated."));
3111
+ console.log(import_chalk25.default.green(" CORS updated."));
3005
3112
  break;
3006
3113
  }
3007
3114
  case "emails":
@@ -3025,7 +3132,7 @@ Tenant ${tenant2}`));
3025
3132
  if (mode === "back") break;
3026
3133
  if (mode === "clear") {
3027
3134
  await admin({ method: "PUT", path: `${base}/opaque`, body: { opaque: null }, summary: "Clear opaque validator" });
3028
- console.log(import_chalk24.default.green(" Cleared."));
3135
+ console.log(import_chalk25.default.green(" Cleared."));
3029
3136
  break;
3030
3137
  }
3031
3138
  const a = await inquirer2.prompt([
@@ -3033,7 +3140,7 @@ Tenant ${tenant2}`));
3033
3140
  { type: "list", name: "method", message: "HTTP method:", choices: ["GET", "POST"], default: cur?.method ?? "GET" }
3034
3141
  ]);
3035
3142
  await admin({ method: "PUT", path: `${base}/opaque`, body: { opaque: { endpoint: a.endpoint, method: a.method } }, summary: "Set opaque validator" });
3036
- console.log(import_chalk24.default.green(" Opaque validator set."));
3143
+ console.log(import_chalk25.default.green(" Opaque validator set."));
3037
3144
  break;
3038
3145
  }
3039
3146
  }
@@ -3049,8 +3156,8 @@ function safeJson(s) {
3049
3156
  async function emailsMenu(base, emails) {
3050
3157
  const { default: inquirer2 } = await import("inquirer");
3051
3158
  console.log();
3052
- if (!emails.length) console.log(import_chalk24.default.dim(" No consumer-admin emails."));
3053
- for (const e of emails) console.log(` ${import_chalk24.default.bold(e.email ?? e)} ${import_chalk24.default.dim(e.status ?? "")}`);
3159
+ if (!emails.length) console.log(import_chalk25.default.dim(" No consumer-admin emails."));
3160
+ for (const e of emails) console.log(` ${import_chalk25.default.bold(e.email ?? e)} ${import_chalk25.default.dim(e.status ?? "")}`);
3054
3161
  const { act } = await inquirer2.prompt([{
3055
3162
  type: "list",
3056
3163
  name: "act",
@@ -3065,7 +3172,7 @@ async function emailsMenu(base, emails) {
3065
3172
  if (act === "add") {
3066
3173
  const { email } = await inquirer2.prompt([{ type: "input", name: "email", message: "Email:", validate: (s) => /.+@.+\..+/.test(s) || "not an email" }]);
3067
3174
  await admin({ method: "POST", path: `${base}/admin-emails`, body: { email }, summary: `Add consumer-admin ${email}` });
3068
- console.log(import_chalk24.default.green(` ${email} added.`));
3175
+ console.log(import_chalk25.default.green(` ${email} added.`));
3069
3176
  } else {
3070
3177
  const { e } = await inquirer2.prompt([{
3071
3178
  type: "list",
@@ -3075,14 +3182,14 @@ async function emailsMenu(base, emails) {
3075
3182
  }]);
3076
3183
  if (!e) return;
3077
3184
  await admin({ method: "DELETE", path: `${base}/admin-emails/${encodeURIComponent(e)}`, summary: `Remove consumer-admin ${e}` });
3078
- console.log(import_chalk24.default.green(` ${e} removed.`));
3185
+ console.log(import_chalk25.default.green(` ${e} removed.`));
3079
3186
  }
3080
3187
  }
3081
3188
  async function issuersMenu(base, issuers) {
3082
3189
  const { default: inquirer2 } = await import("inquirer");
3083
3190
  console.log();
3084
- if (!issuers.length) console.log(import_chalk24.default.dim(" No external issuers \u2014 consumers use APIblaze-issued tokens."));
3085
- for (const i of issuers) console.log(` ${import_chalk24.default.bold(i.iss)} aud=${i.aud} ${import_chalk24.default.dim(i.sub_semantics ?? "")}`);
3191
+ if (!issuers.length) console.log(import_chalk25.default.dim(" No external issuers \u2014 consumers use APIblaze-issued tokens."));
3192
+ for (const i of issuers) console.log(` ${import_chalk25.default.bold(i.iss)} aud=${i.aud} ${import_chalk25.default.dim(i.sub_semantics ?? "")}`);
3086
3193
  const { act } = await inquirer2.prompt([{
3087
3194
  type: "list",
3088
3195
  name: "act",
@@ -3111,7 +3218,7 @@ async function issuersMenu(base, issuers) {
3111
3218
  body: { iss: a.iss.trim(), aud: a.aud.trim(), jwks_url: a.jwks.trim() || null, sub_semantics: a.sem, ...claim ? { claim_name: claim } : {} },
3112
3219
  summary: `Add external issuer ${a.iss.trim()}`
3113
3220
  });
3114
- console.log(import_chalk24.default.green(" Issuer saved."));
3221
+ console.log(import_chalk25.default.green(" Issuer saved."));
3115
3222
  } else {
3116
3223
  const { i } = await inquirer2.prompt([{
3117
3224
  type: "list",
@@ -3125,59 +3232,47 @@ async function issuersMenu(base, issuers) {
3125
3232
  path: `${base}/external-issuers?iss=${encodeURIComponent(i.iss)}&aud=${encodeURIComponent(i.aud)}`,
3126
3233
  summary: `Delete issuer ${i.iss}`
3127
3234
  });
3128
- console.log(import_chalk24.default.green(" Issuer deleted."));
3235
+ console.log(import_chalk25.default.green(" Issuer deleted."));
3129
3236
  }
3130
3237
  }
3131
3238
  async function clientsMenu(teamId, tenant2, base) {
3132
3239
  const { default: inquirer2 } = await import("inquirer");
3133
3240
  for (; ; ) {
3134
- const spinner = (0, import_ora10.default)("Loading app clients...").start();
3241
+ const spinner = (0, import_ora11.default)("Loading app clients...").start();
3135
3242
  const raw = await admin({ method: "GET", path: `${base}/app-clients`, summary: "List app clients" }).catch(() => []);
3136
3243
  spinner.stop();
3137
3244
  const clients = Array.isArray(raw) ? raw : [];
3138
3245
  const { pick: pick2 } = await inquirer2.prompt([{
3139
3246
  type: "list",
3140
3247
  name: "pick",
3141
- message: `App clients of ${tenant2}:`,
3248
+ message: `Login methods for ${tenant2}:`,
3142
3249
  pageSize: 15,
3143
3250
  choices: [
3144
3251
  ...clients.map((c) => ({
3145
- name: `${import_chalk24.default.bold(c.name ?? c.clientId)} ${import_chalk24.default.dim(`${c.clientId}${c.projectName ? ` \xB7 ${c.projectName}` : ""}`)}`,
3252
+ name: `${import_chalk25.default.bold(c.name ?? c.clientId)} ${import_chalk25.default.dim(`${c.clientId}${c.projectName ? ` \xB7 ${c.projectName}` : ""}`)}`,
3146
3253
  value: c
3147
3254
  })),
3148
- ...clients.length ? [] : [new inquirer2.Separator(import_chalk24.default.dim(" no app clients yet"))],
3149
- { name: "\uFF0B Create an app client\u2026", value: " create" },
3255
+ ...clients.length ? [] : [new inquirer2.Separator(import_chalk25.default.dim(" no app clients yet"))],
3256
+ { name: "\uFF0B Add a login method\u2026", value: " create" },
3150
3257
  { name: "\u2190 Back", value: " back" }
3151
3258
  ]
3152
3259
  }]);
3153
3260
  if (pick2 === " back") return;
3154
3261
  if (pick2 === " create") {
3155
- const projects = await getProjects(teamId).catch(() => []);
3156
3262
  const a = await inquirer2.prompt([
3157
3263
  { type: "input", name: "name", message: "Client name:", validate: (s) => !!s.trim() || "required" },
3158
- ...projects.length ? [{
3159
- type: "list",
3160
- name: "proj",
3161
- message: "Reference a project? (adds its portal/MCP token audiences)",
3162
- choices: [
3163
- ...projects.map((p) => ({ name: `${p.projectName} ${import_chalk24.default.dim("v" + p.apiVersion)}`, value: p })),
3164
- { name: import_chalk24.default.dim("Skip \u2014 tenant-only client"), value: null }
3165
- ]
3166
- }] : [],
3167
3264
  { type: "input", name: "callbacks", message: "Callback URLs (comma-separated, empty = none):" }
3168
3265
  ]);
3169
- if (!projects.length) console.log(import_chalk24.default.dim(" (no projects in this team yet \u2014 creating a tenant-only client; you can reference a project later)"));
3170
3266
  const created = await admin({
3171
3267
  method: "POST",
3172
3268
  path: `${base}/app-clients`,
3173
3269
  body: {
3174
3270
  name: a.name.trim(),
3175
- ...a.proj ? { projectName: a.proj.projectName, apiVersion: a.proj.apiVersion } : {},
3176
3271
  ...a.callbacks.trim() ? { authorizedCallbackUrls: parseList(a.callbacks) } : {}
3177
3272
  },
3178
3273
  summary: `Create app client "${a.name.trim()}"`
3179
3274
  });
3180
- console.log(import_chalk24.default.green(` App client created${created?.clientId ? ` (${created.clientId})` : ""}.`));
3275
+ console.log(import_chalk25.default.green(` Login method created${created?.clientId ? ` (${created.clientId})` : ""}.`));
3181
3276
  continue;
3182
3277
  }
3183
3278
  await clientHome(base, pick2);
@@ -3188,7 +3283,7 @@ async function clientHome(base, summary) {
3188
3283
  const id = summary.clientId ?? summary.client_id;
3189
3284
  const cBase = `${base}/app-clients/${encodeURIComponent(id)}`;
3190
3285
  for (; ; ) {
3191
- const spinner = (0, import_ora10.default)("Reading app client...").start();
3286
+ const spinner = (0, import_ora11.default)("Reading app client...").start();
3192
3287
  const c = await admin({ method: "GET", path: cBase, summary: `Read app client ${id}` }).catch(() => summary);
3193
3288
  spinner.stop();
3194
3289
  const cb = c.authorizedCallbackUrls ?? c.authorized_callback_urls ?? [];
@@ -3200,13 +3295,13 @@ async function clientHome(base, summary) {
3200
3295
  message: `${c.name ?? id}:`,
3201
3296
  pageSize: 12,
3202
3297
  choices: [
3203
- { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk24.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
3204
- { name: `Callback URLs: ${cb.length ? import_chalk24.default.cyan(cb.join(", ")) : import_chalk24.default.dim("(none)")}`, value: "callbacks" },
3205
- { name: `Scopes: ${scopes.length ? import_chalk24.default.cyan(scopes.join(" ")) : import_chalk24.default.dim("(defaults)")}`, value: "scopes" },
3298
+ { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk25.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
3299
+ { name: `Callback URLs: ${cb.length ? import_chalk25.default.cyan(cb.join(", ")) : import_chalk25.default.dim("(none)")}`, value: "callbacks" },
3300
+ { name: `Scopes: ${scopes.length ? import_chalk25.default.cyan(scopes.join(" ")) : import_chalk25.default.dim("(defaults)")}`, value: "scopes" },
3206
3301
  { name: `Token expiries: access ${c.accessTokenExpiry ?? 3600}s \xB7 id ${c.idTokenExpiry ?? 3600}s \xB7 refresh ${c.refreshTokenExpiry ?? 2592e3}s`, value: "expiries" },
3207
3302
  { name: "Reveal client secret", value: "secret" },
3208
3303
  { name: "Rotate client secret", value: "rotate" },
3209
- { name: import_chalk24.default.red("Delete this app client"), value: "delete" },
3304
+ { name: import_chalk25.default.red("Delete this app client"), value: "delete" },
3210
3305
  { name: "\u2190 Back", value: "back" }
3211
3306
  ]
3212
3307
  }]);
@@ -3219,13 +3314,13 @@ async function clientHome(base, summary) {
3219
3314
  case "callbacks": {
3220
3315
  const { v } = await inquirer2.prompt([{ type: "input", name: "v", message: "Callback URLs (comma-separated):", default: cb.join(", ") }]);
3221
3316
  await admin({ method: "PATCH", path: cBase, body: { authorizedCallbackUrls: parseList(v) }, summary: "Update callback URLs" });
3222
- console.log(import_chalk24.default.green(" Callbacks updated."));
3317
+ console.log(import_chalk25.default.green(" Callbacks updated."));
3223
3318
  break;
3224
3319
  }
3225
3320
  case "scopes": {
3226
3321
  const { v } = await inquirer2.prompt([{ type: "input", name: "v", message: "Scopes (space/comma-separated):", default: scopes.join(" ") }]);
3227
3322
  await admin({ method: "PATCH", path: cBase, body: { scopes: v.split(/[\s,]+/).filter(Boolean) }, summary: "Update scopes" });
3228
- console.log(import_chalk24.default.green(" Scopes updated."));
3323
+ console.log(import_chalk25.default.green(" Scopes updated."));
3229
3324
  break;
3230
3325
  }
3231
3326
  case "expiries": {
@@ -3240,14 +3335,14 @@ async function clientHome(base, summary) {
3240
3335
  body: { accessTokenExpiry: Number(a.access), idTokenExpiry: Number(a.id), refreshTokenExpiry: Number(a.refresh) },
3241
3336
  summary: "Update token expiries"
3242
3337
  });
3243
- console.log(import_chalk24.default.green(" Expiries updated."));
3338
+ console.log(import_chalk25.default.green(" Expiries updated."));
3244
3339
  break;
3245
3340
  }
3246
3341
  case "secret": {
3247
3342
  const { sure } = await inquirer2.prompt([{ type: "confirm", name: "sure", message: "Print the client secret to this terminal?", default: false }]);
3248
3343
  if (!sure) break;
3249
3344
  const s = await admin({ method: "GET", path: `${cBase}/secret`, summary: "Reveal client secret" });
3250
- console.log(` ${import_chalk24.default.bold("client_secret")}: ${import_chalk24.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3345
+ console.log(` ${import_chalk25.default.bold("client_secret")}: ${import_chalk25.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3251
3346
  break;
3252
3347
  }
3253
3348
  case "rotate": {
@@ -3255,14 +3350,14 @@ async function clientHome(base, summary) {
3255
3350
  if (!sure) break;
3256
3351
  const fresh = randomSecret();
3257
3352
  await admin({ method: "PATCH", path: cBase, body: { clientSecret: fresh }, summary: "Rotate client secret" });
3258
- console.log(` New ${import_chalk24.default.bold("client_secret")}: ${import_chalk24.default.green(fresh)} ${import_chalk24.default.dim("(store it now)")}`);
3353
+ console.log(` New ${import_chalk25.default.bold("client_secret")}: ${import_chalk25.default.green(fresh)} ${import_chalk25.default.dim("(store it now)")}`);
3259
3354
  break;
3260
3355
  }
3261
3356
  case "delete": {
3262
3357
  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 }]);
3263
3358
  if (!sure) break;
3264
3359
  await admin({ method: "DELETE", path: cBase, summary: `Delete app client ${id}` });
3265
- console.log(import_chalk24.default.green(" App client deleted."));
3360
+ console.log(import_chalk25.default.green(" App client deleted."));
3266
3361
  return;
3267
3362
  }
3268
3363
  }
@@ -3274,7 +3369,7 @@ function randomSecret() {
3274
3369
  return Buffer.from(bytes).toString("base64url");
3275
3370
  }
3276
3371
  var PROVIDER_TYPES = ["google", "github", "microsoft", "facebook", "auth0", "other"];
3277
- var DEFAULT_SCOPES = {
3372
+ var DEFAULT_SCOPES2 = {
3278
3373
  google: "openid email profile",
3279
3374
  microsoft: "openid email profile",
3280
3375
  github: "read:user user:email",
@@ -3283,19 +3378,19 @@ var DEFAULT_SCOPES = {
3283
3378
  async function providersMenu(cBase, clientLabel) {
3284
3379
  const { default: inquirer2 } = await import("inquirer");
3285
3380
  for (; ; ) {
3286
- const spinner = (0, import_ora10.default)("Loading providers...").start();
3381
+ const spinner = (0, import_ora11.default)("Loading providers...").start();
3287
3382
  const raw = await admin({ method: "GET", path: `${cBase}/providers`, summary: "List login providers" }).catch(() => []);
3288
3383
  spinner.stop();
3289
3384
  const providers = Array.isArray(raw) ? raw : [];
3290
3385
  console.log();
3291
3386
  for (const p of providers) {
3292
- 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" : ""}`)}`);
3387
+ 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" : ""}`)}`);
3293
3388
  }
3294
- if (!providers.length) console.log(import_chalk24.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
3389
+ if (!providers.length) console.log(import_chalk25.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
3295
3390
  const { act } = await inquirer2.prompt([{
3296
3391
  type: "list",
3297
3392
  name: "act",
3298
- message: `Login providers of ${clientLabel}:`,
3393
+ message: `Sign-in providers for ${clientLabel}:`,
3299
3394
  choices: [
3300
3395
  { name: "\uFF0B Add a provider", value: "add" },
3301
3396
  ...providers.length ? [
@@ -3323,7 +3418,7 @@ async function providersMenu(cBase, clientLabel) {
3323
3418
  { type: "input", name: "clientId", message: `${type} OAuth client id:`, validate: (s) => !!s.trim() || "required" },
3324
3419
  { type: "password", name: "clientSecret", mask: "*", message: `${type} OAuth client secret:`, validate: (s) => s.length >= 6 && s.length <= 200 || "6\u2013200 chars" },
3325
3420
  ...type === "auth0" || type === "other" ? [{ type: "input", name: "domain", message: "Issuer / domain (e.g. your-tenant.auth0.com):" }] : [],
3326
- { type: "input", name: "scopes", message: "Scopes:", default: DEFAULT_SCOPES[type] ?? "" }
3421
+ { type: "input", name: "scopes", message: "Scopes:", default: DEFAULT_SCOPES2[type] ?? "" }
3327
3422
  ]);
3328
3423
  body = {
3329
3424
  type,
@@ -3349,23 +3444,23 @@ async function providersMenu(cBase, clientLabel) {
3349
3444
  body.targetServerToken = routing;
3350
3445
  }
3351
3446
  await admin({ method: "POST", path: `${cBase}/providers`, body, summary: `Add ${type} login provider` });
3352
- console.log(import_chalk24.default.green(` ${type} provider added.`));
3447
+ console.log(import_chalk25.default.green(` ${type} provider added.`));
3353
3448
  } else {
3354
3449
  const { p } = await inquirer2.prompt([{
3355
3450
  type: "list",
3356
3451
  name: "p",
3357
3452
  message: act === "rm" ? "Remove which provider?" : "Reveal which secret?",
3358
- choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk24.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
3453
+ choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk25.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
3359
3454
  }]);
3360
3455
  if (!p) continue;
3361
3456
  if (act === "rm") {
3362
3457
  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 }]);
3363
3458
  if (!sure) continue;
3364
3459
  await admin({ method: "DELETE", path: `${cBase}/providers/${encodeURIComponent(p.id)}`, summary: `Remove ${p.type} provider` });
3365
- console.log(import_chalk24.default.green(` ${p.type} removed.`));
3460
+ console.log(import_chalk25.default.green(` ${p.type} removed.`));
3366
3461
  } else {
3367
3462
  const s = await admin({ method: "GET", path: `${cBase}/providers/${encodeURIComponent(p.id)}/secret`, summary: `Reveal ${p.type} provider secret` });
3368
- console.log(` ${import_chalk24.default.bold("client_secret")}: ${import_chalk24.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3463
+ console.log(` ${import_chalk25.default.bold("client_secret")}: ${import_chalk25.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3369
3464
  }
3370
3465
  }
3371
3466
  }
@@ -3373,8 +3468,8 @@ async function providersMenu(cBase, clientLabel) {
3373
3468
 
3374
3469
  // src/commands/spec.ts
3375
3470
  var fs6 = __toESM(require("fs"));
3376
- var import_chalk25 = __toESM(require("chalk"));
3377
- var import_ora11 = __toESM(require("ora"));
3471
+ var import_chalk26 = __toESM(require("chalk"));
3472
+ var import_ora12 = __toESM(require("ora"));
3378
3473
  init_admin();
3379
3474
  async function runSpecGet(project, opts) {
3380
3475
  const { teamId } = await resolveTeam(opts.team);
@@ -3388,19 +3483,19 @@ async function runSpecGet(project, opts) {
3388
3483
  }
3389
3484
  async function runSpecSet(project, opts) {
3390
3485
  if (!opts.file) {
3391
- console.error(import_chalk25.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
3486
+ console.error(import_chalk26.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
3392
3487
  process.exit(1);
3393
3488
  }
3394
3489
  let specContent;
3395
3490
  try {
3396
3491
  specContent = fs6.readFileSync(opts.file, "utf-8");
3397
3492
  } catch {
3398
- console.error(import_chalk25.default.red(`Cannot read file: ${opts.file}`));
3493
+ console.error(import_chalk26.default.red(`Cannot read file: ${opts.file}`));
3399
3494
  process.exit(1);
3400
3495
  }
3401
3496
  const { teamId } = await resolveTeam(opts.team);
3402
3497
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
3403
- const spinner = (0, import_ora11.default)("Uploading spec...").start();
3498
+ const spinner = (0, import_ora12.default)("Uploading spec...").start();
3404
3499
  try {
3405
3500
  const out = await admin({
3406
3501
  method: "POST",
@@ -3417,12 +3512,12 @@ async function runSpecSet(project, opts) {
3417
3512
  }
3418
3513
 
3419
3514
  // src/commands/agent.ts
3420
- var import_chalk27 = __toESM(require("chalk"));
3421
- var import_ora12 = __toESM(require("ora"));
3515
+ var import_chalk28 = __toESM(require("chalk"));
3516
+ var import_ora13 = __toESM(require("ora"));
3422
3517
  init_auth();
3423
3518
 
3424
3519
  // src/lib/tools.ts
3425
- var import_chalk26 = __toESM(require("chalk"));
3520
+ var import_chalk27 = __toESM(require("chalk"));
3426
3521
  init_admin();
3427
3522
  init_api();
3428
3523
  async function proj(teamId, name, version2) {
@@ -3441,15 +3536,15 @@ var TOOLS = [
3441
3536
  const key = keys.dev ?? Object.values(keys)[0];
3442
3537
  const url = `https://${a.name}.abz.run/${version2}/dev`;
3443
3538
  const tryIt = buildTryItCurl(url, auth, key);
3444
- const lines = [` ${import_chalk26.default.dim("Proxy URL:")} ${import_chalk26.default.bold(url)}`];
3445
- if (res.devPortal) lines.push(` ${import_chalk26.default.dim("Dev portal:")} ${res.devPortal}`);
3539
+ const lines = [` ${import_chalk27.default.dim("Proxy URL:")} ${import_chalk27.default.bold(url)}`];
3540
+ if (res.devPortal) lines.push(` ${import_chalk27.default.dim("Dev portal:")} ${res.devPortal}`);
3446
3541
  const envs = Object.keys(keys);
3447
3542
  if (envs.length) {
3448
- lines.push("", ` ${import_chalk26.default.bold("API keys")} ${import_chalk26.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
3543
+ lines.push("", ` ${import_chalk27.default.bold("API keys")} ${import_chalk27.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
3449
3544
  const w = Math.max(...envs.map((e) => e.length));
3450
- for (const env of envs) lines.push(` ${import_chalk26.default.cyan(env.padEnd(w))} ${import_chalk26.default.green(keys[env])}`);
3545
+ for (const env of envs) lines.push(` ${import_chalk27.default.cyan(env.padEnd(w))} ${import_chalk27.default.green(keys[env])}`);
3451
3546
  }
3452
- if (tryIt) lines.push("", ` ${import_chalk26.default.dim("Try it:")}`, ` ${import_chalk26.default.cyan(tryIt)}`);
3547
+ if (tryIt) lines.push("", ` ${import_chalk27.default.dim("Try it:")}`, ` ${import_chalk27.default.cyan(tryIt)}`);
3453
3548
  return { ...res, proxy_url: url, keys, ...tryIt ? { try_it: tryIt } : {}, display: lines.join("\n") };
3454
3549
  }
3455
3550
  },
@@ -3605,23 +3700,23 @@ function truncate(value, max = 1500) {
3605
3700
  }
3606
3701
  function printCost(llm) {
3607
3702
  const usd = llm.cost > 0 ? `$${llm.cost.toFixed(4)}` : "<$0.0001";
3608
- console.log(import_chalk27.default.magenta(` \u{1F4B3} ${usd}`) + import_chalk27.default.dim(` (${llm.model}, ${llm.total_tokens} tok)`));
3703
+ console.log(import_chalk28.default.magenta(` \u{1F4B3} ${usd}`) + import_chalk28.default.dim(` (${llm.model}, ${llm.total_tokens} tok)`));
3609
3704
  }
3610
3705
  async function runAgent(opts) {
3611
3706
  requireAuth();
3612
3707
  const { teamId, teamName } = await resolveTeam(opts.team);
3613
3708
  const { default: inquirer2 } = await import("inquirer");
3614
- console.log(import_chalk27.default.bold("APIblaze agent") + import_chalk27.default.dim(` \xB7 team ${teamName ?? teamId}`));
3615
- console.log(import_chalk27.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
3709
+ console.log(import_chalk28.default.bold("APIblaze agent") + import_chalk28.default.dim(` \xB7 team ${teamName ?? teamId}`));
3710
+ console.log(import_chalk28.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
3616
3711
  const history = [];
3617
3712
  while (true) {
3618
- const { input } = await inquirer2.prompt([{ type: "input", name: "input", message: import_chalk27.default.cyan("you") + " \u203A" }]);
3713
+ const { input } = await inquirer2.prompt([{ type: "input", name: "input", message: import_chalk28.default.cyan("you") + " \u203A" }]);
3619
3714
  const text = (input ?? "").trim();
3620
3715
  if (!text) continue;
3621
3716
  if (["exit", "quit", ":q"].includes(text.toLowerCase())) break;
3622
3717
  history.push({ role: "user", content: text });
3623
3718
  for (let step = 0; step < MAX_TOOL_STEPS; step++) {
3624
- const spinner = (0, import_ora12.default)({ text: "thinking...", color: "magenta" }).start();
3719
+ const spinner = (0, import_ora13.default)({ text: "thinking...", color: "magenta" }).start();
3625
3720
  let resp;
3626
3721
  try {
3627
3722
  resp = await callAgent(history, teamId);
@@ -3629,21 +3724,21 @@ async function runAgent(opts) {
3629
3724
  } catch (err) {
3630
3725
  spinner.stop();
3631
3726
  if (err instanceof ApiError && err.status === 402) {
3632
- console.log(import_chalk27.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
3727
+ console.log(import_chalk28.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
3633
3728
  break;
3634
3729
  }
3635
3730
  throw err;
3636
3731
  }
3637
3732
  history.push({ role: "assistant", content: resp.raw });
3638
3733
  printCost(resp.llm);
3639
- if (resp.reply) console.log(import_chalk27.default.green("agent") + " \u203A " + resp.reply);
3734
+ if (resp.reply) console.log(import_chalk28.default.green("agent") + " \u203A " + resp.reply);
3640
3735
  if (!resp.action) break;
3641
3736
  const tool = findTool(resp.action.tool);
3642
3737
  if (!tool) {
3643
3738
  history.push({ role: "user", content: `TOOL_RESULT ${resp.action.tool}: error \u2014 unknown tool` });
3644
3739
  continue;
3645
3740
  }
3646
- const runSpinner = (0, import_ora12.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
3741
+ const runSpinner = (0, import_ora13.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
3647
3742
  try {
3648
3743
  const result = await tool.run(resp.action.args, { teamId });
3649
3744
  runSpinner.succeed(`${tool.name} \u2713`);
@@ -3661,11 +3756,11 @@ async function runAgent(opts) {
3661
3756
  }
3662
3757
  renderTrace();
3663
3758
  if (step === MAX_TOOL_STEPS - 1) {
3664
- console.log(import_chalk27.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
3759
+ console.log(import_chalk28.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
3665
3760
  }
3666
3761
  }
3667
3762
  }
3668
- console.log(import_chalk27.default.dim("\nBye."));
3763
+ console.log(import_chalk28.default.dim("\nBye."));
3669
3764
  }
3670
3765
 
3671
3766
  // src/commands/config-browse.ts
@@ -3828,11 +3923,11 @@ function dig(blob, dotted) {
3828
3923
  }
3829
3924
  var readSetting = (s, cfg) => s.read ? s.read(cfg) : dig(cfg, s.key);
3830
3925
  function show(v) {
3831
- if (v === void 0) return import_chalk28.default.dim("(unset)");
3832
- if (v === null) return import_chalk28.default.dim("null");
3833
- if (typeof v === "object") return import_chalk28.default.cyan(JSON.stringify(v));
3834
- if (typeof v === "boolean") return v ? import_chalk28.default.green("on") : import_chalk28.default.red("off");
3835
- return import_chalk28.default.cyan(String(v));
3926
+ if (v === void 0) return import_chalk29.default.dim("(unset)");
3927
+ if (v === null) return import_chalk29.default.dim("null");
3928
+ if (typeof v === "object") return import_chalk29.default.cyan(JSON.stringify(v));
3929
+ if (typeof v === "boolean") return v ? import_chalk29.default.green("on") : import_chalk29.default.red("off");
3930
+ return import_chalk29.default.cyan(String(v));
3836
3931
  }
3837
3932
  function parseValue(raw) {
3838
3933
  if (raw === "true") return true;
@@ -3859,7 +3954,7 @@ async function fetchConfigBlob(proj2) {
3859
3954
  }
3860
3955
  async function patchSetting(proj2, s, value, cfg) {
3861
3956
  const body = s.toPatch(value, cfg);
3862
- const spinner = (0, import_ora13.default)(`Set ${s.key}...`).start();
3957
+ const spinner = (0, import_ora14.default)(`Set ${s.key}...`).start();
3863
3958
  try {
3864
3959
  await admin({
3865
3960
  method: "PATCH",
@@ -3874,10 +3969,10 @@ async function patchSetting(proj2, s, value, cfg) {
3874
3969
  }
3875
3970
  }
3876
3971
  var loginFirst = (what) => {
3877
- console.log(import_chalk28.default.yellow(`
3972
+ console.log(import_chalk29.default.yellow(`
3878
3973
  Log in first to ${what}.`));
3879
- console.log(import_chalk28.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
3880
- console.log(import_chalk28.default.dim(" anonymously and want to bring it into your account.\n"));
3974
+ console.log(import_chalk29.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
3975
+ console.log(import_chalk29.default.dim(" anonymously and want to bring it into your account.\n"));
3881
3976
  };
3882
3977
  async function runConfig(project, key, value, opts) {
3883
3978
  const creds = loadCredentials();
@@ -3894,9 +3989,9 @@ async function runConfig(project, key, value, opts) {
3894
3989
  }
3895
3990
  const setting = SETTINGS.find((s) => s.key === key);
3896
3991
  if (!setting) {
3897
- console.error(import_chalk28.default.red(`Unknown setting "${key}".`));
3898
- console.error(import_chalk28.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
3899
- console.error(import_chalk28.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
3992
+ console.error(import_chalk29.default.red(`Unknown setting "${key}".`));
3993
+ console.error(import_chalk29.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
3994
+ console.error(import_chalk29.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
3900
3995
  process.exit(1);
3901
3996
  }
3902
3997
  if (value === void 0) {
@@ -3911,7 +4006,7 @@ async function pickProject(teamId) {
3911
4006
  const { getProjects: getProjects2 } = await Promise.resolve().then(() => (init_api(), api_exports));
3912
4007
  const projects = await getProjects2(teamId).catch(() => []);
3913
4008
  if (!projects.length) {
3914
- console.error(import_chalk28.default.red("No projects in this team. Create one: `npx apiblaze create`."));
4009
+ console.error(import_chalk29.default.red("No projects in this team. Create one: `npx apiblaze create`."));
3915
4010
  process.exit(1);
3916
4011
  }
3917
4012
  const { default: inquirer2 } = await import("inquirer");
@@ -3919,7 +4014,7 @@ async function pickProject(teamId) {
3919
4014
  type: "list",
3920
4015
  name: "picked",
3921
4016
  message: "Which project?",
3922
- choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk28.default.dim("v" + p.apiVersion)}`, value: p }))
4017
+ choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk29.default.dim("v" + p.apiVersion)}`, value: p }))
3923
4018
  }]);
3924
4019
  return { projectId: picked.projectId, projectName: picked.projectName, apiVersion: picked.apiVersion, teamId, tenant: picked.tenant };
3925
4020
  }
@@ -3930,25 +4025,25 @@ function printAll(proj2, cfg, json) {
3930
4025
  console.log(JSON.stringify(out, null, 2));
3931
4026
  return;
3932
4027
  }
3933
- console.log(import_chalk28.default.bold(`
4028
+ console.log(import_chalk29.default.bold(`
3934
4029
  ${proj2.projectName} v${proj2.apiVersion} \u2014 settings
3935
4030
  `));
3936
4031
  for (const group of SETTING_GROUPS) {
3937
- console.log(import_chalk28.default.bold(group));
4032
+ console.log(import_chalk29.default.bold(group));
3938
4033
  for (const s of SETTINGS.filter((x) => x.group === group)) {
3939
- console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk28.default.dim(s.desc)}`);
4034
+ console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk29.default.dim(s.desc)}`);
3940
4035
  }
3941
4036
  console.log();
3942
4037
  }
3943
- console.log(import_chalk28.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
4038
+ console.log(import_chalk29.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
3944
4039
  }
3945
4040
  async function discoveryMenu(project) {
3946
4041
  const { default: inquirer2 } = await import("inquirer");
3947
- console.log(import_chalk28.default.bold(`
4042
+ console.log(import_chalk29.default.bold(`
3948
4043
  APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
3949
4044
  `));
3950
- console.log(import_chalk28.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
3951
- console.log(import_chalk28.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
4045
+ console.log(import_chalk29.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
4046
+ console.log(import_chalk29.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
3952
4047
  for (; ; ) {
3953
4048
  const { pick: pick2 } = await inquirer2.prompt([{
3954
4049
  type: "list",
@@ -3956,13 +4051,13 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
3956
4051
  message: "Explore:",
3957
4052
  pageSize: 20,
3958
4053
  choices: [
3959
- new inquirer2.Separator(import_chalk28.default.bold("\u2014 Settings \u2014")),
4054
+ new inquirer2.Separator(import_chalk29.default.bold("\u2014 Settings \u2014")),
3960
4055
  ...SETTING_GROUPS.map((g) => ({
3961
- name: `${g} ${import_chalk28.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
4056
+ name: `${g} ${import_chalk29.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
3962
4057
  value: { kind: "settings", g }
3963
4058
  })),
3964
- new inquirer2.Separator(import_chalk28.default.bold("\u2014 Features \u2014")),
3965
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk28.default.dim(f.desc)}`, value: { kind: "feature", f } })),
4059
+ new inquirer2.Separator(import_chalk29.default.bold("\u2014 Features \u2014")),
4060
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk29.default.dim(f.desc)}`, value: { kind: "feature", f } })),
3966
4061
  new inquirer2.Separator(),
3967
4062
  { name: "Exit", value: { kind: "exit" } }
3968
4063
  ]
@@ -3971,24 +4066,24 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
3971
4066
  if (pick2.kind === "settings") {
3972
4067
  console.log();
3973
4068
  for (const s of SETTINGS.filter((x) => x.group === pick2.g)) {
3974
- console.log(` ${import_chalk28.default.bold(s.label.padEnd(28))} ${import_chalk28.default.dim(s.desc)}`);
3975
- console.log(` ${import_chalk28.default.dim(" key: " + s.key)}`);
4069
+ console.log(` ${import_chalk29.default.bold(s.label.padEnd(28))} ${import_chalk29.default.dim(s.desc)}`);
4070
+ console.log(` ${import_chalk29.default.dim(" key: " + s.key)}`);
3976
4071
  }
3977
4072
  loginFirst("view or change these settings");
3978
4073
  } else {
3979
4074
  const f = pick2.f;
3980
4075
  console.log(`
3981
- ${import_chalk28.default.bold(f.label)} \u2014 ${f.desc}`);
4076
+ ${import_chalk29.default.bold(f.label)} \u2014 ${f.desc}`);
3982
4077
  loginFirst(`use ${f.label.toLowerCase()}`);
3983
4078
  }
3984
4079
  }
3985
4080
  }
3986
4081
  async function navigator(proj2, cfg, opts) {
3987
4082
  const { default: inquirer2 } = await import("inquirer");
3988
- console.log(import_chalk28.default.bold(`
4083
+ console.log(import_chalk29.default.bold(`
3989
4084
  ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
3990
4085
  `));
3991
- console.log(import_chalk28.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
4086
+ console.log(import_chalk29.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
3992
4087
  let blob = cfg;
3993
4088
  for (; ; ) {
3994
4089
  const { pick: pick2 } = await inquirer2.prompt([{
@@ -3997,10 +4092,10 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
3997
4092
  message: "Where to?",
3998
4093
  pageSize: 20,
3999
4094
  choices: [
4000
- new inquirer2.Separator(import_chalk28.default.bold("\u2014 Settings \u2014")),
4095
+ new inquirer2.Separator(import_chalk29.default.bold("\u2014 Settings \u2014")),
4001
4096
  ...SETTING_GROUPS.map((g) => ({ name: g, value: { kind: "settings", g } })),
4002
- new inquirer2.Separator(import_chalk28.default.bold("\u2014 Features \u2014")),
4003
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk28.default.dim(f.desc)}`, value: { kind: f.go } })),
4097
+ new inquirer2.Separator(import_chalk29.default.bold("\u2014 Features \u2014")),
4098
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk29.default.dim(f.desc)}`, value: { kind: f.go } })),
4004
4099
  new inquirer2.Separator(),
4005
4100
  { name: "Show all settings", value: { kind: "list" } },
4006
4101
  { name: "Exit", value: { kind: "exit" } }
@@ -4040,7 +4135,7 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
4040
4135
  }
4041
4136
  }
4042
4137
  } catch (err) {
4043
- console.error(import_chalk28.default.red(` ${err instanceof Error ? err.message : String(err)}`));
4138
+ console.error(import_chalk29.default.red(` ${err instanceof Error ? err.message : String(err)}`));
4044
4139
  }
4045
4140
  }
4046
4141
  }
@@ -4054,7 +4149,7 @@ async function settingsGroup(proj2, cfg, group) {
4054
4149
  message: group + ":",
4055
4150
  pageSize: 16,
4056
4151
  choices: [
4057
- ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk28.default.dim(s2.desc)}`, value: s2 })),
4152
+ ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk29.default.dim(s2.desc)}`, value: s2 })),
4058
4153
  new inquirer2.Separator(),
4059
4154
  { name: "\u2190 Back", value: null }
4060
4155
  ]
@@ -4072,7 +4167,7 @@ async function settingsGroup(proj2, cfg, group) {
4072
4167
  } else if (s.type === "number") {
4073
4168
  const { v } = await inquirer2.prompt([{ type: "input", name: "v", message: `${s.label} (number):`, default: readSetting(s, cfg) }]);
4074
4169
  if (v === "" || Number.isNaN(Number(v))) {
4075
- console.log(import_chalk28.default.yellow(" Not a number \u2014 unchanged."));
4170
+ console.log(import_chalk29.default.yellow(" Not a number \u2014 unchanged."));
4076
4171
  continue;
4077
4172
  }
4078
4173
  value = Number(v);
@@ -4153,7 +4248,7 @@ async function buildCondition(phase) {
4153
4248
  const items = [];
4154
4249
  for (; ; ) {
4155
4250
  const a = await inquirer2.prompt([
4156
- { type: "input", name: "source", message: `Condition field ${import_chalk28.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
4251
+ { type: "input", name: "source", message: `Condition field ${import_chalk29.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
4157
4252
  { type: "list", name: "operator", message: "Operator:", choices: [
4158
4253
  "eq",
4159
4254
  "neq",
@@ -4184,7 +4279,7 @@ async function buildCondition(phase) {
4184
4279
  function showCondition(cond) {
4185
4280
  if (!Array.isArray(cond) || !cond.length) return "";
4186
4281
  const s = cond.map((c) => `${c.source} ${c.operator}${c.value !== void 0 ? ` "${c.value}"` : ""}${c.logicOp ? ` ${c.logicOp}` : ""}`).join(" ");
4187
- return import_chalk28.default.dim(` when ${s}`);
4282
+ return import_chalk29.default.dim(` when ${s}`);
4188
4283
  }
4189
4284
  async function transformsMenu(proj2) {
4190
4285
  const { default: inquirer2 } = await import("inquirer");
@@ -4193,12 +4288,12 @@ async function transformsMenu(proj2) {
4193
4288
  const out = await admin({ method: "GET", path: base, summary: "List transform rules" });
4194
4289
  const rules = out?.rules ?? [];
4195
4290
  console.log();
4196
- if (!rules.length) console.log(import_chalk28.default.dim(" No transform rules yet."));
4291
+ if (!rules.length) console.log(import_chalk29.default.dim(" No transform rules yet."));
4197
4292
  for (const r of rules) {
4198
4293
  const a = r.action ?? {};
4199
4294
  const fns = [...a.source_fns ?? [], ...a.dest_fns ?? []].map((f) => f.fn);
4200
- 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")}`) : ""}`;
4201
- 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)}`);
4295
+ 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")}`) : ""}`;
4296
+ 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)}`);
4202
4297
  }
4203
4298
  const { act } = await inquirer2.prompt([{
4204
4299
  type: "list",
@@ -4210,7 +4305,7 @@ async function transformsMenu(proj2) {
4210
4305
  { name: "Enable/disable a rule", value: "toggle" },
4211
4306
  { name: "Delete a rule", value: "delete" }
4212
4307
  ] : [],
4213
- { name: import_chalk28.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
4308
+ { name: import_chalk29.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
4214
4309
  { name: "\u2190 Back", value: "back" }
4215
4310
  ]
4216
4311
  }]);
@@ -4223,11 +4318,11 @@ async function transformsMenu(proj2) {
4223
4318
  }]);
4224
4319
  const body = parseValue(raw);
4225
4320
  if (!body || typeof body !== "object" || Array.isArray(body)) {
4226
- console.log(import_chalk28.default.yellow(" Not a JSON object \u2014 skipped."));
4321
+ console.log(import_chalk29.default.yellow(" Not a JSON object \u2014 skipped."));
4227
4322
  continue;
4228
4323
  }
4229
4324
  await admin({ method: "POST", path: base, body, summary: "Create transform rule (raw JSON)" });
4230
- console.log(import_chalk28.default.green(" Rule created."));
4325
+ console.log(import_chalk29.default.green(" Rule created."));
4231
4326
  continue;
4232
4327
  }
4233
4328
  if (act === "add") {
@@ -4243,7 +4338,7 @@ async function transformsMenu(proj2) {
4243
4338
  { name: "Remove a field", value: "remove" }
4244
4339
  ] }
4245
4340
  ]);
4246
- const fieldHint = import_chalk28.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
4341
+ const fieldHint = import_chalk29.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
4247
4342
  let action2;
4248
4343
  if (ans.kind === "hardcode") {
4249
4344
  const a = await inquirer2.prompt([
@@ -4274,7 +4369,7 @@ async function transformsMenu(proj2) {
4274
4369
  };
4275
4370
  }
4276
4371
  const condition = await buildCondition(ans.phase);
4277
- const spinner = (0, import_ora13.default)("Creating rule...").start();
4372
+ const spinner = (0, import_ora14.default)("Creating rule...").start();
4278
4373
  try {
4279
4374
  await admin({
4280
4375
  method: "POST",
@@ -4292,16 +4387,16 @@ async function transformsMenu(proj2) {
4292
4387
  type: "list",
4293
4388
  name: "rule",
4294
4389
  message: act === "toggle" ? "Which rule?" : "Delete which rule?",
4295
- choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk28.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
4390
+ choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk29.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
4296
4391
  }]);
4297
4392
  if (!rule) continue;
4298
4393
  if (act === "toggle") {
4299
4394
  const flipped = { ...rule, enabled: rule.enabled === false };
4300
4395
  await admin({ method: "PUT", path: `${base}/${rule.id}`, body: flipped, summary: `${flipped.enabled ? "Enable" : "Disable"} transform "${rule.name}"` });
4301
- console.log(import_chalk28.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
4396
+ console.log(import_chalk29.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
4302
4397
  } else {
4303
4398
  await admin({ method: "DELETE", path: `${base}/${rule.id}`, summary: `Delete transform "${rule.name}"` });
4304
- console.log(import_chalk28.default.green(` ${rule.name} deleted.`));
4399
+ console.log(import_chalk29.default.green(` ${rule.name} deleted.`));
4305
4400
  }
4306
4401
  }
4307
4402
  }
@@ -4313,9 +4408,9 @@ async function mappingsMenu(proj2) {
4313
4408
  const out = await admin({ method: "GET", path: base, summary: "List mapping tables" });
4314
4409
  const tables = out?.mappings ?? out?.tables ?? [];
4315
4410
  console.log();
4316
- if (!tables.length) console.log(import_chalk28.default.dim(" No mapping tables yet."));
4411
+ if (!tables.length) console.log(import_chalk29.default.dim(" No mapping tables yet."));
4317
4412
  for (const t of tables) {
4318
- 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" : ""}`)}`);
4413
+ 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" : ""}`)}`);
4319
4414
  }
4320
4415
  const { act } = await inquirer2.prompt([{
4321
4416
  type: "list",
@@ -4335,11 +4430,11 @@ async function mappingsMenu(proj2) {
4335
4430
  ]);
4336
4431
  const entries2 = parseValue(a.entries);
4337
4432
  if (!Array.isArray(entries2)) {
4338
- console.log(import_chalk28.default.yellow(" Entries must be a JSON array \u2014 not created."));
4433
+ console.log(import_chalk29.default.yellow(" Entries must be a JSON array \u2014 not created."));
4339
4434
  continue;
4340
4435
  }
4341
4436
  await admin({ method: "POST", path: base, body: { name: a.name, entries: entries2 }, summary: `Create mapping table "${a.name}"` });
4342
- console.log(import_chalk28.default.green(` Table "${a.name}" created.`));
4437
+ console.log(import_chalk29.default.green(` Table "${a.name}" created.`));
4343
4438
  } else {
4344
4439
  const { table } = await inquirer2.prompt([{
4345
4440
  type: "list",
@@ -4349,7 +4444,7 @@ async function mappingsMenu(proj2) {
4349
4444
  }]);
4350
4445
  if (!table) continue;
4351
4446
  await admin({ method: "DELETE", path: `${base}/${table.id}`, summary: `Delete mapping table "${table.name}"` });
4352
- console.log(import_chalk28.default.green(` ${table.name} deleted.`));
4447
+ console.log(import_chalk29.default.green(` ${table.name} deleted.`));
4353
4448
  }
4354
4449
  }
4355
4450
  }
@@ -4360,14 +4455,14 @@ async function tenantsMenu(proj2, opts) {
4360
4455
  const out = await admin({ method: "GET", path: base, summary: "List attached tenants" });
4361
4456
  const tenants = out?.tenants ?? [];
4362
4457
  console.log();
4363
- if (!tenants.length) console.log(import_chalk28.default.dim(" No tenants attached (consumers use the default tenant)."));
4364
- for (const t of tenants) console.log(` ${import_chalk28.default.bold(t.tenant_name ?? t.name)} ${import_chalk28.default.dim(t.display_name ?? "")}`);
4458
+ if (!tenants.length) console.log(import_chalk29.default.dim(" No tenants attached (consumers use the default tenant)."));
4459
+ for (const t of tenants) console.log(` ${import_chalk29.default.bold(t.tenant_name ?? t.name)} ${import_chalk29.default.dim(t.display_name ?? "")}`);
4365
4460
  const { act } = await inquirer2.prompt([{
4366
4461
  type: "list",
4367
4462
  name: "act",
4368
4463
  message: "Tenants:",
4369
4464
  choices: [
4370
- { name: `Manage a tenant\u2026 ${import_chalk28.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
4465
+ { name: `Manage a tenant\u2026 ${import_chalk29.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
4371
4466
  { name: "Attach a tenant to this project", value: "attach" },
4372
4467
  ...tenants.length ? [{ name: "Detach a tenant from this project", value: "detach" }] : [],
4373
4468
  { name: "\u2190 Back", value: "back" }
@@ -4390,7 +4485,7 @@ async function tenantsMenu(proj2, opts) {
4390
4485
  }]);
4391
4486
  if (!t) continue;
4392
4487
  await admin({ method: "DELETE", path: `${base}/${encodeURIComponent(t.tenant_name ?? t.name)}`, summary: `Detach tenant ${t.tenant_name ?? t.name}` });
4393
- console.log(import_chalk28.default.green(` Detached ${t.tenant_name ?? t.name}.`));
4488
+ console.log(import_chalk29.default.green(` Detached ${t.tenant_name ?? t.name}.`));
4394
4489
  }
4395
4490
  }
4396
4491
  }
@@ -4433,7 +4528,7 @@ async function specMenu(proj2, opts) {
4433
4528
  choices: [
4434
4529
  { name: "Print the stored spec", value: "get" },
4435
4530
  { name: "Refresh the spec from its source", value: "refresh" },
4436
- { name: import_chalk28.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
4531
+ { name: import_chalk29.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
4437
4532
  { name: "\u2190 Back", value: "back" }
4438
4533
  ]
4439
4534
  }]);
@@ -4441,7 +4536,7 @@ async function specMenu(proj2, opts) {
4441
4536
  if (act === "get") await runSpecGet(proj2.projectName, { team: opts.team, apiversion: proj2.apiVersion });
4442
4537
  else if (act === "refresh") {
4443
4538
  await admin({ method: "POST", path: `/projects/${proj2.projectId}/${proj2.apiVersion}/refresh-spec`, summary: "Refresh spec from source" });
4444
- console.log(import_chalk28.default.green(" Spec refresh triggered."));
4539
+ console.log(import_chalk29.default.green(" Spec refresh triggered."));
4445
4540
  } else await runOpenapi(proj2.projectName, proj2.apiVersion);
4446
4541
  }
4447
4542
  async function agentsMenu(proj2, opts) {
@@ -4466,8 +4561,8 @@ async function agentsMenu(proj2, opts) {
4466
4561
  }
4467
4562
 
4468
4563
  // src/commands/key.ts
4469
- var import_chalk29 = __toESM(require("chalk"));
4470
- var import_ora14 = __toESM(require("ora"));
4564
+ var import_chalk30 = __toESM(require("chalk"));
4565
+ var import_ora15 = __toESM(require("ora"));
4471
4566
  init_admin();
4472
4567
  async function runApikeysMenu(opts) {
4473
4568
  await runKeyList(opts);
@@ -4495,11 +4590,11 @@ async function runKeyList(opts) {
4495
4590
  return;
4496
4591
  }
4497
4592
  if (!keys.length) {
4498
- console.log(import_chalk29.default.yellow("No developer keys."));
4593
+ console.log(import_chalk30.default.yellow("No developer keys."));
4499
4594
  return;
4500
4595
  }
4501
4596
  for (const k of keys) {
4502
- 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")}`);
4597
+ 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")}`);
4503
4598
  }
4504
4599
  }
4505
4600
  async function runKeyMint(opts) {
@@ -4507,7 +4602,7 @@ async function runKeyMint(opts) {
4507
4602
  const body = { role: "consumer-admin" };
4508
4603
  if (opts.desc) body.description = opts.desc;
4509
4604
  if (opts.expiresDays) body.expires_in_seconds = Number(opts.expiresDays) * 24 * 60 * 60;
4510
- const spinner = (0, import_ora14.default)("Minting key...").start();
4605
+ const spinner = (0, import_ora15.default)("Minting key...").start();
4511
4606
  try {
4512
4607
  const out = await admin({
4513
4608
  method: "POST",
@@ -4520,9 +4615,9 @@ async function runKeyMint(opts) {
4520
4615
  console.log(JSON.stringify(out));
4521
4616
  return;
4522
4617
  }
4523
- console.log(` ${import_chalk29.default.bold("key_id")}: ${out?.key_id}`);
4524
- console.log(` ${import_chalk29.default.bold("key")}: ${import_chalk29.default.green(out?.key)} ${import_chalk29.default.dim("(shown once \u2014 store it now)")}`);
4525
- if (out?.expires_at) console.log(` ${import_chalk29.default.dim("expires:")} ${out.expires_at}`);
4618
+ console.log(` ${import_chalk30.default.bold("key_id")}: ${out?.key_id}`);
4619
+ console.log(` ${import_chalk30.default.bold("key")}: ${import_chalk30.default.green(out?.key)} ${import_chalk30.default.dim("(shown once \u2014 store it now)")}`);
4620
+ if (out?.expires_at) console.log(` ${import_chalk30.default.dim("expires:")} ${out.expires_at}`);
4526
4621
  } catch (err) {
4527
4622
  spinner.fail("Mint failed.");
4528
4623
  throw err;
@@ -4530,7 +4625,7 @@ async function runKeyMint(opts) {
4530
4625
  }
4531
4626
  async function runKeyRevoke(keyId, opts) {
4532
4627
  const { teamId } = await resolveTeam(opts.team);
4533
- const spinner = (0, import_ora14.default)("Revoking key...").start();
4628
+ const spinner = (0, import_ora15.default)("Revoking key...").start();
4534
4629
  try {
4535
4630
  await admin({
4536
4631
  method: "DELETE",
@@ -4545,8 +4640,8 @@ async function runKeyRevoke(keyId, opts) {
4545
4640
  }
4546
4641
 
4547
4642
  // src/commands/consumer.ts
4548
- var import_chalk30 = __toESM(require("chalk"));
4549
- var import_ora15 = __toESM(require("ora"));
4643
+ var import_chalk31 = __toESM(require("chalk"));
4644
+ var import_ora16 = __toESM(require("ora"));
4550
4645
  init_admin();
4551
4646
  var DEFAULT_SCOPE = "openid email profile offline_access";
4552
4647
  var APIKEYS_BASE = process.env.APIBLAZE_APIKEYS_BASE || "https://apikeys.apiblaze.com";
@@ -4566,7 +4661,7 @@ async function consumerFetch(creds, suffix, init) {
4566
4661
  function requireConsumer() {
4567
4662
  const c = loadConsumer();
4568
4663
  if (!c) {
4569
- console.error(import_chalk30.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
4664
+ console.error(import_chalk31.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
4570
4665
  process.exit(1);
4571
4666
  }
4572
4667
  return c;
@@ -4577,7 +4672,7 @@ async function runConsumerLogin(opts) {
4577
4672
  let clientId = opts.client;
4578
4673
  if (clientId) {
4579
4674
  if (!tenant2) {
4580
- console.error(import_chalk30.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
4675
+ console.error(import_chalk31.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
4581
4676
  process.exit(1);
4582
4677
  }
4583
4678
  } else {
@@ -4589,25 +4684,25 @@ async function runConsumerLogin(opts) {
4589
4684
  if (!picked) process.exit(1);
4590
4685
  tenant2 = picked;
4591
4686
  }
4592
- const s2 = (0, import_ora15.default)("Finding the login app...").start();
4687
+ const s2 = (0, import_ora16.default)("Finding the login app...").start();
4593
4688
  const clients = await admin({ method: "GET", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/app-clients`, summary: `List app clients for ${tenant2}` }).catch(() => []);
4594
4689
  s2.stop();
4595
4690
  const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
4596
4691
  const pick2 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
4597
4692
  if (!pick2) {
4598
- console.error(import_chalk30.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
4693
+ console.error(import_chalk31.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
4599
4694
  process.exit(1);
4600
4695
  }
4601
4696
  clientId = pick2.client_id ?? pick2.clientId;
4602
4697
  }
4603
4698
  const portalResource = `https://${tenant2}.portal.apiblaze.com/1.0.0`;
4604
- console.log(`${import_chalk30.default.cyan("\u2192")} Logging in to ${import_chalk30.default.bold(tenant2)} as a consumer...`);
4699
+ console.log(`${import_chalk31.default.cyan("\u2192")} Logging in to ${import_chalk31.default.bold(tenant2)} as a consumer...`);
4605
4700
  const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
4606
4701
  console.log(`
4607
- Open: ${import_chalk30.default.underline(verificationUri)}`);
4608
- console.log(` Code: ${import_chalk30.default.bold(userCode)}
4702
+ Open: ${import_chalk31.default.underline(verificationUri)}`);
4703
+ console.log(` Code: ${import_chalk31.default.bold(userCode)}
4609
4704
  `);
4610
- console.log(import_chalk30.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
4705
+ console.log(import_chalk31.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
4611
4706
  }, portalResource);
4612
4707
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
4613
4708
  const creds = {
@@ -4622,7 +4717,7 @@ async function runConsumerLogin(opts) {
4622
4717
  obtainedAt: Date.now()
4623
4718
  };
4624
4719
  saveConsumer(creds);
4625
- console.log(import_chalk30.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
4720
+ console.log(import_chalk31.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
4626
4721
  }
4627
4722
  async function runConsumerTokens(opts) {
4628
4723
  const creds = requireConsumer();
@@ -4635,29 +4730,29 @@ async function runConsumerTokens(opts) {
4635
4730
  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));
4636
4731
  return;
4637
4732
  }
4638
- console.log(`${import_chalk30.default.cyan("Consumer")} ${import_chalk30.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk30.default.bold(fresh.tenant)}
4733
+ console.log(`${import_chalk31.default.cyan("Consumer")} ${import_chalk31.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk31.default.bold(fresh.tenant)}
4639
4734
  `);
4640
- console.log(`${import_chalk30.default.bold("access_token")} ${import_chalk30.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
4735
+ console.log(`${import_chalk31.default.bold("access_token")} ${import_chalk31.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
4641
4736
  ${fresh.accessToken}
4642
4737
  `);
4643
- if (fresh.idToken) console.log(`${import_chalk30.default.bold("id_token")} ${import_chalk30.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
4738
+ if (fresh.idToken) console.log(`${import_chalk31.default.bold("id_token")} ${import_chalk31.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
4644
4739
  ${fresh.idToken}
4645
4740
  `);
4646
- if (fresh.refreshToken) console.log(`${import_chalk30.default.bold("refresh_token")}
4741
+ if (fresh.refreshToken) console.log(`${import_chalk31.default.bold("refresh_token")}
4647
4742
  ${fresh.refreshToken}
4648
4743
  `);
4649
- console.log(import_chalk30.default.dim("These are your own tokens \u2014 keep them secret."));
4744
+ console.log(import_chalk31.default.dim("These are your own tokens \u2014 keep them secret."));
4650
4745
  }
4651
4746
  async function runConsumerApikeys(opts) {
4652
4747
  const creds = requireConsumer();
4653
4748
  const { default: inquirer2 } = await import("inquirer");
4654
- const spinner = (0, import_ora15.default)("Loading your API keys...").start();
4749
+ const spinner = (0, import_ora16.default)("Loading your API keys...").start();
4655
4750
  const list = await consumerFetch(creds, "/apikeys");
4656
4751
  const revealed = await consumerFetch(list.creds, "/apikeys/reveal").catch(() => ({ status: 0, data: null, creds: list.creds }));
4657
4752
  spinner.stop();
4658
4753
  if (list.status >= 400) {
4659
- console.error(import_chalk30.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
4660
- if (list.status === 401) console.error(import_chalk30.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
4754
+ console.error(import_chalk31.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
4755
+ if (list.status === 401) console.error(import_chalk31.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
4661
4756
  process.exit(1);
4662
4757
  }
4663
4758
  const keys = list.data?.keys ?? [];
@@ -4665,16 +4760,16 @@ async function runConsumerApikeys(opts) {
4665
4760
  if (opts.json) {
4666
4761
  console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
4667
4762
  } else if (!keys.length) {
4668
- console.log(import_chalk30.default.yellow("No API keys yet."));
4763
+ console.log(import_chalk31.default.yellow("No API keys yet."));
4669
4764
  } else {
4670
4765
  for (const k of keys) {
4671
4766
  const clear = revealMap[k.environment]?.key;
4672
- const shown = clear ? import_chalk30.default.green(clear) : import_chalk30.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
4673
- const exp = k.expires_at ? import_chalk30.default.dim(`exp ${k.expires_at}`) : import_chalk30.default.dim("no expiry");
4674
- console.log(` ${import_chalk30.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk30.default.dim(k.description ?? "")}`);
4767
+ const shown = clear ? import_chalk31.default.green(clear) : import_chalk31.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
4768
+ const exp = k.expires_at ? import_chalk31.default.dim(`exp ${k.expires_at}`) : import_chalk31.default.dim("no expiry");
4769
+ console.log(` ${import_chalk31.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk31.default.dim(k.description ?? "")}`);
4675
4770
  }
4676
4771
  if (Object.keys(revealMap).length === 0 && keys.some((k) => !k.expires_at)) {
4677
- console.log(import_chalk30.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
4772
+ console.log(import_chalk31.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
4678
4773
  }
4679
4774
  }
4680
4775
  if (opts.json) return;
@@ -4688,7 +4783,7 @@ async function runConsumerApikeys(opts) {
4688
4783
  const body = { environment: answers.environment };
4689
4784
  if (answers.description) body.description = answers.description;
4690
4785
  if (answers.expiresDays) body.expires_in_seconds = Number(answers.expiresDays) * 86400;
4691
- const s2 = (0, import_ora15.default)("Creating key...").start();
4786
+ const s2 = (0, import_ora16.default)("Creating key...").start();
4692
4787
  const created = await consumerFetch(list.creds, "/apikeys", { method: "POST", body: JSON.stringify(body) });
4693
4788
  if (created.status >= 400) {
4694
4789
  s2.fail(`Create failed (${created.status}): ${created.data?.error ?? ""}`);
@@ -4696,13 +4791,13 @@ async function runConsumerApikeys(opts) {
4696
4791
  }
4697
4792
  s2.succeed("Key created.");
4698
4793
  const key = created.data?.key ?? created.data?.fullKey;
4699
- if (key) console.log(` ${import_chalk30.default.green(key)} ${import_chalk30.default.dim("(shown once \u2014 store it now)")}`);
4700
- else console.log(import_chalk30.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
4794
+ if (key) console.log(` ${import_chalk31.default.green(key)} ${import_chalk31.default.dim("(shown once \u2014 store it now)")}`);
4795
+ else console.log(import_chalk31.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
4701
4796
  }
4702
4797
 
4703
4798
  // src/commands/sidecar.ts
4704
- var import_chalk31 = __toESM(require("chalk"));
4705
- var import_ora16 = __toESM(require("ora"));
4799
+ var import_chalk32 = __toESM(require("chalk"));
4800
+ var import_ora17 = __toESM(require("ora"));
4706
4801
  var fs7 = __toESM(require("fs"));
4707
4802
  var path4 = __toESM(require("path"));
4708
4803
  init_admin();
@@ -4743,18 +4838,18 @@ function upsertEnvLocal(root, token) {
4743
4838
  }
4744
4839
  function installSidecarPackage(root) {
4745
4840
  if (fs7.existsSync(path4.join(root, "node_modules", "apiblaze", "package.json"))) {
4746
- console.log(` ${import_chalk31.default.green("\u2713")} apiblaze package already installed`);
4841
+ console.log(` ${import_chalk32.default.green("\u2713")} apiblaze package already installed`);
4747
4842
  return;
4748
4843
  }
4749
4844
  const has = (f) => fs7.existsSync(path4.join(root, f));
4750
4845
  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" };
4751
- const spinner = (0, import_ora16.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
4846
+ const spinner = (0, import_ora17.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
4752
4847
  try {
4753
4848
  const { execSync } = require("child_process");
4754
4849
  execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
4755
4850
  spinner.succeed("Installed apiblaze (the sidecar runtime).");
4756
4851
  } catch {
4757
- 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")}.`);
4852
+ 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")}.`);
4758
4853
  }
4759
4854
  }
4760
4855
  function readEnvKey(root) {
@@ -4893,7 +4988,7 @@ async function runAnonymousInit(root, router, opts) {
4893
4988
  const { sidecarInitAnonymous: sidecarInitAnonymous2 } = await Promise.resolve().then(() => (init_api(), api_exports));
4894
4989
  const { saveAnonCred: saveAnonCred2, clearAnonCred: clearAnonCred2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
4895
4990
  if (opts.newSession) clearAnonCred2();
4896
- const spinner = (0, import_ora16.default)("Setting up a sidecar (no login needed)...").start();
4991
+ const spinner = (0, import_ora17.default)("Setting up a sidecar (no login needed)...").start();
4897
4992
  let out;
4898
4993
  try {
4899
4994
  out = await sidecarInitAnonymous2();
@@ -4905,29 +5000,29 @@ async function runAnonymousInit(root, router, opts) {
4905
5000
  if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
4906
5001
  const envState = upsertEnvLocal(root, out.token);
4907
5002
  ensureGitignored(root);
4908
- console.log(` ${import_chalk31.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
4909
- console.log(` ${import_chalk31.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
5003
+ console.log(` ${import_chalk32.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
5004
+ console.log(` ${import_chalk32.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
4910
5005
  installSidecarPackage(root);
4911
5006
  let inspectorPath = null;
4912
5007
  if (!opts.noInspector) {
4913
5008
  inspectorPath = generateInspector(root, router);
4914
- if (inspectorPath) console.log(` ${import_chalk31.default.green("\u2713")} inspector at ${inspectorPath}`);
5009
+ if (inspectorPath) console.log(` ${import_chalk32.default.green("\u2713")} inspector at ${inspectorPath}`);
4915
5010
  }
4916
5011
  console.log("");
4917
- console.log(import_chalk31.default.bold("Done (no account needed). What happens next:"));
4918
- console.log(` 1. ${import_chalk31.default.cyan("npm run dev")} and use your app.`);
5012
+ console.log(import_chalk32.default.bold("Done (no account needed). What happens next:"));
5013
+ console.log(` 1. ${import_chalk32.default.cyan("npm run dev")} and use your app.`);
4919
5014
  console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
4920
- console.log(` ${import_chalk31.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
5015
+ console.log(` ${import_chalk32.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
4921
5016
  console.log("");
4922
- console.log(import_chalk31.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
4923
- console.log(` ${import_chalk31.default.cyan("apiblaze login")} then ${import_chalk31.default.cyan("apiblaze claim")} ${import_chalk31.default.dim("(no code needed here)")}`);
4924
- console.log(import_chalk31.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
5017
+ console.log(import_chalk32.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
5018
+ console.log(` ${import_chalk32.default.cyan("apiblaze login")} then ${import_chalk32.default.cyan("apiblaze claim")} ${import_chalk32.default.dim("(no code needed here)")}`);
5019
+ console.log(import_chalk32.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
4925
5020
  }
4926
5021
  async function runSidecar(opts) {
4927
5022
  const root = path4.resolve(opts.dir ?? process.cwd());
4928
5023
  const detected = detectNextProject(root);
4929
5024
  if (!detected.found) {
4930
- console.log(import_chalk31.default.yellow(`No Next.js project detected in ${root}.`));
5025
+ console.log(import_chalk32.default.yellow(`No Next.js project detected in ${root}.`));
4931
5026
  console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
4932
5027
  return;
4933
5028
  }
@@ -4938,10 +5033,10 @@ async function runSidecar(opts) {
4938
5033
  if (!loadCredentials()) {
4939
5034
  upsertEnvLocal(root, readEnvKey(root));
4940
5035
  ensureGitignored(root);
4941
- console.log(` ${import_chalk31.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
4942
- console.log(` ${import_chalk31.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
5036
+ console.log(` ${import_chalk32.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
5037
+ console.log(` ${import_chalk32.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
4943
5038
  installSidecarPackage(root);
4944
- console.log(import_chalk31.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
5039
+ console.log(import_chalk32.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
4945
5040
  return;
4946
5041
  }
4947
5042
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -4950,7 +5045,7 @@ async function runSidecar(opts) {
4950
5045
  const mustMint = !existingKey || opts.rotate || switchingTeam;
4951
5046
  let token = existingKey ?? "";
4952
5047
  if (mustMint) {
4953
- 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();
5048
+ 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();
4954
5049
  try {
4955
5050
  const out = await admin({
4956
5051
  method: "POST",
@@ -4964,39 +5059,39 @@ async function runSidecar(opts) {
4964
5059
  throw err;
4965
5060
  }
4966
5061
  } else {
4967
- 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).`));
5062
+ 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).`));
4968
5063
  }
4969
5064
  const envState = upsertEnvLocal(root, token);
4970
5065
  ensureGitignored(root);
4971
- console.log(` ${import_chalk31.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
5066
+ console.log(` ${import_chalk32.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
4972
5067
  const wireState = wireInstrumentation(root);
4973
- console.log(` ${import_chalk31.default.green("\u2713")} instrumentation.ts ${wireState}`);
5068
+ console.log(` ${import_chalk32.default.green("\u2713")} instrumentation.ts ${wireState}`);
4974
5069
  installSidecarPackage(root);
4975
5070
  let inspectorPath = null;
4976
5071
  if (!opts.noInspector) {
4977
5072
  inspectorPath = generateInspector(root, detected.router);
4978
- if (inspectorPath) console.log(` ${import_chalk31.default.green("\u2713")} inspector at ${inspectorPath}`);
5073
+ if (inspectorPath) console.log(` ${import_chalk32.default.green("\u2713")} inspector at ${inspectorPath}`);
4979
5074
  }
4980
5075
  console.log("");
4981
- console.log(import_chalk31.default.bold("Done. What happens next:"));
4982
- console.log(` 1. ${import_chalk31.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
4983
- console.log(` 2. The origins your app calls appear as ${import_chalk31.default.bold("candidates")} \u2014 list them: ${import_chalk31.default.cyan("apiblaze sidecar")}`);
4984
- console.log(` 3. Approve the ones to route: ${import_chalk31.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
5076
+ console.log(import_chalk32.default.bold("Done. What happens next:"));
5077
+ console.log(` 1. ${import_chalk32.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
5078
+ console.log(` 2. The origins your app calls appear as ${import_chalk32.default.bold("candidates")} \u2014 list them: ${import_chalk32.default.cyan("apiblaze sidecar")}`);
5079
+ console.log(` 3. Approve the ones to route: ${import_chalk32.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
4985
5080
  console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
4986
- 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)`);
4987
- 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>\`.`));
5081
+ 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)`);
5082
+ 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>\`.`));
4988
5083
  console.log("");
4989
- console.log(import_chalk31.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
4990
- console.log(import_chalk31.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
4991
- console.log(import_chalk31.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
5084
+ console.log(import_chalk32.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
5085
+ console.log(import_chalk32.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
5086
+ console.log(import_chalk32.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
4992
5087
  console.log("");
4993
- 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."));
4994
- console.log(import_chalk31.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
5088
+ 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."));
5089
+ console.log(import_chalk32.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
4995
5090
  }
4996
5091
 
4997
5092
  // src/commands/origins.ts
4998
- var import_chalk32 = __toESM(require("chalk"));
4999
- var import_ora17 = __toESM(require("ora"));
5093
+ var import_chalk33 = __toESM(require("chalk"));
5094
+ var import_ora18 = __toESM(require("ora"));
5000
5095
  init_admin();
5001
5096
  init_auth();
5002
5097
  init_anon_cred();
@@ -5005,7 +5100,7 @@ async function runOriginsList(opts) {
5005
5100
  if (!loadCredentials()) {
5006
5101
  const cred = loadAnonCred();
5007
5102
  if (!cred) {
5008
- console.log(import_chalk32.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
5103
+ console.log(import_chalk33.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
5009
5104
  return;
5010
5105
  }
5011
5106
  out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
@@ -5023,30 +5118,30 @@ async function runOriginsList(opts) {
5023
5118
  }
5024
5119
  const routed = out.routed ?? [];
5025
5120
  const candidates = out.candidates ?? [];
5026
- console.log(import_chalk32.default.bold(`
5121
+ console.log(import_chalk33.default.bold(`
5027
5122
  Routed through APIblaze (${routed.length})`));
5028
- if (!routed.length) console.log(import_chalk32.default.dim(" none yet"));
5029
- for (const r of routed) console.log(` ${import_chalk32.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk32.default.dim(`\u2192 ${r.project_id}`)}`);
5030
- console.log(import_chalk32.default.bold(`
5123
+ if (!routed.length) console.log(import_chalk33.default.dim(" none yet"));
5124
+ for (const r of routed) console.log(` ${import_chalk33.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk33.default.dim(`\u2192 ${r.project_id}`)}`);
5125
+ console.log(import_chalk33.default.bold(`
5031
5126
  Candidates \u2014 going direct, not yet approved (${candidates.length})`));
5032
- if (!candidates.length) console.log(import_chalk32.default.dim(" none \u2014 run your app to discover the origins it calls"));
5127
+ if (!candidates.length) console.log(import_chalk33.default.dim(" none \u2014 run your app to discover the origins it calls"));
5033
5128
  for (const c of candidates) {
5034
- console.log(` ${import_chalk32.default.yellow("\u25CB")} ${c.origin} ${import_chalk32.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
5129
+ console.log(` ${import_chalk33.default.yellow("\u25CB")} ${c.origin} ${import_chalk33.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
5035
5130
  }
5036
5131
  if (candidates.length) {
5037
- console.log(import_chalk32.default.dim(`
5132
+ console.log(import_chalk33.default.dim(`
5038
5133
  Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
5039
- console.log(import_chalk32.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
5134
+ console.log(import_chalk33.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
5040
5135
  }
5041
5136
  }
5042
5137
  async function runOriginsApprove(origin, opts) {
5043
5138
  if (!loadCredentials()) {
5044
5139
  const cred = loadAnonCred();
5045
5140
  if (!cred) {
5046
- console.error(import_chalk32.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
5141
+ console.error(import_chalk33.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
5047
5142
  process.exit(1);
5048
5143
  }
5049
- const spinner2 = (0, import_ora17.default)(`Approving ${origin} (anonymous)...`).start();
5144
+ const spinner2 = (0, import_ora18.default)(`Approving ${origin} (anonymous)...`).start();
5050
5145
  try {
5051
5146
  const out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/approve`, { method: "POST", body: JSON.stringify({ origin }) });
5052
5147
  spinner2.succeed(`Approved ${origin} \u2192 proxy ${out.project_id}. Routing within ~5 min.`);
@@ -5057,7 +5152,7 @@ async function runOriginsApprove(origin, opts) {
5057
5152
  return;
5058
5153
  }
5059
5154
  const { teamId } = await resolveTeam(opts.team);
5060
- const spinner = (0, import_ora17.default)(`Approving ${origin}...`).start();
5155
+ const spinner = (0, import_ora18.default)(`Approving ${origin}...`).start();
5061
5156
  try {
5062
5157
  const out = await admin({
5063
5158
  method: "POST",
@@ -5074,7 +5169,7 @@ async function runOriginsApprove(origin, opts) {
5074
5169
  }
5075
5170
  async function runOriginsDeny(origin, opts) {
5076
5171
  const { teamId } = await resolveTeam(opts.team);
5077
- const spinner = (0, import_ora17.default)(`Dismissing ${origin}...`).start();
5172
+ const spinner = (0, import_ora18.default)(`Dismissing ${origin}...`).start();
5078
5173
  try {
5079
5174
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/dismiss`, body: { origin }, summary: `Dismiss sidecar origin ${origin}` });
5080
5175
  spinner.succeed(`Dismissed ${origin}. It won't be suggested again.`);
@@ -5085,7 +5180,7 @@ async function runOriginsDeny(origin, opts) {
5085
5180
  }
5086
5181
  async function runOriginsRemove(origin, opts) {
5087
5182
  const { teamId } = await resolveTeam(opts.team);
5088
- const spinner = (0, import_ora17.default)(`Removing the proxy for ${origin}...`).start();
5183
+ const spinner = (0, import_ora18.default)(`Removing the proxy for ${origin}...`).start();
5089
5184
  try {
5090
5185
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/remove`, body: { origin }, summary: `Un-route sidecar origin ${origin}` });
5091
5186
  spinner.succeed(`Removed ${origin}. Your app will stop routing it (goes direct) within ~5 min.`);
@@ -5096,7 +5191,7 @@ async function runOriginsRemove(origin, opts) {
5096
5191
  }
5097
5192
 
5098
5193
  // src/commands/op.ts
5099
- var import_chalk33 = __toESM(require("chalk"));
5194
+ var import_chalk34 = __toESM(require("chalk"));
5100
5195
  init_auth();
5101
5196
  init_trace();
5102
5197
  init_types();
@@ -5129,82 +5224,82 @@ function printResidue(report, applied) {
5129
5224
  const up = report?.upstash ?? {};
5130
5225
  const fga = report?.fga ?? {};
5131
5226
  const ghosts = report?.ghosts ?? {};
5132
- console.log(import_chalk33.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
5133
- console.log(import_chalk33.default.bold("\n Upstash"));
5227
+ console.log(import_chalk34.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
5228
+ console.log(import_chalk34.default.bold("\n Upstash"));
5134
5229
  const orphans = up.orphans ?? [];
5135
- if (orphans.length === 0) console.log(import_chalk33.default.green(" no orphaned keys"));
5136
- for (const o of orphans) console.log(` ${import_chalk33.default.yellow(o.key)} ${import_chalk33.default.dim(`\u2014 ${o.reason}`)}`);
5137
- console.log(import_chalk33.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
5230
+ if (orphans.length === 0) console.log(import_chalk34.default.green(" no orphaned keys"));
5231
+ for (const o of orphans) console.log(` ${import_chalk34.default.yellow(o.key)} ${import_chalk34.default.dim(`\u2014 ${o.reason}`)}`);
5232
+ console.log(import_chalk34.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
5138
5233
  if (up.anon_wallet_detail) {
5139
5234
  const d = up.anon_wallet_detail;
5140
- 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)"}`));
5235
+ 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)"}`));
5141
5236
  }
5142
5237
  if (up.keyspace_census) {
5143
5238
  const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
5144
- console.log(import_chalk33.default.dim(` keyspace: ${census}`));
5239
+ console.log(import_chalk34.default.dim(` keyspace: ${census}`));
5145
5240
  }
5146
- if (up.unknown?.length) console.log(import_chalk33.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
5147
- if (applied) console.log(` ${import_chalk33.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
5148
- for (const e of up.errors ?? []) console.log(import_chalk33.default.red(` error: ${e}`));
5149
- console.log(import_chalk33.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
5241
+ if (up.unknown?.length) console.log(import_chalk34.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
5242
+ if (applied) console.log(` ${import_chalk34.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
5243
+ for (const e of up.errors ?? []) console.log(import_chalk34.default.red(` error: ${e}`));
5244
+ console.log(import_chalk34.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
5150
5245
  if (applied) {
5151
5246
  const swept = fga?.swept ?? [];
5152
- if (swept.length === 0) console.log(import_chalk33.default.green(" no orphaned stores"));
5247
+ if (swept.length === 0) console.log(import_chalk34.default.green(" no orphaned stores"));
5153
5248
  for (const s of swept) {
5154
5249
  console.log(
5155
- ` ${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`)}`
5250
+ ` ${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`)}`
5156
5251
  );
5157
5252
  }
5158
- if (fga?.remaining) console.log(import_chalk33.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
5253
+ if (fga?.remaining) console.log(import_chalk34.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
5159
5254
  const st = fga?.side_tables;
5160
- 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})` : ""}`));
5255
+ 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})` : ""}`));
5161
5256
  } else {
5162
5257
  const fgaOrphans = fga?.orphans ?? [];
5163
- if (fgaOrphans.length === 0) console.log(import_chalk33.default.green(" no orphaned stores"));
5258
+ if (fgaOrphans.length === 0) console.log(import_chalk34.default.green(" no orphaned stores"));
5164
5259
  for (const s of fgaOrphans) {
5165
5260
  const src = s.in_openfga ? "live in OpenFGA" : "Neon tuples only";
5166
- 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)`)}`);
5261
+ 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)`)}`);
5167
5262
  }
5168
- console.log(import_chalk33.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
5263
+ console.log(import_chalk34.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
5169
5264
  const st = fga?.side_tables;
5170
- 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`));
5265
+ 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`));
5171
5266
  }
5172
- for (const e of fga?.errors ?? []) console.log(import_chalk33.default.red(` error: ${e}`));
5173
- console.log(import_chalk33.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
5267
+ for (const e of fga?.errors ?? []) console.log(import_chalk34.default.red(` error: ${e}`));
5268
+ console.log(import_chalk34.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
5174
5269
  if (applied) {
5175
- if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk33.default.green(" no ghost tuples"));
5176
- 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)`)}`);
5270
+ if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk34.default.green(" no ghost tuples"));
5271
+ 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)`)}`);
5177
5272
  } else {
5178
5273
  const n = ghosts?.ghost_count ?? 0;
5179
- 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)`)}`));
5274
+ 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)`)}`));
5180
5275
  else {
5181
- console.log(import_chalk33.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
5276
+ console.log(import_chalk34.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
5182
5277
  for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
5183
- console.log(import_chalk33.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
5278
+ console.log(import_chalk34.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
5184
5279
  }
5185
- if (n > 20) console.log(import_chalk33.default.dim(` \u2026 and ${n - 20} more`));
5280
+ if (n > 20) console.log(import_chalk34.default.dim(` \u2026 and ${n - 20} more`));
5186
5281
  }
5187
5282
  }
5188
- for (const e of ghosts?.errors ?? []) console.log(import_chalk33.default.red(` error: ${e}`));
5283
+ for (const e of ghosts?.errors ?? []) console.log(import_chalk34.default.red(` error: ${e}`));
5189
5284
  console.log();
5190
5285
  }
5191
5286
  async function runOp(sub, opts = {}) {
5192
5287
  if (!loadCredentials()) {
5193
- console.log(import_chalk33.default.dim("Not logged in. Run `apiblaze login`."));
5288
+ console.log(import_chalk34.default.dim("Not logged in. Run `apiblaze login`."));
5194
5289
  return;
5195
5290
  }
5196
5291
  if (!isOperatorLogin()) {
5197
- console.log(import_chalk33.default.dim("`apiblaze op` is only available to platform operators."));
5292
+ console.log(import_chalk34.default.dim("`apiblaze op` is only available to platform operators."));
5198
5293
  return;
5199
5294
  }
5200
5295
  switch (sub) {
5201
5296
  case void 0:
5202
5297
  case "menu": {
5203
- console.log(import_chalk33.default.bold("\nOperator menu"));
5204
- console.log(` ${import_chalk33.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
5205
- console.log(` ${import_chalk33.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk33.default.dim("-y to skip")})`);
5206
- console.log(` ${import_chalk33.default.cyan("apiblaze op credits")} list credit wallets`);
5207
- console.log(import_chalk33.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
5298
+ console.log(import_chalk34.default.bold("\nOperator menu"));
5299
+ console.log(` ${import_chalk34.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
5300
+ console.log(` ${import_chalk34.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk34.default.dim("-y to skip")})`);
5301
+ console.log(` ${import_chalk34.default.cyan("apiblaze op credits")} list credit wallets`);
5302
+ console.log(import_chalk34.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
5208
5303
  `));
5209
5304
  return;
5210
5305
  }
@@ -5223,17 +5318,17 @@ async function runOp(sub, opts = {}) {
5223
5318
  const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
5224
5319
  printResidue(report, false);
5225
5320
  if (nUp + nFga + nGhost + nSide === 0) {
5226
- console.log(import_chalk33.default.green("Nothing to sweep."));
5321
+ console.log(import_chalk34.default.green("Nothing to sweep."));
5227
5322
  return;
5228
5323
  }
5229
5324
  if (!opts.yes) {
5230
5325
  const readline2 = await import("readline/promises");
5231
5326
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
5232
5327
  const answer = await rl.question(
5233
- 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: `)
5328
+ 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: `)
5234
5329
  );
5235
5330
  rl.close();
5236
- if (answer.trim() !== "sweep") return void console.log(import_chalk33.default.dim("Aborted."));
5331
+ if (answer.trim() !== "sweep") return void console.log(import_chalk34.default.dim("Aborted."));
5237
5332
  }
5238
5333
  const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
5239
5334
  if (opts.json) return void console.log(JSON.stringify(result, null, 2));
@@ -5244,15 +5339,15 @@ async function runOp(sub, opts = {}) {
5244
5339
  const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list credit wallets" });
5245
5340
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
5246
5341
  const accounts = data?.accounts ?? [];
5247
- if (accounts.length === 0) return void console.log(import_chalk33.default.dim("No credit wallets."));
5342
+ if (accounts.length === 0) return void console.log(import_chalk34.default.dim("No credit wallets."));
5248
5343
  for (const a of accounts) {
5249
5344
  const bal = typeof a.balance_cents === "number" ? `$${(a.balance_cents / 100).toFixed(2)}` : "?";
5250
- 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") : ""}`);
5345
+ 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") : ""}`);
5251
5346
  }
5252
5347
  return;
5253
5348
  }
5254
5349
  default:
5255
- console.log(import_chalk33.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
5350
+ console.log(import_chalk34.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
5256
5351
  }
5257
5352
  }
5258
5353
 
@@ -5309,7 +5404,7 @@ program.command("dev").description("Put your localhost behind a public URL (dev
5309
5404
  try {
5310
5405
  const resolved = parseInt(port ?? opts.port, 10);
5311
5406
  if (Number.isNaN(resolved)) {
5312
- console.error(import_chalk34.default.red(`Invalid port: ${port ?? opts.port}`));
5407
+ console.error(import_chalk35.default.red(`Invalid port: ${port ?? opts.port}`));
5313
5408
  process.exit(1);
5314
5409
  }
5315
5410
  await runDev({ port: resolved, captureFile: opts.captureFile });
@@ -5407,7 +5502,7 @@ function groupedCommandHelp() {
5407
5502
  const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
5408
5503
  return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
5409
5504
  }).filter(Boolean).join("\n");
5410
- return `${import_chalk34.default.bold(g.title)}
5505
+ return `${import_chalk35.default.bold(g.title)}
5411
5506
  ${rows}`;
5412
5507
  }).join("\n\n");
5413
5508
  }
@@ -5440,14 +5535,14 @@ async function recoverStaleTeam() {
5440
5535
  const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
5441
5536
  const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
5442
5537
  if (!linked) {
5443
- console.error(import_chalk34.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
5538
+ console.error(import_chalk35.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
5444
5539
  return;
5445
5540
  }
5446
5541
  if (linked.teamId === creds.teamId) return;
5447
5542
  const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
5448
5543
  delete next.activeTenant;
5449
5544
  saveCredentials(next);
5450
- 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.`));
5545
+ 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.`));
5451
5546
  } catch {
5452
5547
  }
5453
5548
  }
@@ -5455,16 +5550,16 @@ async function printError(err) {
5455
5550
  if (err instanceof ApiError) {
5456
5551
  const data = err.body;
5457
5552
  const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
5458
- console.error(import_chalk34.default.red(`
5553
+ console.error(import_chalk35.default.red(`
5459
5554
  API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
5460
5555
  if (err.status === 403 || err.status === 404) {
5461
5556
  await recoverStaleTeam();
5462
5557
  }
5463
5558
  } else if (err instanceof Error) {
5464
- console.error(import_chalk34.default.red(`
5559
+ console.error(import_chalk35.default.red(`
5465
5560
  Error: ${err.message}`));
5466
5561
  } else {
5467
- console.error(import_chalk34.default.red("\nUnknown error"));
5562
+ console.error(import_chalk35.default.red("\nUnknown error"));
5468
5563
  }
5469
5564
  }
5470
5565
  program.parse(process.argv);