apiblaze 0.18.2 → 0.18.6

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.
package/dist/index.js CHANGED
@@ -485,7 +485,7 @@ async function createTenantRow(teamId) {
485
485
  const { name } = await inquirer3.prompt([{
486
486
  type: "input",
487
487
  name: "name",
488
- message: `Tenant name ${import_chalk23.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
488
+ message: `Tenant name ${import_chalk25.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
489
489
  validate: (s) => /^[a-z0-9]+$/.test(s.trim()) ? true : "lowercase letters and numbers only"
490
490
  }]);
491
491
  const slug = name.trim();
@@ -500,7 +500,7 @@ async function createTenantRow(teamId) {
500
500
  } catch (err) {
501
501
  const msg = err instanceof Error ? err.message : String(err);
502
502
  if (/taken|unique|exists|reserved|conflict/i.test(msg)) {
503
- console.log(import_chalk23.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
503
+ console.log(import_chalk25.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
504
504
  continue;
505
505
  }
506
506
  throw err;
@@ -517,11 +517,11 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
517
517
  pageSize: 10,
518
518
  choices: [
519
519
  ...PROVIDERS.map((p) => ({ name: p.label, value: p.id })),
520
- ...opts.allowSkip ? [new inquirer3.Separator(), { name: import_chalk23.default.dim("Skip for now \u2014 set up a login method later"), value: null }] : []
520
+ ...opts.allowSkip ? [new inquirer3.Separator(), { name: import_chalk25.default.dim("Skip for now \u2014 set up a login method later"), value: null }] : []
521
521
  ]
522
522
  }]);
523
523
  if (!provider) {
524
- console.log(import_chalk23.default.dim(" No login method yet \u2014 add one later under Login methods."));
524
+ console.log(import_chalk25.default.dim(" No login method yet \u2014 add one later under Login methods."));
525
525
  return false;
526
526
  }
527
527
  const opt = PROVIDERS.find((p) => p.id === provider);
@@ -552,7 +552,7 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
552
552
  if (a.callbacks.trim()) clientBody.authorizedCallbackUrls = a.callbacks.split(/\s*,\s*/).map((s) => s.trim()).filter(Boolean);
553
553
  if (a.scopes.trim() && opt.own) providerBody.scopes = a.scopes.split(/\s+/).filter(Boolean);
554
554
  }
555
- const spinner = (0, import_ora8.default)("Setting up login...").start();
555
+ const spinner = (0, import_ora9.default)("Setting up login...").start();
556
556
  try {
557
557
  const client = await admin({ method: "POST", path: `${base}/app-clients`, body: clientBody, summary: `Create login for ${tenant2}` });
558
558
  const clientId = client?.clientId ?? client?.client_id;
@@ -567,27 +567,27 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
567
567
  async function createTenantInteractive(teamId) {
568
568
  const { default: inquirer3 } = await import("inquirer");
569
569
  const tenant2 = await createTenantRow(teamId);
570
- console.log(import_chalk23.default.green(` Tenant ${import_chalk23.default.bold(tenant2)} created.`));
570
+ console.log(import_chalk25.default.green(` Tenant ${import_chalk25.default.bold(tenant2)} created.`));
571
571
  const { users } = await inquirer3.prompt([{
572
572
  type: "confirm",
573
573
  name: "users",
574
574
  default: false,
575
- message: `Enable Users & groups? ${import_chalk23.default.dim(`(identity/key management at iam.apiblaze.com)`)}`
575
+ message: `Enable Users & groups? ${import_chalk25.default.dim(`(identity/key management at iam.apiblaze.com)`)}`
576
576
  }]);
577
577
  if (users) {
578
578
  await admin({ method: "PATCH", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/iam`, body: { enabled: true }, summary: "Enable Users & groups" }).catch(() => {
579
579
  });
580
- console.log(import_chalk23.default.green(" Users & groups enabled."));
580
+ console.log(import_chalk25.default.green(" Users & groups enabled."));
581
581
  }
582
582
  await addApiblazeHostedLogin(teamId, tenant2, { allowSkip: true });
583
583
  return tenant2;
584
584
  }
585
- var import_chalk23, import_ora8, PROVIDERS, DEFAULT_SCOPES;
585
+ var import_chalk25, import_ora9, PROVIDERS, DEFAULT_SCOPES;
586
586
  var init_tenant_create = __esm({
587
587
  "src/lib/tenant-create.ts"() {
588
588
  "use strict";
589
- import_chalk23 = __toESM(require("chalk"));
590
- import_ora8 = __toESM(require("ora"));
589
+ import_chalk25 = __toESM(require("chalk"));
590
+ import_ora9 = __toESM(require("ora"));
591
591
  init_admin();
592
592
  PROVIDERS = [
593
593
  { id: "apiblaze", label: "APIblaze (via GitHub) \u2014 zero setup, recommended", own: false },
@@ -625,10 +625,10 @@ async function fetchPage(teamId, q) {
625
625
  }
626
626
  function label(t, defaultTenant, active) {
627
627
  const tags = [
628
- t.tenant_name === active ? import_chalk24.default.cyan("active scope") : "",
629
- t.tenant_name === defaultTenant ? import_chalk24.default.dim("team default") : ""
628
+ t.tenant_name === active ? import_chalk26.default.cyan("active scope") : "",
629
+ t.tenant_name === defaultTenant ? import_chalk26.default.dim("team default") : ""
630
630
  ].filter(Boolean).join(", ");
631
- const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk24.default.dim(` ${t.display_name}`) : "";
631
+ const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk26.default.dim(` ${t.display_name}`) : "";
632
632
  return `${t.tenant_name}${disp}${tags ? ` (${tags})` : ""}`;
633
633
  }
634
634
  async function pickTenant(teamId, opts = {}) {
@@ -636,14 +636,14 @@ async function pickTenant(teamId, opts = {}) {
636
636
  const active = loadCredentials()?.activeTenant;
637
637
  let q = opts.initialQuery ?? "";
638
638
  for (; ; ) {
639
- const spinner = (0, import_ora9.default)(q ? `Searching tenants for "${q}"...` : "Loading tenants...").start();
639
+ const spinner = (0, import_ora10.default)(q ? `Searching tenants for "${q}"...` : "Loading tenants...").start();
640
640
  const page = await fetchPage(teamId, q).finally(() => spinner.stop());
641
641
  if (!page.total && !q) {
642
642
  if (opts.allowCreate) {
643
643
  const { make } = await inquirer3.prompt([{ type: "confirm", name: "make", message: "No tenants yet \u2014 create one?", default: true }]);
644
644
  if (make) return await createTenantInline(teamId);
645
645
  }
646
- console.error(import_chalk24.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
646
+ console.error(import_chalk26.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
647
647
  return null;
648
648
  }
649
649
  const truncated = page.total > page.rows.length;
@@ -652,7 +652,7 @@ async function pickTenant(teamId, opts = {}) {
652
652
  value: t.tenant_name
653
653
  }));
654
654
  if (truncated || q) {
655
- choices.push(new inquirer3.Separator(import_chalk24.default.dim(
655
+ choices.push(new inquirer3.Separator(import_chalk26.default.dim(
656
656
  truncated ? `showing ${page.rows.length} of ${page.total}${q ? ` matching "${q}"` : ""} \u2014 search to narrow` : `matches for "${q}"`
657
657
  )));
658
658
  choices.push({ name: `\u{1F50D} Search${q ? " again" : ""}\u2026`, value: "\0search" });
@@ -686,12 +686,12 @@ async function createTenantInline(teamId) {
686
686
  const { createTenantInteractive: createTenantInteractive2 } = await Promise.resolve().then(() => (init_tenant_create(), tenant_create_exports));
687
687
  return createTenantInteractive2(teamId);
688
688
  }
689
- var import_chalk24, import_ora9, PAGE;
689
+ var import_chalk26, import_ora10, PAGE;
690
690
  var init_tenant_pick = __esm({
691
691
  "src/lib/tenant-pick.ts"() {
692
692
  "use strict";
693
- import_chalk24 = __toESM(require("chalk"));
694
- import_ora9 = __toESM(require("ora"));
693
+ import_chalk26 = __toESM(require("chalk"));
694
+ import_ora10 = __toESM(require("ora"));
695
695
  init_admin();
696
696
  init_auth();
697
697
  PAGE = 15;
@@ -700,10 +700,10 @@ var init_tenant_pick = __esm({
700
700
 
701
701
  // src/index.ts
702
702
  var import_commander = require("commander");
703
- var import_chalk39 = __toESM(require("chalk"));
703
+ var import_chalk41 = __toESM(require("chalk"));
704
704
 
705
705
  // package.json
706
- var version = "0.18.2";
706
+ var version = "0.18.6";
707
707
 
708
708
  // src/index.ts
709
709
  init_types();
@@ -2331,7 +2331,7 @@ async function runTeam(arg) {
2331
2331
  }
2332
2332
 
2333
2333
  // src/commands/authz.ts
2334
- var import_chalk15 = __toESM(require("chalk"));
2334
+ var import_chalk16 = __toESM(require("chalk"));
2335
2335
  init_auth();
2336
2336
  init_api();
2337
2337
 
@@ -2424,6 +2424,56 @@ async function runAgentChatRepl(opts) {
2424
2424
  rl.close();
2425
2425
  }
2426
2426
 
2427
+ // src/lib/authz-apply.ts
2428
+ var import_chalk15 = __toESM(require("chalk"));
2429
+ init_api();
2430
+ async function applyProposal(opts) {
2431
+ const log = opts.log ?? ((s) => console.log(s));
2432
+ const { projectId, apiVersion, tenant: tenant2, proposal, enable } = opts;
2433
+ if (!enable) {
2434
+ const m = await agentCall(`/projects/${projectId}/${apiVersion}/policies/model?tenantId=${encodeURIComponent(tenant2)}`, "POST", proposal.model);
2435
+ if (m.status === 404) {
2436
+ log(import_chalk15.default.red(" Authorization store not provisioned yet. Open the dashboard Authorization tab for this project once (it auto-provisions the store), then re-run.\n"));
2437
+ return { ok: 0, fail: 0, enabled: false, storeMissing: true };
2438
+ }
2439
+ if (m.status >= 400) {
2440
+ log(import_chalk15.default.red(` Model save failed (${m.status}): ${m.data?.error ?? ""}
2441
+ `));
2442
+ return { ok: 0, fail: 0, enabled: false };
2443
+ }
2444
+ }
2445
+ let ok = 0;
2446
+ let fail5 = 0;
2447
+ for (const r of proposal.routes) {
2448
+ const resource = "/" + String(r.resource || "").replace(/^\/+/, "");
2449
+ const policiesBody = {
2450
+ rule_mode: r.rule_mode === "list" ? "list" : "check-write",
2451
+ on_request_read: Array.isArray(r.on_request_read) ? r.on_request_read : [],
2452
+ post_response_write: Array.isArray(r.post_response_write) ? r.post_response_write : [],
2453
+ list_objects_read: r.list_objects_read ?? null,
2454
+ authentication_config: { require_authentication: true },
2455
+ authorization_enabled: enable
2456
+ };
2457
+ const encoded = resource.replace(/\{/g, "%7B").replace(/\}/g, "%7D");
2458
+ const putPath = `/projects/${projectId}/${apiVersion}/policies/route/${r.method.toUpperCase()}${encoded}`;
2459
+ let res = await agentCall(putPath, "PUT", { ...policiesBody, resource });
2460
+ if (res.status === 404) {
2461
+ res = await agentCall(`/projects/${projectId}/${apiVersion}/policies/route`, "POST", { method: r.method.toUpperCase(), resource, ...policiesBody });
2462
+ }
2463
+ if (res.status >= 200 && res.status < 300) ok++;
2464
+ else fail5++;
2465
+ }
2466
+ if (enable) {
2467
+ const e = await agentCall(`/${projectId}/${apiVersion}/config`, "PATCH", { authorization: { enforce_authorization: true }, tenant: tenant2 });
2468
+ if (e.status >= 400) {
2469
+ log(import_chalk15.default.red(` Enforced ${ok} route(s) but turning on the project-level switch failed (${e.status}). Toggle "Enforce Authorization" on in the dashboard.
2470
+ `));
2471
+ return { ok, fail: fail5, enabled: false };
2472
+ }
2473
+ }
2474
+ return { ok, fail: fail5, enabled: enable };
2475
+ }
2476
+
2427
2477
  // src/commands/authz.ts
2428
2478
  async function runAuthz(projectArg, apiVersionArg) {
2429
2479
  const creds = loadCredentials();
@@ -2439,50 +2489,13 @@ async function runAuthz(projectArg, apiVersionArg) {
2439
2489
  const tenant2 = match.tenant || projectId;
2440
2490
  async function apply(ctx, enable) {
2441
2491
  const proposal = ctx.proposal;
2442
- if (!enable) {
2443
- const m = await agentCall(`/projects/${projectId}/${apiVersion}/policies/model?tenantId=${encodeURIComponent(tenant2)}`, "POST", proposal.model);
2444
- if (m.status === 404) {
2445
- ctx.log(import_chalk15.default.red(" Authorization store not provisioned yet. Open the dashboard Authorization tab for this project once (it auto-provisions the store), then re-run.\n"));
2446
- return;
2447
- }
2448
- if (m.status >= 400) {
2449
- ctx.log(import_chalk15.default.red(` Model save failed (${m.status}): ${m.data?.error ?? ""}
2450
- `));
2451
- return;
2452
- }
2453
- }
2454
- let ok = 0;
2455
- let fail5 = 0;
2456
- for (const r of proposal.routes) {
2457
- const resource = "/" + String(r.resource || "").replace(/^\/+/, "");
2458
- const policiesBody = {
2459
- rule_mode: r.rule_mode === "list" ? "list" : "check-write",
2460
- on_request_read: Array.isArray(r.on_request_read) ? r.on_request_read : [],
2461
- post_response_write: Array.isArray(r.post_response_write) ? r.post_response_write : [],
2462
- list_objects_read: r.list_objects_read ?? null,
2463
- authentication_config: { require_authentication: true },
2464
- authorization_enabled: enable
2465
- };
2466
- const encoded = resource.replace(/\{/g, "%7B").replace(/\}/g, "%7D");
2467
- const putPath = `/projects/${projectId}/${apiVersion}/policies/route/${r.method.toUpperCase()}${encoded}`;
2468
- let res = await agentCall(putPath, "PUT", { ...policiesBody, resource });
2469
- if (res.status === 404) {
2470
- res = await agentCall(`/projects/${projectId}/${apiVersion}/policies/route`, "POST", { method: r.method.toUpperCase(), resource, ...policiesBody });
2471
- }
2472
- if (res.status >= 200 && res.status < 300) ok++;
2473
- else fail5++;
2474
- }
2475
- if (enable) {
2476
- const e = await agentCall(`/${projectId}/${apiVersion}/config`, "PATCH", { authorization: { enforce_authorization: true }, tenant: tenant2 });
2477
- if (e.status >= 400) {
2478
- ctx.log(import_chalk15.default.red(` Enforced ${ok} route(s) but turning on the project-level switch failed (${e.status}). Toggle "Enforce Authorization" on in the dashboard.
2492
+ const r = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable, log: ctx.log });
2493
+ if (r.storeMissing) return;
2494
+ if (enable && r.enabled) {
2495
+ ctx.log(import_chalk16.default.green(` \u2713 Enforcement ON \u2014 ${r.ok} route(s) + project switch on${r.fail ? `, ${r.fail} failed` : ""}.
2479
2496
  `));
2480
- return;
2481
- }
2482
- ctx.log(import_chalk15.default.green(` \u2713 Enforcement ON \u2014 ${ok} route(s) + project switch on${fail5 ? `, ${fail5} failed` : ""}.
2483
- `));
2484
- } else {
2485
- ctx.log(import_chalk15.default.green(` \u2713 Published (shadow): model + ${ok} route(s)${fail5 ? `, ${fail5} failed` : ""}. Review, then /enable.
2497
+ } else if (!enable) {
2498
+ ctx.log(import_chalk16.default.green(` \u2713 Published (shadow): model + ${r.ok} route(s)${r.fail ? `, ${r.fail} failed` : ""}. Review, then /enable.
2486
2499
  `));
2487
2500
  }
2488
2501
  }
@@ -2506,8 +2519,63 @@ async function runAuthz(projectArg, apiVersionArg) {
2506
2519
  });
2507
2520
  }
2508
2521
 
2522
+ // src/commands/rule.ts
2523
+ var import_chalk17 = __toESM(require("chalk"));
2524
+ var import_ora5 = __toESM(require("ora"));
2525
+ init_auth();
2526
+ init_api();
2527
+ async function runRule(ruleText, projectArg, opts) {
2528
+ const rule = (ruleText ?? "").trim();
2529
+ if (!rule) throw new Error('Provide the rule in quotes, e.g. apiblaze rule "users see only their own rows" myproject');
2530
+ const creds = loadCredentials();
2531
+ if (!creds) throw new Error("Not authenticated. Run `apiblaze login` first.");
2532
+ const teamId = creds.teamId ?? "";
2533
+ const projects = await getProjects(teamId);
2534
+ const match = projects.find((p) => p.projectId === projectArg || p.projectName === projectArg);
2535
+ if (!match) {
2536
+ throw new Error(`Project "${projectArg}" not found in your active team (${creds.teamName ?? teamId}). Run \`apiblaze projects\`.`);
2537
+ }
2538
+ const projectId = match.projectId;
2539
+ const apiVersion = opts.apiversion || match.apiVersion;
2540
+ const tenant2 = match.tenant || projectId;
2541
+ const spinner = (0, import_ora5.default)("Designing the rule\u2026").start();
2542
+ const messages = [{
2543
+ role: "user",
2544
+ content: `Author this authorization rule and generate the COMPLETE proposal (OpenFGA model + per-route rules) NOW for every affected route. Do not ask clarifying questions; make reasonable assumptions and state them briefly. Rule: "${rule}"`
2545
+ }];
2546
+ const { status, data } = await agentCall(
2547
+ `/projects/${projectId}/${apiVersion}/authz/chat`,
2548
+ "POST",
2549
+ { messages, included_sample_ids: [], existing_model: null, existing_routes: [] }
2550
+ );
2551
+ if (status >= 400) {
2552
+ spinner.fail(`Authorization agent error (${status}): ${data?.error ?? ""}`);
2553
+ return;
2554
+ }
2555
+ const proposal = data?.proposal;
2556
+ if (!proposal || !Array.isArray(proposal.routes) || proposal.routes.length === 0) {
2557
+ spinner.fail("The agent couldn\u2019t turn that into a rule in one shot.");
2558
+ if (data?.reply) console.log(import_chalk17.default.dim("\n " + String(data.reply).slice(0, 500) + "\n"));
2559
+ console.log(import_chalk17.default.dim(" Try an interactive session for anything nuanced: ") + import_chalk17.default.cyan(`apiblaze agent authz ${projectArg}`));
2560
+ return;
2561
+ }
2562
+ spinner.succeed(`Rule designed \u2014 ${proposal.routes.length} route(s) affected.`);
2563
+ if (data?.reply) console.log(import_chalk17.default.dim(" " + String(data.reply).slice(0, 240)));
2564
+ const pub = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable: false });
2565
+ if (pub.storeMissing) return;
2566
+ console.log(import_chalk17.default.green(` \u2713 Published in shadow mode \u2014 model + ${pub.ok} route(s)${pub.fail ? `, ${pub.fail} failed` : ""}.`));
2567
+ if (opts.enforce) {
2568
+ const enf = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable: true });
2569
+ if (enf.enabled) {
2570
+ console.log(import_chalk17.default.green(` \u2713 Enforcement ON \u2014 ${enf.ok} route(s) + project switch on${enf.fail ? `, ${enf.fail} failed` : ""}.`));
2571
+ }
2572
+ } else {
2573
+ console.log(import_chalk17.default.dim(` Review it (shadow logs), then enforce: `) + import_chalk17.default.cyan(`apiblaze rule "${rule}" ${projectArg} --enforce`));
2574
+ }
2575
+ }
2576
+
2509
2577
  // src/commands/openapi.ts
2510
- var import_chalk16 = __toESM(require("chalk"));
2578
+ var import_chalk18 = __toESM(require("chalk"));
2511
2579
  init_auth();
2512
2580
  init_api();
2513
2581
  async function runOpenapi(projectArg, apiVersionArg) {
@@ -2518,10 +2586,10 @@ async function runOpenapi(projectArg, apiVersionArg) {
2518
2586
  if (!match) throw new Error(`Project "${projectArg}" not found in your active team. Run \`apiblaze projects\`.`);
2519
2587
  const projectId = match.projectId;
2520
2588
  const apiVersion = apiVersionArg || match.apiVersion;
2521
- console.log(import_chalk16.default.dim("Gathering captured traffic samples\u2026"));
2589
+ console.log(import_chalk18.default.dim("Gathering captured traffic samples\u2026"));
2522
2590
  const routesRes = await agentCall(`/projects/${projectId}/${apiVersion}/samples/routes`, "GET");
2523
2591
  if (routesRes.status >= 400) {
2524
- console.log(import_chalk16.default.red(`Could not list traffic (${routesRes.status}): ${routesRes.data?.error ?? ""}`));
2592
+ console.log(import_chalk18.default.red(`Could not list traffic (${routesRes.status}): ${routesRes.data?.error ?? ""}`));
2525
2593
  return;
2526
2594
  }
2527
2595
  const routes = routesRes.data?.routes ?? (Array.isArray(routesRes.data) ? routesRes.data : []);
@@ -2534,25 +2602,25 @@ async function runOpenapi(projectArg, apiVersionArg) {
2534
2602
  }
2535
2603
  const sampleIds = [...ids];
2536
2604
  if (sampleIds.length === 0) {
2537
- console.log(import_chalk16.default.yellow("No captured traffic samples found. Hit the dev environment of this proxy to capture some traces, then retry."));
2605
+ console.log(import_chalk18.default.yellow("No captured traffic samples found. Hit the dev environment of this proxy to capture some traces, then retry."));
2538
2606
  return;
2539
2607
  }
2540
2608
  async function publish(ctx) {
2541
2609
  const patch = ctx.proposal.patch;
2542
2610
  if (!Array.isArray(patch) || patch.length === 0) {
2543
- ctx.log(import_chalk16.default.green(" Nothing to publish \u2014 the spec already covers the observed traffic.\n"));
2611
+ ctx.log(import_chalk18.default.green(" Nothing to publish \u2014 the spec already covers the observed traffic.\n"));
2544
2612
  return;
2545
2613
  }
2546
2614
  const specSource = ctx.lastData?.spec_source ?? "unknown";
2547
2615
  const endpoint = specSource === "github" ? "open-pr" : "publish-openapi";
2548
2616
  const pub = await agentCall(`/projects/${projectId}/${apiVersion}/samples/${endpoint}`, "POST", { patch, sample_ids_used: sampleIds });
2549
2617
  if (pub.status >= 400) {
2550
- ctx.log(import_chalk16.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
2618
+ ctx.log(import_chalk18.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
2551
2619
  `));
2552
2620
  return;
2553
2621
  }
2554
2622
  const prUrl = pub.data?.pr_url;
2555
- ctx.log(import_chalk16.default.green(prUrl ? ` \u2713 Pull request opened: ${prUrl}
2623
+ ctx.log(import_chalk18.default.green(prUrl ? ` \u2713 Pull request opened: ${prUrl}
2556
2624
  ` : " \u2713 Published updated OpenAPI spec.\n"));
2557
2625
  }
2558
2626
  await runAgentChatRepl({
@@ -2573,7 +2641,7 @@ async function runOpenapi(projectArg, apiVersionArg) {
2573
2641
  }
2574
2642
 
2575
2643
  // src/commands/mcp.ts
2576
- var import_chalk17 = __toESM(require("chalk"));
2644
+ var import_chalk19 = __toESM(require("chalk"));
2577
2645
  init_auth();
2578
2646
  init_api();
2579
2647
  async function runMcp(projectArg, apiVersionArg, opts) {
@@ -2590,11 +2658,11 @@ async function runMcp(projectArg, apiVersionArg, opts) {
2590
2658
  const spec2 = ctx.proposal;
2591
2659
  const pub = await agentCall(`/projects/${projectId}/${apiVersion}/mcp/spec`, "PUT", { environment, spec: spec2 });
2592
2660
  if (pub.status >= 400) {
2593
- ctx.log(import_chalk17.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
2661
+ ctx.log(import_chalk19.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
2594
2662
  `));
2595
2663
  return;
2596
2664
  }
2597
- ctx.log(import_chalk17.default.green(` \u2713 Published MCP server \u2014 ${mcpHost}.mcp.apiblaze.com/${apiVersion}/${environment}.
2665
+ ctx.log(import_chalk19.default.green(` \u2713 Published MCP server \u2014 ${mcpHost}.mcp.apiblaze.com/${apiVersion}/${environment}.
2598
2666
  `));
2599
2667
  }
2600
2668
  await runAgentChatRepl({
@@ -2616,18 +2684,18 @@ async function runMcp(projectArg, apiVersionArg, opts) {
2616
2684
  }
2617
2685
 
2618
2686
  // src/commands/delete.ts
2619
- var import_chalk19 = __toESM(require("chalk"));
2620
- var import_ora5 = __toESM(require("ora"));
2687
+ var import_chalk21 = __toESM(require("chalk"));
2688
+ var import_ora6 = __toESM(require("ora"));
2621
2689
  init_admin();
2622
2690
 
2623
2691
  // src/lib/resolve.ts
2624
- var import_chalk18 = __toESM(require("chalk"));
2692
+ var import_chalk20 = __toESM(require("chalk"));
2625
2693
  init_auth();
2626
2694
  init_api();
2627
2695
  function requireAuth() {
2628
2696
  const creds = loadCredentials();
2629
2697
  if (!creds) {
2630
- console.error(import_chalk18.default.red("Not logged in. Run `apiblaze login` first."));
2698
+ console.error(import_chalk20.default.red("Not logged in. Run `apiblaze login` first."));
2631
2699
  process.exit(1);
2632
2700
  }
2633
2701
  return creds;
@@ -2636,7 +2704,7 @@ async function resolveTeam(opt) {
2636
2704
  const creds = requireAuth();
2637
2705
  if (!opt) {
2638
2706
  if (!creds.teamId) {
2639
- console.error(import_chalk18.default.red("No active team. Run `apiblaze login` or pass --team."));
2707
+ console.error(import_chalk20.default.red("No active team. Run `apiblaze login` or pass --team."));
2640
2708
  process.exit(1);
2641
2709
  }
2642
2710
  return { teamId: creds.teamId, teamName: creds.teamName };
@@ -2645,7 +2713,7 @@ async function resolveTeam(opt) {
2645
2713
  const teams = await getTeams().catch(() => []);
2646
2714
  const match = teams.find((t) => t.name === opt || t.teamId === opt);
2647
2715
  if (!match) {
2648
- console.error(import_chalk18.default.red(`Team "${opt}" not found.${teams.length ? " Available: " + teams.map((t) => t.name).join(", ") : ""}`));
2716
+ console.error(import_chalk20.default.red(`Team "${opt}" not found.${teams.length ? " Available: " + teams.map((t) => t.name).join(", ") : ""}`));
2649
2717
  process.exit(1);
2650
2718
  }
2651
2719
  return { teamId: match.teamId, teamName: match.name };
@@ -2656,13 +2724,13 @@ async function resolveProject(teamId, nameOrId, version2) {
2656
2724
  (p) => p.projectId === nameOrId || p.projectName === nameOrId
2657
2725
  );
2658
2726
  if (candidates.length === 0) {
2659
- console.error(import_chalk18.default.red(`Project "${nameOrId}" not found in this team.`));
2660
- if (projects.length) console.error(import_chalk18.default.dim(" Known: " + projects.map((p) => p.projectName).join(", ")));
2727
+ console.error(import_chalk20.default.red(`Project "${nameOrId}" not found in this team.`));
2728
+ if (projects.length) console.error(import_chalk20.default.dim(" Known: " + projects.map((p) => p.projectName).join(", ")));
2661
2729
  process.exit(1);
2662
2730
  }
2663
2731
  const chosen = version2 ? candidates.find((p) => p.apiVersion === version2) : candidates[0];
2664
2732
  if (!chosen) {
2665
- console.error(import_chalk18.default.red(`Project "${nameOrId}" has no version ${version2}. Versions: ${candidates.map((p) => p.apiVersion).join(", ")}`));
2733
+ console.error(import_chalk20.default.red(`Project "${nameOrId}" has no version ${version2}. Versions: ${candidates.map((p) => p.apiVersion).join(", ")}`));
2666
2734
  process.exit(1);
2667
2735
  }
2668
2736
  return {
@@ -2678,7 +2746,7 @@ async function resolveProject(teamId, nameOrId, version2) {
2678
2746
  async function runDelete(project, version2, opts) {
2679
2747
  const { teamId } = await resolveTeam(opts.team);
2680
2748
  const proj2 = await resolveProject(teamId, project, version2);
2681
- const spinner = (0, import_ora5.default)("Checking delete impact...").start();
2749
+ const spinner = (0, import_ora6.default)("Checking delete impact...").start();
2682
2750
  let impact;
2683
2751
  try {
2684
2752
  impact = await admin({
@@ -2697,10 +2765,10 @@ async function runDelete(project, version2, opts) {
2697
2765
  return;
2698
2766
  }
2699
2767
  } else {
2700
- console.log(`${import_chalk19.default.red.bold("Delete")} ${import_chalk19.default.bold(proj2.projectName)} ${import_chalk19.default.dim("v" + proj2.apiVersion)} ${import_chalk19.default.dim("(" + proj2.projectId + ")")}`);
2768
+ console.log(`${import_chalk21.default.red.bold("Delete")} ${import_chalk21.default.bold(proj2.projectName)} ${import_chalk21.default.dim("v" + proj2.apiVersion)} ${import_chalk21.default.dim("(" + proj2.projectId + ")")}`);
2701
2769
  if (impact && typeof impact === "object") {
2702
2770
  const counts = impact.counts ?? impact.impact ?? impact;
2703
- console.log(import_chalk19.default.dim(" This removes (cascade): ") + import_chalk19.default.yellow(JSON.stringify(counts)));
2771
+ console.log(import_chalk21.default.dim(" This removes (cascade): ") + import_chalk21.default.yellow(JSON.stringify(counts)));
2704
2772
  }
2705
2773
  if (!opts.yes) {
2706
2774
  const { default: inquirer3 } = await import("inquirer");
@@ -2708,12 +2776,12 @@ async function runDelete(project, version2, opts) {
2708
2776
  { type: "confirm", name: "confirm", message: `Permanently delete ${proj2.projectName} v${proj2.apiVersion}? This cannot be undone.`, default: false }
2709
2777
  ]);
2710
2778
  if (!confirm) {
2711
- console.log(import_chalk19.default.dim("Aborted."));
2779
+ console.log(import_chalk21.default.dim("Aborted."));
2712
2780
  return;
2713
2781
  }
2714
2782
  }
2715
2783
  }
2716
- const s2 = (0, import_ora5.default)("Deleting...").start();
2784
+ const s2 = (0, import_ora6.default)("Deleting...").start();
2717
2785
  try {
2718
2786
  await admin({
2719
2787
  method: "DELETE",
@@ -2729,7 +2797,7 @@ async function runDelete(project, version2, opts) {
2729
2797
  }
2730
2798
 
2731
2799
  // src/commands/export.ts
2732
- var import_chalk20 = __toESM(require("chalk"));
2800
+ var import_chalk22 = __toESM(require("chalk"));
2733
2801
  var import_fs3 = require("fs");
2734
2802
  init_admin();
2735
2803
  init_auth();
@@ -2747,7 +2815,7 @@ async function runExport(projectArg, versionArg, opts) {
2747
2815
  if (opts.noConsumers) q.set("include_consumers", "0");
2748
2816
  if (opts.keys) q.set("keys", opts.keys);
2749
2817
  const qs = q.toString() ? `?${q.toString()}` : "";
2750
- console.log(import_chalk20.default.dim(`Queuing ${target} export of ${projectId}@${version2}\u2026`));
2818
+ console.log(import_chalk22.default.dim(`Queuing ${target} export of ${projectId}@${version2}\u2026`));
2751
2819
  const job = await admin({
2752
2820
  path: `/projects/${projectId}/${version2}/export/${target}${qs}`,
2753
2821
  method: "GET",
@@ -2757,11 +2825,11 @@ async function runExport(projectArg, versionArg, opts) {
2757
2825
  const statusPath = `/projects/${projectId}/${version2}/export/jobs/${job.job_id}`;
2758
2826
  let status = "queued";
2759
2827
  const started = Date.now();
2760
- process.stdout.write(import_chalk20.default.dim("Building bundle"));
2828
+ process.stdout.write(import_chalk22.default.dim("Building bundle"));
2761
2829
  while (status !== "ready" && status !== "failed") {
2762
2830
  if (Date.now() - started > 10 * 6e4) throw new Error("Export timed out after 10 minutes.");
2763
2831
  await new Promise((r) => setTimeout(r, 3e3));
2764
- process.stdout.write(import_chalk20.default.dim("."));
2832
+ process.stdout.write(import_chalk22.default.dim("."));
2765
2833
  const st = await admin({ path: statusPath, method: "GET", summary: "poll export" });
2766
2834
  status = st?.status ?? "queued";
2767
2835
  if (status === "failed") {
@@ -2779,20 +2847,20 @@ async function runExport(projectArg, versionArg, opts) {
2779
2847
  if (!res.ok) throw new Error(`Download failed (${res.status}): ${await res.text().catch(() => "")}`);
2780
2848
  const buf = Buffer.from(await res.arrayBuffer());
2781
2849
  (0, import_fs3.writeFileSync)(outFile, buf);
2782
- console.log(import_chalk20.default.green(`\u2713 Saved ${outFile} (${(buf.length / 1024).toFixed(0)} KB)`));
2783
- if (job.decryption_key) console.log(import_chalk20.default.yellow(`Decryption key (shown once): ${job.decryption_key}`));
2784
- console.log(import_chalk20.default.dim("Read MIGRATION-REPORT.json inside the zip for the full fidelity ledger."));
2785
- if (target === "kong") console.log(import_chalk20.default.dim("Kong: unzip, then `cd kong && docker compose up` (see kong/README.md)."));
2850
+ console.log(import_chalk22.default.green(`\u2713 Saved ${outFile} (${(buf.length / 1024).toFixed(0)} KB)`));
2851
+ if (job.decryption_key) console.log(import_chalk22.default.yellow(`Decryption key (shown once): ${job.decryption_key}`));
2852
+ console.log(import_chalk22.default.dim("Read MIGRATION-REPORT.json inside the zip for the full fidelity ledger."));
2853
+ if (target === "kong") console.log(import_chalk22.default.dim("Kong: unzip, then `cd kong && docker compose up` (see kong/README.md)."));
2786
2854
  }
2787
2855
 
2788
2856
  // src/commands/config.ts
2789
- var import_chalk21 = __toESM(require("chalk"));
2790
- var import_ora6 = __toESM(require("ora"));
2857
+ var import_chalk23 = __toESM(require("chalk"));
2858
+ var import_ora7 = __toESM(require("ora"));
2791
2859
  init_admin();
2792
2860
  async function patchConfig(project, opts, body, summary) {
2793
2861
  const { teamId } = await resolveTeam(opts.team);
2794
2862
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
2795
- const spinner = (0, import_ora6.default)(summary + "...").start();
2863
+ const spinner = (0, import_ora7.default)(summary + "...").start();
2796
2864
  try {
2797
2865
  const out = await admin({
2798
2866
  method: "PATCH",
@@ -2809,7 +2877,7 @@ async function patchConfig(project, opts, body, summary) {
2809
2877
  }
2810
2878
  async function runTargetSet(project, opts) {
2811
2879
  if (!opts.url) {
2812
- console.error(import_chalk21.default.red("--url is required."));
2880
+ console.error(import_chalk23.default.red("--url is required."));
2813
2881
  process.exit(1);
2814
2882
  }
2815
2883
  const body = opts.env ? { environments: { [opts.env]: { target: opts.url } } } : { target_url: opts.url };
@@ -2822,43 +2890,43 @@ async function runThrottleSet(project, opts) {
2822
2890
  if (opts.quota !== void 0) throttling.proxyQuota = Number(opts.quota);
2823
2891
  if (opts.period !== void 0) {
2824
2892
  if (!["daily", "weekly", "monthly"].includes(opts.period)) {
2825
- console.error(import_chalk21.default.red("--period must be daily, weekly, or monthly."));
2893
+ console.error(import_chalk23.default.red("--period must be daily, weekly, or monthly."));
2826
2894
  process.exit(1);
2827
2895
  }
2828
2896
  throttling.quotaPeriod = opts.period;
2829
2897
  }
2830
2898
  if (Object.keys(throttling).length === 0) {
2831
- console.error(import_chalk21.default.red("Nothing to set. Pass at least one of --rate, --end-user-rate, --quota, --period."));
2899
+ console.error(import_chalk23.default.red("Nothing to set. Pass at least one of --rate, --end-user-rate, --quota, --period."));
2832
2900
  process.exit(1);
2833
2901
  }
2834
2902
  await patchConfig(project, opts, { throttling }, `Update throttling ${JSON.stringify(throttling)}`);
2835
2903
  }
2836
2904
  async function runRename(project, opts) {
2837
2905
  if (!opts.displayName) {
2838
- console.error(import_chalk21.default.red("--display-name is required."));
2906
+ console.error(import_chalk23.default.red("--display-name is required."));
2839
2907
  process.exit(1);
2840
2908
  }
2841
2909
  await patchConfig(project, opts, { display_name: opts.displayName }, `Rename \u2192 "${opts.displayName}"`);
2842
2910
  }
2843
2911
 
2844
2912
  // src/commands/config-browse.ts
2845
- var import_chalk30 = __toESM(require("chalk"));
2846
- var import_ora14 = __toESM(require("ora"));
2913
+ var import_chalk32 = __toESM(require("chalk"));
2914
+ var import_ora15 = __toESM(require("ora"));
2847
2915
  init_admin();
2848
2916
  init_auth();
2849
2917
 
2850
2918
  // src/commands/domain.ts
2851
- var import_chalk22 = __toESM(require("chalk"));
2852
- var import_ora7 = __toESM(require("ora"));
2919
+ var import_chalk24 = __toESM(require("chalk"));
2920
+ var import_ora8 = __toESM(require("ora"));
2853
2921
  init_admin();
2854
2922
  async function runDomainAdd(project, opts) {
2855
2923
  if (!opts.domain) {
2856
- console.error(import_chalk22.default.red("--domain is required."));
2924
+ console.error(import_chalk24.default.red("--domain is required."));
2857
2925
  process.exit(1);
2858
2926
  }
2859
2927
  const { teamId } = await resolveTeam(opts.team);
2860
2928
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
2861
- const spinner = (0, import_ora7.default)(`Registering ${opts.domain}...`).start();
2929
+ const spinner = (0, import_ora8.default)(`Registering ${opts.domain}...`).start();
2862
2930
  try {
2863
2931
  const out = await admin({
2864
2932
  method: "POST",
@@ -2872,9 +2940,9 @@ async function runDomainAdd(project, opts) {
2872
2940
  console.log(JSON.stringify(out));
2873
2941
  return;
2874
2942
  }
2875
- if (out?.cnameRecord) console.log(` ${import_chalk22.default.cyan("CNAME")} ${out.cnameRecord.name ?? opts.domain} \u2192 ${out.cnameRecord.value ?? out.cnameRecord.target}`);
2876
- if (out?.dcv) console.log(` ${import_chalk22.default.cyan("TXT")} ${out.dcv.name} = ${out.dcv.value}`);
2877
- if (out?.id) console.log(import_chalk22.default.dim(` domain id: ${out.id}`));
2943
+ if (out?.cnameRecord) console.log(` ${import_chalk24.default.cyan("CNAME")} ${out.cnameRecord.name ?? opts.domain} \u2192 ${out.cnameRecord.value ?? out.cnameRecord.target}`);
2944
+ if (out?.dcv) console.log(` ${import_chalk24.default.cyan("TXT")} ${out.dcv.name} = ${out.dcv.value}`);
2945
+ if (out?.id) console.log(import_chalk24.default.dim(` domain id: ${out.id}`));
2878
2946
  } catch (err) {
2879
2947
  spinner.fail("Domain registration failed.");
2880
2948
  throw err;
@@ -2894,14 +2962,14 @@ async function runDomainList(project, opts) {
2894
2962
  return;
2895
2963
  }
2896
2964
  if (!domains.length) {
2897
- console.log(import_chalk22.default.yellow("No custom domains."));
2965
+ console.log(import_chalk24.default.yellow("No custom domains."));
2898
2966
  return;
2899
2967
  }
2900
- for (const d of domains) console.log(` ${import_chalk22.default.bold(d.hostname)} ${import_chalk22.default.dim(d.status ?? "")} ${import_chalk22.default.dim(d.id ?? "")}`);
2968
+ for (const d of domains) console.log(` ${import_chalk24.default.bold(d.hostname)} ${import_chalk24.default.dim(d.status ?? "")} ${import_chalk24.default.dim(d.id ?? "")}`);
2901
2969
  }
2902
2970
  async function runDomainStatus(project, opts) {
2903
2971
  if (!opts.id) {
2904
- console.error(import_chalk22.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
2972
+ console.error(import_chalk24.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
2905
2973
  process.exit(1);
2906
2974
  }
2907
2975
  const { teamId } = await resolveTeam(opts.team);
@@ -2911,16 +2979,16 @@ async function runDomainStatus(project, opts) {
2911
2979
  path: `/projects/${proj2.projectId}/domains/${encodeURIComponent(opts.id)}/status`,
2912
2980
  summary: `Check custom-domain status`
2913
2981
  });
2914
- console.log(opts.json ? JSON.stringify(out) : ` ${import_chalk22.default.bold(out?.hostname ?? opts.id)}: ${import_chalk22.default.cyan(out?.status ?? "unknown")}`);
2982
+ console.log(opts.json ? JSON.stringify(out) : ` ${import_chalk24.default.bold(out?.hostname ?? opts.id)}: ${import_chalk24.default.cyan(out?.status ?? "unknown")}`);
2915
2983
  }
2916
2984
  async function runDomainRemove(project, opts) {
2917
2985
  if (!opts.id) {
2918
- console.error(import_chalk22.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
2986
+ console.error(import_chalk24.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
2919
2987
  process.exit(1);
2920
2988
  }
2921
2989
  const { teamId } = await resolveTeam(opts.team);
2922
2990
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
2923
- const spinner = (0, import_ora7.default)("Removing domain...").start();
2991
+ const spinner = (0, import_ora8.default)("Removing domain...").start();
2924
2992
  try {
2925
2993
  await admin({
2926
2994
  method: "DELETE",
@@ -2937,7 +3005,7 @@ async function runDomainSetBase(project, opts) {
2937
3005
  const env = opts.env ?? "prod";
2938
3006
  const { teamId } = await resolveTeam(opts.team);
2939
3007
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
2940
- const spinner = (0, import_ora7.default)("Setting base domain...").start();
3008
+ const spinner = (0, import_ora8.default)("Setting base domain...").start();
2941
3009
  try {
2942
3010
  await admin({
2943
3011
  method: "PUT",
@@ -2953,28 +3021,28 @@ async function runDomainSetBase(project, opts) {
2953
3021
  }
2954
3022
 
2955
3023
  // src/commands/tenant.ts
2956
- var import_chalk25 = __toESM(require("chalk"));
2957
- var import_ora10 = __toESM(require("ora"));
3024
+ var import_chalk27 = __toESM(require("chalk"));
3025
+ var import_ora11 = __toESM(require("ora"));
2958
3026
  init_admin();
2959
3027
  init_auth();
2960
3028
  init_tenant_pick();
2961
3029
  async function runTenantUse(query, opts) {
2962
3030
  const creds = loadCredentials();
2963
3031
  if (!creds) {
2964
- console.error(import_chalk25.default.red("Not logged in. Run `apiblaze login` first."));
3032
+ console.error(import_chalk27.default.red("Not logged in. Run `apiblaze login` first."));
2965
3033
  process.exit(1);
2966
3034
  }
2967
3035
  if (opts.clear) {
2968
3036
  delete creds.activeTenant;
2969
3037
  saveCredentials(creds);
2970
- console.log(import_chalk25.default.green("Tenant scope cleared."));
3038
+ console.log(import_chalk27.default.green("Tenant scope cleared."));
2971
3039
  return;
2972
3040
  }
2973
3041
  const { teamId } = await resolveTeam(opts.team);
2974
3042
  const slug = await pickTenant(teamId, { message: "Scope future commands to which tenant?", initialQuery: query });
2975
3043
  if (!slug) process.exit(1);
2976
3044
  saveCredentials({ ...creds, activeTenant: slug });
2977
- console.log(import_chalk25.default.green(`Tenant scope set to ${import_chalk25.default.bold(slug)}.`) + import_chalk25.default.dim(" (clear with `apiblaze tenant use --clear`)"));
3045
+ console.log(import_chalk27.default.green(`Tenant scope set to ${import_chalk27.default.bold(slug)}.`) + import_chalk27.default.dim(" (clear with `apiblaze tenant use --clear`)"));
2978
3046
  }
2979
3047
  async function runTenantList(opts) {
2980
3048
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -2991,26 +3059,26 @@ async function runTenantList(opts) {
2991
3059
  return;
2992
3060
  }
2993
3061
  if (!tenants.length) {
2994
- console.log(import_chalk25.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
3062
+ console.log(import_chalk27.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
2995
3063
  return;
2996
3064
  }
2997
3065
  for (const t of tenants) {
2998
3066
  const name = typeof t === "string" ? t : t.tenant_name;
2999
- const display = typeof t === "string" ? "" : import_chalk25.default.dim(` ${t.display_name ?? ""}`);
3000
- console.log(` ${import_chalk25.default.bold(name)}${display}`);
3067
+ const display = typeof t === "string" ? "" : import_chalk27.default.dim(` ${t.display_name ?? ""}`);
3068
+ console.log(` ${import_chalk27.default.bold(name)}${display}`);
3001
3069
  }
3002
3070
  const total = out?.total ?? tenants.length;
3003
3071
  if (total > tenants.length) {
3004
- console.log(import_chalk25.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
3072
+ console.log(import_chalk27.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
3005
3073
  }
3006
3074
  }
3007
3075
  async function runTenantCreate(opts) {
3008
3076
  if (!opts.name) {
3009
- console.error(import_chalk25.default.red("--name (display name) is required."));
3077
+ console.error(import_chalk27.default.red("--name (display name) is required."));
3010
3078
  process.exit(1);
3011
3079
  }
3012
3080
  const { teamId } = await resolveTeam(opts.team);
3013
- const spinner = (0, import_ora10.default)("Creating tenant...").start();
3081
+ const spinner = (0, import_ora11.default)("Creating tenant...").start();
3014
3082
  try {
3015
3083
  const out = await admin({
3016
3084
  method: "POST",
@@ -3018,7 +3086,7 @@ async function runTenantCreate(opts) {
3018
3086
  body: { display_name: opts.name, ...opts.slug ? { tenant_name: opts.slug } : {} },
3019
3087
  summary: `Create tenant "${opts.name}"`
3020
3088
  });
3021
- spinner.succeed(`Created tenant ${import_chalk25.default.bold(out?.tenant_name ?? opts.name)}.`);
3089
+ spinner.succeed(`Created tenant ${import_chalk27.default.bold(out?.tenant_name ?? opts.name)}.`);
3022
3090
  if (opts.json) console.log(JSON.stringify(out));
3023
3091
  } catch (err) {
3024
3092
  spinner.fail("Tenant create failed.");
@@ -3027,12 +3095,12 @@ async function runTenantCreate(opts) {
3027
3095
  }
3028
3096
  async function runTenantAttach(project, opts) {
3029
3097
  if (!opts.tenant) {
3030
- console.error(import_chalk25.default.red("--tenant <slug> is required."));
3098
+ console.error(import_chalk27.default.red("--tenant <slug> is required."));
3031
3099
  process.exit(1);
3032
3100
  }
3033
3101
  const { teamId } = await resolveTeam(opts.team);
3034
3102
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
3035
- const spinner = (0, import_ora10.default)("Attaching tenant...").start();
3103
+ const spinner = (0, import_ora11.default)("Attaching tenant...").start();
3036
3104
  try {
3037
3105
  const out = await admin({
3038
3106
  method: "POST",
@@ -3055,11 +3123,11 @@ async function runTenantDelete(slug, opts) {
3055
3123
  { type: "confirm", name: "confirm", message: `Permanently delete tenant "${slug}" and everything under it? This cannot be undone.`, default: false }
3056
3124
  ]);
3057
3125
  if (!confirm) {
3058
- console.log(import_chalk25.default.dim("Aborted."));
3126
+ console.log(import_chalk27.default.dim("Aborted."));
3059
3127
  return;
3060
3128
  }
3061
3129
  }
3062
- const spinner = (0, import_ora10.default)("Deleting tenant...").start();
3130
+ const spinner = (0, import_ora11.default)("Deleting tenant...").start();
3063
3131
  try {
3064
3132
  await admin({
3065
3133
  method: "DELETE",
@@ -3074,13 +3142,13 @@ async function runTenantDelete(slug, opts) {
3074
3142
  }
3075
3143
  async function runTenantCors(opts) {
3076
3144
  if (!opts.tenant) {
3077
- console.error(import_chalk25.default.red("--tenant <slug> is required."));
3145
+ console.error(import_chalk27.default.red("--tenant <slug> is required."));
3078
3146
  process.exit(1);
3079
3147
  }
3080
3148
  const { teamId } = await resolveTeam(opts.team);
3081
3149
  const origins = (opts.origins ?? "").split(",").map((s) => s.trim()).filter(Boolean);
3082
3150
  const cors = origins.length ? { allowed_origins: origins } : null;
3083
- const spinner = (0, import_ora10.default)("Updating CORS...").start();
3151
+ const spinner = (0, import_ora11.default)("Updating CORS...").start();
3084
3152
  try {
3085
3153
  await admin({
3086
3154
  method: "PUT",
@@ -3096,8 +3164,8 @@ async function runTenantCors(opts) {
3096
3164
  }
3097
3165
 
3098
3166
  // src/commands/tenant-drill.ts
3099
- var import_chalk26 = __toESM(require("chalk"));
3100
- var import_ora11 = __toESM(require("ora"));
3167
+ var import_chalk28 = __toESM(require("chalk"));
3168
+ var import_ora12 = __toESM(require("ora"));
3101
3169
  var import_crypto = require("crypto");
3102
3170
  init_admin();
3103
3171
  init_auth();
@@ -3126,17 +3194,17 @@ async function validScopedTenant(teamId, query) {
3126
3194
  const next = { ...creds };
3127
3195
  delete next.activeTenant;
3128
3196
  saveCredentials2(next);
3129
- console.log(import_chalk26.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
3197
+ console.log(import_chalk28.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
3130
3198
  return void 0;
3131
3199
  }
3132
3200
  async function tenantHome(teamId, tenant2) {
3133
3201
  const { default: inquirer3 } = await import("inquirer");
3134
3202
  const base = `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}`;
3135
- console.log(import_chalk26.default.bold(`
3203
+ console.log(import_chalk28.default.bold(`
3136
3204
  Tenant ${tenant2}`));
3137
- console.log(import_chalk26.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
3205
+ console.log(import_chalk28.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
3138
3206
  for (; ; ) {
3139
- const spinner = (0, import_ora11.default)("Reading tenant state...").start();
3207
+ const spinner = (0, import_ora12.default)("Reading tenant state...").start();
3140
3208
  const [iam, cors, emails, issuers, opaque, clients] = await Promise.all([
3141
3209
  admin({ method: "GET", path: `${base}/iam`, summary: "Read IAM toggle" }).catch(() => null),
3142
3210
  admin({ method: "GET", path: `${base}/cors`, summary: "Read tenant CORS" }).catch(() => null),
@@ -3150,18 +3218,18 @@ Tenant ${tenant2}`));
3150
3218
  const nClients = Array.isArray(clients) ? clients.length : 0;
3151
3219
  const nOpaque = opaque?.opaque?.endpoint ? 1 : 0;
3152
3220
  const nLogin = nClients + nIssuers + nOpaque;
3153
- const onOff = (b) => b ? import_chalk26.default.green("on") : import_chalk26.default.dim("off");
3221
+ const onOff = (b) => b ? import_chalk28.default.green("on") : import_chalk28.default.dim("off");
3154
3222
  const { pick: pick2 } = await inquirer3.prompt([{
3155
3223
  type: "list",
3156
3224
  name: "pick",
3157
3225
  message: `Tenant ${tenant2}:`,
3158
3226
  pageSize: 12,
3159
3227
  choices: [
3160
- { name: `Login methods (${nLogin}) ${import_chalk26.default.dim("how your consumers sign in")}`, value: "login" },
3161
- { name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk26.default.dim(`identity & key management (iam.apiblaze.com)`)}`, value: "iam" },
3162
- { name: `Portal admins (${nEmails}) ${import_chalk26.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
3163
- new inquirer3.Separator(import_chalk26.default.dim(" Settings")),
3164
- { name: `CORS: ${cors?.cors ? import_chalk26.default.cyan(JSON.stringify(cors.cors)) : import_chalk26.default.dim("(unset)")} ${import_chalk26.default.dim("browser origins allowed to call this tenant")}`, value: "cors" },
3228
+ { name: `Login methods (${nLogin}) ${import_chalk28.default.dim("how your consumers sign in")}`, value: "login" },
3229
+ { name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk28.default.dim(`identity & key management (iam.apiblaze.com)`)}`, value: "iam" },
3230
+ { name: `Portal admins (${nEmails}) ${import_chalk28.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
3231
+ new inquirer3.Separator(import_chalk28.default.dim(" Settings")),
3232
+ { name: `CORS: ${cors?.cors ? import_chalk28.default.cyan(JSON.stringify(cors.cors)) : import_chalk28.default.dim("(unset)")} ${import_chalk28.default.dim("browser origins allowed to call this tenant")}`, value: "cors" },
3165
3233
  { name: "\u2190 Back", value: "back" }
3166
3234
  ]
3167
3235
  }]);
@@ -3174,7 +3242,7 @@ Tenant ${tenant2}`));
3174
3242
  case "iam": {
3175
3243
  const { v } = await inquirer3.prompt([{ type: "confirm", name: "v", message: "Enable Users & groups?", default: !!iam?.iam_enabled }]);
3176
3244
  await admin({ method: "PATCH", path: `${base}/iam`, body: { enabled: v }, summary: `IAM enforcement \u2192 ${v ? "on" : "off"}` });
3177
- console.log(import_chalk26.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
3245
+ console.log(import_chalk28.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
3178
3246
  break;
3179
3247
  }
3180
3248
  case "cors": {
@@ -3187,11 +3255,11 @@ Tenant ${tenant2}`));
3187
3255
  if (v === "") break;
3188
3256
  const parsed = v === "null" ? null : safeJson(v);
3189
3257
  if (parsed === void 0) {
3190
- console.log(import_chalk26.default.yellow(" Not valid JSON \u2014 unchanged."));
3258
+ console.log(import_chalk28.default.yellow(" Not valid JSON \u2014 unchanged."));
3191
3259
  break;
3192
3260
  }
3193
3261
  await admin({ method: "PUT", path: `${base}/cors`, body: { cors: parsed }, summary: "Set tenant CORS" });
3194
- console.log(import_chalk26.default.green(" CORS updated."));
3262
+ console.log(import_chalk28.default.green(" CORS updated."));
3195
3263
  break;
3196
3264
  }
3197
3265
  case "emails":
@@ -3203,7 +3271,7 @@ Tenant ${tenant2}`));
3203
3271
  async function loginMethodsMenu(teamId, tenant2, base) {
3204
3272
  const { default: inquirer3 } = await import("inquirer");
3205
3273
  for (; ; ) {
3206
- const spinner = (0, import_ora11.default)("Loading login methods...").start();
3274
+ const spinner = (0, import_ora12.default)("Loading login methods...").start();
3207
3275
  const [rawClients, rawIssuers, rawOpaque] = await Promise.all([
3208
3276
  admin({ method: "GET", path: `${base}/app-clients`, summary: "List APIblaze-hosted logins" }).catch(() => []),
3209
3277
  admin({ method: "GET", path: `${base}/external-issuers`, summary: "List your-own-JWT logins" }).catch(() => null),
@@ -3215,15 +3283,15 @@ async function loginMethodsMenu(teamId, tenant2, base) {
3215
3283
  const choices = [];
3216
3284
  for (const c of appClients) {
3217
3285
  const nP = (c.providers ?? []).length || c.providers_count || 0;
3218
- choices.push({ name: `${import_chalk26.default.cyan("APIblaze-hosted")} ${import_chalk26.default.bold(c.name ?? c.clientId)} ${import_chalk26.default.dim(`${c.clientId}${nP ? ` \xB7 ${nP} provider${nP === 1 ? "" : "s"}` : import_chalk26.default.yellow(" \xB7 needs a provider")}`)}`, value: { kind: "client", item: c } });
3286
+ choices.push({ name: `${import_chalk28.default.cyan("APIblaze-hosted")} ${import_chalk28.default.bold(c.name ?? c.clientId)} ${import_chalk28.default.dim(`${c.clientId}${nP ? ` \xB7 ${nP} provider${nP === 1 ? "" : "s"}` : import_chalk28.default.yellow(" \xB7 needs a provider")}`)}`, value: { kind: "client", item: c } });
3219
3287
  }
3220
3288
  for (const i of issuers) {
3221
- choices.push({ name: `${import_chalk26.default.cyan("Your own \u2014 JWT ")} ${import_chalk26.default.bold(i.iss)} ${import_chalk26.default.dim(`aud=${i.aud}`)}`, value: { kind: "issuer", item: i } });
3289
+ choices.push({ name: `${import_chalk28.default.cyan("Your own \u2014 JWT ")} ${import_chalk28.default.bold(i.iss)} ${import_chalk28.default.dim(`aud=${i.aud}`)}`, value: { kind: "issuer", item: i } });
3222
3290
  }
3223
3291
  if (opaque?.endpoint) {
3224
- choices.push({ name: `${import_chalk26.default.cyan("Your own \u2014 opaque")} ${import_chalk26.default.bold(opaque.endpoint)}`, value: { kind: "opaque", item: opaque } });
3292
+ choices.push({ name: `${import_chalk28.default.cyan("Your own \u2014 opaque")} ${import_chalk28.default.bold(opaque.endpoint)}`, value: { kind: "opaque", item: opaque } });
3225
3293
  }
3226
- if (!choices.length) console.log(import_chalk26.default.dim("\n No login methods yet \u2014 consumers cannot sign in until you add one."));
3294
+ if (!choices.length) console.log(import_chalk28.default.dim("\n No login methods yet \u2014 consumers cannot sign in until you add one."));
3227
3295
  const { pick: pick2 } = await inquirer3.prompt([{
3228
3296
  type: "list",
3229
3297
  name: "pick",
@@ -3263,9 +3331,9 @@ async function addLoginMethod(teamId, tenant2, base) {
3263
3331
  message: "How do people log in?",
3264
3332
  pageSize: 8,
3265
3333
  choices: [
3266
- { name: `APIblaze hosted login page ${import_chalk26.default.dim("we host login; pick a provider (GitHub/Google/\u2026) \u2014 easiest")}`, value: "apiblaze" },
3267
- { name: `Your own hosted login \u2014 JWT ${import_chalk26.default.dim("your identity provider issues JWTs; we trust them")}`, value: "jwt" },
3268
- { name: `Your own login \u2014 opaque token ${import_chalk26.default.dim("we validate your opaque tokens via an introspection endpoint")}`, value: "opaque" },
3334
+ { name: `APIblaze hosted login page ${import_chalk28.default.dim("we host login; pick a provider (GitHub/Google/\u2026) \u2014 easiest")}`, value: "apiblaze" },
3335
+ { name: `Your own hosted login \u2014 JWT ${import_chalk28.default.dim("your identity provider issues JWTs; we trust them")}`, value: "jwt" },
3336
+ { name: `Your own login \u2014 opaque token ${import_chalk28.default.dim("we validate your opaque tokens via an introspection endpoint")}`, value: "opaque" },
3269
3337
  { name: "\u2190 Back", value: null }
3270
3338
  ]
3271
3339
  }]);
@@ -3289,8 +3357,8 @@ function safeJson(s) {
3289
3357
  async function emailsMenu(base, emails) {
3290
3358
  const { default: inquirer3 } = await import("inquirer");
3291
3359
  console.log();
3292
- if (!emails.length) console.log(import_chalk26.default.dim(" No consumer-admin emails."));
3293
- for (const e of emails) console.log(` ${import_chalk26.default.bold(e.email ?? e)} ${import_chalk26.default.dim(e.status ?? "")}`);
3360
+ if (!emails.length) console.log(import_chalk28.default.dim(" No consumer-admin emails."));
3361
+ for (const e of emails) console.log(` ${import_chalk28.default.bold(e.email ?? e)} ${import_chalk28.default.dim(e.status ?? "")}`);
3294
3362
  const { act } = await inquirer3.prompt([{
3295
3363
  type: "list",
3296
3364
  name: "act",
@@ -3305,7 +3373,7 @@ async function emailsMenu(base, emails) {
3305
3373
  if (act === "add") {
3306
3374
  const { email } = await inquirer3.prompt([{ type: "input", name: "email", message: "Email:", validate: (s) => /.+@.+\..+/.test(s) || "not an email" }]);
3307
3375
  await admin({ method: "POST", path: `${base}/admin-emails`, body: { email }, summary: `Add consumer-admin ${email}` });
3308
- console.log(import_chalk26.default.green(` ${email} added.`));
3376
+ console.log(import_chalk28.default.green(` ${email} added.`));
3309
3377
  } else {
3310
3378
  const { e } = await inquirer3.prompt([{
3311
3379
  type: "list",
@@ -3315,7 +3383,7 @@ async function emailsMenu(base, emails) {
3315
3383
  }]);
3316
3384
  if (!e) return;
3317
3385
  await admin({ method: "DELETE", path: `${base}/admin-emails/${encodeURIComponent(e)}`, summary: `Remove consumer-admin ${e}` });
3318
- console.log(import_chalk26.default.green(` ${e} removed.`));
3386
+ console.log(import_chalk28.default.green(` ${e} removed.`));
3319
3387
  }
3320
3388
  }
3321
3389
  async function addIssuer(base) {
@@ -3336,19 +3404,19 @@ async function addIssuer(base) {
3336
3404
  body: { iss: a.iss.trim(), aud: a.aud.trim(), jwks_url: a.jwks.trim() || null, sub_semantics: a.sem, ...claim ? { claim_name: claim } : {} },
3337
3405
  summary: `Add external issuer ${a.iss.trim()}`
3338
3406
  });
3339
- console.log(import_chalk26.default.green(" JWT login method saved."));
3407
+ console.log(import_chalk28.default.green(" JWT login method saved."));
3340
3408
  }
3341
3409
  async function issuerHome(base, issuer) {
3342
3410
  const { default: inquirer3 } = await import("inquirer");
3343
3411
  console.log(`
3344
- ${import_chalk26.default.bold(issuer.iss)} ${import_chalk26.default.dim(`aud=${issuer.aud} \xB7 ${issuer.sub_semantics ?? ""}`)}`);
3412
+ ${import_chalk28.default.bold(issuer.iss)} ${import_chalk28.default.dim(`aud=${issuer.aud} \xB7 ${issuer.sub_semantics ?? ""}`)}`);
3345
3413
  const { act } = await inquirer3.prompt([{
3346
3414
  type: "list",
3347
3415
  name: "act",
3348
3416
  message: "This JWT login method:",
3349
3417
  choices: [
3350
3418
  { name: "Replace it (re-enter details)", value: "edit" },
3351
- { name: import_chalk26.default.red("Delete it"), value: "rm" },
3419
+ { name: import_chalk28.default.red("Delete it"), value: "rm" },
3352
3420
  { name: "\u2190 Back", value: "back" }
3353
3421
  ]
3354
3422
  }]);
@@ -3364,7 +3432,7 @@ async function issuerHome(base, issuer) {
3364
3432
  path: `${base}/external-issuers?iss=${encodeURIComponent(issuer.iss)}&aud=${encodeURIComponent(issuer.aud)}`,
3365
3433
  summary: `Delete issuer ${issuer.iss}`
3366
3434
  });
3367
- console.log(import_chalk26.default.green(" Deleted."));
3435
+ console.log(import_chalk28.default.green(" Deleted."));
3368
3436
  }
3369
3437
  async function setOpaque(base, cur) {
3370
3438
  const { default: inquirer3 } = await import("inquirer");
@@ -3373,19 +3441,19 @@ async function setOpaque(base, cur) {
3373
3441
  { type: "list", name: "method", message: "HTTP method:", choices: ["GET", "POST"], default: cur?.method ?? "GET" }
3374
3442
  ]);
3375
3443
  await admin({ method: "PUT", path: `${base}/opaque`, body: { opaque: { endpoint: a.endpoint, method: a.method } }, summary: "Set opaque validator" });
3376
- console.log(import_chalk26.default.green(" Opaque login method set."));
3444
+ console.log(import_chalk28.default.green(" Opaque login method set."));
3377
3445
  }
3378
3446
  async function opaqueHome(base, cur) {
3379
3447
  const { default: inquirer3 } = await import("inquirer");
3380
3448
  console.log(`
3381
- ${import_chalk26.default.bold(cur.endpoint)} ${import_chalk26.default.dim(cur.method ?? "GET")}`);
3449
+ ${import_chalk28.default.bold(cur.endpoint)} ${import_chalk28.default.dim(cur.method ?? "GET")}`);
3382
3450
  const { act } = await inquirer3.prompt([{
3383
3451
  type: "list",
3384
3452
  name: "act",
3385
3453
  message: "This opaque login method:",
3386
3454
  choices: [
3387
3455
  { name: "Replace it", value: "edit" },
3388
- { name: import_chalk26.default.red("Delete it"), value: "rm" },
3456
+ { name: import_chalk28.default.red("Delete it"), value: "rm" },
3389
3457
  { name: "\u2190 Back", value: "back" }
3390
3458
  ]
3391
3459
  }]);
@@ -3395,14 +3463,14 @@ async function opaqueHome(base, cur) {
3395
3463
  return;
3396
3464
  }
3397
3465
  await admin({ method: "PUT", path: `${base}/opaque`, body: { opaque: null }, summary: "Clear opaque validator" });
3398
- console.log(import_chalk26.default.green(" Deleted."));
3466
+ console.log(import_chalk28.default.green(" Deleted."));
3399
3467
  }
3400
3468
  async function clientHome(base, summary) {
3401
3469
  const { default: inquirer3 } = await import("inquirer");
3402
3470
  const id = summary.clientId ?? summary.client_id;
3403
3471
  const cBase = `${base}/app-clients/${encodeURIComponent(id)}`;
3404
3472
  for (; ; ) {
3405
- const spinner = (0, import_ora11.default)("Reading app client...").start();
3473
+ const spinner = (0, import_ora12.default)("Reading app client...").start();
3406
3474
  const c = await admin({ method: "GET", path: cBase, summary: `Read app client ${id}` }).catch(() => summary);
3407
3475
  spinner.stop();
3408
3476
  const cb = c.authorizedCallbackUrls ?? c.authorized_callback_urls ?? [];
@@ -3414,13 +3482,13 @@ async function clientHome(base, summary) {
3414
3482
  message: `${c.name ?? id}:`,
3415
3483
  pageSize: 12,
3416
3484
  choices: [
3417
- { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk26.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
3418
- { name: `Callback URLs: ${cb.length ? import_chalk26.default.cyan(cb.join(", ")) : import_chalk26.default.dim("(none)")}`, value: "callbacks" },
3419
- { name: `Scopes: ${scopes.length ? import_chalk26.default.cyan(scopes.join(" ")) : import_chalk26.default.dim("(defaults)")}`, value: "scopes" },
3485
+ { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk28.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
3486
+ { name: `Callback URLs: ${cb.length ? import_chalk28.default.cyan(cb.join(", ")) : import_chalk28.default.dim("(none)")}`, value: "callbacks" },
3487
+ { name: `Scopes: ${scopes.length ? import_chalk28.default.cyan(scopes.join(" ")) : import_chalk28.default.dim("(defaults)")}`, value: "scopes" },
3420
3488
  { name: `Token expiries: access ${c.accessTokenExpiry ?? 3600}s \xB7 id ${c.idTokenExpiry ?? 3600}s \xB7 refresh ${c.refreshTokenExpiry ?? 2592e3}s`, value: "expiries" },
3421
3489
  { name: "Reveal client secret", value: "secret" },
3422
3490
  { name: "Rotate client secret", value: "rotate" },
3423
- { name: import_chalk26.default.red("Delete this app client"), value: "delete" },
3491
+ { name: import_chalk28.default.red("Delete this app client"), value: "delete" },
3424
3492
  { name: "\u2190 Back", value: "back" }
3425
3493
  ]
3426
3494
  }]);
@@ -3433,13 +3501,13 @@ async function clientHome(base, summary) {
3433
3501
  case "callbacks": {
3434
3502
  const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Callback URLs (comma-separated):", default: cb.join(", ") }]);
3435
3503
  await admin({ method: "PATCH", path: cBase, body: { authorizedCallbackUrls: parseList(v) }, summary: "Update callback URLs" });
3436
- console.log(import_chalk26.default.green(" Callbacks updated."));
3504
+ console.log(import_chalk28.default.green(" Callbacks updated."));
3437
3505
  break;
3438
3506
  }
3439
3507
  case "scopes": {
3440
3508
  const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Scopes (space/comma-separated):", default: scopes.join(" ") }]);
3441
3509
  await admin({ method: "PATCH", path: cBase, body: { scopes: v.split(/[\s,]+/).filter(Boolean) }, summary: "Update scopes" });
3442
- console.log(import_chalk26.default.green(" Scopes updated."));
3510
+ console.log(import_chalk28.default.green(" Scopes updated."));
3443
3511
  break;
3444
3512
  }
3445
3513
  case "expiries": {
@@ -3454,14 +3522,14 @@ async function clientHome(base, summary) {
3454
3522
  body: { accessTokenExpiry: Number(a.access), idTokenExpiry: Number(a.id), refreshTokenExpiry: Number(a.refresh) },
3455
3523
  summary: "Update token expiries"
3456
3524
  });
3457
- console.log(import_chalk26.default.green(" Expiries updated."));
3525
+ console.log(import_chalk28.default.green(" Expiries updated."));
3458
3526
  break;
3459
3527
  }
3460
3528
  case "secret": {
3461
3529
  const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: "Print the client secret to this terminal?", default: false }]);
3462
3530
  if (!sure) break;
3463
3531
  const s = await admin({ method: "GET", path: `${cBase}/secret`, summary: "Reveal client secret" });
3464
- console.log(` ${import_chalk26.default.bold("client_secret")}: ${import_chalk26.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3532
+ console.log(` ${import_chalk28.default.bold("client_secret")}: ${import_chalk28.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3465
3533
  break;
3466
3534
  }
3467
3535
  case "rotate": {
@@ -3469,14 +3537,14 @@ async function clientHome(base, summary) {
3469
3537
  if (!sure) break;
3470
3538
  const fresh = randomSecret();
3471
3539
  await admin({ method: "PATCH", path: cBase, body: { clientSecret: fresh }, summary: "Rotate client secret" });
3472
- console.log(` New ${import_chalk26.default.bold("client_secret")}: ${import_chalk26.default.green(fresh)} ${import_chalk26.default.dim("(store it now)")}`);
3540
+ console.log(` New ${import_chalk28.default.bold("client_secret")}: ${import_chalk28.default.green(fresh)} ${import_chalk28.default.dim("(store it now)")}`);
3473
3541
  break;
3474
3542
  }
3475
3543
  case "delete": {
3476
3544
  const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: `Delete app client "${c.name ?? id}"? Consumers logged in through it will lose access.`, default: false }]);
3477
3545
  if (!sure) break;
3478
3546
  await admin({ method: "DELETE", path: cBase, summary: `Delete app client ${id}` });
3479
- console.log(import_chalk26.default.green(" App client deleted."));
3547
+ console.log(import_chalk28.default.green(" App client deleted."));
3480
3548
  return;
3481
3549
  }
3482
3550
  }
@@ -3497,15 +3565,15 @@ var DEFAULT_SCOPES2 = {
3497
3565
  async function providersMenu(cBase, clientLabel) {
3498
3566
  const { default: inquirer3 } = await import("inquirer");
3499
3567
  for (; ; ) {
3500
- const spinner = (0, import_ora11.default)("Loading providers...").start();
3568
+ const spinner = (0, import_ora12.default)("Loading providers...").start();
3501
3569
  const raw = await admin({ method: "GET", path: `${cBase}/providers`, summary: "List login providers" }).catch(() => []);
3502
3570
  spinner.stop();
3503
3571
  const providers = Array.isArray(raw) ? raw : [];
3504
3572
  console.log();
3505
3573
  for (const p of providers) {
3506
- console.log(` ${import_chalk26.default.bold(p.type)} ${import_chalk26.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
3574
+ console.log(` ${import_chalk28.default.bold(p.type)} ${import_chalk28.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
3507
3575
  }
3508
- if (!providers.length) console.log(import_chalk26.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
3576
+ if (!providers.length) console.log(import_chalk28.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
3509
3577
  const { act } = await inquirer3.prompt([{
3510
3578
  type: "list",
3511
3579
  name: "act",
@@ -3563,23 +3631,23 @@ async function providersMenu(cBase, clientLabel) {
3563
3631
  body.targetServerToken = routing;
3564
3632
  }
3565
3633
  await admin({ method: "POST", path: `${cBase}/providers`, body, summary: `Add ${type} login provider` });
3566
- console.log(import_chalk26.default.green(` ${type} provider added.`));
3634
+ console.log(import_chalk28.default.green(` ${type} provider added.`));
3567
3635
  } else {
3568
3636
  const { p } = await inquirer3.prompt([{
3569
3637
  type: "list",
3570
3638
  name: "p",
3571
3639
  message: act === "rm" ? "Remove which provider?" : "Reveal which secret?",
3572
- choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk26.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
3640
+ choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk28.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
3573
3641
  }]);
3574
3642
  if (!p) continue;
3575
3643
  if (act === "rm") {
3576
3644
  const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: `Remove the ${p.type} provider? Consumers using it can no longer sign in.`, default: false }]);
3577
3645
  if (!sure) continue;
3578
3646
  await admin({ method: "DELETE", path: `${cBase}/providers/${encodeURIComponent(p.id)}`, summary: `Remove ${p.type} provider` });
3579
- console.log(import_chalk26.default.green(` ${p.type} removed.`));
3647
+ console.log(import_chalk28.default.green(` ${p.type} removed.`));
3580
3648
  } else {
3581
3649
  const s = await admin({ method: "GET", path: `${cBase}/providers/${encodeURIComponent(p.id)}/secret`, summary: `Reveal ${p.type} provider secret` });
3582
- console.log(` ${import_chalk26.default.bold("client_secret")}: ${import_chalk26.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3650
+ console.log(` ${import_chalk28.default.bold("client_secret")}: ${import_chalk28.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
3583
3651
  }
3584
3652
  }
3585
3653
  }
@@ -3587,8 +3655,8 @@ async function providersMenu(cBase, clientLabel) {
3587
3655
 
3588
3656
  // src/commands/spec.ts
3589
3657
  var fs7 = __toESM(require("fs"));
3590
- var import_chalk27 = __toESM(require("chalk"));
3591
- var import_ora12 = __toESM(require("ora"));
3658
+ var import_chalk29 = __toESM(require("chalk"));
3659
+ var import_ora13 = __toESM(require("ora"));
3592
3660
  init_admin();
3593
3661
  async function runSpecGet(project, opts) {
3594
3662
  const { teamId } = await resolveTeam(opts.team);
@@ -3602,19 +3670,19 @@ async function runSpecGet(project, opts) {
3602
3670
  }
3603
3671
  async function runSpecSet(project, opts) {
3604
3672
  if (!opts.file) {
3605
- console.error(import_chalk27.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
3673
+ console.error(import_chalk29.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
3606
3674
  process.exit(1);
3607
3675
  }
3608
3676
  let specContent;
3609
3677
  try {
3610
3678
  specContent = fs7.readFileSync(opts.file, "utf-8");
3611
3679
  } catch {
3612
- console.error(import_chalk27.default.red(`Cannot read file: ${opts.file}`));
3680
+ console.error(import_chalk29.default.red(`Cannot read file: ${opts.file}`));
3613
3681
  process.exit(1);
3614
3682
  }
3615
3683
  const { teamId } = await resolveTeam(opts.team);
3616
3684
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
3617
- const spinner = (0, import_ora12.default)("Uploading spec...").start();
3685
+ const spinner = (0, import_ora13.default)("Uploading spec...").start();
3618
3686
  try {
3619
3687
  const out = await admin({
3620
3688
  method: "POST",
@@ -3631,13 +3699,13 @@ async function runSpecSet(project, opts) {
3631
3699
  }
3632
3700
 
3633
3701
  // src/commands/agent.ts
3634
- var import_chalk29 = __toESM(require("chalk"));
3635
- var import_ora13 = __toESM(require("ora"));
3702
+ var import_chalk31 = __toESM(require("chalk"));
3703
+ var import_ora14 = __toESM(require("ora"));
3636
3704
  init_auth();
3637
3705
  init_admin();
3638
3706
 
3639
3707
  // src/lib/tools.ts
3640
- var import_chalk28 = __toESM(require("chalk"));
3708
+ var import_chalk30 = __toESM(require("chalk"));
3641
3709
  init_admin();
3642
3710
  init_api();
3643
3711
  async function proj(teamId, name, version2) {
@@ -3656,15 +3724,15 @@ var TOOLS = [
3656
3724
  const key = keys.dev ?? Object.values(keys)[0];
3657
3725
  const url = `https://${a.name}.abz.run/${version2}/dev`;
3658
3726
  const tryIt = buildTryItCurl(url, auth, key);
3659
- const lines = [` ${import_chalk28.default.dim("Proxy URL:")} ${import_chalk28.default.bold(url)}`];
3660
- if (res.devPortal) lines.push(` ${import_chalk28.default.dim("Dev portal:")} ${res.devPortal}`);
3727
+ const lines = [` ${import_chalk30.default.dim("Proxy URL:")} ${import_chalk30.default.bold(url)}`];
3728
+ if (res.devPortal) lines.push(` ${import_chalk30.default.dim("Dev portal:")} ${res.devPortal}`);
3661
3729
  const envs = Object.keys(keys);
3662
3730
  if (envs.length) {
3663
- lines.push("", ` ${import_chalk28.default.bold("API keys")} ${import_chalk28.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
3731
+ lines.push("", ` ${import_chalk30.default.bold("API keys")} ${import_chalk30.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
3664
3732
  const w = Math.max(...envs.map((e) => e.length));
3665
- for (const env of envs) lines.push(` ${import_chalk28.default.cyan(env.padEnd(w))} ${import_chalk28.default.green(keys[env])}`);
3733
+ for (const env of envs) lines.push(` ${import_chalk30.default.cyan(env.padEnd(w))} ${import_chalk30.default.green(keys[env])}`);
3666
3734
  }
3667
- if (tryIt) lines.push("", ` ${import_chalk28.default.dim("Try it:")}`, ` ${import_chalk28.default.cyan(tryIt)}`);
3735
+ if (tryIt) lines.push("", ` ${import_chalk30.default.dim("Try it:")}`, ` ${import_chalk30.default.cyan(tryIt)}`);
3668
3736
  return { ...res, proxy_url: url, keys, ...tryIt ? { try_it: tryIt } : {}, display: lines.join("\n") };
3669
3737
  }
3670
3738
  },
@@ -3820,23 +3888,23 @@ function truncate(value, max = 1500) {
3820
3888
  }
3821
3889
  function printCost(resp) {
3822
3890
  const line = formatBilling(resp.billing);
3823
- if (line) console.log(import_chalk29.default.magenta(` ${line}`) + import_chalk29.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
3891
+ if (line) console.log(import_chalk31.default.magenta(` ${line}`) + import_chalk31.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
3824
3892
  }
3825
3893
  async function runAgent(opts) {
3826
3894
  requireAuth();
3827
3895
  const { teamId, teamName } = await resolveTeam(opts.team);
3828
3896
  const { default: inquirer3 } = await import("inquirer");
3829
- console.log(import_chalk29.default.bold("APIblaze agent") + import_chalk29.default.dim(` \xB7 team ${teamName ?? teamId}`));
3830
- console.log(import_chalk29.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
3897
+ console.log(import_chalk31.default.bold("APIblaze agent") + import_chalk31.default.dim(` \xB7 team ${teamName ?? teamId}`));
3898
+ console.log(import_chalk31.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
3831
3899
  const history = [];
3832
3900
  while (true) {
3833
- const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk29.default.cyan("you") + " \u203A" }]);
3901
+ const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk31.default.cyan("you") + " \u203A" }]);
3834
3902
  const text = (input ?? "").trim();
3835
3903
  if (!text) continue;
3836
3904
  if (["exit", "quit", ":q"].includes(text.toLowerCase())) break;
3837
3905
  history.push({ role: "user", content: text });
3838
3906
  for (let step = 0; step < MAX_TOOL_STEPS; step++) {
3839
- const spinner = (0, import_ora13.default)({ text: "thinking...", color: "magenta" }).start();
3907
+ const spinner = (0, import_ora14.default)({ text: "thinking...", color: "magenta" }).start();
3840
3908
  let resp;
3841
3909
  try {
3842
3910
  resp = await callAgent(history, teamId);
@@ -3844,21 +3912,21 @@ async function runAgent(opts) {
3844
3912
  } catch (err) {
3845
3913
  spinner.stop();
3846
3914
  if (err instanceof ApiError && err.status === 402) {
3847
- console.log(import_chalk29.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
3915
+ console.log(import_chalk31.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
3848
3916
  break;
3849
3917
  }
3850
3918
  throw err;
3851
3919
  }
3852
3920
  history.push({ role: "assistant", content: resp.raw });
3853
3921
  printCost(resp);
3854
- if (resp.reply) console.log(import_chalk29.default.green("agent") + " \u203A " + resp.reply);
3922
+ if (resp.reply) console.log(import_chalk31.default.green("agent") + " \u203A " + resp.reply);
3855
3923
  if (!resp.action) break;
3856
3924
  const tool = findTool(resp.action.tool);
3857
3925
  if (!tool) {
3858
3926
  history.push({ role: "user", content: `TOOL_RESULT ${resp.action.tool}: error \u2014 unknown tool` });
3859
3927
  continue;
3860
3928
  }
3861
- const runSpinner = (0, import_ora13.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
3929
+ const runSpinner = (0, import_ora14.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
3862
3930
  try {
3863
3931
  const result = await tool.run(resp.action.args, { teamId });
3864
3932
  runSpinner.succeed(`${tool.name} \u2713`);
@@ -3876,11 +3944,11 @@ async function runAgent(opts) {
3876
3944
  }
3877
3945
  renderTrace();
3878
3946
  if (step === MAX_TOOL_STEPS - 1) {
3879
- console.log(import_chalk29.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
3947
+ console.log(import_chalk31.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
3880
3948
  }
3881
3949
  }
3882
3950
  }
3883
- console.log(import_chalk29.default.dim("\nBye."));
3951
+ console.log(import_chalk31.default.dim("\nBye."));
3884
3952
  }
3885
3953
 
3886
3954
  // src/commands/config-browse.ts
@@ -4119,11 +4187,11 @@ function dig(blob, dotted) {
4119
4187
  }
4120
4188
  var readSetting = (s, cfg) => s.read ? s.read(cfg) : dig(cfg, s.key);
4121
4189
  function show(v) {
4122
- if (v === void 0) return import_chalk30.default.dim("(unset)");
4123
- if (v === null) return import_chalk30.default.dim("null");
4124
- if (typeof v === "object") return import_chalk30.default.cyan(JSON.stringify(v));
4125
- if (typeof v === "boolean") return v ? import_chalk30.default.green("on") : import_chalk30.default.red("off");
4126
- return import_chalk30.default.cyan(String(v));
4190
+ if (v === void 0) return import_chalk32.default.dim("(unset)");
4191
+ if (v === null) return import_chalk32.default.dim("null");
4192
+ if (typeof v === "object") return import_chalk32.default.cyan(JSON.stringify(v));
4193
+ if (typeof v === "boolean") return v ? import_chalk32.default.green("on") : import_chalk32.default.red("off");
4194
+ return import_chalk32.default.cyan(String(v));
4127
4195
  }
4128
4196
  function parseValue(raw) {
4129
4197
  if (raw === "true") return true;
@@ -4150,7 +4218,7 @@ async function fetchConfigBlob(proj2) {
4150
4218
  }
4151
4219
  async function patchSetting(proj2, s, value, cfg) {
4152
4220
  const body = s.toPatch(value, cfg);
4153
- const spinner = (0, import_ora14.default)(`Set ${s.key}...`).start();
4221
+ const spinner = (0, import_ora15.default)(`Set ${s.key}...`).start();
4154
4222
  try {
4155
4223
  await admin({
4156
4224
  method: "PATCH",
@@ -4165,10 +4233,10 @@ async function patchSetting(proj2, s, value, cfg) {
4165
4233
  }
4166
4234
  }
4167
4235
  var loginFirst = (what) => {
4168
- console.log(import_chalk30.default.yellow(`
4236
+ console.log(import_chalk32.default.yellow(`
4169
4237
  Log in first to ${what}.`));
4170
- console.log(import_chalk30.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
4171
- console.log(import_chalk30.default.dim(" anonymously and want to bring it into your account.\n"));
4238
+ console.log(import_chalk32.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
4239
+ console.log(import_chalk32.default.dim(" anonymously and want to bring it into your account.\n"));
4172
4240
  };
4173
4241
  async function runConfig(project, key, value, opts) {
4174
4242
  const creds = loadCredentials();
@@ -4185,9 +4253,9 @@ async function runConfig(project, key, value, opts) {
4185
4253
  }
4186
4254
  const setting = SETTINGS.find((s) => s.key === key);
4187
4255
  if (!setting) {
4188
- console.error(import_chalk30.default.red(`Unknown setting "${key}".`));
4189
- console.error(import_chalk30.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
4190
- console.error(import_chalk30.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
4256
+ console.error(import_chalk32.default.red(`Unknown setting "${key}".`));
4257
+ console.error(import_chalk32.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
4258
+ console.error(import_chalk32.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
4191
4259
  process.exit(1);
4192
4260
  }
4193
4261
  if (value === void 0) {
@@ -4202,7 +4270,7 @@ async function pickProject(teamId) {
4202
4270
  const { getProjects: getProjects2 } = await Promise.resolve().then(() => (init_api(), api_exports));
4203
4271
  const projects = await getProjects2(teamId).catch(() => []);
4204
4272
  if (!projects.length) {
4205
- console.error(import_chalk30.default.red("No projects in this team. Create one: `npx apiblaze create`."));
4273
+ console.error(import_chalk32.default.red("No projects in this team. Create one: `npx apiblaze create`."));
4206
4274
  process.exit(1);
4207
4275
  }
4208
4276
  const { default: inquirer3 } = await import("inquirer");
@@ -4210,7 +4278,7 @@ async function pickProject(teamId) {
4210
4278
  type: "list",
4211
4279
  name: "picked",
4212
4280
  message: "Which project?",
4213
- choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk30.default.dim("v" + p.apiVersion)}`, value: p }))
4281
+ choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk32.default.dim("v" + p.apiVersion)}`, value: p }))
4214
4282
  }]);
4215
4283
  return { projectId: picked.projectId, projectName: picked.projectName, apiVersion: picked.apiVersion, teamId, tenant: picked.tenant };
4216
4284
  }
@@ -4221,25 +4289,25 @@ function printAll(proj2, cfg, json) {
4221
4289
  console.log(JSON.stringify(out, null, 2));
4222
4290
  return;
4223
4291
  }
4224
- console.log(import_chalk30.default.bold(`
4292
+ console.log(import_chalk32.default.bold(`
4225
4293
  ${proj2.projectName} v${proj2.apiVersion} \u2014 settings
4226
4294
  `));
4227
4295
  for (const group2 of SETTING_GROUPS) {
4228
- console.log(import_chalk30.default.bold(group2));
4296
+ console.log(import_chalk32.default.bold(group2));
4229
4297
  for (const s of SETTINGS.filter((x) => x.group === group2)) {
4230
- console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk30.default.dim(s.desc)}`);
4298
+ console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk32.default.dim(s.desc)}`);
4231
4299
  }
4232
4300
  console.log();
4233
4301
  }
4234
- console.log(import_chalk30.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
4302
+ console.log(import_chalk32.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
4235
4303
  }
4236
4304
  async function discoveryMenu(project) {
4237
4305
  const { default: inquirer3 } = await import("inquirer");
4238
- console.log(import_chalk30.default.bold(`
4306
+ console.log(import_chalk32.default.bold(`
4239
4307
  APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
4240
4308
  `));
4241
- console.log(import_chalk30.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
4242
- console.log(import_chalk30.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
4309
+ console.log(import_chalk32.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
4310
+ console.log(import_chalk32.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
4243
4311
  for (; ; ) {
4244
4312
  const { pick: pick2 } = await inquirer3.prompt([{
4245
4313
  type: "list",
@@ -4247,13 +4315,13 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
4247
4315
  message: "Explore:",
4248
4316
  pageSize: 20,
4249
4317
  choices: [
4250
- new inquirer3.Separator(import_chalk30.default.bold("\u2014 Settings \u2014")),
4318
+ new inquirer3.Separator(import_chalk32.default.bold("\u2014 Settings \u2014")),
4251
4319
  ...SETTING_GROUPS.map((g) => ({
4252
- name: `${g} ${import_chalk30.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
4320
+ name: `${g} ${import_chalk32.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
4253
4321
  value: { kind: "settings", g }
4254
4322
  })),
4255
- new inquirer3.Separator(import_chalk30.default.bold("\u2014 Features \u2014")),
4256
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk30.default.dim(f.desc)}`, value: { kind: "feature", f } })),
4323
+ new inquirer3.Separator(import_chalk32.default.bold("\u2014 Features \u2014")),
4324
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk32.default.dim(f.desc)}`, value: { kind: "feature", f } })),
4257
4325
  new inquirer3.Separator(),
4258
4326
  { name: "Exit", value: { kind: "exit" } }
4259
4327
  ]
@@ -4262,24 +4330,24 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
4262
4330
  if (pick2.kind === "settings") {
4263
4331
  console.log();
4264
4332
  for (const s of SETTINGS.filter((x) => x.group === pick2.g)) {
4265
- console.log(` ${import_chalk30.default.bold(s.label.padEnd(28))} ${import_chalk30.default.dim(s.desc)}`);
4266
- console.log(` ${import_chalk30.default.dim(" key: " + s.key)}`);
4333
+ console.log(` ${import_chalk32.default.bold(s.label.padEnd(28))} ${import_chalk32.default.dim(s.desc)}`);
4334
+ console.log(` ${import_chalk32.default.dim(" key: " + s.key)}`);
4267
4335
  }
4268
4336
  loginFirst("view or change these settings");
4269
4337
  } else {
4270
4338
  const f = pick2.f;
4271
4339
  console.log(`
4272
- ${import_chalk30.default.bold(f.label)} \u2014 ${f.desc}`);
4340
+ ${import_chalk32.default.bold(f.label)} \u2014 ${f.desc}`);
4273
4341
  loginFirst(`use ${f.label.toLowerCase()}`);
4274
4342
  }
4275
4343
  }
4276
4344
  }
4277
4345
  async function navigator(proj2, cfg, opts) {
4278
4346
  const { default: inquirer3 } = await import("inquirer");
4279
- console.log(import_chalk30.default.bold(`
4347
+ console.log(import_chalk32.default.bold(`
4280
4348
  ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
4281
4349
  `));
4282
- console.log(import_chalk30.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
4350
+ console.log(import_chalk32.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
4283
4351
  let blob = cfg;
4284
4352
  for (; ; ) {
4285
4353
  const { pick: pick2 } = await inquirer3.prompt([{
@@ -4288,10 +4356,10 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
4288
4356
  message: "Where to?",
4289
4357
  pageSize: 20,
4290
4358
  choices: [
4291
- new inquirer3.Separator(import_chalk30.default.bold("\u2014 Settings \u2014")),
4359
+ new inquirer3.Separator(import_chalk32.default.bold("\u2014 Settings \u2014")),
4292
4360
  ...SETTING_GROUPS.map((g) => ({ name: g, value: { kind: "settings", g } })),
4293
- new inquirer3.Separator(import_chalk30.default.bold("\u2014 Features \u2014")),
4294
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk30.default.dim(f.desc)}`, value: { kind: f.go } })),
4361
+ new inquirer3.Separator(import_chalk32.default.bold("\u2014 Features \u2014")),
4362
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk32.default.dim(f.desc)}`, value: { kind: f.go } })),
4295
4363
  new inquirer3.Separator(),
4296
4364
  { name: "Show all settings", value: { kind: "list" } },
4297
4365
  { name: "Exit", value: { kind: "exit" } }
@@ -4331,7 +4399,7 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
4331
4399
  }
4332
4400
  }
4333
4401
  } catch (err) {
4334
- console.error(import_chalk30.default.red(` ${err instanceof Error ? err.message : String(err)}`));
4402
+ console.error(import_chalk32.default.red(` ${err instanceof Error ? err.message : String(err)}`));
4335
4403
  }
4336
4404
  }
4337
4405
  }
@@ -4345,7 +4413,7 @@ async function settingsGroup(proj2, cfg, group2) {
4345
4413
  message: group2 + ":",
4346
4414
  pageSize: 16,
4347
4415
  choices: [
4348
- ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk30.default.dim(s2.desc)}`, value: s2 })),
4416
+ ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk32.default.dim(s2.desc)}`, value: s2 })),
4349
4417
  new inquirer3.Separator(),
4350
4418
  { name: "\u2190 Back", value: null }
4351
4419
  ]
@@ -4363,7 +4431,7 @@ async function settingsGroup(proj2, cfg, group2) {
4363
4431
  } else if (s.type === "number") {
4364
4432
  const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: `${s.label} (number):`, default: readSetting(s, cfg) }]);
4365
4433
  if (v === "" || Number.isNaN(Number(v))) {
4366
- console.log(import_chalk30.default.yellow(" Not a number \u2014 unchanged."));
4434
+ console.log(import_chalk32.default.yellow(" Not a number \u2014 unchanged."));
4367
4435
  continue;
4368
4436
  }
4369
4437
  value = Number(v);
@@ -4444,7 +4512,7 @@ async function buildCondition(phase) {
4444
4512
  const items = [];
4445
4513
  for (; ; ) {
4446
4514
  const a = await inquirer3.prompt([
4447
- { type: "input", name: "source", message: `Condition field ${import_chalk30.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
4515
+ { type: "input", name: "source", message: `Condition field ${import_chalk32.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
4448
4516
  { type: "list", name: "operator", message: "Operator:", choices: [
4449
4517
  "eq",
4450
4518
  "neq",
@@ -4475,7 +4543,7 @@ async function buildCondition(phase) {
4475
4543
  function showCondition(cond) {
4476
4544
  if (!Array.isArray(cond) || !cond.length) return "";
4477
4545
  const s = cond.map((c) => `${c.source} ${c.operator}${c.value !== void 0 ? ` "${c.value}"` : ""}${c.logicOp ? ` ${c.logicOp}` : ""}`).join(" ");
4478
- return import_chalk30.default.dim(` when ${s}`);
4546
+ return import_chalk32.default.dim(` when ${s}`);
4479
4547
  }
4480
4548
  async function transformsMenu(proj2) {
4481
4549
  const { default: inquirer3 } = await import("inquirer");
@@ -4484,12 +4552,12 @@ async function transformsMenu(proj2) {
4484
4552
  const out = await admin({ method: "GET", path: base, summary: "List transform rules" });
4485
4553
  const rules = out?.rules ?? [];
4486
4554
  console.log();
4487
- if (!rules.length) console.log(import_chalk30.default.dim(" No transform rules yet."));
4555
+ if (!rules.length) console.log(import_chalk32.default.dim(" No transform rules yet."));
4488
4556
  for (const r of rules) {
4489
4557
  const a = r.action ?? {};
4490
4558
  const fns = [...a.source_fns ?? [], ...a.dest_fns ?? []].map((f) => f.fn);
4491
- 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_chalk30.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
4492
- console.log(` ${r.enabled ? import_chalk30.default.green("\u25CF") : import_chalk30.default.dim("\u25CB")} ${import_chalk30.default.bold(r.name)} ${import_chalk30.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
4559
+ 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_chalk32.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
4560
+ console.log(` ${r.enabled ? import_chalk32.default.green("\u25CF") : import_chalk32.default.dim("\u25CB")} ${import_chalk32.default.bold(r.name)} ${import_chalk32.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
4493
4561
  }
4494
4562
  const { act } = await inquirer3.prompt([{
4495
4563
  type: "list",
@@ -4501,7 +4569,7 @@ async function transformsMenu(proj2) {
4501
4569
  { name: "Enable/disable a rule", value: "toggle" },
4502
4570
  { name: "Delete a rule", value: "delete" }
4503
4571
  ] : [],
4504
- { name: import_chalk30.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
4572
+ { name: import_chalk32.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
4505
4573
  { name: "\u2190 Back", value: "back" }
4506
4574
  ]
4507
4575
  }]);
@@ -4514,11 +4582,11 @@ async function transformsMenu(proj2) {
4514
4582
  }]);
4515
4583
  const body = parseValue(raw);
4516
4584
  if (!body || typeof body !== "object" || Array.isArray(body)) {
4517
- console.log(import_chalk30.default.yellow(" Not a JSON object \u2014 skipped."));
4585
+ console.log(import_chalk32.default.yellow(" Not a JSON object \u2014 skipped."));
4518
4586
  continue;
4519
4587
  }
4520
4588
  await admin({ method: "POST", path: base, body, summary: "Create transform rule (raw JSON)" });
4521
- console.log(import_chalk30.default.green(" Rule created."));
4589
+ console.log(import_chalk32.default.green(" Rule created."));
4522
4590
  continue;
4523
4591
  }
4524
4592
  if (act === "add") {
@@ -4534,7 +4602,7 @@ async function transformsMenu(proj2) {
4534
4602
  { name: "Remove a field", value: "remove" }
4535
4603
  ] }
4536
4604
  ]);
4537
- const fieldHint = import_chalk30.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
4605
+ const fieldHint = import_chalk32.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
4538
4606
  let action2;
4539
4607
  if (ans.kind === "hardcode") {
4540
4608
  const a = await inquirer3.prompt([
@@ -4563,7 +4631,7 @@ async function transformsMenu(proj2) {
4563
4631
  };
4564
4632
  }
4565
4633
  const condition = await buildCondition(ans.phase);
4566
- const spinner = (0, import_ora14.default)("Creating rule...").start();
4634
+ const spinner = (0, import_ora15.default)("Creating rule...").start();
4567
4635
  try {
4568
4636
  await admin({
4569
4637
  method: "POST",
@@ -4581,16 +4649,16 @@ async function transformsMenu(proj2) {
4581
4649
  type: "list",
4582
4650
  name: "rule",
4583
4651
  message: act === "toggle" ? "Which rule?" : "Delete which rule?",
4584
- choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk30.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
4652
+ choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk32.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
4585
4653
  }]);
4586
4654
  if (!rule) continue;
4587
4655
  if (act === "toggle") {
4588
4656
  const flipped = { ...rule, enabled: rule.enabled === false };
4589
4657
  await admin({ method: "PUT", path: `${base}/${rule.id}`, body: flipped, summary: `${flipped.enabled ? "Enable" : "Disable"} transform "${rule.name}"` });
4590
- console.log(import_chalk30.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
4658
+ console.log(import_chalk32.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
4591
4659
  } else {
4592
4660
  await admin({ method: "DELETE", path: `${base}/${rule.id}`, summary: `Delete transform "${rule.name}"` });
4593
- console.log(import_chalk30.default.green(` ${rule.name} deleted.`));
4661
+ console.log(import_chalk32.default.green(` ${rule.name} deleted.`));
4594
4662
  }
4595
4663
  }
4596
4664
  }
@@ -4602,9 +4670,9 @@ async function mappingsMenu(proj2) {
4602
4670
  const out = await admin({ method: "GET", path: base, summary: "List mapping tables" });
4603
4671
  const tables = out?.mappings ?? out?.tables ?? [];
4604
4672
  console.log();
4605
- if (!tables.length) console.log(import_chalk30.default.dim(" No mapping tables yet."));
4673
+ if (!tables.length) console.log(import_chalk32.default.dim(" No mapping tables yet."));
4606
4674
  for (const t of tables) {
4607
- console.log(` ${import_chalk30.default.bold(t.name)} ${import_chalk30.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
4675
+ console.log(` ${import_chalk32.default.bold(t.name)} ${import_chalk32.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
4608
4676
  }
4609
4677
  const { act } = await inquirer3.prompt([{
4610
4678
  type: "list",
@@ -4624,11 +4692,11 @@ async function mappingsMenu(proj2) {
4624
4692
  ]);
4625
4693
  const entries2 = parseValue(a.entries);
4626
4694
  if (!Array.isArray(entries2)) {
4627
- console.log(import_chalk30.default.yellow(" Entries must be a JSON array \u2014 not created."));
4695
+ console.log(import_chalk32.default.yellow(" Entries must be a JSON array \u2014 not created."));
4628
4696
  continue;
4629
4697
  }
4630
4698
  await admin({ method: "POST", path: base, body: { name: a.name, entries: entries2 }, summary: `Create mapping table "${a.name}"` });
4631
- console.log(import_chalk30.default.green(` Table "${a.name}" created.`));
4699
+ console.log(import_chalk32.default.green(` Table "${a.name}" created.`));
4632
4700
  } else {
4633
4701
  const { table } = await inquirer3.prompt([{
4634
4702
  type: "list",
@@ -4638,7 +4706,7 @@ async function mappingsMenu(proj2) {
4638
4706
  }]);
4639
4707
  if (!table) continue;
4640
4708
  await admin({ method: "DELETE", path: `${base}/${table.id}`, summary: `Delete mapping table "${table.name}"` });
4641
- console.log(import_chalk30.default.green(` ${table.name} deleted.`));
4709
+ console.log(import_chalk32.default.green(` ${table.name} deleted.`));
4642
4710
  }
4643
4711
  }
4644
4712
  }
@@ -4649,14 +4717,14 @@ async function tenantsMenu(proj2, opts) {
4649
4717
  const out = await admin({ method: "GET", path: base, summary: "List attached tenants" });
4650
4718
  const tenants = out?.tenants ?? [];
4651
4719
  console.log();
4652
- if (!tenants.length) console.log(import_chalk30.default.dim(" No tenants attached (consumers use the default tenant)."));
4653
- for (const t of tenants) console.log(` ${import_chalk30.default.bold(t.tenant_name ?? t.name)} ${import_chalk30.default.dim(t.display_name ?? "")}`);
4720
+ if (!tenants.length) console.log(import_chalk32.default.dim(" No tenants attached (consumers use the default tenant)."));
4721
+ for (const t of tenants) console.log(` ${import_chalk32.default.bold(t.tenant_name ?? t.name)} ${import_chalk32.default.dim(t.display_name ?? "")}`);
4654
4722
  const { act } = await inquirer3.prompt([{
4655
4723
  type: "list",
4656
4724
  name: "act",
4657
4725
  message: "Tenants:",
4658
4726
  choices: [
4659
- { name: `Manage a tenant\u2026 ${import_chalk30.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
4727
+ { name: `Manage a tenant\u2026 ${import_chalk32.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
4660
4728
  { name: "Attach a tenant to this project", value: "attach" },
4661
4729
  ...tenants.length ? [{ name: "Detach a tenant from this project", value: "detach" }] : [],
4662
4730
  { name: "\u2190 Back", value: "back" }
@@ -4679,7 +4747,7 @@ async function tenantsMenu(proj2, opts) {
4679
4747
  }]);
4680
4748
  if (!t) continue;
4681
4749
  await admin({ method: "DELETE", path: `${base}/${encodeURIComponent(t.tenant_name ?? t.name)}`, summary: `Detach tenant ${t.tenant_name ?? t.name}` });
4682
- console.log(import_chalk30.default.green(` Detached ${t.tenant_name ?? t.name}.`));
4750
+ console.log(import_chalk32.default.green(` Detached ${t.tenant_name ?? t.name}.`));
4683
4751
  }
4684
4752
  }
4685
4753
  }
@@ -4722,7 +4790,7 @@ async function specMenu(proj2, opts) {
4722
4790
  choices: [
4723
4791
  { name: "Print the stored spec", value: "get" },
4724
4792
  { name: "Refresh the spec from its source", value: "refresh" },
4725
- { name: import_chalk30.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
4793
+ { name: import_chalk32.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
4726
4794
  { name: "\u2190 Back", value: "back" }
4727
4795
  ]
4728
4796
  }]);
@@ -4730,7 +4798,7 @@ async function specMenu(proj2, opts) {
4730
4798
  if (act === "get") await runSpecGet(proj2.projectName, { team: opts.team, apiversion: proj2.apiVersion });
4731
4799
  else if (act === "refresh") {
4732
4800
  await admin({ method: "POST", path: `/projects/${proj2.projectId}/${proj2.apiVersion}/refresh-spec`, summary: "Refresh spec from source" });
4733
- console.log(import_chalk30.default.green(" Spec refresh triggered."));
4801
+ console.log(import_chalk32.default.green(" Spec refresh triggered."));
4734
4802
  } else await runOpenapi(proj2.projectName, proj2.apiVersion);
4735
4803
  }
4736
4804
  async function agentsMenu(proj2, opts) {
@@ -4755,8 +4823,8 @@ async function agentsMenu(proj2, opts) {
4755
4823
  }
4756
4824
 
4757
4825
  // src/commands/group.ts
4758
- var import_chalk31 = __toESM(require("chalk"));
4759
- var import_ora15 = __toESM(require("ora"));
4826
+ var import_chalk33 = __toESM(require("chalk"));
4827
+ var import_ora16 = __toESM(require("ora"));
4760
4828
  init_auth();
4761
4829
  init_admin();
4762
4830
  init_types();
@@ -4845,11 +4913,11 @@ async function runGroupList(opts) {
4845
4913
  const t = await resolveTransport(opts);
4846
4914
  const groups = await listGroups(t);
4847
4915
  if (opts.json) return void console.log(JSON.stringify(groups));
4848
- if (!groups.length) return void console.log(import_chalk31.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
4849
- console.log(import_chalk31.default.dim(`Tenant ${t.tenant}:`));
4916
+ if (!groups.length) return void console.log(import_chalk33.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
4917
+ console.log(import_chalk33.default.dim(`Tenant ${t.tenant}:`));
4850
4918
  for (const g of groups) {
4851
- const sealed = g.name === "apiblaze_admins" ? import_chalk31.default.dim(" (admins \u2014 managed by allowlist)") : "";
4852
- console.log(` ${import_chalk31.default.bold(g.name)} ${import_chalk31.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
4919
+ const sealed = g.name === "apiblaze_admins" ? import_chalk33.default.dim(" (admins \u2014 managed by allowlist)") : "";
4920
+ console.log(` ${import_chalk33.default.bold(g.name)} ${import_chalk33.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
4853
4921
  }
4854
4922
  }
4855
4923
  async function runGroupCreate(name, opts) {
@@ -4874,10 +4942,10 @@ async function runGroupCreate(name, opts) {
4874
4942
  }
4875
4943
  }
4876
4944
  }
4877
- const spinner = (0, import_ora15.default)(`Creating group ${name}...`).start();
4945
+ const spinner = (0, import_ora16.default)(`Creating group ${name}...`).start();
4878
4946
  try {
4879
4947
  await t.call("/v1/admin/groups", "POST", { name, admins: [adminSub] });
4880
- spinner.succeed(`Group ${import_chalk31.default.bold(name)} created in ${t.tenant}.`);
4948
+ spinner.succeed(`Group ${import_chalk33.default.bold(name)} created in ${t.tenant}.`);
4881
4949
  } catch (e) {
4882
4950
  spinner.fail("Create failed.");
4883
4951
  throw e;
@@ -4886,10 +4954,10 @@ async function runGroupCreate(name, opts) {
4886
4954
  async function runGroupDelete(name, opts) {
4887
4955
  const t = await resolveTransport(opts);
4888
4956
  const g = await groupByName(t, name);
4889
- const spinner = (0, import_ora15.default)(`Deleting group ${name}...`).start();
4957
+ const spinner = (0, import_ora16.default)(`Deleting group ${name}...`).start();
4890
4958
  try {
4891
4959
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}`, "DELETE");
4892
- spinner.succeed(`Group ${import_chalk31.default.bold(name)} deleted.`);
4960
+ spinner.succeed(`Group ${import_chalk33.default.bold(name)} deleted.`);
4893
4961
  } catch (e) {
4894
4962
  spinner.fail("Delete failed.");
4895
4963
  throw e;
@@ -4902,20 +4970,20 @@ async function runGroupMembers(name, opts) {
4902
4970
  const subs = await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/subgroups`);
4903
4971
  if (opts.json) return void console.log(JSON.stringify({ ...detail, subgroups: subs?.subgroups ?? [] }));
4904
4972
  const members = detail?.members ?? [];
4905
- console.log(import_chalk31.default.bold(`${g.name}`) + import_chalk31.default.dim(` (${t.tenant})`));
4906
- for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk31.default.cyan("group-admin") : import_chalk31.default.dim("member")}`);
4907
- if (!members.length) console.log(import_chalk31.default.dim(" no members"));
4973
+ console.log(import_chalk33.default.bold(`${g.name}`) + import_chalk33.default.dim(` (${t.tenant})`));
4974
+ for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk33.default.cyan("group-admin") : import_chalk33.default.dim("member")}`);
4975
+ if (!members.length) console.log(import_chalk33.default.dim(" no members"));
4908
4976
  const sg = subs?.subgroups ?? [];
4909
- if (sg.length) console.log(import_chalk31.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
4977
+ if (sg.length) console.log(import_chalk33.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
4910
4978
  }
4911
4979
  async function runGroupAddUser(userRef, groupName, opts) {
4912
4980
  const t = await resolveTransport(opts);
4913
4981
  const [g, u] = [await groupByName(t, groupName), await userByRef(t, userRef)];
4914
4982
  const role = opts.role === "admin" ? "admin" : "member";
4915
- const spinner = (0, import_ora15.default)(`Adding ${label2(u)} to ${g.name}...`).start();
4983
+ const spinner = (0, import_ora16.default)(`Adding ${label2(u)} to ${g.name}...`).start();
4916
4984
  try {
4917
4985
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members`, "POST", { abz_sub: u.abz_sub, role });
4918
- spinner.succeed(`${import_chalk31.default.bold(label2(u))} added to ${import_chalk31.default.bold(g.name)} as ${role}.`);
4986
+ spinner.succeed(`${import_chalk33.default.bold(label2(u))} added to ${import_chalk33.default.bold(g.name)} as ${role}.`);
4919
4987
  } catch (e) {
4920
4988
  spinner.fail("Add failed.");
4921
4989
  throw e;
@@ -4924,10 +4992,10 @@ async function runGroupAddUser(userRef, groupName, opts) {
4924
4992
  async function runGroupRemoveUser(userRef, groupName, opts) {
4925
4993
  const t = await resolveTransport(opts);
4926
4994
  const [g, u] = [await groupByName(t, groupName), await userByRef(t, userRef)];
4927
- const spinner = (0, import_ora15.default)(`Removing ${label2(u)} from ${g.name}...`).start();
4995
+ const spinner = (0, import_ora16.default)(`Removing ${label2(u)} from ${g.name}...`).start();
4928
4996
  try {
4929
4997
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members/_?abz_sub=${encodeURIComponent(u.abz_sub)}`, "DELETE");
4930
- spinner.succeed(`${import_chalk31.default.bold(label2(u))} removed from ${import_chalk31.default.bold(g.name)}.`);
4998
+ spinner.succeed(`${import_chalk33.default.bold(label2(u))} removed from ${import_chalk33.default.bold(g.name)}.`);
4931
4999
  } catch (e) {
4932
5000
  spinner.fail("Remove failed.");
4933
5001
  throw e;
@@ -4936,10 +5004,10 @@ async function runGroupRemoveUser(userRef, groupName, opts) {
4936
5004
  async function runGroupAddGroup(childName, parentName, opts) {
4937
5005
  const t = await resolveTransport(opts);
4938
5006
  const [child, parent] = [await groupByName(t, childName), await groupByName(t, parentName)];
4939
- const spinner = (0, import_ora15.default)(`Nesting ${child.name} under ${parent.name}...`).start();
5007
+ const spinner = (0, import_ora16.default)(`Nesting ${child.name} under ${parent.name}...`).start();
4940
5008
  try {
4941
5009
  await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups`, "POST", { child_group_id: child.id });
4942
- spinner.succeed(`${import_chalk31.default.bold(child.name)} is now a subgroup of ${import_chalk31.default.bold(parent.name)}.`);
5010
+ spinner.succeed(`${import_chalk33.default.bold(child.name)} is now a subgroup of ${import_chalk33.default.bold(parent.name)}.`);
4943
5011
  } catch (e) {
4944
5012
  spinner.fail("Nest failed.");
4945
5013
  throw e;
@@ -4948,10 +5016,10 @@ async function runGroupAddGroup(childName, parentName, opts) {
4948
5016
  async function runGroupRemoveGroup(childName, parentName, opts) {
4949
5017
  const t = await resolveTransport(opts);
4950
5018
  const [child, parent] = [await groupByName(t, childName), await groupByName(t, parentName)];
4951
- const spinner = (0, import_ora15.default)(`Un-nesting ${child.name} from ${parent.name}...`).start();
5019
+ const spinner = (0, import_ora16.default)(`Un-nesting ${child.name} from ${parent.name}...`).start();
4952
5020
  try {
4953
5021
  await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups/${encodeURIComponent(child.id)}`, "DELETE");
4954
- spinner.succeed(`${import_chalk31.default.bold(child.name)} un-nested from ${import_chalk31.default.bold(parent.name)}.`);
5022
+ spinner.succeed(`${import_chalk33.default.bold(child.name)} un-nested from ${import_chalk33.default.bold(parent.name)}.`);
4955
5023
  } catch (e) {
4956
5024
  spinner.fail("Un-nest failed.");
4957
5025
  throw e;
@@ -4962,19 +5030,19 @@ async function runGroupUsers(opts) {
4962
5030
  const users = await listUsers(t);
4963
5031
  const observed = await t.call("/v1/admin/observed-identities").catch(() => ({ identities: [] }));
4964
5032
  if (opts.json) return void console.log(JSON.stringify({ users, observed: observed?.identities ?? [] }));
4965
- console.log(import_chalk31.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
4966
- for (const u of users) console.log(` ${label2(u)} ${import_chalk31.default.dim(u.abz_sub)}`);
4967
- if (!users.length) console.log(import_chalk31.default.dim(" no users yet"));
5033
+ console.log(import_chalk33.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
5034
+ for (const u of users) console.log(` ${label2(u)} ${import_chalk33.default.dim(u.abz_sub)}`);
5035
+ if (!users.length) console.log(import_chalk33.default.dim(" no users yet"));
4968
5036
  const fresh = (observed?.identities ?? []).filter((o) => !o.provisioned);
4969
5037
  if (fresh.length) {
4970
- console.log(import_chalk31.default.dim("Seen in traffic (not yet users):"));
4971
- for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk31.default.dim(o.source_label ?? "")}`);
5038
+ console.log(import_chalk33.default.dim("Seen in traffic (not yet users):"));
5039
+ for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk33.default.dim(o.source_label ?? "")}`);
4972
5040
  }
4973
5041
  }
4974
5042
 
4975
5043
  // src/commands/key.ts
4976
- var import_chalk32 = __toESM(require("chalk"));
4977
- var import_ora16 = __toESM(require("ora"));
5044
+ var import_chalk34 = __toESM(require("chalk"));
5045
+ var import_ora17 = __toESM(require("ora"));
4978
5046
  init_admin();
4979
5047
  async function runApikeysMenu(opts) {
4980
5048
  await runKeyList(opts);
@@ -5002,11 +5070,11 @@ async function runKeyList(opts) {
5002
5070
  return;
5003
5071
  }
5004
5072
  if (!keys.length) {
5005
- console.log(import_chalk32.default.yellow("No developer keys."));
5073
+ console.log(import_chalk34.default.yellow("No developer keys."));
5006
5074
  return;
5007
5075
  }
5008
5076
  for (const k of keys) {
5009
- console.log(` ${import_chalk32.default.bold(k.key_id ?? k.id)} ${import_chalk32.default.dim(k.description ?? "")} ${import_chalk32.default.dim(k.expires_at ?? "no expiry")}`);
5077
+ console.log(` ${import_chalk34.default.bold(k.key_id ?? k.id)} ${import_chalk34.default.dim(k.description ?? "")} ${import_chalk34.default.dim(k.expires_at ?? "no expiry")}`);
5010
5078
  }
5011
5079
  }
5012
5080
  async function runKeyMint(opts) {
@@ -5014,7 +5082,7 @@ async function runKeyMint(opts) {
5014
5082
  const body = { role: "consumer-admin" };
5015
5083
  if (opts.desc) body.description = opts.desc;
5016
5084
  if (opts.expiresDays) body.expires_in_seconds = Number(opts.expiresDays) * 24 * 60 * 60;
5017
- const spinner = (0, import_ora16.default)("Minting key...").start();
5085
+ const spinner = (0, import_ora17.default)("Minting key...").start();
5018
5086
  try {
5019
5087
  const out = await admin({
5020
5088
  method: "POST",
@@ -5027,9 +5095,9 @@ async function runKeyMint(opts) {
5027
5095
  console.log(JSON.stringify(out));
5028
5096
  return;
5029
5097
  }
5030
- console.log(` ${import_chalk32.default.bold("key_id")}: ${out?.key_id}`);
5031
- console.log(` ${import_chalk32.default.bold("key")}: ${import_chalk32.default.green(out?.key)} ${import_chalk32.default.dim("(shown once \u2014 store it now)")}`);
5032
- if (out?.expires_at) console.log(` ${import_chalk32.default.dim("expires:")} ${out.expires_at}`);
5098
+ console.log(` ${import_chalk34.default.bold("key_id")}: ${out?.key_id}`);
5099
+ console.log(` ${import_chalk34.default.bold("key")}: ${import_chalk34.default.green(out?.key)} ${import_chalk34.default.dim("(shown once \u2014 store it now)")}`);
5100
+ if (out?.expires_at) console.log(` ${import_chalk34.default.dim("expires:")} ${out.expires_at}`);
5033
5101
  } catch (err) {
5034
5102
  spinner.fail("Mint failed.");
5035
5103
  throw err;
@@ -5037,7 +5105,7 @@ async function runKeyMint(opts) {
5037
5105
  }
5038
5106
  async function runKeyRevoke(keyId, opts) {
5039
5107
  const { teamId } = await resolveTeam(opts.team);
5040
- const spinner = (0, import_ora16.default)("Revoking key...").start();
5108
+ const spinner = (0, import_ora17.default)("Revoking key...").start();
5041
5109
  try {
5042
5110
  await admin({
5043
5111
  method: "DELETE",
@@ -5055,8 +5123,8 @@ async function runKeyRevoke(keyId, opts) {
5055
5123
  var fs9 = __toESM(require("fs"));
5056
5124
  var path6 = __toESM(require("path"));
5057
5125
  var crypto2 = __toESM(require("crypto"));
5058
- var import_chalk34 = __toESM(require("chalk"));
5059
- var import_ora17 = __toESM(require("ora"));
5126
+ var import_chalk36 = __toESM(require("chalk"));
5127
+ var import_ora18 = __toESM(require("ora"));
5060
5128
  var import_yaml = require("yaml");
5061
5129
  init_auth();
5062
5130
  init_anon_cred();
@@ -5066,7 +5134,7 @@ init_admin();
5066
5134
  // src/commands/llm.ts
5067
5135
  var fs8 = __toESM(require("fs"));
5068
5136
  var path5 = __toESM(require("path"));
5069
- var import_chalk33 = __toESM(require("chalk"));
5137
+ var import_chalk35 = __toESM(require("chalk"));
5070
5138
  var import_inquirer2 = __toESM(require("inquirer"));
5071
5139
  init_auth();
5072
5140
  var LLM_PATH = path5.join(getApiblazeDir(), "llm.json");
@@ -5110,27 +5178,27 @@ async function runLlmSetKey(keyArg, opts) {
5110
5178
  }
5111
5179
  const existing = loadLlmConfig();
5112
5180
  saveLlmConfig({ key, provider, model: opts.model ?? existing?.model });
5113
- console.log(`${import_chalk33.default.green("\u2713")} Saved ${import_chalk33.default.bold(provider)} key ${maskSecret(key)}`);
5114
- console.log(import_chalk33.default.gray(` Stored locally at ${LLM_PATH} (0600) \u2014 never sent to APIblaze except per chat turn.`));
5115
- if (opts.model) console.log(import_chalk33.default.gray(` Model: ${opts.model}`));
5181
+ console.log(`${import_chalk35.default.green("\u2713")} Saved ${import_chalk35.default.bold(provider)} key ${maskSecret(key)}`);
5182
+ console.log(import_chalk35.default.gray(` Stored locally at ${LLM_PATH} (0600) \u2014 never sent to APIblaze except per chat turn.`));
5183
+ if (opts.model) console.log(import_chalk35.default.gray(` Model: ${opts.model}`));
5116
5184
  }
5117
5185
  async function runLlmShow() {
5118
5186
  const cfg = loadLlmConfig();
5119
5187
  if (!cfg) {
5120
- console.log(import_chalk33.default.gray("No LLM key set. `apiblaze llm set-key sk-...` to add one (optional \u2014 chat works without it)."));
5188
+ console.log(import_chalk35.default.gray("No LLM key set. `apiblaze llm set-key sk-...` to add one (optional \u2014 chat works without it)."));
5121
5189
  return;
5122
5190
  }
5123
- console.log(`Provider: ${import_chalk33.default.bold(cfg.provider)}`);
5191
+ console.log(`Provider: ${import_chalk35.default.bold(cfg.provider)}`);
5124
5192
  console.log(`Key: ${maskSecret(cfg.key)}`);
5125
5193
  if (cfg.model) console.log(`Model: ${cfg.model}`);
5126
- console.log(import_chalk33.default.gray(`Stored at ${LLM_PATH}`));
5194
+ console.log(import_chalk35.default.gray(`Stored at ${LLM_PATH}`));
5127
5195
  }
5128
5196
  async function runLlmClearKey() {
5129
5197
  try {
5130
5198
  fs8.unlinkSync(LLM_PATH);
5131
- console.log(`${import_chalk33.default.green("\u2713")} Removed local LLM key.`);
5199
+ console.log(`${import_chalk35.default.green("\u2713")} Removed local LLM key.`);
5132
5200
  } catch {
5133
- console.log(import_chalk33.default.gray("No LLM key was set."));
5201
+ console.log(import_chalk35.default.gray("No LLM key was set."));
5134
5202
  }
5135
5203
  }
5136
5204
 
@@ -5138,9 +5206,9 @@ async function runLlmClearKey() {
5138
5206
  init_trace();
5139
5207
  init_types();
5140
5208
  function fail4(message, hint) {
5141
- console.error(import_chalk34.default.red(`
5209
+ console.error(import_chalk36.default.red(`
5142
5210
  Error: ${message}`));
5143
- if (hint) console.error(import_chalk34.default.dim(hint));
5211
+ if (hint) console.error(import_chalk36.default.dim(hint));
5144
5212
  process.exit(1);
5145
5213
  }
5146
5214
  function normalizeName2(raw) {
@@ -5288,7 +5356,7 @@ async function resolveTargetAuth(spec2, opts) {
5288
5356
  "Re-run with --force to provision anyway (configure target auth later with `apiblaze config`),\nor use an api_key / bearer / basic scheme."
5289
5357
  );
5290
5358
  }
5291
- if (sawOAuth) console.log(import_chalk34.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
5359
+ if (sawOAuth) console.log(import_chalk36.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
5292
5360
  return null;
5293
5361
  }
5294
5362
  if (candidates.length === 1 && !noneAllowed) return candidates[0];
@@ -5365,7 +5433,7 @@ async function provision(spec2, target, opts) {
5365
5433
  if (!base && spec2.info && typeof spec2.info.title === "string") base = normalizeName2(spec2.info.title);
5366
5434
  if (!base || base.length < 3) base = "apichat";
5367
5435
  let name = opts.name ? base : `${base}${salt()}`;
5368
- const spinner = (0, import_ora17.default)("Provisioning an api_key proxy...").start();
5436
+ const spinner = (0, import_ora18.default)("Provisioning an api_key proxy...").start();
5369
5437
  let result;
5370
5438
  for (let attempt = 0; attempt < 4; attempt++) {
5371
5439
  try {
@@ -5445,7 +5513,7 @@ async function provision(spec2, target, opts) {
5445
5513
  return { projectId, version: version2, environment, dpKey, mcpHost, proxyUrl, anon };
5446
5514
  }
5447
5515
  async function writeTargetAuth(p, auth, secret) {
5448
- const spinner = (0, import_ora17.default)("Storing target credentials (encrypted)...").start();
5516
+ const spinner = (0, import_ora18.default)("Storing target credentials (encrypted)...").start();
5449
5517
  try {
5450
5518
  await cpPost(
5451
5519
  p.anon,
@@ -5467,7 +5535,7 @@ async function writeTargetAuth(p, auth, secret) {
5467
5535
  }
5468
5536
  }
5469
5537
  async function uploadSpec(p, specText, opts) {
5470
- const spinner = (0, import_ora17.default)("Uploading the spec...").start();
5538
+ const spinner = (0, import_ora18.default)("Uploading the spec...").start();
5471
5539
  let out;
5472
5540
  try {
5473
5541
  out = await cpPost(
@@ -5482,7 +5550,7 @@ async function uploadSpec(p, specText, opts) {
5482
5550
  throw err;
5483
5551
  }
5484
5552
  if (out && out.reused === true) {
5485
- console.log(import_chalk34.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
5553
+ console.log(import_chalk36.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
5486
5554
  } else if (out && out.changed === true && out.previous_spec_hash) {
5487
5555
  const interactive = !!process.stdin.isTTY && !opts.yes;
5488
5556
  if (interactive) {
@@ -5490,12 +5558,12 @@ async function uploadSpec(p, specText, opts) {
5490
5558
  const { go } = await inquirer3.prompt([
5491
5559
  { type: "confirm", name: "go", message: "The spec changed since the last provision \u2014 re-publish the MCP catalogue?", default: true }
5492
5560
  ]);
5493
- if (!go) console.log(import_chalk34.default.dim(" Keeping the existing MCP catalogue."));
5561
+ if (!go) console.log(import_chalk36.default.dim(" Keeping the existing MCP catalogue."));
5494
5562
  }
5495
5563
  }
5496
5564
  }
5497
5565
  async function publishMcp(p, spec2) {
5498
- const spinner = (0, import_ora17.default)("Publishing the MCP catalogue...").start();
5566
+ const spinner = (0, import_ora18.default)("Publishing the MCP catalogue...").start();
5499
5567
  try {
5500
5568
  const url = `https://${p.mcpHost}/${p.version}/${p.environment}/mcp/generate`;
5501
5569
  const res = await fetch(url, {
@@ -5531,14 +5599,14 @@ var revealAuth = false;
5531
5599
  function renderToolEvents(events, dpKey) {
5532
5600
  for (const e of events ?? []) {
5533
5601
  const ok = typeof e.status === "number" ? e.status < 400 : String(e.status).toLowerCase() === "ok";
5534
- const mark = ok ? import_chalk34.default.green("\u2713") : import_chalk34.default.red("\u2717");
5535
- console.log(` ${mark} ${import_chalk34.default.cyan(e.name)} ${import_chalk34.default.dim(`(${e.status}, ${e.ms}ms)`)}`);
5602
+ const mark = ok ? import_chalk36.default.green("\u2713") : import_chalk36.default.red("\u2717");
5603
+ console.log(` ${mark} ${import_chalk36.default.cyan(e.name)} ${import_chalk36.default.dim(`(${e.status}, ${e.ms}ms)`)}`);
5536
5604
  if (isVerbose() && e.method && e.url) {
5537
- console.log(import_chalk34.default.dim(` curl -sS -X ${e.method} '${e.url}'${dpKey ? " \\" : ""}`));
5605
+ console.log(import_chalk36.default.dim(` curl -sS -X ${e.method} '${e.url}'${dpKey ? " \\" : ""}`));
5538
5606
  if (dpKey) {
5539
5607
  const keyLine = ` -H 'X-API-Key: ${revealAuth ? dpKey : maskKey(dpKey)}'`;
5540
- const hint = revealAuth ? "" : import_chalk34.default.yellow(" \u2190 /showauth will reveal this");
5541
- console.log(import_chalk34.default.dim(keyLine) + hint);
5608
+ const hint = revealAuth ? "" : import_chalk36.default.yellow(" \u2190 /showauth will reveal this");
5609
+ console.log(import_chalk36.default.dim(keyLine) + hint);
5542
5610
  }
5543
5611
  }
5544
5612
  }
@@ -5546,9 +5614,9 @@ function renderToolEvents(events, dpKey) {
5546
5614
  function billingLine(billing) {
5547
5615
  if (!billing || typeof billing.cents !== "number") return null;
5548
5616
  const usd = (billing.cents / 100).toFixed(Math.abs(billing.cents - Math.round(billing.cents)) < 1e-9 ? 2 : 4);
5549
- let line = import_chalk34.default.magenta(` \u{1F4B3} $${usd}`) + import_chalk34.default.dim(billing.model ? ` \xB7 ${billing.model}` : "");
5617
+ let line = import_chalk36.default.magenta(` \u{1F4B3} $${usd}`) + import_chalk36.default.dim(billing.model ? ` \xB7 ${billing.model}` : "");
5550
5618
  if (typeof billing.credits_remaining === "number") {
5551
- line += import_chalk34.default.dim(` \xB7 balance $${(billing.credits_remaining / 100).toFixed(2)}`);
5619
+ line += import_chalk36.default.dim(` \xB7 balance $${(billing.credits_remaining / 100).toFixed(2)}`);
5552
5620
  }
5553
5621
  return line;
5554
5622
  }
@@ -5557,14 +5625,14 @@ function freeBudgetWarning(billing, anon) {
5557
5625
  const perTurn = Math.max(billing.cents || 0, 0.02);
5558
5626
  const left = Math.floor(billing.free_remaining_cents / perTurn);
5559
5627
  if (left > 8) return null;
5560
- if (left <= 0) return import_chalk34.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
5561
- return import_chalk34.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
5628
+ if (left <= 0) return import_chalk36.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
5629
+ return import_chalk36.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
5562
5630
  }
5563
5631
  function printAssistant(delta) {
5564
5632
  for (let i = delta.length - 1; i >= 0; i--) {
5565
5633
  const m = delta[i];
5566
5634
  if (m && m.role === "assistant" && typeof m.content === "string" && m.content.trim()) {
5567
- console.log("\n" + import_chalk34.default.green("assistant \u203A ") + m.content + "\n");
5635
+ console.log("\n" + import_chalk36.default.green("assistant \u203A ") + m.content + "\n");
5568
5636
  return;
5569
5637
  }
5570
5638
  }
@@ -5574,7 +5642,7 @@ async function replTurn(p, messages, userText) {
5574
5642
  const llm2 = loadLlmConfig();
5575
5643
  const turnId = crypto2.randomUUID();
5576
5644
  for (let round = 0; round < CLIENT_ROUND_CAP; round++) {
5577
- const spinner = (0, import_ora17.default)({ text: round === 0 ? "thinking..." : "working...", color: "magenta" }).start();
5645
+ const spinner = (0, import_ora18.default)({ text: round === 0 ? "thinking..." : "working...", color: "magenta" }).start();
5578
5646
  const body = {
5579
5647
  turn_id: turnId,
5580
5648
  messages,
@@ -5590,7 +5658,7 @@ async function replTurn(p, messages, userText) {
5590
5658
  });
5591
5659
  } catch (err) {
5592
5660
  spinner.fail("Network error.");
5593
- console.log(import_chalk34.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
5661
+ console.log(import_chalk36.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
5594
5662
  return;
5595
5663
  }
5596
5664
  let data = null;
@@ -5608,12 +5676,12 @@ async function replTurn(p, messages, userText) {
5608
5676
  return;
5609
5677
  }
5610
5678
  if (res.status === 401) {
5611
- console.log(import_chalk34.default.red(" The proxy rejected the API key (401). The key may have been revoked; re-run `apiblaze apichat` to re-provision."));
5679
+ console.log(import_chalk36.default.red(" The proxy rejected the API key (401). The key may have been revoked; re-run `apiblaze apichat` to re-provision."));
5612
5680
  return;
5613
5681
  }
5614
5682
  if (!res.ok || !data) {
5615
5683
  const err = data && data.error || `HTTP ${res.status}`;
5616
- console.log(import_chalk34.default.red(` Chat error: ${err}`));
5684
+ console.log(import_chalk36.default.red(` Chat error: ${err}`));
5617
5685
  return;
5618
5686
  }
5619
5687
  if (Array.isArray(data.delta)) {
@@ -5627,25 +5695,25 @@ async function replTurn(p, messages, userText) {
5627
5695
  if (warn) console.log(warn);
5628
5696
  if (!data.continue) return;
5629
5697
  }
5630
- console.log(import_chalk34.default.dim(" (stopped after several tool rounds \u2014 ask again to continue)"));
5698
+ console.log(import_chalk36.default.dim(" (stopped after several tool rounds \u2014 ask again to continue)"));
5631
5699
  }
5632
5700
  function renderUpsell(p, upsell) {
5633
5701
  const loggedIn = !!loadCredentials();
5634
5702
  if (upsell.reason === "CAPPED" && !loggedIn) {
5635
- console.log("\n" + import_chalk34.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
5636
- console.log(import_chalk34.default.dim(" (or `/login` right here \u2014 your chat is preserved \u2014 or `apiblaze llm set-key` for your own model key.)"));
5703
+ console.log("\n" + import_chalk36.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
5704
+ console.log(import_chalk36.default.dim(" (or `/login` right here \u2014 your chat is preserved \u2014 or `apiblaze llm set-key` for your own model key.)"));
5637
5705
  console.log();
5638
5706
  return;
5639
5707
  }
5640
- console.log("\n" + import_chalk34.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
5708
+ console.log("\n" + import_chalk36.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
5641
5709
  if (upsell.reason === "INSUFFICIENT" || upsell.reason === "BREAKER" || upsell.reason === "CAPPED" || upsell.reason === "PAUSED") {
5642
5710
  if (!loggedIn) {
5643
- console.log(import_chalk34.default.dim(" Options: `/login` for free login credit and higher limits, or `apiblaze llm set-key` to bring your own model key."));
5711
+ console.log(import_chalk36.default.dim(" Options: `/login` for free login credit and higher limits, or `apiblaze llm set-key` to bring your own model key."));
5644
5712
  } else {
5645
- console.log(import_chalk34.default.dim(" Options: top up your wallet, or `apiblaze llm set-key` to bring your own model key (bypasses platform limits)."));
5713
+ console.log(import_chalk36.default.dim(" Options: top up your wallet, or `apiblaze llm set-key` to bring your own model key (bypasses platform limits)."));
5646
5714
  }
5647
5715
  } else if (upsell.reason === "INFLIGHT") {
5648
- console.log(import_chalk34.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
5716
+ console.log(import_chalk36.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
5649
5717
  }
5650
5718
  console.log();
5651
5719
  }
@@ -5714,9 +5782,9 @@ async function openServerProxy(project) {
5714
5782
  const prior = loadApichats().find((a) => a.projectId === project.projectId && a.dpKey);
5715
5783
  let dpKey = prior?.dpKey;
5716
5784
  if (!dpKey) {
5717
- console.log(import_chalk34.default.dim(` Minting an API key for tenant ${import_chalk34.default.bold(tenant2)} to query project ${import_chalk34.default.bold(project.projectName)}\u2026`));
5785
+ console.log(import_chalk36.default.dim(` Minting an API key for tenant ${import_chalk36.default.bold(tenant2)} to query project ${import_chalk36.default.bold(project.projectName)}\u2026`));
5718
5786
  dpKey = await mintDurableProxyKey(project.teamId, tenant2);
5719
- console.log(` ${import_chalk34.default.green("\u2714")} API key: ${import_chalk34.default.dim(maskKey(dpKey))}`);
5787
+ console.log(` ${import_chalk36.default.green("\u2714")} API key: ${import_chalk36.default.dim(maskKey(dpKey))}`);
5720
5788
  }
5721
5789
  const p = {
5722
5790
  projectId: project.projectId,
@@ -5727,7 +5795,7 @@ async function openServerProxy(project) {
5727
5795
  proxyUrl: `https://${project.projectId}.abz.run/${version2}/${environment}`,
5728
5796
  anon: false
5729
5797
  };
5730
- const spinner = (0, import_ora17.default)("Preparing the chat\u2026").start();
5798
+ const spinner = (0, import_ora18.default)("Preparing the chat\u2026").start();
5731
5799
  try {
5732
5800
  const raw = await admin({
5733
5801
  method: "GET",
@@ -5739,7 +5807,7 @@ async function openServerProxy(project) {
5739
5807
  if (spec2 && (spec2.paths || spec2.openapi)) {
5740
5808
  await publishMcp(p, spec2);
5741
5809
  } else {
5742
- console.log(import_chalk34.default.yellow(" This proxy has no OpenAPI spec yet \u2014 chat will have no tools. Build one with `apiblaze agent openapi`."));
5810
+ console.log(import_chalk36.default.yellow(" This proxy has no OpenAPI spec yet \u2014 chat will have no tools. Build one with `apiblaze agent openapi`."));
5743
5811
  }
5744
5812
  } catch (err) {
5745
5813
  spinner.fail("Could not open the proxy.");
@@ -5792,7 +5860,7 @@ async function noArgsMenu(opts) {
5792
5860
  const me = loadCredentials()?.apiblazeUserId;
5793
5861
  const saved = loadApichats().filter((a) => a.anon ? true : a.ownerUserId !== void 0 && a.ownerUserId === me);
5794
5862
  const choices = saved.map((a) => ({
5795
- name: `Chat with ${import_chalk34.default.bold(a.name)} ${import_chalk34.default.dim(`(${a.target})${a.messages && a.messages.length ? ` \xB7 ${a.messages.length} msgs` : ""}`)}`,
5863
+ name: `Chat with ${import_chalk36.default.bold(a.name)} ${import_chalk36.default.dim(`(${a.target})${a.messages && a.messages.length ? ` \xB7 ${a.messages.length} msgs` : ""}`)}`,
5796
5864
  value: { type: "existing", a }
5797
5865
  }));
5798
5866
  const creds = loadCredentials();
@@ -5802,14 +5870,14 @@ async function noArgsMenu(opts) {
5802
5870
  const proxies = (await getProjects(creds.teamId)).filter((pr) => !savedIds.has(pr.projectId));
5803
5871
  for (const pr of proxies) {
5804
5872
  choices.push({
5805
- name: `Chat with ${import_chalk34.default.bold(pr.projectName)} ${import_chalk34.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
5873
+ name: `Chat with ${import_chalk36.default.bold(pr.projectName)} ${import_chalk36.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
5806
5874
  value: { type: "server", project: pr }
5807
5875
  });
5808
5876
  }
5809
5877
  } catch {
5810
5878
  }
5811
5879
  }
5812
- choices.push({ name: import_chalk34.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
5880
+ choices.push({ name: import_chalk36.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
5813
5881
  const { pick: pick2 } = await inquirer3.prompt([
5814
5882
  { type: "list", name: "pick", message: "What would you like to do?", choices }
5815
5883
  ]);
@@ -5881,31 +5949,31 @@ async function noArgsMenu(opts) {
5881
5949
  async function runRepl(p, initialMessages) {
5882
5950
  const { default: inquirer3 } = await import("inquirer");
5883
5951
  const messages = initialMessages && initialMessages.length ? initialMessages.slice() : [];
5884
- console.log("\n" + import_chalk34.default.cyan.bold("Chat with your API") + import_chalk34.default.dim(` \xB7 ${p.mcpHost}`));
5885
- if (messages.length) console.log(import_chalk34.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
5952
+ console.log("\n" + import_chalk36.default.cyan.bold("Chat with your API") + import_chalk36.default.dim(` \xB7 ${p.mcpHost}`));
5953
+ if (messages.length) console.log(import_chalk36.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
5886
5954
  const llm2 = loadLlmConfig();
5887
5955
  console.log(
5888
- import_chalk34.default.dim(
5956
+ import_chalk36.default.dim(
5889
5957
  llm2 ? `Using your local ${llm2.provider} key for the model. Type a question, or /exit. /login /claim manage your workspace.` : "Ask a question in plain English. /exit to quit \xB7 /login for credit \xB7 /claim to keep this workspace \xB7 `apiblaze llm set-key` for BYO models."
5890
5958
  )
5891
5959
  );
5892
5960
  for (; ; ) {
5893
- const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk34.default.green("you \u203A") }]);
5961
+ const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk36.default.green("you \u203A") }]);
5894
5962
  const text = (input ?? "").trim();
5895
5963
  if (!text) continue;
5896
5964
  if (["/exit", "/quit", "exit", "quit", ":q"].includes(text.toLowerCase())) break;
5897
5965
  if (text === "/login") {
5898
5966
  try {
5899
5967
  await runLogin();
5900
- console.log(import_chalk34.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
5968
+ console.log(import_chalk36.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
5901
5969
  } catch (err) {
5902
- console.log(import_chalk34.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
5970
+ console.log(import_chalk36.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
5903
5971
  }
5904
5972
  continue;
5905
5973
  }
5906
5974
  if (text === "/claim") {
5907
5975
  if (!loadCredentials()) {
5908
- console.log(import_chalk34.default.yellow(" Log in first: `/login`, then `/claim`."));
5976
+ console.log(import_chalk36.default.yellow(" Log in first: `/login`, then `/claim`."));
5909
5977
  continue;
5910
5978
  }
5911
5979
  try {
@@ -5914,30 +5982,30 @@ async function runRepl(p, initialMessages) {
5914
5982
  p.mcpHost = p.mcpHost.replace(".mcp.tryabz.run", ".mcp.abz.run");
5915
5983
  p.anon = false;
5916
5984
  claimApichat(p, loadCredentials()?.apiblazeUserId);
5917
- console.log(import_chalk34.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
5985
+ console.log(import_chalk36.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
5918
5986
  }
5919
5987
  } catch (err) {
5920
- console.log(import_chalk34.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
5988
+ console.log(import_chalk36.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
5921
5989
  }
5922
5990
  continue;
5923
5991
  }
5924
5992
  if (text === "/showauth") {
5925
5993
  revealAuth = !revealAuth;
5926
- console.log(import_chalk34.default.dim(revealAuth ? " The real API key will be shown in the next call's curl. /showauth again to re-mask." : " API key re-masked."));
5994
+ console.log(import_chalk36.default.dim(revealAuth ? " The real API key will be shown in the next call's curl. /showauth again to re-mask." : " API key re-masked."));
5927
5995
  continue;
5928
5996
  }
5929
5997
  if (text.startsWith("/")) {
5930
- console.log(import_chalk34.default.dim(" Commands: /login /claim /showauth /exit"));
5998
+ console.log(import_chalk36.default.dim(" Commands: /login /claim /showauth /exit"));
5931
5999
  continue;
5932
6000
  }
5933
6001
  await replTurn(p, messages, text);
5934
6002
  saveTranscript(p, messages);
5935
6003
  }
5936
- console.log(import_chalk34.default.dim("\nBye."));
6004
+ console.log(import_chalk36.default.dim("\nBye."));
5937
6005
  }
5938
6006
  async function runApichat(opts) {
5939
6007
  setVerbose(opts.verbose !== false);
5940
- console.log(import_chalk34.default.bold("\napichat \u2014 turn any API into a chat\n"));
6008
+ console.log(import_chalk36.default.bold("\napichat \u2014 turn any API into a chat\n"));
5941
6009
  if (!opts.openapispec && !opts.target) {
5942
6010
  if (!process.stdin.isTTY) {
5943
6011
  fail4("No spec source. Pass --openapispec <file|url> or --target <url>.", GENERATOR_HINT);
@@ -5950,7 +6018,7 @@ async function runApichat(opts) {
5950
6018
  }
5951
6019
  const { spec: spec2, sourceUrl } = await loadSpec(opts);
5952
6020
  const target = resolveTarget(spec2, opts, sourceUrl);
5953
- console.log(` ${import_chalk34.default.dim("Target:")} ${import_chalk34.default.bold(target)}`);
6021
+ console.log(` ${import_chalk36.default.dim("Target:")} ${import_chalk36.default.bold(target)}`);
5954
6022
  const auth = await resolveTargetAuth(spec2, opts);
5955
6023
  if (auth && !process.stdin.isTTY && !opts.targetAuthEnv) {
5956
6024
  fail4(
@@ -5959,7 +6027,7 @@ async function runApichat(opts) {
5959
6027
  );
5960
6028
  }
5961
6029
  const p = await provision(spec2, target, opts);
5962
- console.log(` ${import_chalk34.default.dim("Proxy: ")} ${import_chalk34.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
6030
+ console.log(` ${import_chalk36.default.dim("Proxy: ")} ${import_chalk36.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
5963
6031
  upsertApichat({
5964
6032
  name: p.projectId,
5965
6033
  target,
@@ -5978,23 +6046,23 @@ async function runApichat(opts) {
5978
6046
  const secret = await captureTargetSecret(auth, opts);
5979
6047
  if (secret) await writeTargetAuth(p, auth, secret);
5980
6048
  } else {
5981
- console.log(import_chalk34.default.dim(" Target auth: none required."));
6049
+ console.log(import_chalk36.default.dim(" Target auth: none required."));
5982
6050
  }
5983
6051
  const specText = JSON.stringify(spec2);
5984
6052
  await uploadSpec(p, specText, opts);
5985
6053
  const mcpUrl = await publishMcp(p, spec2);
5986
6054
  console.log();
5987
- if (p.proxyUrl) console.log(` ${import_chalk34.default.green("\u2713")} proxy ${import_chalk34.default.bold(p.proxyUrl)}`);
5988
- if (mcpUrl) console.log(` ${import_chalk34.default.green("\u2713")} mcp ${import_chalk34.default.bold(mcpUrl)}`);
6055
+ if (p.proxyUrl) console.log(` ${import_chalk36.default.green("\u2713")} proxy ${import_chalk36.default.bold(p.proxyUrl)}`);
6056
+ if (mcpUrl) console.log(` ${import_chalk36.default.green("\u2713")} mcp ${import_chalk36.default.bold(mcpUrl)}`);
5989
6057
  if (p.anon) {
5990
- console.log(import_chalk34.default.dim("\n Anonymous workspace \u2014 /claim inside the chat (after /login) to keep it beyond 30 days."));
6058
+ console.log(import_chalk36.default.dim("\n Anonymous workspace \u2014 /claim inside the chat (after /login) to keep it beyond 30 days."));
5991
6059
  }
5992
6060
  await runRepl(p);
5993
6061
  }
5994
6062
 
5995
6063
  // src/commands/consumer.ts
5996
- var import_chalk35 = __toESM(require("chalk"));
5997
- var import_ora18 = __toESM(require("ora"));
6064
+ var import_chalk37 = __toESM(require("chalk"));
6065
+ var import_ora19 = __toESM(require("ora"));
5998
6066
  init_admin();
5999
6067
  var DEFAULT_SCOPE = "openid email profile offline_access";
6000
6068
  var APIKEYS_BASE = process.env.APIBLAZE_APIKEYS_BASE || "https://apikeys.apiblaze.com";
@@ -6014,7 +6082,7 @@ async function consumerFetch(creds, suffix, init) {
6014
6082
  function requireConsumer() {
6015
6083
  const c = loadConsumer();
6016
6084
  if (!c) {
6017
- console.error(import_chalk35.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
6085
+ console.error(import_chalk37.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
6018
6086
  process.exit(1);
6019
6087
  }
6020
6088
  return c;
@@ -6025,7 +6093,7 @@ async function runConsumerLogin(opts) {
6025
6093
  let clientId = opts.client;
6026
6094
  if (clientId) {
6027
6095
  if (!tenant2) {
6028
- console.error(import_chalk35.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
6096
+ console.error(import_chalk37.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
6029
6097
  process.exit(1);
6030
6098
  }
6031
6099
  } else {
@@ -6037,25 +6105,25 @@ async function runConsumerLogin(opts) {
6037
6105
  if (!picked) process.exit(1);
6038
6106
  tenant2 = picked;
6039
6107
  }
6040
- const s2 = (0, import_ora18.default)("Finding the login app...").start();
6108
+ const s2 = (0, import_ora19.default)("Finding the login app...").start();
6041
6109
  const clients = await admin({ method: "GET", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/app-clients`, summary: `List app clients for ${tenant2}` }).catch(() => []);
6042
6110
  s2.stop();
6043
6111
  const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
6044
6112
  const pick2 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
6045
6113
  if (!pick2) {
6046
- console.error(import_chalk35.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
6114
+ console.error(import_chalk37.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
6047
6115
  process.exit(1);
6048
6116
  }
6049
6117
  clientId = pick2.client_id ?? pick2.clientId;
6050
6118
  }
6051
6119
  const portalResource = `https://${tenant2}.portal.apiblaze.com/1.0.0`;
6052
- console.log(`${import_chalk35.default.cyan("\u2192")} Logging in to ${import_chalk35.default.bold(tenant2)} as a consumer...`);
6120
+ console.log(`${import_chalk37.default.cyan("\u2192")} Logging in to ${import_chalk37.default.bold(tenant2)} as a consumer...`);
6053
6121
  const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
6054
6122
  console.log(`
6055
- Open: ${import_chalk35.default.underline(verificationUri)}`);
6056
- console.log(` Code: ${import_chalk35.default.bold(userCode)}
6123
+ Open: ${import_chalk37.default.underline(verificationUri)}`);
6124
+ console.log(` Code: ${import_chalk37.default.bold(userCode)}
6057
6125
  `);
6058
- console.log(import_chalk35.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
6126
+ console.log(import_chalk37.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
6059
6127
  }, portalResource);
6060
6128
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
6061
6129
  const creds = {
@@ -6070,7 +6138,7 @@ async function runConsumerLogin(opts) {
6070
6138
  obtainedAt: Date.now()
6071
6139
  };
6072
6140
  saveConsumer(creds);
6073
- console.log(import_chalk35.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
6141
+ console.log(import_chalk37.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
6074
6142
  }
6075
6143
  async function runConsumerTokens(opts) {
6076
6144
  const creds = requireConsumer();
@@ -6083,29 +6151,29 @@ async function runConsumerTokens(opts) {
6083
6151
  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));
6084
6152
  return;
6085
6153
  }
6086
- console.log(`${import_chalk35.default.cyan("Consumer")} ${import_chalk35.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk35.default.bold(fresh.tenant)}
6154
+ console.log(`${import_chalk37.default.cyan("Consumer")} ${import_chalk37.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk37.default.bold(fresh.tenant)}
6087
6155
  `);
6088
- console.log(`${import_chalk35.default.bold("access_token")} ${import_chalk35.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
6156
+ console.log(`${import_chalk37.default.bold("access_token")} ${import_chalk37.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
6089
6157
  ${fresh.accessToken}
6090
6158
  `);
6091
- if (fresh.idToken) console.log(`${import_chalk35.default.bold("id_token")} ${import_chalk35.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
6159
+ if (fresh.idToken) console.log(`${import_chalk37.default.bold("id_token")} ${import_chalk37.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
6092
6160
  ${fresh.idToken}
6093
6161
  `);
6094
- if (fresh.refreshToken) console.log(`${import_chalk35.default.bold("refresh_token")}
6162
+ if (fresh.refreshToken) console.log(`${import_chalk37.default.bold("refresh_token")}
6095
6163
  ${fresh.refreshToken}
6096
6164
  `);
6097
- console.log(import_chalk35.default.dim("These are your own tokens \u2014 keep them secret."));
6165
+ console.log(import_chalk37.default.dim("These are your own tokens \u2014 keep them secret."));
6098
6166
  }
6099
6167
  async function runConsumerApikeys(opts) {
6100
6168
  const creds = requireConsumer();
6101
6169
  const { default: inquirer3 } = await import("inquirer");
6102
- const spinner = (0, import_ora18.default)("Loading your API keys...").start();
6170
+ const spinner = (0, import_ora19.default)("Loading your API keys...").start();
6103
6171
  const list = await consumerFetch(creds, "/apikeys");
6104
6172
  const revealed = await consumerFetch(list.creds, "/apikeys/reveal").catch(() => ({ status: 0, data: null, creds: list.creds }));
6105
6173
  spinner.stop();
6106
6174
  if (list.status >= 400) {
6107
- console.error(import_chalk35.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
6108
- if (list.status === 401) console.error(import_chalk35.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
6175
+ console.error(import_chalk37.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
6176
+ if (list.status === 401) console.error(import_chalk37.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
6109
6177
  process.exit(1);
6110
6178
  }
6111
6179
  const keys = list.data?.keys ?? [];
@@ -6113,16 +6181,16 @@ async function runConsumerApikeys(opts) {
6113
6181
  if (opts.json) {
6114
6182
  console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
6115
6183
  } else if (!keys.length) {
6116
- console.log(import_chalk35.default.yellow("No API keys yet."));
6184
+ console.log(import_chalk37.default.yellow("No API keys yet."));
6117
6185
  } else {
6118
6186
  for (const k of keys) {
6119
6187
  const clear = revealMap[k.environment]?.key;
6120
- const shown = clear ? import_chalk35.default.green(clear) : import_chalk35.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
6121
- const exp = k.expires_at ? import_chalk35.default.dim(`exp ${k.expires_at}`) : import_chalk35.default.dim("no expiry");
6122
- console.log(` ${import_chalk35.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk35.default.dim(k.description ?? "")}`);
6188
+ const shown = clear ? import_chalk37.default.green(clear) : import_chalk37.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
6189
+ const exp = k.expires_at ? import_chalk37.default.dim(`exp ${k.expires_at}`) : import_chalk37.default.dim("no expiry");
6190
+ console.log(` ${import_chalk37.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk37.default.dim(k.description ?? "")}`);
6123
6191
  }
6124
6192
  if (Object.keys(revealMap).length === 0 && keys.some((k) => !k.expires_at)) {
6125
- console.log(import_chalk35.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
6193
+ console.log(import_chalk37.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
6126
6194
  }
6127
6195
  }
6128
6196
  if (opts.json) return;
@@ -6136,7 +6204,7 @@ async function runConsumerApikeys(opts) {
6136
6204
  const body = { environment: answers.environment };
6137
6205
  if (answers.description) body.description = answers.description;
6138
6206
  if (answers.expiresDays) body.expires_in_seconds = Number(answers.expiresDays) * 86400;
6139
- const s2 = (0, import_ora18.default)("Creating key...").start();
6207
+ const s2 = (0, import_ora19.default)("Creating key...").start();
6140
6208
  const created = await consumerFetch(list.creds, "/apikeys", { method: "POST", body: JSON.stringify(body) });
6141
6209
  if (created.status >= 400) {
6142
6210
  s2.fail(`Create failed (${created.status}): ${created.data?.error ?? ""}`);
@@ -6144,13 +6212,13 @@ async function runConsumerApikeys(opts) {
6144
6212
  }
6145
6213
  s2.succeed("Key created.");
6146
6214
  const key = created.data?.key ?? created.data?.fullKey;
6147
- if (key) console.log(` ${import_chalk35.default.green(key)} ${import_chalk35.default.dim("(shown once \u2014 store it now)")}`);
6148
- else console.log(import_chalk35.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
6215
+ if (key) console.log(` ${import_chalk37.default.green(key)} ${import_chalk37.default.dim("(shown once \u2014 store it now)")}`);
6216
+ else console.log(import_chalk37.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
6149
6217
  }
6150
6218
 
6151
6219
  // src/commands/sidecar.ts
6152
- var import_chalk36 = __toESM(require("chalk"));
6153
- var import_ora19 = __toESM(require("ora"));
6220
+ var import_chalk38 = __toESM(require("chalk"));
6221
+ var import_ora20 = __toESM(require("ora"));
6154
6222
  var fs10 = __toESM(require("fs"));
6155
6223
  var path7 = __toESM(require("path"));
6156
6224
  init_admin();
@@ -6191,18 +6259,18 @@ function upsertEnvLocal(root, token) {
6191
6259
  }
6192
6260
  function installSidecarPackage(root) {
6193
6261
  if (fs10.existsSync(path7.join(root, "node_modules", "apiblaze", "package.json"))) {
6194
- console.log(` ${import_chalk36.default.green("\u2713")} apiblaze package already installed`);
6262
+ console.log(` ${import_chalk38.default.green("\u2713")} apiblaze package already installed`);
6195
6263
  return;
6196
6264
  }
6197
6265
  const has = (f) => fs10.existsSync(path7.join(root, f));
6198
6266
  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" };
6199
- const spinner = (0, import_ora19.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
6267
+ const spinner = (0, import_ora20.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
6200
6268
  try {
6201
6269
  const { execSync } = require("child_process");
6202
6270
  execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
6203
6271
  spinner.succeed("Installed apiblaze (the sidecar runtime).");
6204
6272
  } catch {
6205
- spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk36.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk36.default.cyan("npm run dev")}.`);
6273
+ spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk38.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk38.default.cyan("npm run dev")}.`);
6206
6274
  }
6207
6275
  }
6208
6276
  function readEnvKey(root) {
@@ -6341,7 +6409,7 @@ async function runAnonymousInit(root, router, opts) {
6341
6409
  const { sidecarInitAnonymous: sidecarInitAnonymous2 } = await Promise.resolve().then(() => (init_api(), api_exports));
6342
6410
  const { saveAnonCred: saveAnonCred2, clearAnonCred: clearAnonCred2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
6343
6411
  if (opts.newSession) clearAnonCred2();
6344
- const spinner = (0, import_ora19.default)("Setting up a sidecar (no login needed)...").start();
6412
+ const spinner = (0, import_ora20.default)("Setting up a sidecar (no login needed)...").start();
6345
6413
  let out;
6346
6414
  try {
6347
6415
  out = await sidecarInitAnonymous2();
@@ -6353,29 +6421,29 @@ async function runAnonymousInit(root, router, opts) {
6353
6421
  if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
6354
6422
  const envState = upsertEnvLocal(root, out.token);
6355
6423
  ensureGitignored(root);
6356
- console.log(` ${import_chalk36.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
6357
- console.log(` ${import_chalk36.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
6424
+ console.log(` ${import_chalk38.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
6425
+ console.log(` ${import_chalk38.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
6358
6426
  installSidecarPackage(root);
6359
6427
  let inspectorPath = null;
6360
6428
  if (!opts.noInspector) {
6361
6429
  inspectorPath = generateInspector(root, router);
6362
- if (inspectorPath) console.log(` ${import_chalk36.default.green("\u2713")} inspector at ${inspectorPath}`);
6430
+ if (inspectorPath) console.log(` ${import_chalk38.default.green("\u2713")} inspector at ${inspectorPath}`);
6363
6431
  }
6364
6432
  console.log("");
6365
- console.log(import_chalk36.default.bold("Done (no account needed). What happens next:"));
6366
- console.log(` 1. ${import_chalk36.default.cyan("npm run dev")} and use your app.`);
6433
+ console.log(import_chalk38.default.bold("Done (no account needed). What happens next:"));
6434
+ console.log(` 1. ${import_chalk38.default.cyan("npm run dev")} and use your app.`);
6367
6435
  console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
6368
- console.log(` ${import_chalk36.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
6436
+ console.log(` ${import_chalk38.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
6369
6437
  console.log("");
6370
- console.log(import_chalk36.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
6371
- console.log(` ${import_chalk36.default.cyan("apiblaze login")} then ${import_chalk36.default.cyan("apiblaze claim")} ${import_chalk36.default.dim("(no code needed here)")}`);
6372
- console.log(import_chalk36.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
6438
+ console.log(import_chalk38.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
6439
+ console.log(` ${import_chalk38.default.cyan("apiblaze login")} then ${import_chalk38.default.cyan("apiblaze claim")} ${import_chalk38.default.dim("(no code needed here)")}`);
6440
+ console.log(import_chalk38.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
6373
6441
  }
6374
6442
  async function runSidecar(opts) {
6375
6443
  const root = path7.resolve(opts.dir ?? process.cwd());
6376
6444
  const detected = detectNextProject(root);
6377
6445
  if (!detected.found) {
6378
- console.log(import_chalk36.default.yellow(`No Next.js project detected in ${root}.`));
6446
+ console.log(import_chalk38.default.yellow(`No Next.js project detected in ${root}.`));
6379
6447
  console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
6380
6448
  return;
6381
6449
  }
@@ -6386,10 +6454,10 @@ async function runSidecar(opts) {
6386
6454
  if (!loadCredentials()) {
6387
6455
  upsertEnvLocal(root, readEnvKey(root));
6388
6456
  ensureGitignored(root);
6389
- console.log(` ${import_chalk36.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
6390
- console.log(` ${import_chalk36.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
6457
+ console.log(` ${import_chalk38.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
6458
+ console.log(` ${import_chalk38.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
6391
6459
  installSidecarPackage(root);
6392
- console.log(import_chalk36.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
6460
+ console.log(import_chalk38.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
6393
6461
  return;
6394
6462
  }
6395
6463
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -6398,7 +6466,7 @@ async function runSidecar(opts) {
6398
6466
  const mustMint = !existingKey || opts.rotate || switchingTeam;
6399
6467
  let token = existingKey ?? "";
6400
6468
  if (mustMint) {
6401
- const spinner = (0, import_ora19.default)(existingKey ? "Re-establishing the sidecar (minting a fresh invoke key)..." : "Setting up the sidecar (tenant + non-expiring invoke key)...").start();
6469
+ const spinner = (0, import_ora20.default)(existingKey ? "Re-establishing the sidecar (minting a fresh invoke key)..." : "Setting up the sidecar (tenant + non-expiring invoke key)...").start();
6402
6470
  try {
6403
6471
  const out = await admin({
6404
6472
  method: "POST",
@@ -6412,39 +6480,39 @@ async function runSidecar(opts) {
6412
6480
  throw err;
6413
6481
  }
6414
6482
  } else {
6415
- console.log(import_chalk36.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
6483
+ console.log(import_chalk38.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
6416
6484
  }
6417
6485
  const envState = upsertEnvLocal(root, token);
6418
6486
  ensureGitignored(root);
6419
- console.log(` ${import_chalk36.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
6487
+ console.log(` ${import_chalk38.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
6420
6488
  const wireState = wireInstrumentation(root);
6421
- console.log(` ${import_chalk36.default.green("\u2713")} instrumentation.ts ${wireState}`);
6489
+ console.log(` ${import_chalk38.default.green("\u2713")} instrumentation.ts ${wireState}`);
6422
6490
  installSidecarPackage(root);
6423
6491
  let inspectorPath = null;
6424
6492
  if (!opts.noInspector) {
6425
6493
  inspectorPath = generateInspector(root, detected.router);
6426
- if (inspectorPath) console.log(` ${import_chalk36.default.green("\u2713")} inspector at ${inspectorPath}`);
6494
+ if (inspectorPath) console.log(` ${import_chalk38.default.green("\u2713")} inspector at ${inspectorPath}`);
6427
6495
  }
6428
6496
  console.log("");
6429
- console.log(import_chalk36.default.bold("Done. What happens next:"));
6430
- console.log(` 1. ${import_chalk36.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
6431
- console.log(` 2. The origins your app calls appear as ${import_chalk36.default.bold("candidates")} \u2014 list them: ${import_chalk36.default.cyan("apiblaze sidecar")}`);
6432
- console.log(` 3. Approve the ones to route: ${import_chalk36.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
6497
+ console.log(import_chalk38.default.bold("Done. What happens next:"));
6498
+ console.log(` 1. ${import_chalk38.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
6499
+ console.log(` 2. The origins your app calls appear as ${import_chalk38.default.bold("candidates")} \u2014 list them: ${import_chalk38.default.cyan("apiblaze sidecar")}`);
6500
+ console.log(` 3. Approve the ones to route: ${import_chalk38.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
6433
6501
  console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
6434
- if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk36.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path7.dirname(inspectorPath)} before shipping)`);
6435
- if (switchingTeam) console.log(import_chalk36.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
6502
+ if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk38.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path7.dirname(inspectorPath)} before shipping)`);
6503
+ if (switchingTeam) console.log(import_chalk38.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
6436
6504
  console.log("");
6437
- console.log(import_chalk36.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
6438
- console.log(import_chalk36.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
6439
- console.log(import_chalk36.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
6505
+ console.log(import_chalk38.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
6506
+ console.log(import_chalk38.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
6507
+ console.log(import_chalk38.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
6440
6508
  console.log("");
6441
- console.log(import_chalk36.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
6442
- console.log(import_chalk36.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
6509
+ console.log(import_chalk38.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
6510
+ console.log(import_chalk38.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
6443
6511
  }
6444
6512
 
6445
6513
  // src/commands/origins.ts
6446
- var import_chalk37 = __toESM(require("chalk"));
6447
- var import_ora20 = __toESM(require("ora"));
6514
+ var import_chalk39 = __toESM(require("chalk"));
6515
+ var import_ora21 = __toESM(require("ora"));
6448
6516
  init_admin();
6449
6517
  init_auth();
6450
6518
  init_anon_cred();
@@ -6453,7 +6521,7 @@ async function runOriginsList(opts) {
6453
6521
  if (!loadCredentials()) {
6454
6522
  const cred = loadAnonCred();
6455
6523
  if (!cred) {
6456
- console.log(import_chalk37.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
6524
+ console.log(import_chalk39.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
6457
6525
  return;
6458
6526
  }
6459
6527
  out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
@@ -6471,30 +6539,30 @@ async function runOriginsList(opts) {
6471
6539
  }
6472
6540
  const routed = out.routed ?? [];
6473
6541
  const candidates = out.candidates ?? [];
6474
- console.log(import_chalk37.default.bold(`
6542
+ console.log(import_chalk39.default.bold(`
6475
6543
  Routed through APIblaze (${routed.length})`));
6476
- if (!routed.length) console.log(import_chalk37.default.dim(" none yet"));
6477
- for (const r of routed) console.log(` ${import_chalk37.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk37.default.dim(`\u2192 ${r.project_id}`)}`);
6478
- console.log(import_chalk37.default.bold(`
6544
+ if (!routed.length) console.log(import_chalk39.default.dim(" none yet"));
6545
+ for (const r of routed) console.log(` ${import_chalk39.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk39.default.dim(`\u2192 ${r.project_id}`)}`);
6546
+ console.log(import_chalk39.default.bold(`
6479
6547
  Candidates \u2014 going direct, not yet approved (${candidates.length})`));
6480
- if (!candidates.length) console.log(import_chalk37.default.dim(" none \u2014 run your app to discover the origins it calls"));
6548
+ if (!candidates.length) console.log(import_chalk39.default.dim(" none \u2014 run your app to discover the origins it calls"));
6481
6549
  for (const c of candidates) {
6482
- console.log(` ${import_chalk37.default.yellow("\u25CB")} ${c.origin} ${import_chalk37.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
6550
+ console.log(` ${import_chalk39.default.yellow("\u25CB")} ${c.origin} ${import_chalk39.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
6483
6551
  }
6484
6552
  if (candidates.length) {
6485
- console.log(import_chalk37.default.dim(`
6553
+ console.log(import_chalk39.default.dim(`
6486
6554
  Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
6487
- console.log(import_chalk37.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
6555
+ console.log(import_chalk39.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
6488
6556
  }
6489
6557
  }
6490
6558
  async function runOriginsApprove(origin, opts) {
6491
6559
  if (!loadCredentials()) {
6492
6560
  const cred = loadAnonCred();
6493
6561
  if (!cred) {
6494
- console.error(import_chalk37.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
6562
+ console.error(import_chalk39.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
6495
6563
  process.exit(1);
6496
6564
  }
6497
- const spinner2 = (0, import_ora20.default)(`Approving ${origin} (anonymous)...`).start();
6565
+ const spinner2 = (0, import_ora21.default)(`Approving ${origin} (anonymous)...`).start();
6498
6566
  try {
6499
6567
  const out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/approve`, { method: "POST", body: JSON.stringify({ origin }) });
6500
6568
  spinner2.succeed(`Approved ${origin} \u2192 proxy ${out.project_id}. Routing within ~5 min.`);
@@ -6505,7 +6573,7 @@ async function runOriginsApprove(origin, opts) {
6505
6573
  return;
6506
6574
  }
6507
6575
  const { teamId } = await resolveTeam(opts.team);
6508
- const spinner = (0, import_ora20.default)(`Approving ${origin}...`).start();
6576
+ const spinner = (0, import_ora21.default)(`Approving ${origin}...`).start();
6509
6577
  try {
6510
6578
  const out = await admin({
6511
6579
  method: "POST",
@@ -6522,7 +6590,7 @@ async function runOriginsApprove(origin, opts) {
6522
6590
  }
6523
6591
  async function runOriginsDeny(origin, opts) {
6524
6592
  const { teamId } = await resolveTeam(opts.team);
6525
- const spinner = (0, import_ora20.default)(`Dismissing ${origin}...`).start();
6593
+ const spinner = (0, import_ora21.default)(`Dismissing ${origin}...`).start();
6526
6594
  try {
6527
6595
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/dismiss`, body: { origin }, summary: `Dismiss sidecar origin ${origin}` });
6528
6596
  spinner.succeed(`Dismissed ${origin}. It won't be suggested again.`);
@@ -6533,7 +6601,7 @@ async function runOriginsDeny(origin, opts) {
6533
6601
  }
6534
6602
  async function runOriginsRemove(origin, opts) {
6535
6603
  const { teamId } = await resolveTeam(opts.team);
6536
- const spinner = (0, import_ora20.default)(`Removing the proxy for ${origin}...`).start();
6604
+ const spinner = (0, import_ora21.default)(`Removing the proxy for ${origin}...`).start();
6537
6605
  try {
6538
6606
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/remove`, body: { origin }, summary: `Un-route sidecar origin ${origin}` });
6539
6607
  spinner.succeed(`Removed ${origin}. Your app will stop routing it (goes direct) within ~5 min.`);
@@ -6544,7 +6612,7 @@ async function runOriginsRemove(origin, opts) {
6544
6612
  }
6545
6613
 
6546
6614
  // src/commands/op.ts
6547
- var import_chalk38 = __toESM(require("chalk"));
6615
+ var import_chalk40 = __toESM(require("chalk"));
6548
6616
  init_auth();
6549
6617
  init_trace();
6550
6618
  init_types();
@@ -6577,82 +6645,82 @@ function printResidue(report, applied) {
6577
6645
  const up = report?.upstash ?? {};
6578
6646
  const fga = report?.fga ?? {};
6579
6647
  const ghosts = report?.ghosts ?? {};
6580
- console.log(import_chalk38.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
6581
- console.log(import_chalk38.default.bold("\n Upstash"));
6648
+ console.log(import_chalk40.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
6649
+ console.log(import_chalk40.default.bold("\n Upstash"));
6582
6650
  const orphans = up.orphans ?? [];
6583
- if (orphans.length === 0) console.log(import_chalk38.default.green(" no orphaned keys"));
6584
- for (const o of orphans) console.log(` ${import_chalk38.default.yellow(o.key)} ${import_chalk38.default.dim(`\u2014 ${o.reason}`)}`);
6585
- console.log(import_chalk38.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
6651
+ if (orphans.length === 0) console.log(import_chalk40.default.green(" no orphaned keys"));
6652
+ for (const o of orphans) console.log(` ${import_chalk40.default.yellow(o.key)} ${import_chalk40.default.dim(`\u2014 ${o.reason}`)}`);
6653
+ console.log(import_chalk40.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
6586
6654
  if (up.anon_wallet_detail) {
6587
6655
  const d = up.anon_wallet_detail;
6588
- console.log(import_chalk38.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)"}`));
6656
+ console.log(import_chalk40.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)"}`));
6589
6657
  }
6590
6658
  if (up.keyspace_census) {
6591
6659
  const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
6592
- console.log(import_chalk38.default.dim(` keyspace: ${census}`));
6660
+ console.log(import_chalk40.default.dim(` keyspace: ${census}`));
6593
6661
  }
6594
- if (up.unknown?.length) console.log(import_chalk38.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
6595
- if (applied) console.log(` ${import_chalk38.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
6596
- for (const e of up.errors ?? []) console.log(import_chalk38.default.red(` error: ${e}`));
6597
- console.log(import_chalk38.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
6662
+ if (up.unknown?.length) console.log(import_chalk40.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
6663
+ if (applied) console.log(` ${import_chalk40.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
6664
+ for (const e of up.errors ?? []) console.log(import_chalk40.default.red(` error: ${e}`));
6665
+ console.log(import_chalk40.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
6598
6666
  if (applied) {
6599
6667
  const swept = fga?.swept ?? [];
6600
- if (swept.length === 0) console.log(import_chalk38.default.green(" no orphaned stores"));
6668
+ if (swept.length === 0) console.log(import_chalk40.default.green(" no orphaned stores"));
6601
6669
  for (const s of swept) {
6602
6670
  console.log(
6603
- ` ${import_chalk38.default.yellow(s.store_id)} ${import_chalk38.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
6671
+ ` ${import_chalk40.default.yellow(s.store_id)} ${import_chalk40.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
6604
6672
  );
6605
6673
  }
6606
- if (fga?.remaining) console.log(import_chalk38.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
6674
+ if (fga?.remaining) console.log(import_chalk40.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
6607
6675
  const st = fga?.side_tables;
6608
- if (st) console.log(import_chalk38.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})` : ""}`));
6676
+ if (st) console.log(import_chalk40.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})` : ""}`));
6609
6677
  } else {
6610
6678
  const fgaOrphans = fga?.orphans ?? [];
6611
- if (fgaOrphans.length === 0) console.log(import_chalk38.default.green(" no orphaned stores"));
6679
+ if (fgaOrphans.length === 0) console.log(import_chalk40.default.green(" no orphaned stores"));
6612
6680
  for (const s of fgaOrphans) {
6613
6681
  const src = s.in_openfga ? "live in OpenFGA" : "Neon tuples only";
6614
- console.log(` ${import_chalk38.default.yellow(s.store_id)} ${import_chalk38.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
6682
+ console.log(` ${import_chalk40.default.yellow(s.store_id)} ${import_chalk40.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
6615
6683
  }
6616
- console.log(import_chalk38.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
6684
+ console.log(import_chalk40.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
6617
6685
  const st = fga?.side_tables;
6618
- if (st) console.log(import_chalk38.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`));
6686
+ if (st) console.log(import_chalk40.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`));
6619
6687
  }
6620
- for (const e of fga?.errors ?? []) console.log(import_chalk38.default.red(` error: ${e}`));
6621
- console.log(import_chalk38.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
6688
+ for (const e of fga?.errors ?? []) console.log(import_chalk40.default.red(` error: ${e}`));
6689
+ console.log(import_chalk40.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
6622
6690
  if (applied) {
6623
- if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk38.default.green(" no ghost tuples"));
6624
- else console.log(` ${import_chalk38.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk38.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
6691
+ if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk40.default.green(" no ghost tuples"));
6692
+ else console.log(` ${import_chalk40.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk40.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
6625
6693
  } else {
6626
6694
  const n = ghosts?.ghost_count ?? 0;
6627
- if (n === 0) console.log(import_chalk38.default.green(` no ghost tuples ${import_chalk38.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
6695
+ if (n === 0) console.log(import_chalk40.default.green(` no ghost tuples ${import_chalk40.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
6628
6696
  else {
6629
- console.log(import_chalk38.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
6697
+ console.log(import_chalk40.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
6630
6698
  for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
6631
- console.log(import_chalk38.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
6699
+ console.log(import_chalk40.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
6632
6700
  }
6633
- if (n > 20) console.log(import_chalk38.default.dim(` \u2026 and ${n - 20} more`));
6701
+ if (n > 20) console.log(import_chalk40.default.dim(` \u2026 and ${n - 20} more`));
6634
6702
  }
6635
6703
  }
6636
- for (const e of ghosts?.errors ?? []) console.log(import_chalk38.default.red(` error: ${e}`));
6704
+ for (const e of ghosts?.errors ?? []) console.log(import_chalk40.default.red(` error: ${e}`));
6637
6705
  console.log();
6638
6706
  }
6639
6707
  async function runOp(sub, opts = {}) {
6640
6708
  if (!loadCredentials()) {
6641
- console.log(import_chalk38.default.dim("Not logged in. Run `apiblaze login`."));
6709
+ console.log(import_chalk40.default.dim("Not logged in. Run `apiblaze login`."));
6642
6710
  return;
6643
6711
  }
6644
6712
  if (!isOperatorLogin()) {
6645
- console.log(import_chalk38.default.dim("`apiblaze op` is only available to platform operators."));
6713
+ console.log(import_chalk40.default.dim("`apiblaze op` is only available to platform operators."));
6646
6714
  return;
6647
6715
  }
6648
6716
  switch (sub) {
6649
6717
  case void 0:
6650
6718
  case "menu": {
6651
- console.log(import_chalk38.default.bold("\nOperator menu"));
6652
- console.log(` ${import_chalk38.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
6653
- console.log(` ${import_chalk38.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk38.default.dim("-y to skip")})`);
6654
- console.log(` ${import_chalk38.default.cyan("apiblaze op credits")} list credit wallets`);
6655
- console.log(import_chalk38.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
6719
+ console.log(import_chalk40.default.bold("\nOperator menu"));
6720
+ console.log(` ${import_chalk40.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
6721
+ console.log(` ${import_chalk40.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk40.default.dim("-y to skip")})`);
6722
+ console.log(` ${import_chalk40.default.cyan("apiblaze op credits")} list credit wallets`);
6723
+ console.log(import_chalk40.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
6656
6724
  `));
6657
6725
  return;
6658
6726
  }
@@ -6671,17 +6739,17 @@ async function runOp(sub, opts = {}) {
6671
6739
  const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
6672
6740
  printResidue(report, false);
6673
6741
  if (nUp + nFga + nGhost + nSide === 0) {
6674
- console.log(import_chalk38.default.green("Nothing to sweep."));
6742
+ console.log(import_chalk40.default.green("Nothing to sweep."));
6675
6743
  return;
6676
6744
  }
6677
6745
  if (!opts.yes) {
6678
6746
  const readline2 = await import("readline/promises");
6679
6747
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
6680
6748
  const answer = await rl.question(
6681
- import_chalk38.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: `)
6749
+ import_chalk40.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: `)
6682
6750
  );
6683
6751
  rl.close();
6684
- if (answer.trim() !== "sweep") return void console.log(import_chalk38.default.dim("Aborted."));
6752
+ if (answer.trim() !== "sweep") return void console.log(import_chalk40.default.dim("Aborted."));
6685
6753
  }
6686
6754
  const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
6687
6755
  if (opts.json) return void console.log(JSON.stringify(result, null, 2));
@@ -6692,15 +6760,15 @@ async function runOp(sub, opts = {}) {
6692
6760
  const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list credit wallets" });
6693
6761
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
6694
6762
  const accounts = data?.accounts ?? [];
6695
- if (accounts.length === 0) return void console.log(import_chalk38.default.dim("No credit wallets."));
6763
+ if (accounts.length === 0) return void console.log(import_chalk40.default.dim("No credit wallets."));
6696
6764
  for (const a of accounts) {
6697
6765
  const bal = typeof a.balance_cents === "number" ? `$${(a.balance_cents / 100).toFixed(2)}` : "?";
6698
- console.log(` ${import_chalk38.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk38.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk38.default.dim(" \u2014 anon") : ""}`);
6766
+ console.log(` ${import_chalk40.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk40.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk40.default.dim(" \u2014 anon") : ""}`);
6699
6767
  }
6700
6768
  return;
6701
6769
  }
6702
6770
  default:
6703
- console.log(import_chalk38.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
6771
+ console.log(import_chalk40.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
6704
6772
  }
6705
6773
  }
6706
6774
 
@@ -6743,6 +6811,7 @@ program.command("create").description("Create a new API proxy (no login needed \
6743
6811
  });
6744
6812
  var agent = program.command("agent").description("Chat with an assistant that builds and runs your APIs (billed per turn)").option("--team <id|name>", "Team to work in (defaults to your active team)").action(action((opts) => runAgent(opts)));
6745
6813
  agent.command("authz").description("Chat to design and turn on access rules for an API").argument("<project>", "Project name or id").argument("[apiVersion]", "API version (defaults to the project's)").action(action((project, apiVersion) => runAuthz(project, apiVersion)));
6814
+ program.command("rule").description("Author an object-level access rule in plain English, in one shot (billed per turn)").argument("<rule>", 'The rule in plain English, e.g. "users see only their own rows"').argument("<project>", "Project name or id").option("--enforce", "Turn enforcement on immediately (default: shadow-publish only)").option("--apiversion <version>", "API version (defaults to the project's)").action(action((rule, project, opts) => runRule(rule, project, opts)));
6746
6815
  agent.command("openapi").description("Chat to build your API spec from real traffic").argument("<project>", "Project name or id").argument("[apiVersion]", "API version (defaults to the project's)").action(action((project, apiVersion) => runOpenapi(project, apiVersion)));
6747
6816
  agent.command("mcp").description("Chat to build an MCP server for an API").argument("<project>", "Project name or id").argument("[apiVersion]", "API version (defaults to the project's)").option("--environment <env>", "Environment to publish (default: prod)").action(action((project, apiVersion, opts) => runMcp(project, apiVersion, opts)));
6748
6817
  program.command("apichat").description("Turn any API into a chat: point at an OpenAPI spec and start asking questions (no login needed)").option("--openapispec <file|url>", "OpenAPI/Swagger spec to build from (JSON or YAML; file path or URL)").option("--target <url>", "Upstream base URL (overrides servers[0].url; enables spec discovery when --openapispec is omitted)").option("--name <name>", "Proxy name (defaults to the target host)").option("--apiversion <version>", "API version to create (e.g. 1.0.0)").option("--environment <env>", "Environment to chat against (default: prod anonymous / dev logged-in)").option("--target-auth-env <ENV_VAR>", "Read the upstream credential from this env var (CI-safe; required when there is no TTY and the API needs auth)").option("--force", "Proceed even if the API uses oauth2/openIdConnect target auth (you configure target auth yourself later)").option("-y, --yes", "Skip confirmation prompts").option("--no-verbose", "Hide the per-turn proxy curl trace (shown by default for apichat)").action(action((opts) => runApichat(opts)));
@@ -6762,7 +6831,7 @@ program.command("dev").description("Put your localhost behind a public URL (dev
6762
6831
  try {
6763
6832
  const resolved = parseInt(port ?? opts.port, 10);
6764
6833
  if (Number.isNaN(resolved)) {
6765
- console.error(import_chalk39.default.red(`Invalid port: ${port ?? opts.port}`));
6834
+ console.error(import_chalk41.default.red(`Invalid port: ${port ?? opts.port}`));
6766
6835
  process.exit(1);
6767
6836
  }
6768
6837
  await runDev({ port: resolved, captureFile: opts.captureFile });
@@ -6852,7 +6921,7 @@ spec.command("set").description("Replace the stored OpenAPI spec from a local fi
6852
6921
  var HELP_GROUPS = [
6853
6922
  { title: "Chat", commands: ["apichat", "agent"] },
6854
6923
  { title: "Setup", commands: ["login", "create", "init", "sidecar", "dev", "claim", "team", "whoami", "logout"] },
6855
- { title: "Control plane commands", commands: ["config", "projects", "tenant", "group", "domain", "delete", "target", "throttle", "rename", "spec", "export"] },
6924
+ { title: "Control plane commands", commands: ["config", "projects", "tenant", "group", "rule", "domain", "delete", "target", "throttle", "rename", "spec", "export"] },
6856
6925
  { title: "Data plane commands", commands: [
6857
6926
  { parent: "consumer", sub: "login" },
6858
6927
  { parent: "consumer", sub: "apikeys" }
@@ -6871,7 +6940,7 @@ function groupedCommandHelp() {
6871
6940
  const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
6872
6941
  return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
6873
6942
  }).filter(Boolean).join("\n");
6874
- return `${import_chalk39.default.bold(g.title)}
6943
+ return `${import_chalk41.default.bold(g.title)}
6875
6944
  ${rows}`;
6876
6945
  }).join("\n\n");
6877
6946
  }
@@ -6905,14 +6974,14 @@ async function recoverStaleTeam() {
6905
6974
  const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
6906
6975
  const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
6907
6976
  if (!linked) {
6908
- console.error(import_chalk39.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
6977
+ console.error(import_chalk41.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
6909
6978
  return;
6910
6979
  }
6911
6980
  if (linked.teamId === creds.teamId) return;
6912
6981
  const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
6913
6982
  delete next.activeTenant;
6914
6983
  saveCredentials(next);
6915
- console.error(import_chalk39.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk39.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
6984
+ console.error(import_chalk41.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk41.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
6916
6985
  } catch {
6917
6986
  }
6918
6987
  }
@@ -6920,16 +6989,16 @@ async function printError(err) {
6920
6989
  if (err instanceof ApiError) {
6921
6990
  const data = err.body;
6922
6991
  const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
6923
- console.error(import_chalk39.default.red(`
6992
+ console.error(import_chalk41.default.red(`
6924
6993
  API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
6925
6994
  if (err.status === 403 || err.status === 404) {
6926
6995
  await recoverStaleTeam();
6927
6996
  }
6928
6997
  } else if (err instanceof Error) {
6929
- console.error(import_chalk39.default.red(`
6998
+ console.error(import_chalk41.default.red(`
6930
6999
  Error: ${err.message}`));
6931
7000
  } else {
6932
- console.error(import_chalk39.default.red("\nUnknown error"));
7001
+ console.error(import_chalk41.default.red("\nUnknown error"));
6933
7002
  }
6934
7003
  }
6935
7004
  program.parse(process.argv);