apiblaze 0.19.32 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1869 -581
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -714,7 +714,7 @@ async function createTenantRow(teamId) {
714
714
  const { name } = await inquirer3.prompt([{
715
715
  type: "input",
716
716
  name: "name",
717
- message: `Tenant name ${import_chalk30.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
717
+ message: `Tenant name ${import_chalk33.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
718
718
  validate: (s) => /^[a-z0-9]+$/.test(s.trim()) ? true : "lowercase letters and numbers only"
719
719
  }]);
720
720
  const slug = name.trim();
@@ -729,7 +729,7 @@ async function createTenantRow(teamId) {
729
729
  } catch (err) {
730
730
  const msg = err instanceof Error ? err.message : String(err);
731
731
  if (/taken|unique|exists|reserved|conflict/i.test(msg)) {
732
- console.log(import_chalk30.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
732
+ console.log(import_chalk33.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
733
733
  continue;
734
734
  }
735
735
  throw err;
@@ -746,11 +746,11 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
746
746
  pageSize: 10,
747
747
  choices: [
748
748
  ...PROVIDERS.map((p) => ({ name: p.label, value: p.id })),
749
- ...opts.allowSkip ? [new inquirer3.Separator(), { name: import_chalk30.default.dim("Skip for now \u2014 set up a login method later"), value: null }] : []
749
+ ...opts.allowSkip ? [new inquirer3.Separator(), { name: import_chalk33.default.dim("Skip for now \u2014 set up a login method later"), value: null }] : []
750
750
  ]
751
751
  }]);
752
752
  if (!provider) {
753
- console.log(import_chalk30.default.dim(" No login method yet \u2014 add one later under Login methods."));
753
+ console.log(import_chalk33.default.dim(" No login method yet \u2014 add one later under Login methods."));
754
754
  return false;
755
755
  }
756
756
  const opt = PROVIDERS.find((p) => p.id === provider);
@@ -781,7 +781,7 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
781
781
  if (a.callbacks.trim()) clientBody.authorizedCallbackUrls = a.callbacks.split(/\s*,\s*/).map((s) => s.trim()).filter(Boolean);
782
782
  if (a.scopes.trim() && opt.own) providerBody.scopes = a.scopes.split(/\s+/).filter(Boolean);
783
783
  }
784
- const spinner = (0, import_ora10.default)("Setting up login...").start();
784
+ const spinner = (0, import_ora12.default)("Setting up login...").start();
785
785
  try {
786
786
  const client = await admin({ method: "POST", path: `${base2}/app-clients`, body: clientBody, summary: `Create login for ${tenant2}` });
787
787
  const clientId = client?.clientId ?? client?.client_id;
@@ -796,27 +796,27 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
796
796
  async function createTenantInteractive(teamId) {
797
797
  const { default: inquirer3 } = await import("inquirer");
798
798
  const tenant2 = await createTenantRow(teamId);
799
- console.log(import_chalk30.default.green(` Tenant ${import_chalk30.default.bold(tenant2)} created.`));
799
+ console.log(import_chalk33.default.green(` Tenant ${import_chalk33.default.bold(tenant2)} created.`));
800
800
  const { users } = await inquirer3.prompt([{
801
801
  type: "confirm",
802
802
  name: "users",
803
803
  default: false,
804
- message: `Enable Users & groups? ${import_chalk30.default.dim(`(identity/key management at iam.apiblaze.com)`)}`
804
+ message: `Enable Users & groups? ${import_chalk33.default.dim(`(identity/key management at iam.apiblaze.com)`)}`
805
805
  }]);
806
806
  if (users) {
807
807
  await admin({ method: "PATCH", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/iam`, body: { enabled: true }, summary: "Enable Users & groups" }).catch(() => {
808
808
  });
809
- console.log(import_chalk30.default.green(" Users & groups enabled."));
809
+ console.log(import_chalk33.default.green(" Users & groups enabled."));
810
810
  }
811
811
  await addApiblazeHostedLogin(teamId, tenant2, { allowSkip: true });
812
812
  return tenant2;
813
813
  }
814
- var import_chalk30, import_ora10, PROVIDERS, DEFAULT_SCOPES;
814
+ var import_chalk33, import_ora12, PROVIDERS, DEFAULT_SCOPES;
815
815
  var init_tenant_create = __esm({
816
816
  "src/lib/tenant-create.ts"() {
817
817
  "use strict";
818
- import_chalk30 = __toESM(require("chalk"));
819
- import_ora10 = __toESM(require("ora"));
818
+ import_chalk33 = __toESM(require("chalk"));
819
+ import_ora12 = __toESM(require("ora"));
820
820
  init_admin();
821
821
  PROVIDERS = [
822
822
  { id: "apiblaze", label: "APIblaze (via GitHub) \u2014 zero setup, recommended", own: false },
@@ -854,10 +854,10 @@ async function fetchPage2(teamId, q) {
854
854
  }
855
855
  function label(t, defaultTenant, active) {
856
856
  const tags = [
857
- t.tenant_name === active ? import_chalk31.default.cyan("active scope") : "",
858
- t.tenant_name === defaultTenant ? import_chalk31.default.dim("team default") : ""
857
+ t.tenant_name === active ? import_chalk34.default.cyan("active scope") : "",
858
+ t.tenant_name === defaultTenant ? import_chalk34.default.dim("team default") : ""
859
859
  ].filter(Boolean).join(", ");
860
- const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk31.default.dim(` ${t.display_name}`) : "";
860
+ const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk34.default.dim(` ${t.display_name}`) : "";
861
861
  return `${t.tenant_name}${disp}${tags ? ` (${tags})` : ""}`;
862
862
  }
863
863
  async function pickTenant(teamId, opts = {}) {
@@ -865,14 +865,14 @@ async function pickTenant(teamId, opts = {}) {
865
865
  const active = loadCredentials()?.activeTenant;
866
866
  let q = opts.initialQuery ?? "";
867
867
  for (; ; ) {
868
- const spinner = (0, import_ora11.default)(q ? `Searching tenants for "${q}"...` : "Loading tenants...").start();
868
+ const spinner = (0, import_ora13.default)(q ? `Searching tenants for "${q}"...` : "Loading tenants...").start();
869
869
  const page = await fetchPage2(teamId, q).finally(() => spinner.stop());
870
870
  if (!page.total && !q) {
871
871
  if (opts.allowCreate) {
872
872
  const { make } = await inquirer3.prompt([{ type: "confirm", name: "make", message: "No tenants yet \u2014 create one?", default: true }]);
873
873
  if (make) return await createTenantInline(teamId);
874
874
  }
875
- console.error(import_chalk31.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
875
+ console.error(import_chalk34.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
876
876
  return null;
877
877
  }
878
878
  const truncated = page.total > page.rows.length;
@@ -881,7 +881,7 @@ async function pickTenant(teamId, opts = {}) {
881
881
  value: t.tenant_name
882
882
  }));
883
883
  if (truncated || q) {
884
- choices.push(new inquirer3.Separator(import_chalk31.default.dim(
884
+ choices.push(new inquirer3.Separator(import_chalk34.default.dim(
885
885
  truncated ? `showing ${page.rows.length} of ${page.total}${q ? ` matching "${q}"` : ""} \u2014 search to narrow` : `matches for "${q}"`
886
886
  )));
887
887
  choices.push({ name: `\u{1F50D} Search${q ? " again" : ""}\u2026`, value: "\0search" });
@@ -915,12 +915,12 @@ async function createTenantInline(teamId) {
915
915
  const { createTenantInteractive: createTenantInteractive2 } = await Promise.resolve().then(() => (init_tenant_create(), tenant_create_exports));
916
916
  return createTenantInteractive2(teamId);
917
917
  }
918
- var import_chalk31, import_ora11, PAGE;
918
+ var import_chalk34, import_ora13, PAGE;
919
919
  var init_tenant_pick = __esm({
920
920
  "src/lib/tenant-pick.ts"() {
921
921
  "use strict";
922
- import_chalk31 = __toESM(require("chalk"));
923
- import_ora11 = __toESM(require("ora"));
922
+ import_chalk34 = __toESM(require("chalk"));
923
+ import_ora13 = __toESM(require("ora"));
924
924
  init_admin();
925
925
  init_auth();
926
926
  PAGE = 15;
@@ -929,10 +929,10 @@ var init_tenant_pick = __esm({
929
929
 
930
930
  // src/index.ts
931
931
  var import_commander = require("commander");
932
- var import_chalk48 = __toESM(require("chalk"));
932
+ var import_chalk51 = __toESM(require("chalk"));
933
933
 
934
934
  // package.json
935
- var version = "0.19.32";
935
+ var version = "0.20.1";
936
936
 
937
937
  // src/index.ts
938
938
  init_types();
@@ -3225,10 +3225,10 @@ async function runDelete(project, version2, opts) {
3225
3225
  }
3226
3226
  if (!opts.yes) {
3227
3227
  const { default: inquirer3 } = await import("inquirer");
3228
- const { confirm } = await inquirer3.prompt([
3228
+ const { confirm: confirm2 } = await inquirer3.prompt([
3229
3229
  { type: "confirm", name: "confirm", message: `Permanently delete ${proj2.projectName} v${proj2.apiVersion}? This cannot be undone.`, default: false }
3230
3230
  ]);
3231
- if (!confirm) {
3231
+ if (!confirm2) {
3232
3232
  console.log(import_chalk23.default.dim("Aborted."));
3233
3233
  return;
3234
3234
  }
@@ -3307,34 +3307,1313 @@ async function runExport(projectArg, versionArg, opts) {
3307
3307
  if (target === "kong") console.log(import_chalk24.default.dim("Kong: unzip, then `cd kong && docker compose up` (see kong/README.md)."));
3308
3308
  }
3309
3309
 
3310
- // src/commands/logs.ts
3310
+ // src/commands/recipe-search.ts
3311
+ var import_chalk25 = __toESM(require("chalk"));
3312
+ var import_ora8 = __toESM(require("ora"));
3313
+ init_caller();
3314
+
3315
+ // src/lib/recipes.ts
3316
+ init_types();
3317
+ init_caller();
3318
+ var RECIPES_BASE = process.env.APIBLAZE_RECIPES_BASE || "https://recipes.apiblaze.com";
3319
+ function parseRecipeRef(raw) {
3320
+ const m = /^@([a-z0-9]+)\/([a-z0-9]+)(?:@(\d+))?$/.exec((raw || "").trim().toLowerCase());
3321
+ if (!m || m[1].length < 3 || m[2].length < 3) {
3322
+ throw new Error(
3323
+ `"${raw}" is not a recipe name. A recipe looks like @julien/gmail (or @julien/gmail@2 to pin a revision) \u2014 lowercase letters and digits only, at least 3 of each.`
3324
+ );
3325
+ }
3326
+ return {
3327
+ handle: m[1],
3328
+ slug: m[2],
3329
+ revision: m[3] ? Number(m[3]) : void 0,
3330
+ name: `@${m[1]}/${m[2]}`
3331
+ };
3332
+ }
3333
+ function resolveRecipeName(raw, githubHandle, proxyName) {
3334
+ const given = (raw ?? "").trim();
3335
+ if (given.startsWith("@")) {
3336
+ return { ref: parseRecipeRef(given), derivedHandle: false, normalizedFrom: null };
3337
+ }
3338
+ const slug = normalizeName2(given || proxyName);
3339
+ const handleRaw = (githubHandle ?? "").trim();
3340
+ const handle = normalizeName2(handleRaw);
3341
+ if (!handle || handle.length < 3) {
3342
+ throw new Error(
3343
+ "Could not work out a handle for you, so pass one: --as @yourhandle/name\n (a handle is lowercase letters and digits, at least 3.)"
3344
+ );
3345
+ }
3346
+ if (slug.length < 3) {
3347
+ throw new Error(`"${given || proxyName}" is too short for a recipe name \u2014 at least 3 letters or digits.`);
3348
+ }
3349
+ return {
3350
+ ref: parseRecipeRef(`@${handle}/${slug}`),
3351
+ derivedHandle: true,
3352
+ // GitHub allows hyphens; apiblaze names do not. Say so rather than silently
3353
+ // publishing under a name they did not type.
3354
+ normalizedFrom: handleRaw && handleRaw.toLowerCase() !== handle ? handleRaw : null
3355
+ };
3356
+ }
3357
+ function normalizeName2(raw) {
3358
+ return (raw || "").toLowerCase().replace(/[^a-z0-9]/g, "");
3359
+ }
3360
+ async function publicFetch(path8) {
3361
+ const res = await fetch(`${RECIPES_BASE}/api/recipes${path8}`, {
3362
+ headers: { accept: "application/json" }
3363
+ }).catch((err) => {
3364
+ throw new Error(`Could not reach the recipe registry at ${RECIPES_BASE} \u2014 ${err.message}`);
3365
+ });
3366
+ let data = null;
3367
+ let json = false;
3368
+ try {
3369
+ data = await res.json();
3370
+ json = true;
3371
+ } catch {
3372
+ }
3373
+ return { status: res.status, data, json };
3374
+ }
3375
+ function registryDown(status) {
3376
+ return new Error(
3377
+ `The recipe registry at ${RECIPES_BASE}/api/recipes did not answer with JSON (HTTP ${status}).
3378
+ Set APIBLAZE_RECIPES_BASE if you are pointing at a different deployment.`
3379
+ );
3380
+ }
3381
+ async function searchRecipes(query, limit) {
3382
+ const q = `?q=${encodeURIComponent(query ?? "")}${limit ? `&limit=${limit}` : ""}`;
3383
+ const { status, data, json } = await publicFetch(`/search${q}`);
3384
+ if (!json) throw registryDown(status);
3385
+ if (status >= 400) throw new ApiError(status, data?.error ?? "Search failed.");
3386
+ return data?.recipes ?? [];
3387
+ }
3388
+ async function getRecipeHead(ref) {
3389
+ const { status, data, json } = await publicFetch(`/${ref.handle}/${ref.slug}`);
3390
+ if (!json) throw registryDown(status);
3391
+ if (status === 404) return null;
3392
+ if (status >= 400) throw new ApiError(status, data?.error ?? "Lookup failed.");
3393
+ return data;
3394
+ }
3395
+ async function fetchRecipeFile(ref, caller) {
3396
+ const head = ref.revision !== void 0 ? null : await getRecipeHead(ref);
3397
+ const revision = ref.revision ?? head?.revision;
3398
+ if (revision !== void 0) {
3399
+ const { status, data, json } = await publicFetch(
3400
+ `/${ref.handle}/${ref.slug}/${revision}`
3401
+ );
3402
+ if (!json) throw registryDown(status);
3403
+ if (status === 410) {
3404
+ throw new Error(`${ref.name}@${revision} was withdrawn by its publisher. Try a different revision.`);
3405
+ }
3406
+ if (status < 400 && data) return data;
3407
+ }
3408
+ if (!caller) {
3409
+ throw new Error(
3410
+ `${ref.name} does not exist, or it is private.
3411
+ Private recipes are visible only to the publisher's team \u2014 run \`apiblaze login\` if you are on it.`
3412
+ );
3413
+ }
3414
+ const path8 = revision !== void 0 ? `/recipes/${ref.handle}/${ref.slug}/${revision}` : `/recipes/${ref.handle}/${ref.slug}/file`;
3415
+ try {
3416
+ return await producer(caller, {
3417
+ method: "GET",
3418
+ path: path8,
3419
+ summary: `Read private recipe ${ref.name}${revision !== void 0 ? `@${revision}` : ""}`
3420
+ });
3421
+ } catch (err) {
3422
+ const status = err instanceof ApiError ? err.status : 0;
3423
+ if (status === 404 || status === 400) {
3424
+ throw new Error(
3425
+ `${ref.name} does not exist, or it is private and your team does not own it.
3426
+ (admin-api exposes no authorized read for a private recipe file yet \u2014 only GET /recipes/public/* is registered, so private install cannot resolve.)`
3427
+ );
3428
+ }
3429
+ throw err;
3430
+ }
3431
+ }
3432
+ function installUrls(ctx) {
3433
+ return {
3434
+ proxy_url: `https://${ctx.project}.abz.run`,
3435
+ redirect_uri: `https://${ctx.tenant}.auth.apiblaze.com/callback`,
3436
+ mcp_url: `https://${ctx.project}-${ctx.tenant}.mcp.apiblaze.com`,
3437
+ portal_url: `https://${ctx.tenant}.portal.apiblaze.com`
3438
+ };
3439
+ }
3440
+ function fillContext(text, ctx) {
3441
+ const u = installUrls(ctx);
3442
+ const table = {
3443
+ redirect_uri: u.redirect_uri,
3444
+ proxy_url: u.proxy_url,
3445
+ mcp_url: u.mcp_url,
3446
+ portal_url: u.portal_url,
3447
+ project: ctx.project,
3448
+ tenant: ctx.tenant
3449
+ };
3450
+ return (text || "").replace(/\{(redirect_uri|proxy_url|mcp_url|portal_url|project|tenant)\}/g, (m, k) => table[k] ?? m);
3451
+ }
3452
+ function fillAnswers(value, answers) {
3453
+ if (typeof value === "string") {
3454
+ return value.replace(/\{\{([A-Za-z0-9_]+)\}\}/g, (m, id) => Object.prototype.hasOwnProperty.call(answers, id) ? answers[id] : m);
3455
+ }
3456
+ if (Array.isArray(value)) return value.map((v) => fillAnswers(v, answers));
3457
+ if (value && typeof value === "object") {
3458
+ const out = {};
3459
+ for (const [k, v] of Object.entries(value)) out[k] = fillAnswers(v, answers);
3460
+ return out;
3461
+ }
3462
+ return value;
3463
+ }
3464
+ function countRoutes(spec2) {
3465
+ const paths = spec2?.paths;
3466
+ if (!paths || typeof paths !== "object") return 0;
3467
+ const VERBS = ["get", "post", "put", "patch", "delete", "head", "options"];
3468
+ let n = 0;
3469
+ for (const item of Object.values(paths)) {
3470
+ if (!item || typeof item !== "object") continue;
3471
+ for (const k of Object.keys(item)) if (VERBS.includes(k.toLowerCase())) n++;
3472
+ }
3473
+ return n;
3474
+ }
3475
+ function firstUpstream(recipe) {
3476
+ const envs = recipe.settings?.environments ?? {};
3477
+ for (const e of Object.values(envs)) {
3478
+ const t = typeof e?.target === "string" ? e.target.trim() : "";
3479
+ if (t) return t;
3480
+ }
3481
+ return null;
3482
+ }
3483
+ function upstreamHosts(recipe) {
3484
+ const envs = recipe.settings?.environments ?? {};
3485
+ const out = [];
3486
+ for (const e of Object.values(envs)) {
3487
+ try {
3488
+ const h = new URL(String(e?.target ?? "")).host;
3489
+ if (h && !out.includes(h)) out.push(h);
3490
+ } catch {
3491
+ }
3492
+ }
3493
+ return out;
3494
+ }
3495
+
3496
+ // src/commands/recipe-search.ts
3497
+ async function runRecipeSearch(query, opts) {
3498
+ const spinner = !opts.json ? (0, import_ora8.default)("Searching recipes...").start() : null;
3499
+ let hits;
3500
+ try {
3501
+ hits = await searchRecipes(query ?? "", opts.limit ? Number(opts.limit) : void 0);
3502
+ spinner?.stop();
3503
+ } catch (err) {
3504
+ spinner?.fail("Search failed.");
3505
+ throw err;
3506
+ }
3507
+ if (opts.json) {
3508
+ console.log(JSON.stringify(hits));
3509
+ return;
3510
+ }
3511
+ if (!hits.length) {
3512
+ console.log(import_chalk25.default.yellow(query ? `No public recipes match "${query}".` : "No public recipes yet."));
3513
+ console.log(import_chalk25.default.dim(" Publish one with: apiblaze publish <proxy> --as @yourhandle/name"));
3514
+ return;
3515
+ }
3516
+ console.log();
3517
+ for (const h of hits) {
3518
+ const pin = h.latest_revision ? import_chalk25.default.dim(`@${h.latest_revision}`) : "";
3519
+ const installs = h.install_count ? import_chalk25.default.dim(` ${h.install_count} install${h.install_count === 1 ? "" : "s"}`) : "";
3520
+ console.log(` ${import_chalk25.default.bold(h.name)}${pin}${h.display_name ? import_chalk25.default.dim(` \u2014 ${h.display_name}`) : ""}${installs}`);
3521
+ if (h.summary) console.log(` ${import_chalk25.default.dim(h.summary)}`);
3522
+ }
3523
+ console.log();
3524
+ console.log(import_chalk25.default.dim(` Install one with: ${import_chalk25.default.cyan(`npx apiblaze install ${hits[0].name}`)}`));
3525
+ console.log(import_chalk25.default.dim(` Read one first: ${import_chalk25.default.cyan(`npx apiblaze show ${hits[0].name}`)}`));
3526
+ console.log();
3527
+ }
3528
+ async function runRecipeShow(nameArg, opts) {
3529
+ const ref = parseRecipeRef(nameArg);
3530
+ const wantsSection = !!(opts.transforms || opts.settings || opts.auth || opts.openapi);
3531
+ const caller = resolveCaller();
3532
+ const head = ref.revision === void 0 ? await getRecipeHead(ref).catch(() => null) : null;
3533
+ const spinner = !opts.json ? (0, import_ora8.default)(`Reading ${ref.name}...`).start() : null;
3534
+ let recipe;
3535
+ try {
3536
+ recipe = await fetchRecipeFile(ref, caller);
3537
+ spinner?.stop();
3538
+ } catch (err) {
3539
+ spinner?.stop();
3540
+ throw err;
3541
+ }
3542
+ if (opts.json) {
3543
+ if (opts.transforms) console.log(JSON.stringify(recipe.transformations));
3544
+ else if (opts.settings) console.log(JSON.stringify(recipe.settings));
3545
+ else if (opts.auth) console.log(JSON.stringify(recipe.auth));
3546
+ else if (opts.openapi) console.log(JSON.stringify(recipe.openapi));
3547
+ else console.log(JSON.stringify(recipe));
3548
+ return;
3549
+ }
3550
+ console.log();
3551
+ console.log(`${import_chalk25.default.bold(`${recipe.name}@${recipe.revision}`)}${import_chalk25.default.dim(` \u2014 by ${ref.handle}`)}`);
3552
+ if (recipe.display_name) console.log(` ${import_chalk25.default.bold(recipe.display_name)}`);
3553
+ if (recipe.summary) console.log(` ${recipe.summary}`);
3554
+ const meta = [
3555
+ head?.install_count !== void 0 ? `${head.install_count} install${head.install_count === 1 ? "" : "s"}` : null,
3556
+ recipe.license ? `licence ${recipe.license}` : null,
3557
+ recipe.published_at ? `published ${recipe.published_at.slice(0, 10)}` : null,
3558
+ `api version ${recipe.api_version}`
3559
+ ].filter(Boolean).join(" \xB7 ");
3560
+ console.log(import_chalk25.default.dim(` ${meta}`));
3561
+ console.log();
3562
+ if (wantsSection) {
3563
+ if (opts.settings) printSection("settings", recipe.settings);
3564
+ if (opts.auth) printAuth(recipe);
3565
+ if (opts.transforms) printTransforms(recipe);
3566
+ if (opts.openapi) console.log(JSON.stringify(recipe.openapi, null, 2));
3567
+ return;
3568
+ }
3569
+ const hosts = upstreamHosts(recipe);
3570
+ const routes = countRoutes(recipe.openapi);
3571
+ const rules = recipe.transformations?.rules?.length ?? 0;
3572
+ const tables = recipe.transformations?.mapping_tables?.length ?? 0;
3573
+ const keyTypes = recipe.auth?.key_types?.length ?? 0;
3574
+ if (hosts.length) console.log(` ${import_chalk25.default.dim("sends requests to")} ${hosts.join(", ")}`);
3575
+ console.log(` ${import_chalk25.default.dim("creates ")} ${describeCreates(keyTypes, routes, !!recipe.settings.mcp_enabled)}`);
3576
+ console.log(` ${import_chalk25.default.dim("asks you for ")} ${recipe.questions.length} value${recipe.questions.length === 1 ? "" : "s"}`);
3577
+ if (rules || tables) {
3578
+ console.log(` ${import_chalk25.default.dim("transforms ")} ${rules} rule${rules === 1 ? "" : "s"}${tables ? `, ${tables} mapping table${tables === 1 ? "" : "s"}` : ""}`);
3579
+ }
3580
+ if (recipe.settings.publish_openapi === true) {
3581
+ console.log(` ${import_chalk25.default.dim("makes public ")} this API's spec`);
3582
+ }
3583
+ if (recipe.questions.length) {
3584
+ console.log();
3585
+ console.log(import_chalk25.default.bold(" It will ask you for"));
3586
+ for (const q of recipe.questions) {
3587
+ console.log(` ${q.prompt}${q.secret ? import_chalk25.default.dim(" (hidden while you type)") : ""}`);
3588
+ if (q.example) console.log(import_chalk25.default.dim(` e.g. ${q.example}`));
3589
+ }
3590
+ }
3591
+ if (recipe.requires_confirmation?.length) {
3592
+ console.log();
3593
+ console.log(import_chalk25.default.yellow(" Needs your explicit consent at install time"));
3594
+ for (const c of recipe.requires_confirmation) {
3595
+ console.log(` ${import_chalk25.default.bold(c.kind)} ${c.value}`);
3596
+ console.log(import_chalk25.default.dim(` ${c.why}`));
3597
+ }
3598
+ }
3599
+ console.log();
3600
+ console.log(import_chalk25.default.dim(` Install: ${import_chalk25.default.cyan(`npx apiblaze install ${recipe.name}`)}`));
3601
+ console.log(import_chalk25.default.dim(" Sections: --settings --auth --transforms --openapi"));
3602
+ console.log();
3603
+ }
3604
+ function describeCreates(keyTypes, routes, mcp) {
3605
+ const parts = ["1 proxy", "1 tenant"];
3606
+ if (keyTypes) parts.push(`${keyTypes} key type${keyTypes === 1 ? "" : "s"}`);
3607
+ if (routes) parts.push(mcp ? `${routes} MCP tools` : `${routes} route${routes === 1 ? "" : "s"}`);
3608
+ return parts.join(", ");
3609
+ }
3610
+ function printSection(title, value) {
3611
+ console.log(import_chalk25.default.bold(` ${title}`));
3612
+ console.log(indent(JSON.stringify(value ?? null, null, 2), " "));
3613
+ console.log();
3614
+ }
3615
+ function printAuth(recipe) {
3616
+ const a = recipe.auth ?? { app_client: null, provider: null, key_types: [] };
3617
+ console.log(import_chalk25.default.bold(" auth"));
3618
+ if (a.provider) {
3619
+ console.log(` ${import_chalk25.default.dim("provider ")} ${a.provider.type ?? "(unknown)"}`);
3620
+ if (a.provider.scopes) console.log(` ${import_chalk25.default.dim("scopes ")} ${a.provider.scopes}`);
3621
+ if (a.provider.target_server_token) console.log(` ${import_chalk25.default.dim("sends to API")} ${a.provider.target_server_token}`);
3622
+ console.log(import_chalk25.default.dim(" (no credentials travel in a recipe \u2014 install asks you for your own)"));
3623
+ } else {
3624
+ console.log(import_chalk25.default.dim(" no login provider \u2014 consumers call it with an API key"));
3625
+ }
3626
+ if (a.app_client) {
3627
+ console.log(` ${import_chalk25.default.dim("login app ")} ${a.app_client.name ?? "(unnamed)"}`);
3628
+ }
3629
+ if (a.key_types?.length) {
3630
+ console.log(` ${import_chalk25.default.dim("key types ")} ${a.key_types.map((k) => String(k.name)).join(", ")}`);
3631
+ }
3632
+ console.log();
3633
+ }
3634
+ function printTransforms(recipe) {
3635
+ const rules = recipe.transformations?.rules ?? [];
3636
+ const tables = recipe.transformations?.mapping_tables ?? [];
3637
+ console.log(import_chalk25.default.bold(` transforms (${rules.length})`));
3638
+ for (const r of rules) {
3639
+ const off = r.enabled === false ? import_chalk25.default.dim(" (disabled)") : "";
3640
+ console.log(` ${import_chalk25.default.bold(String(r.name ?? "(unnamed)"))} ${import_chalk25.default.dim(String(r.phase ?? "request"))}${off}`);
3641
+ console.log(indent(JSON.stringify(r.action ?? null, null, 2), " "));
3642
+ if (r.condition) console.log(indent(`when ${JSON.stringify(r.condition)}`, " "));
3643
+ }
3644
+ if (tables.length) {
3645
+ console.log();
3646
+ console.log(import_chalk25.default.bold(` mapping tables (${tables.length})`));
3647
+ for (const t of tables) {
3648
+ const entries2 = Array.isArray(t.entries) ? t.entries.length : 0;
3649
+ console.log(` ${import_chalk25.default.bold(String(t.name ?? "(unnamed)"))} ${import_chalk25.default.dim(`${entries2} entr${entries2 === 1 ? "y" : "ies"}`)}`);
3650
+ }
3651
+ }
3652
+ console.log();
3653
+ }
3654
+ function indent(text, pad) {
3655
+ return text.split("\n").map((l) => `${pad}${l}`).join("\n");
3656
+ }
3657
+
3658
+ // src/commands/recipe-install.ts
3311
3659
  var import_chalk26 = __toESM(require("chalk"));
3660
+ init_types();
3661
+ init_caller();
3662
+ init_api();
3663
+ var APIKEYS_BASE = process.env.APIBLAZE_APIKEYS_BASE || "https://apikeys.apiblaze.com";
3664
+ async function runRecipeInstall(nameArg, opts) {
3665
+ const ref = parseRecipeRef(nameArg);
3666
+ const assumeYes = !!opts.yes;
3667
+ const interactive = !!process.stdin.isTTY && !assumeYes;
3668
+ const caller = requireCallerForInstall();
3669
+ const recipe = await fetchRecipeFile(ref, caller);
3670
+ const pinned = `${recipe.name}@${recipe.revision}`;
3671
+ const picked = await chooseTeam(caller, opts.team, interactive);
3672
+ const teamId = picked.teamId;
3673
+ const chosenTeamId = picked.chosen ? picked.teamId : void 0;
3674
+ const teamName = picked.teamName;
3675
+ console.log();
3676
+ console.log(`${import_chalk26.default.bold(pinned)}${import_chalk26.default.dim(` \u2014 by ${ref.handle}`)}`);
3677
+ if (recipe.summary) console.log(` ${recipe.summary}`);
3678
+ console.log();
3679
+ let project;
3680
+ let apiVersion;
3681
+ let tenant2;
3682
+ let reinstall = false;
3683
+ if (opts.into) {
3684
+ reinstall = true;
3685
+ const target = normalizeName2(opts.into);
3686
+ const proj2 = await resolveProjectVia(caller, teamId, target, opts.apiversion);
3687
+ project = proj2.projectId;
3688
+ apiVersion = proj2.apiVersion;
3689
+ tenant2 = await resolveReinstallTenant(caller, project, apiVersion);
3690
+ await confirmReinstall(recipe, project, tenant2, interactive);
3691
+ } else {
3692
+ project = await chooseProxyName(ref.slug, opts.as, teamId, interactive);
3693
+ apiVersion = recipe.api_version || "1.0.0";
3694
+ tenant2 = `${project}users`;
3695
+ await assertTenantFree(tenant2, teamId);
3696
+ printSummary(recipe, project, tenant2);
3697
+ if (!assumeYes && !await confirmYesNo(" continue?", interactive)) {
3698
+ console.log(import_chalk26.default.yellow(" Cancelled \u2014 nothing was created."));
3699
+ return;
3700
+ }
3701
+ }
3702
+ const ctx = { project, tenant: tenant2 };
3703
+ const declined = assumeYes ? declineAll(recipe.requires_confirmation ?? []) : await askConsent(recipe.requires_confirmation ?? [], interactive);
3704
+ const answers = await askQuestions(recipe.questions ?? [], ctx, interactive);
3705
+ const started = Date.now();
3706
+ const steps = buildSteps({ recipe, caller, teamId, chosenTeamId, teamName, ctx, answers, declined, apiVersion, reinstall, pinned });
3707
+ console.log();
3708
+ for (const step of steps) {
3709
+ if (step.skip) continue;
3710
+ process.stdout.write(` ${step.label.padEnd(33)}`);
3711
+ try {
3712
+ const note = await step.run();
3713
+ console.log(`${import_chalk26.default.green("\u2713")}${note ? ` ${import_chalk26.default.dim(note)}` : ""}`);
3714
+ } catch (err) {
3715
+ console.log(`${import_chalk26.default.red("\u2717")} ${import_chalk26.default.red(describeError(err))}`);
3716
+ console.log();
3717
+ if (step.n === 1) {
3718
+ console.log(import_chalk26.default.red(`stopped at step 1 of ${steps.length}. Nothing was created.`));
3719
+ console.log("run the same command again once the problem above is fixed:");
3720
+ console.log(import_chalk26.default.cyan(` npx apiblaze install ${nameArg}`));
3721
+ } else {
3722
+ console.log(import_chalk26.default.red(`stopped at step ${step.n} of ${steps.length}. ${project} exists but is not finished.`));
3723
+ console.log("continue with:");
3724
+ console.log(import_chalk26.default.cyan(` npx apiblaze install ${nameArg} --into ${project}`));
3725
+ }
3726
+ console.log();
3727
+ process.exit(1);
3728
+ }
3729
+ }
3730
+ const secs = ((Date.now() - started) / 1e3).toFixed(0);
3731
+ const urls = installUrls(ctx);
3732
+ console.log();
3733
+ console.log(`done in ${secs}s.`);
3734
+ console.log(` ${import_chalk26.default.dim("proxy ")} ${import_chalk26.default.bold(urls.proxy_url)}`);
3735
+ if (recipe.settings.mcp_enabled === true) console.log(` ${import_chalk26.default.dim("mcp ")} ${import_chalk26.default.bold(urls.mcp_url)}`);
3736
+ if (recipe.settings.enable_portal === true) console.log(` ${import_chalk26.default.dim("portal")} ${import_chalk26.default.bold(urls.portal_url)}`);
3737
+ console.log();
3738
+ }
3739
+ function buildSteps(inp) {
3740
+ const { recipe, caller, ctx, answers, declined, reinstall, pinned } = inp;
3741
+ const { project, tenant: tenant2 } = ctx;
3742
+ let teamId = inp.teamId;
3743
+ const { chosenTeamId, teamName } = inp;
3744
+ const filled = fillAnswers(
3745
+ {
3746
+ settings: recipe.settings ?? {},
3747
+ auth: recipe.auth ?? { app_client: null, provider: null, key_types: [] },
3748
+ transformations: recipe.transformations ?? { rules: [], mapping_tables: [] },
3749
+ openapi: recipe.openapi ?? null
3750
+ },
3751
+ answers
3752
+ );
3753
+ let apiVersion = inp.apiVersion;
3754
+ const rules = (filled.transformations.rules ?? []).filter((r) => !declined.has(`transform:${String(r.name ?? "")}`));
3755
+ const tables = filled.transformations.mapping_tables ?? [];
3756
+ const keyTypes = filled.auth.key_types ?? [];
3757
+ const routes = countRoutes(filled.openapi);
3758
+ return [
3759
+ {
3760
+ n: 1,
3761
+ label: `creating ${project}`,
3762
+ skip: reinstall,
3763
+ run: async () => {
3764
+ const target = firstUpstream(recipe);
3765
+ if (!target) throw new Error("this recipe carries no upstream URL, so there is nothing to create a proxy against");
3766
+ const out = await producer(caller, {
3767
+ method: "POST",
3768
+ path: "/projects",
3769
+ body: {
3770
+ name: project,
3771
+ target,
3772
+ tenant: tenant2,
3773
+ product_slug: project,
3774
+ api_version: apiVersion,
3775
+ auth_type: "api_key",
3776
+ // Sent so a chosen team is honoured. create-project.ts:919 IGNORES an
3777
+ // unauthorized team_id and silently substitutes the caller's default,
3778
+ // returning 201 — so the landing team is verified below rather than
3779
+ // assumed. Without that check "install into team B" could quietly
3780
+ // create the proxy in team A.
3781
+ team_id: chosenTeamId
3782
+ },
3783
+ summary: `Create proxy ${project} (tenant ${tenant2}) from ${pinned}`
3784
+ });
3785
+ if (out?.api_version) apiVersion = out.api_version;
3786
+ const landed = await owningTeam(caller, project, teamId);
3787
+ if (chosenTeamId && landed !== chosenTeamId) {
3788
+ throw new Error(
3789
+ `${project} was created in a different team than you chose. You may not have permission to create proxies there \u2014 delete it and re-run with a team you belong to.`
3790
+ );
3791
+ }
3792
+ teamId = landed;
3793
+ const landedName = teamName ?? await teamLabel(caller, landed);
3794
+ return landedName ? `proxy + tenant in ${landedName}` : "proxy + tenant";
3795
+ }
3796
+ },
3797
+ {
3798
+ n: 2,
3799
+ label: `recording ${pinned}`,
3800
+ run: async () => {
3801
+ await producer(caller, {
3802
+ method: "PATCH",
3803
+ path: `/projects/${encodeURIComponent(project)}/${encodeURIComponent(apiVersion)}/installed`,
3804
+ body: { installed_from: pinned, installed_tenant: tenant2 },
3805
+ summary: `Stamp provenance ${pinned} on ${project}`
3806
+ });
3807
+ return "provenance";
3808
+ }
3809
+ },
3810
+ {
3811
+ n: 3,
3812
+ label: "settings and environments",
3813
+ run: async () => {
3814
+ const s = filled.settings;
3815
+ const body = {};
3816
+ if (!declined.has("kind:upstream") && s.environments) body.environments = s.environments;
3817
+ if (!declined.has("kind:quota") && s.throttling) body.throttling = s.throttling;
3818
+ if (!declined.has("kind:cors") && s.cors !== void 0) body.cors = s.cors;
3819
+ if (!declined.has("kind:request policy") && s.requests_policy) body.requests_policy = s.requests_policy;
3820
+ if (!declined.has("kind:dev portal") && typeof s.enable_portal === "boolean") body.enable_portal = s.enable_portal;
3821
+ if (!declined.has("kind:mcp server") && typeof s.mcp_enabled === "boolean") body.mcp_enabled = s.mcp_enabled;
3822
+ if (typeof s.project_display_name === "string") body.display_name = s.project_display_name;
3823
+ if (typeof s.publish_openapi === "boolean") body.publish_openapi = s.publish_openapi;
3824
+ if (!Object.keys(body).length) return "nothing to apply";
3825
+ await producer(caller, {
3826
+ method: "PATCH",
3827
+ path: `/projects/${encodeURIComponent(project)}/${encodeURIComponent(apiVersion)}`,
3828
+ body,
3829
+ summary: `Apply recipe settings to ${project}`
3830
+ });
3831
+ return Object.keys(body).join(", ");
3832
+ }
3833
+ },
3834
+ {
3835
+ n: 4,
3836
+ label: providerLabel(filled.auth.provider),
3837
+ skip: !filled.auth.provider,
3838
+ run: async () => {
3839
+ const p = filled.auth.provider;
3840
+ const clientId = answers.oauth_client_id;
3841
+ const clientSecret = answers.oauth_client_secret;
3842
+ if (!clientId || !clientSecret) {
3843
+ throw new Error("the OAuth client id and secret were not supplied, so the login provider cannot be created");
3844
+ }
3845
+ const appClientId = await defaultAppClientId(caller, teamId, tenant2);
3846
+ await producer(caller, {
3847
+ method: "POST",
3848
+ path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/app-clients/${encodeURIComponent(appClientId)}/providers`,
3849
+ body: {
3850
+ type: p.type,
3851
+ clientId,
3852
+ clientSecret,
3853
+ scopes: p.scopes,
3854
+ tokenType: p.token_type,
3855
+ targetServerToken: p.target_server_token,
3856
+ includeApiblazeAccessTokenHeader: p.include_apiblaze_access_token_header === true,
3857
+ includeApiblazeIdTokenHeader: p.include_apiblaze_id_token_header === true
3858
+ },
3859
+ summary: `Create the ${String(p.type)} login provider on ${tenant2}`
3860
+ });
3861
+ return String(p.type);
3862
+ }
3863
+ },
3864
+ {
3865
+ n: 5,
3866
+ label: keyTypes.length ? `${keyTypes.length} key type${keyTypes.length === 1 ? "" : "s"}` : "key types",
3867
+ skip: !keyTypes.length,
3868
+ run: async () => {
3869
+ let added = 0;
3870
+ let existed = 0;
3871
+ await withCpKey(caller, teamId, async (cpKey) => {
3872
+ for (const kt of keyTypes) {
3873
+ const scopes = parseMaybeJson(kt.scopes_json);
3874
+ const res = await fetch(`${APIKEYS_BASE}/key-types?product=apiblaze&tenant=${encodeURIComponent(tenant2)}`, {
3875
+ method: "POST",
3876
+ headers: { "Content-Type": "application/json", "X-API-Key": cpKey },
3877
+ body: JSON.stringify({
3878
+ tenant: tenant2,
3879
+ name: kt.name,
3880
+ scopes: Array.isArray(scopes) ? scopes : [],
3881
+ ...kt.default_expires_at_seconds != null ? { default_expires_at_seconds: kt.default_expires_at_seconds } : {}
3882
+ })
3883
+ });
3884
+ if (res.status === 409) {
3885
+ existed++;
3886
+ continue;
3887
+ }
3888
+ if (!res.ok) {
3889
+ const body = await res.json().catch(() => ({}));
3890
+ const msg = typeof body.error === "string" ? body.error : body.error?.message;
3891
+ throw new ApiError(res.status, `key type "${String(kt.name)}": ${msg ?? res.statusText}`);
3892
+ }
3893
+ added++;
3894
+ }
3895
+ });
3896
+ return existed ? `${added} added, ${existed} already there` : `${added} added`;
3897
+ }
3898
+ },
3899
+ {
3900
+ n: 6,
3901
+ label: transformsLabel(rules.length, tables.length),
3902
+ skip: !rules.length && !tables.length,
3903
+ run: async () => {
3904
+ for (const t of tables) {
3905
+ await producer(caller, {
3906
+ method: "POST",
3907
+ path: `/projects/${encodeURIComponent(project)}/${encodeURIComponent(apiVersion)}/mappings`,
3908
+ body: { name: t.name, entries: t.entries ?? [], encrypt_values: t.encrypt_values === true },
3909
+ summary: `Create mapping table "${String(t.name)}"`
3910
+ }).catch((err) => {
3911
+ throw wrap(err, `mapping table "${String(t.name)}"`);
3912
+ });
3913
+ }
3914
+ for (const r of rules) {
3915
+ await producer(caller, {
3916
+ method: "POST",
3917
+ path: `/projects/${encodeURIComponent(project)}/${encodeURIComponent(apiVersion)}/transforms`,
3918
+ // The recipe carries `ord`; the create route reads `order`.
3919
+ body: {
3920
+ name: r.name,
3921
+ action: r.action,
3922
+ phase: r.phase ?? "request",
3923
+ enabled: r.enabled !== false,
3924
+ ...r.ord != null ? { order: r.ord } : {},
3925
+ ...r.condition ? { condition: r.condition } : {}
3926
+ },
3927
+ summary: `Create transform rule "${String(r.name)}"`
3928
+ }).catch((err) => {
3929
+ throw wrap(err, `rule "${String(r.name)}"`);
3930
+ });
3931
+ }
3932
+ return void 0;
3933
+ }
3934
+ },
3935
+ {
3936
+ n: 7,
3937
+ label: routes ? `API spec \u2192 ${routes} routes${filled.settings.mcp_enabled === true ? ", MCP tools" : ""}` : "API spec",
3938
+ skip: !filled.openapi,
3939
+ run: async () => {
3940
+ const out = await producer(caller, {
3941
+ method: "POST",
3942
+ path: `/projects/${encodeURIComponent(project)}/${encodeURIComponent(apiVersion)}/refresh-spec`,
3943
+ body: { specContent: JSON.stringify(filled.openapi) },
3944
+ summary: `Install the recipe's OpenAPI spec on ${project}`
3945
+ });
3946
+ const added = out?.report?.routes?.added?.length ?? routes;
3947
+ return out?.report?.applied?.mcp_regenerated ? `${added} routes, MCP rebuilt` : `${added} routes`;
3948
+ }
3949
+ }
3950
+ ];
3951
+ }
3952
+ function providerLabel(provider) {
3953
+ if (!provider) return "login provider";
3954
+ const t = String(provider.type ?? "oauth");
3955
+ return `${t.charAt(0).toUpperCase()}${t.slice(1)} provider`;
3956
+ }
3957
+ function transformsLabel(rules, tables) {
3958
+ const parts = [];
3959
+ if (rules) parts.push(`${rules} transform${rules === 1 ? "" : "s"}`);
3960
+ if (tables) parts.push(`${tables} mapping table${tables === 1 ? "" : "s"}`);
3961
+ return parts.join(", ") || "transforms";
3962
+ }
3963
+ function parseMaybeJson(v) {
3964
+ if (typeof v !== "string") return v;
3965
+ try {
3966
+ return JSON.parse(v);
3967
+ } catch {
3968
+ return v;
3969
+ }
3970
+ }
3971
+ function wrap(err, what) {
3972
+ const msg = err instanceof Error ? err.message : String(err);
3973
+ return new Error(`${what}: ${msg}`);
3974
+ }
3975
+ function describeError(err) {
3976
+ if (err instanceof ApiError) {
3977
+ const body = err.body;
3978
+ return `${err.message}${body?.details && body.details !== err.message ? ` \u2014 ${body.details}` : ""}`;
3979
+ }
3980
+ return err instanceof Error ? err.message : String(err);
3981
+ }
3982
+ async function withCpKey(caller, teamId, fn) {
3983
+ if (caller.mode === "anon" && caller.cpKey) return fn(caller.cpKey);
3984
+ const minted = await producer(caller, {
3985
+ method: "POST",
3986
+ path: `/teams/${encodeURIComponent(teamId)}/developer-keys`,
3987
+ body: { description: "apiblaze install (temporary)", expires_in_seconds: 300 },
3988
+ summary: "Mint a 5-minute control-plane key for the key-types step"
3989
+ });
3990
+ if (!minted?.key) throw new Error("could not mint a control-plane key for the key-types step");
3991
+ try {
3992
+ return await fn(minted.key);
3993
+ } finally {
3994
+ if (minted.key_id) {
3995
+ await producer(caller, {
3996
+ method: "DELETE",
3997
+ path: `/teams/${encodeURIComponent(teamId)}/developer-keys/${encodeURIComponent(minted.key_id)}`,
3998
+ summary: "Revoke the temporary control-plane key"
3999
+ }).catch(() => {
4000
+ });
4001
+ }
4002
+ }
4003
+ }
4004
+ async function teamLabel(caller, teamId) {
4005
+ if (caller.mode === "anon") return null;
4006
+ const teams = await getTeams().catch(() => []);
4007
+ return teams.find((t) => t.teamId === teamId)?.name ?? null;
4008
+ }
4009
+ async function owningTeam(caller, project, preferred) {
4010
+ const has = async (teamId) => {
4011
+ const out = await producer(caller, {
4012
+ method: "GET",
4013
+ path: `/projects?team_id=${encodeURIComponent(teamId)}`,
4014
+ summary: `Confirm ${project} landed in ${teamId}`
4015
+ }).catch(() => ({ projects: [] }));
4016
+ return (out?.projects ?? []).some((p) => p.project_id === project);
4017
+ };
4018
+ if (await has(preferred)) return preferred;
4019
+ if (caller.mode === "anon") return preferred;
4020
+ const { getTeams: getTeams2 } = await Promise.resolve().then(() => (init_api(), api_exports));
4021
+ const teams = await getTeams2().catch(() => []);
4022
+ for (const t of teams) {
4023
+ if (t.teamId !== preferred && await has(t.teamId)) return t.teamId;
4024
+ }
4025
+ return preferred;
4026
+ }
4027
+ async function defaultAppClientId(caller, teamId, tenant2) {
4028
+ const out = await producer(caller, {
4029
+ method: "GET",
4030
+ path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/app-clients`,
4031
+ summary: `Find the login app for ${tenant2}`
4032
+ });
4033
+ const list = Array.isArray(out) ? out : out?.app_clients ?? out?.clients ?? [];
4034
+ const chosen = list.find((c) => c.is_default === true || c.default === true) ?? list[0];
4035
+ const id = chosen?.client_id ?? chosen?.id;
4036
+ if (typeof id !== "string" || !id) {
4037
+ throw new Error(`tenant ${tenant2} has no login app to attach the provider to`);
4038
+ }
4039
+ return id;
4040
+ }
4041
+ async function nameIsFree(name, teamId) {
4042
+ try {
4043
+ const check = await checkProxyName(name, teamId);
4044
+ return check.canUseProjectName && check.canUseApiVersion;
4045
+ } catch {
4046
+ return null;
4047
+ }
4048
+ }
4049
+ async function chooseProxyName(slug, asOpt, teamId, interactive) {
4050
+ if (asOpt !== void 0) {
4051
+ const name = normalizeName2(asOpt);
4052
+ if (name !== asOpt) console.log(import_chalk26.default.yellow(` Using "${name}" \u2014 names are lowercase letters and digits only.`));
4053
+ if (name.length < 3) throw new Error("A proxy name must be at least 3 characters (lowercase letters and digits only).");
4054
+ const free = await nameIsFree(name, teamId);
4055
+ if (free === false) throw new Error(`"${name}" is already taken. Pick another with --as.`);
4056
+ return name;
4057
+ }
4058
+ const base2 = normalizeName2(`my${slug}`) || normalizeName2(slug);
4059
+ let suggested = base2;
4060
+ for (let i = 1; i <= 20; i++) {
4061
+ const candidate = i === 1 ? base2 : `${base2}${i}`;
4062
+ if (await nameIsFree(candidate, teamId) !== false) {
4063
+ suggested = candidate;
4064
+ break;
4065
+ }
4066
+ }
4067
+ if (!interactive) return suggested;
4068
+ const { default: inquirer3 } = await import("inquirer");
4069
+ console.log(` ${import_chalk26.default.dim("proxy")} ${slug} \u2192 ${import_chalk26.default.bold(suggested)} ${import_chalk26.default.dim("[enter to accept, or type a name]")}`);
4070
+ for (; ; ) {
4071
+ const { raw } = await inquirer3.prompt([{
4072
+ type: "input",
4073
+ name: "raw",
4074
+ message: ">",
4075
+ default: suggested,
4076
+ transformer: (v) => normalizeName2(v)
4077
+ }]);
4078
+ const name = normalizeName2(raw);
4079
+ if (name !== String(raw).trim()) {
4080
+ console.log(import_chalk26.default.yellow(` \u2192 using ${import_chalk26.default.bold(name)} (lowercase letters and digits only)`));
4081
+ }
4082
+ if (name.length < 3) {
4083
+ console.log(import_chalk26.default.yellow(" Name must be at least 3 characters.\n"));
4084
+ continue;
4085
+ }
4086
+ const free = await nameIsFree(name, teamId);
4087
+ if (free === false) {
4088
+ console.log(import_chalk26.default.yellow(` "${name}" is taken. Try another.
4089
+ `));
4090
+ continue;
4091
+ }
4092
+ if (free === null) console.log(import_chalk26.default.dim(" (could not verify availability; continuing)"));
4093
+ console.log(` ${import_chalk26.default.cyan("\u2192")} ${import_chalk26.default.bold(`https://${name}.abz.run`)} ${import_chalk26.default.dim(`users live in the tenant ${name}users`)}`);
4094
+ return name;
4095
+ }
4096
+ }
4097
+ async function assertTenantFree(tenant2, teamId) {
4098
+ if (await nameIsFree(tenant2, teamId) === false) {
4099
+ throw new Error(
4100
+ `The tenant name "${tenant2}" is already taken, so this proxy name cannot be used.
4101
+ Pick a different proxy name (the tenant is always <proxy>users).`
4102
+ );
4103
+ }
4104
+ }
4105
+ function printSummary(recipe, project, tenant2) {
4106
+ const hosts = upstreamHosts(recipe);
4107
+ const routes = countRoutes(recipe.openapi);
4108
+ const keyTypes = recipe.auth?.key_types?.length ?? 0;
4109
+ const questions = recipe.questions?.length ?? 0;
4110
+ console.log();
4111
+ if (hosts.length) console.log(` ${import_chalk26.default.dim("sends requests to")} ${hosts.join(", ")}`);
4112
+ console.log(` ${import_chalk26.default.dim("creates ")} ${describeCreates(keyTypes, routes, recipe.settings.mcp_enabled === true)}`);
4113
+ console.log(` ${import_chalk26.default.dim("asks you for ")} ${questions} value${questions === 1 ? "" : "s"}`);
4114
+ if (recipe.settings.publish_openapi === true) {
4115
+ console.log(` ${import_chalk26.default.dim("makes public ")} this API's spec, at ${project}.abz.run/${recipe.api_version}/openapi.json`);
4116
+ }
4117
+ console.log(import_chalk26.default.dim(` ${"users live in".padEnd(17)} ${tenant2}`));
4118
+ console.log();
4119
+ }
4120
+ function declineAll(items) {
4121
+ const skippable = items.filter((i) => i.kind !== "upstream");
4122
+ const upstreams = items.filter((i) => i.kind === "upstream");
4123
+ console.log();
4124
+ for (const u of upstreams) {
4125
+ console.log(import_chalk26.default.yellow(` --yes: this proxy sends every request to ${import_chalk26.default.bold(u.value)}.`));
4126
+ }
4127
+ if (skippable.length) {
4128
+ console.log(import_chalk26.default.yellow(` --yes: installing without ${skippable.length} setting${skippable.length === 1 ? "" : "s"} that need consent.`));
4129
+ for (const i of skippable) console.log(import_chalk26.default.dim(` skipped ${i.kind} ${i.value}`));
4130
+ }
4131
+ return new Set(skippable.map((i) => i.kind));
4132
+ }
4133
+ async function confirmYesNo(message, interactive) {
4134
+ if (!interactive) {
4135
+ throw new Error(`${message.trim()} needs an answer, but there is no terminal to ask on. Run this from an interactive shell.`);
4136
+ }
4137
+ const { default: inquirer3 } = await import("inquirer");
4138
+ const { ok } = await inquirer3.prompt([{ type: "confirm", name: "ok", message, default: false }]);
4139
+ return !!ok;
4140
+ }
4141
+ async function askConsent(items, interactive) {
4142
+ const declined = /* @__PURE__ */ new Set();
4143
+ if (!items.length) return declined;
4144
+ const count = items.length;
4145
+ const word = ["", "it", "both", "all three", "all four", "all five", "all six"][count] ?? `all ${count}`;
4146
+ console.log();
4147
+ console.log(import_chalk26.default.yellow("\u26A0 This recipe changes who can reach your proxy, what it trusts, and what it can cost."));
4148
+ console.log();
4149
+ for (const item of items) {
4150
+ console.log(` ${import_chalk26.default.bold(item.kind.padEnd(16))} ${item.value}`);
4151
+ for (const line of wrapText(item.why, 62)) console.log(` ${" ".repeat(16)} ${import_chalk26.default.dim(line)}`);
4152
+ }
4153
+ console.log();
4154
+ console.log(`Type "${import_chalk26.default.bold("yes")}" to accept ${word}.`);
4155
+ console.log("Press enter to install the recipe without them.");
4156
+ let typed = "";
4157
+ if (interactive) {
4158
+ const { default: inquirer3 } = await import("inquirer");
4159
+ const { answer } = await inquirer3.prompt([{ type: "input", name: "answer", message: ">" }]);
4160
+ typed = String(answer ?? "").trim();
4161
+ }
4162
+ if (typed.toLowerCase() === "yes") return declined;
4163
+ for (const item of items) {
4164
+ declined.add(item.kind === "transform" ? `transform:${item.value}` : `kind:${item.kind}`);
4165
+ }
4166
+ console.log(import_chalk26.default.dim(` Installing without ${count} setting${count === 1 ? "" : "s"} \u2014 everything else is applied.`));
4167
+ return declined;
4168
+ }
4169
+ async function askQuestions(questions, ctx, interactive) {
4170
+ const answers = {};
4171
+ if (!questions.length) return answers;
4172
+ for (const q of questions) {
4173
+ const envName = `ABZ_ANSWER_${q.id.toUpperCase()}`;
4174
+ const fromEnv = process.env[envName];
4175
+ if (q.before) {
4176
+ const BOX = 64;
4177
+ const title = "\u2500\u2500 from the publisher ";
4178
+ console.log();
4179
+ console.log(` ${import_chalk26.default.dim(title + "\u2500".repeat(BOX - title.length))}`);
4180
+ for (const line of fillContext(q.before, ctx).split("\n")) console.log(` ${import_chalk26.default.dim("\u2502")} ${line}`);
4181
+ console.log(` ${import_chalk26.default.dim("\u2500".repeat(BOX))}`);
4182
+ }
4183
+ if (fromEnv !== void 0 && fromEnv !== "") {
4184
+ answers[q.id] = fromEnv;
4185
+ console.log(` ${q.prompt}: ${import_chalk26.default.dim(`(from ${envName})`)}`);
4186
+ continue;
4187
+ }
4188
+ if (!interactive) {
4189
+ throw new Error(
4190
+ `This recipe needs "${q.prompt}" and there is no terminal to ask on.
4191
+ Set ${envName} in the environment (never as a flag \u2014 a flag lands in shell history and CI logs).`
4192
+ );
4193
+ }
4194
+ const { default: inquirer3 } = await import("inquirer");
4195
+ if (q.example && !q.secret) console.log(import_chalk26.default.dim(` e.g. ${q.example}`));
4196
+ const { value } = await inquirer3.prompt([{
4197
+ // `secret: true` masks the input — the Google client secret is typed once,
4198
+ // goes to provider creation, and is never echoed or stored.
4199
+ type: q.secret ? "password" : "input",
4200
+ name: "value",
4201
+ mask: "\u2022",
4202
+ message: ` ${q.prompt}:`,
4203
+ validate: (v) => String(v ?? "").trim() ? true : "Required."
4204
+ }]);
4205
+ answers[q.id] = String(value).trim();
4206
+ }
4207
+ return answers;
4208
+ }
4209
+ async function resolveReinstallTenant(caller, project, apiVersion) {
4210
+ const out = await producer(caller, {
4211
+ method: "GET",
4212
+ path: `/projects/${encodeURIComponent(project)}/${encodeURIComponent(apiVersion)}/tenants`,
4213
+ summary: `List tenants attached to ${project}`
4214
+ });
4215
+ const names = (out?.tenants ?? []).map((t) => typeof t === "string" ? t : t?.tenant_name).filter((t) => typeof t === "string" && !!t);
4216
+ const derived = `${project}users`;
4217
+ if (names.includes(derived)) return derived;
4218
+ if (names.length === 1) return names[0];
4219
+ if (!names.length) throw new Error(`${project} has no tenant attached, so there is nothing to reinstall into.`);
4220
+ throw new Error(
4221
+ `${project} has ${names.length} tenants (${names.join(", ")}) and none of them is ${derived}, so this proxy was not created by an install. Refusing to guess which one the recipe should overwrite.`
4222
+ );
4223
+ }
4224
+ async function confirmReinstall(recipe, project, tenant2, interactive) {
4225
+ const rules = recipe.transformations?.rules?.length ?? 0;
4226
+ const tables = recipe.transformations?.mapping_tables?.length ?? 0;
4227
+ const routes = countRoutes(recipe.openapi);
4228
+ const keyTypes = recipe.auth?.key_types?.length ?? 0;
4229
+ console.log(`This installs ${import_chalk26.default.bold(`${recipe.name}@${recipe.revision}`)} over ${import_chalk26.default.bold(project)}.`);
4230
+ console.log();
4231
+ console.log(` ${import_chalk26.default.dim("settings ".padEnd(16))}replaced`);
4232
+ if (rules || tables) {
4233
+ console.log(` ${import_chalk26.default.dim("transforms".padEnd(16))}${rules} rule${rules === 1 ? "" : "s"}${tables ? ` and ${tables} mapping table${tables === 1 ? "" : "s"}` : ""} replaced \u2014 your edits to them are lost`);
4234
+ }
4235
+ if (routes) {
4236
+ console.log(` ${import_chalk26.default.dim("api spec ".padEnd(16))}replaced, ${routes} routes regenerated${recipe.settings.mcp_enabled === true ? ", MCP rebuilt" : ""}`);
4237
+ }
4238
+ if (keyTypes) {
4239
+ console.log(` ${import_chalk26.default.dim("key types ".padEnd(16))}${keyTypes} added if missing; existing types left alone`);
4240
+ }
4241
+ console.log();
4242
+ console.log(` ${import_chalk26.default.dim("unchanged ".padEnd(16))}your API keys, your proxy URL, your users,`);
4243
+ console.log(` ${" ".repeat(16)}and any tenant other than ${tenant2}`);
4244
+ console.log();
4245
+ console.log(import_chalk26.default.yellow("This cannot be undone."));
4246
+ if (!interactive) {
4247
+ throw new Error("Reinstall needs a typed confirmation and there is no terminal to ask on.");
4248
+ }
4249
+ const { default: inquirer3 } = await import("inquirer");
4250
+ const { typed } = await inquirer3.prompt([{ type: "input", name: "typed", message: `Type the proxy name (${project}) to continue:` }]);
4251
+ if (String(typed ?? "").trim() !== project) {
4252
+ console.log(import_chalk26.default.yellow("Cancelled \u2014 nothing was changed."));
4253
+ process.exit(0);
4254
+ }
4255
+ }
4256
+ function requireCallerForInstall() {
4257
+ try {
4258
+ return requireCaller();
4259
+ } catch {
4260
+ console.error(import_chalk26.default.red(
4261
+ "Installing writes a proxy into an account, so it needs a credential.\n Run `apiblaze login`, or `apiblaze create` first (an anonymous workspace works too)."
4262
+ ));
4263
+ process.exit(1);
4264
+ }
4265
+ }
4266
+ function wrapText(text, width) {
4267
+ const words = (text || "").split(/\s+/).filter(Boolean);
4268
+ const lines = [];
4269
+ let cur = "";
4270
+ for (const w of words) {
4271
+ if (cur && `${cur} ${w}`.length > width) {
4272
+ lines.push(cur);
4273
+ cur = w;
4274
+ } else {
4275
+ cur = cur ? `${cur} ${w}` : w;
4276
+ }
4277
+ }
4278
+ if (cur) lines.push(cur);
4279
+ return lines;
4280
+ }
4281
+ async function chooseTeam(caller, optTeam, interactive) {
4282
+ if (optTeam) return { ...await resolveActingTeam(caller, optTeam), chosen: true };
4283
+ if (caller.mode === "anon" || !interactive) {
4284
+ return { ...await resolveActingTeam(caller, void 0), chosen: false };
4285
+ }
4286
+ const active = await resolveActingTeam(caller, void 0);
4287
+ const teams = await getTeams().catch(() => []);
4288
+ if (teams.length < 2) return { ...active, chosen: false };
4289
+ const { default: inquirer3 } = await import("inquirer");
4290
+ const { picked } = await inquirer3.prompt([{
4291
+ type: "list",
4292
+ name: "picked",
4293
+ message: " which team should own this proxy?",
4294
+ default: active.teamId,
4295
+ choices: teams.map((t) => ({
4296
+ name: t.teamId === active.teamId ? `${t.name} ${import_chalk26.default.dim("(active)")}` : t.name,
4297
+ value: t.teamId
4298
+ }))
4299
+ }]);
4300
+ const match = teams.find((t) => t.teamId === picked);
4301
+ return { teamId: picked, teamName: match?.name, chosen: true };
4302
+ }
4303
+
4304
+ // src/commands/recipe-publish.ts
4305
+ var import_chalk27 = __toESM(require("chalk"));
4306
+ var import_ora9 = __toESM(require("ora"));
4307
+ init_caller();
4308
+ init_auth();
4309
+ async function runRecipePublish(projectArg, opts) {
4310
+ const creds = loadCredentials();
4311
+ let resolved;
4312
+ try {
4313
+ resolved = resolveRecipeName(opts.as, creds?.githubHandle, normalizeName2(projectArg));
4314
+ } catch (err) {
4315
+ console.error(import_chalk27.default.red(err instanceof Error ? err.message : String(err)));
4316
+ process.exitCode = 1;
4317
+ return;
4318
+ }
4319
+ const ref = resolved.ref;
4320
+ if (resolved.derivedHandle) {
4321
+ console.log(import_chalk27.default.dim(` publishing as ${import_chalk27.default.bold(ref.name)}`));
4322
+ if (resolved.normalizedFrom) {
4323
+ console.log(import_chalk27.default.dim(` (your GitHub login is ${resolved.normalizedFrom}; apiblaze names are letters and digits only)`));
4324
+ }
4325
+ }
4326
+ const interactive = !!process.stdin.isTTY && !opts.json;
4327
+ const caller = requireCaller();
4328
+ const { teamId } = await resolveActingTeam(caller, opts.team);
4329
+ const proj2 = await resolveProjectVia(caller, teamId, projectArg, opts.apiversion);
4330
+ const spinner = !opts.json ? (0, import_ora9.default)(`Reading ${proj2.projectId} v${proj2.apiVersion}...`).start() : null;
4331
+ let prep;
4332
+ try {
4333
+ prep = await prepare(caller, proj2.projectId, proj2.apiVersion, ref.name, opts.tenant);
4334
+ spinner?.stop();
4335
+ } catch (err) {
4336
+ spinner?.fail("Could not read the proxy.");
4337
+ throw err;
4338
+ }
4339
+ let tenant2 = opts.tenant;
4340
+ if (!prep.tenant_used && prep.tenants.length > 1) {
4341
+ if (!interactive) {
4342
+ console.error(import_chalk27.default.red(
4343
+ `${proj2.projectId} has ${prep.tenants.length} tenants (${prep.tenants.join(", ")}). Pass --tenant <slug> to say which auth setup the recipe carries.`
4344
+ ));
4345
+ process.exit(1);
4346
+ }
4347
+ const { default: inquirer3 } = await import("inquirer");
4348
+ const { picked } = await inquirer3.prompt([{
4349
+ type: "list",
4350
+ name: "picked",
4351
+ choices: prep.tenants,
4352
+ message: "This proxy has several tenants. Which auth setup should the recipe carry?"
4353
+ }]);
4354
+ tenant2 = picked;
4355
+ prep = await prepare(caller, proj2.projectId, proj2.apiVersion, ref.name, tenant2);
4356
+ }
4357
+ if (!prep.name_available) {
4358
+ console.error(import_chalk27.default.red(`${ref.name} belongs to another team, so you cannot publish a revision of it.`));
4359
+ process.exit(1);
4360
+ }
4361
+ if (prep.envelope_violations.length) {
4362
+ printEnvelopeViolations(prep.envelope_violations);
4363
+ process.exit(1);
4364
+ }
4365
+ if (prep.dropped.length) {
4366
+ console.log();
4367
+ console.log(`${prep.dropped.length} setting${prep.dropped.length === 1 ? " was" : "s were"} not included, because they are not on the publish list:`);
4368
+ for (const d of prep.dropped) console.log(import_chalk27.default.dim(` ${d}`));
4369
+ if (prep.hidden_tables_excluded) {
4370
+ console.log(import_chalk27.default.dim(` (${prep.hidden_tables_excluded} hidden mapping table${prep.hidden_tables_excluded === 1 ? "" : "s"} excluded \u2014 those values belong to your consumers.)`));
4371
+ }
4372
+ console.log();
4373
+ if (!opts.yes && !await confirm(" continue without them?", interactive)) {
4374
+ console.log(import_chalk27.default.yellow("Cancelled."));
4375
+ return;
4376
+ }
4377
+ }
4378
+ const decisions = {};
4379
+ const promotions = [];
4380
+ console.log();
4381
+ console.log(`checked ${prep.checked_count} values against 12 known patterns. ${prep.findings.length || "none"} need${prep.findings.length === 1 ? "s" : ""} your decision${prep.findings.length ? ":" : "."}`);
4382
+ if (prep.findings.length) {
4383
+ if (opts.yes) {
4384
+ console.log();
4385
+ for (const f of prep.findings) printFinding(f);
4386
+ console.log();
4387
+ console.error(import_chalk27.default.red("--yes cannot accept scanner findings. Fix the value in the proxy, or publish interactively and decide."));
4388
+ process.exit(1);
4389
+ }
4390
+ if (!interactive) {
4391
+ for (const f of prep.findings) printFinding(f);
4392
+ console.error(import_chalk27.default.red("\nThese need a decision and there is no terminal to ask on."));
4393
+ process.exit(1);
4394
+ }
4395
+ const { default: inquirer3 } = await import("inquirer");
4396
+ for (const f of prep.findings) {
4397
+ console.log();
4398
+ printFinding(f);
4399
+ const { verdict } = await inquirer3.prompt([{
4400
+ type: "list",
4401
+ name: "verdict",
4402
+ message: " ",
4403
+ choices: [
4404
+ { name: "keep it as it is", value: "keep" },
4405
+ { name: "ask the installer for their own value", value: "ask" },
4406
+ { name: "remove it from the recipe", value: "remove" }
4407
+ ]
4408
+ }]);
4409
+ decisions[f.path] = verdict;
4410
+ if (verdict === "ask") promotions.push(await askPromotion(f.path));
4411
+ }
4412
+ }
4413
+ console.log(import_chalk27.default.dim(`we cannot judge the other ${prep.unjudged_count} values. run \`apiblaze show ${ref.name}\` after publishing to read the whole recipe.`));
4414
+ const totalQuestions = prep.question_ids.length + promotions.length;
4415
+ if (totalQuestions > 5) {
4416
+ console.log(import_chalk27.default.yellow(`
4417
+ \u26A0 installers will have to supply ${totalQuestions} values before this works.`));
4418
+ }
4419
+ const visibility = opts.private ? "private" : "public";
4420
+ let confirmSpecPublic = false;
4421
+ if (visibility === "public" && prep.spec_will_become_public) {
4422
+ console.log();
4423
+ console.log("Publishing publicly also makes this API's spec readable at");
4424
+ console.log(` ${import_chalk27.default.bold(`https://${proj2.projectId}.abz.run/${proj2.apiVersion}/openapi.json`)}`);
4425
+ console.log("It is currently private.");
4426
+ confirmSpecPublic = opts.yes ? true : await confirm("Continue?", interactive);
4427
+ if (!confirmSpecPublic) {
4428
+ console.log(import_chalk27.default.yellow("Cancelled \u2014 nothing was published."));
4429
+ return;
4430
+ }
4431
+ }
4432
+ const spin2 = !opts.json ? (0, import_ora9.default)(`Publishing ${ref.name}...`).start() : null;
4433
+ let out;
4434
+ try {
4435
+ out = await producer(caller, {
4436
+ method: "POST",
4437
+ path: "/recipes/publish",
4438
+ body: {
4439
+ project_id: proj2.projectId,
4440
+ api_version: proj2.apiVersion,
4441
+ name: ref.name,
4442
+ visibility,
4443
+ candidate_sha256: prep.candidate_sha256,
4444
+ decisions,
4445
+ promotions,
4446
+ ...opts.displayName ? { display_name: opts.displayName } : {},
4447
+ ...opts.summary ? { summary: opts.summary } : {},
4448
+ ...opts.license ? { license: opts.license } : {},
4449
+ ...tenant2 ? { tenant: tenant2 } : {},
4450
+ ...confirmSpecPublic ? { confirm_spec_public: true } : {}
4451
+ },
4452
+ summary: `Publish ${proj2.projectId} as ${ref.name} (${visibility})`
4453
+ });
4454
+ spin2?.succeed(`Published ${import_chalk27.default.bold(`${out.name}@${out.revision}`)} (${out.visibility}).`);
4455
+ } catch (err) {
4456
+ spin2?.fail("Publish failed.");
4457
+ throw err;
4458
+ }
4459
+ if (opts.json) {
4460
+ console.log(JSON.stringify(out));
4461
+ return;
4462
+ }
4463
+ console.log(` ${import_chalk27.default.dim("size ")} ${(out.size_bytes / 1024).toFixed(1)} KB`);
4464
+ console.log(` ${import_chalk27.default.dim("checksum")} ${out.sha256.slice(0, 16)}\u2026`);
4465
+ console.log();
4466
+ if (out.visibility === "public") {
4467
+ console.log(import_chalk27.default.dim(` Anyone can now run: ${import_chalk27.default.cyan(`npx apiblaze install ${out.name}`)}`));
4468
+ } else {
4469
+ console.log(import_chalk27.default.dim(" Private \u2014 only members of this team can see or install it."));
4470
+ }
4471
+ console.log(import_chalk27.default.dim(` Pull it back with: ${import_chalk27.default.cyan(`npx apiblaze withdraw ${out.name}@${out.revision}`)}`));
4472
+ console.log();
4473
+ }
4474
+ async function prepare(caller, projectId, apiVersion, name, tenant2) {
4475
+ return producer(caller, {
4476
+ method: "POST",
4477
+ path: "/recipes/prepare",
4478
+ body: { project_id: projectId, api_version: apiVersion, name, ...tenant2 ? { tenant: tenant2 } : {} },
4479
+ summary: `Prepare ${projectId} v${apiVersion} for publishing as ${name}`
4480
+ });
4481
+ }
4482
+ function printFinding(f) {
4483
+ const preview = (f.preview ?? "").replace(/\s+/g, " ").trim();
4484
+ console.log(` ${import_chalk27.default.bold(f.path)}`);
4485
+ console.log(` ${import_chalk27.default.yellow(preview.padEnd(38))}${import_chalk27.default.dim(f.why)}`);
4486
+ }
4487
+ function printEnvelopeViolations(violations) {
4488
+ console.log();
4489
+ console.error(import_chalk27.default.red("This proxy has transform rules a recipe cannot carry."));
4490
+ console.log();
4491
+ for (const v of violations) {
4492
+ console.log(` ${import_chalk27.default.bold(v.rule)} ${import_chalk27.default.dim(`(${v.kind}s ${v.field})`)}`);
4493
+ console.log(` ${v.why}`);
4494
+ }
4495
+ console.log();
4496
+ console.log("A recipe runs in a stranger's account, after apiblaze has attached their end user's");
4497
+ console.log("real third-party token, so two rules are absolute:");
4498
+ console.log(` ${import_chalk27.default.dim("\u2022")} a rule may never READ Authorization, Cookie, or the third-party token headers \u2014`);
4499
+ console.log(" those hold a live credential that works at the provider without apiblaze;");
4500
+ console.log(` ${import_chalk27.default.dim("\u2022")} a rule may never WRITE an identity header (x-end-user-id and friends) \u2014`);
4501
+ console.log(" those tell the installer's own backend who is calling.");
4502
+ console.log();
4503
+ console.log("Writing Authorization from a question or a fixed value is fine \u2014 that is the");
4504
+ console.log("bring-your-own-key case. Change the rules above, then publish again.");
4505
+ console.log();
4506
+ }
4507
+ async function askPromotion(path8) {
4508
+ const { default: inquirer3 } = await import("inquirer");
4509
+ const suggestedId = path8.split(/[.[\]]/).filter(Boolean).slice(-2).join("_").toLowerCase().replace(/[^a-z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "") || "value";
4510
+ const answers = await inquirer3.prompt([
4511
+ { type: "input", name: "prompt", message: " prompt them with:", validate: (v) => v.trim() ? true : "Required." },
4512
+ { type: "input", name: "example", message: " example:" },
4513
+ { type: "input", name: "before", message: " before (optional):" },
4514
+ { type: "confirm", name: "secret", message: " is the answer a secret (hide it while they type)?", default: false },
4515
+ { type: "input", name: "id", message: " id:", default: suggestedId }
4516
+ ]);
4517
+ const id = String(answers.id || suggestedId).toLowerCase().replace(/[^a-z0-9_]/g, "_");
4518
+ console.log(import_chalk27.default.dim(` \u2192 replaced with {{${id}}}`));
4519
+ return {
4520
+ path: path8,
4521
+ id,
4522
+ prompt: String(answers.prompt).trim(),
4523
+ ...answers.example ? { example: String(answers.example).trim() } : {},
4524
+ ...answers.before ? { before: String(answers.before).trim() } : {},
4525
+ secret: answers.secret === true
4526
+ };
4527
+ }
4528
+ async function confirm(message, interactive) {
4529
+ if (!interactive) return false;
4530
+ const { default: inquirer3 } = await import("inquirer");
4531
+ const { ok } = await inquirer3.prompt([{ type: "confirm", name: "ok", message, default: false }]);
4532
+ return !!ok;
4533
+ }
4534
+ async function runRecipeWithdraw(nameArg, opts) {
4535
+ const ref = parseRecipeRef(nameArg);
4536
+ if (ref.revision === void 0) {
4537
+ console.error(import_chalk27.default.red(`Name the revision to withdraw, e.g. ${nameArg}@3. Revisions are withdrawn one at a time.`));
4538
+ process.exit(1);
4539
+ }
4540
+ const interactive = !!process.stdin.isTTY && !opts.json;
4541
+ const caller = requireCaller();
4542
+ const { teamId } = await resolveActingTeam(caller, opts.team);
4543
+ const mine = await producer(caller, {
4544
+ method: "GET",
4545
+ path: `/recipes/mine?team_id=${encodeURIComponent(teamId)}`,
4546
+ summary: `List recipes published by ${teamId}`
4547
+ }).catch(() => ({ recipes: [] }));
4548
+ const row = (mine?.recipes ?? []).find((r) => r.name === ref.name);
4549
+ const installs = row?.install_count ?? 0;
4550
+ console.log();
4551
+ console.log(`this permanently deletes revision ${ref.revision}. installs of it will fail.`);
4552
+ if (installs) console.log(`${installs} account${installs === 1 ? "" : "s"} installed it \u2014 rotate any secrets it contained.`);
4553
+ if (interactive) {
4554
+ const { default: inquirer3 } = await import("inquirer");
4555
+ const { typed } = await inquirer3.prompt([{ type: "input", name: "typed", message: `type the recipe name to confirm (${ref.name}):` }]);
4556
+ if (String(typed ?? "").trim() !== ref.name) {
4557
+ console.log(import_chalk27.default.yellow("Cancelled \u2014 nothing was withdrawn."));
4558
+ return;
4559
+ }
4560
+ } else {
4561
+ console.error(import_chalk27.default.red("Withdrawing needs a typed confirmation and there is no terminal to ask on."));
4562
+ process.exit(1);
4563
+ }
4564
+ const spinner = !opts.json ? (0, import_ora9.default)("Withdrawing...").start() : null;
4565
+ let out;
4566
+ try {
4567
+ out = await producer(caller, {
4568
+ method: "DELETE",
4569
+ path: `/recipes/${ref.handle}/${ref.slug}/${ref.revision}`,
4570
+ summary: `Withdraw ${ref.name}@${ref.revision}`
4571
+ });
4572
+ spinner?.stop();
4573
+ } catch (err) {
4574
+ spinner?.fail("Withdraw failed.");
4575
+ throw err;
4576
+ }
4577
+ if (opts.json) {
4578
+ console.log(JSON.stringify(out));
4579
+ return;
4580
+ }
4581
+ console.log();
4582
+ console.log(
4583
+ out.cache_purged === true ? "withdrawn. cached copies were purged." : `withdrawn. ${out.cache_note ?? "cached copies may be served for a few more minutes"}.`
4584
+ );
4585
+ console.log("rotate any secrets it contained now, not later.");
4586
+ console.log();
4587
+ }
4588
+
4589
+ // src/commands/logs.ts
4590
+ var import_chalk29 = __toESM(require("chalk"));
3312
4591
  init_admin();
3313
4592
  init_auth();
3314
4593
  init_resolve();
3315
4594
 
3316
4595
  // src/lib/log-view.ts
3317
- var import_chalk25 = __toESM(require("chalk"));
4596
+ var import_chalk28 = __toESM(require("chalk"));
3318
4597
  var readline2 = __toESM(require("readline"));
3319
4598
  function statusColor(status) {
3320
- if (status < 300) return import_chalk25.default.green;
3321
- if (status < 400) return import_chalk25.default.blue;
3322
- if (status < 500) return import_chalk25.default.yellow;
3323
- return import_chalk25.default.red;
4599
+ if (status < 300) return import_chalk28.default.green;
4600
+ if (status < 400) return import_chalk28.default.blue;
4601
+ if (status < 500) return import_chalk28.default.yellow;
4602
+ return import_chalk28.default.red;
3324
4603
  }
3325
4604
  function methodColor(method) {
3326
4605
  switch ((method || "").toUpperCase()) {
3327
4606
  case "GET":
3328
- return import_chalk25.default.green;
4607
+ return import_chalk28.default.green;
3329
4608
  case "POST":
3330
- return import_chalk25.default.blue;
4609
+ return import_chalk28.default.blue;
3331
4610
  case "PUT":
3332
4611
  case "PATCH":
3333
- return import_chalk25.default.yellow;
4612
+ return import_chalk28.default.yellow;
3334
4613
  case "DELETE":
3335
- return import_chalk25.default.red;
4614
+ return import_chalk28.default.red;
3336
4615
  default:
3337
- return import_chalk25.default.white;
4616
+ return import_chalk28.default.white;
3338
4617
  }
3339
4618
  }
3340
4619
  function clock(ts) {
@@ -3346,12 +4625,12 @@ function routeCell(route) {
3346
4625
  return (r.length > ROUTE_W ? `\u2026${r.slice(-(ROUTE_W - 1))}` : r).padEnd(ROUTE_W);
3347
4626
  }
3348
4627
  function formatRow(r) {
3349
- const time = import_chalk25.default.dim(clock(r.ts));
4628
+ const time = import_chalk28.default.dim(clock(r.ts));
3350
4629
  const method = methodColor(r.method)(String(r.method || "\u2014").padEnd(6));
3351
4630
  const route = routeCell(String(r.route || "\u2014"));
3352
4631
  const status = statusColor(r.status)(String(r.status ?? "\u2014").padStart(3));
3353
- const ms = import_chalk25.default.dim(`${r.duration_ms}ms`.padStart(8));
3354
- const step = r.error_step ? import_chalk25.default.dim(` ${r.error_step}`) : "";
4632
+ const ms = import_chalk28.default.dim(`${r.duration_ms}ms`.padStart(8));
4633
+ const step = r.error_step ? import_chalk28.default.dim(` ${r.error_step}`) : "";
3355
4634
  return `${time} ${method} ${route} ${status} ${ms}${step}`;
3356
4635
  }
3357
4636
  function printRow(r, json) {
@@ -3366,15 +4645,15 @@ var WindowNotices = class {
3366
4645
  note(res) {
3367
4646
  if (res.history_unavailable && !this.saidUnavailable) {
3368
4647
  this.saidUnavailable = true;
3369
- console.error(import_chalk25.default.yellow("\u26A0 log history is unreachable right now \u2014 showing the live buffer only, older requests exist but cannot be read."));
4648
+ console.error(import_chalk28.default.yellow("\u26A0 log history is unreachable right now \u2014 showing the live buffer only, older requests exist but cannot be read."));
3370
4649
  }
3371
4650
  if ((res.history_markers?.length ?? 0) > 0 && !this.saidGap) {
3372
4651
  this.saidGap = true;
3373
- console.error(import_chalk25.default.yellow("\u26A0 this range includes a volume-ceiling gap \u2014 some rows were dropped at intake and are gone; counts are incomplete."));
4652
+ console.error(import_chalk28.default.yellow("\u26A0 this range includes a volume-ceiling gap \u2014 some rows were dropped at intake and are gone; counts are incomplete."));
3374
4653
  }
3375
4654
  if ((res.dropped_this_hour ?? 0) > 0 && !this.saidDropped) {
3376
4655
  this.saidDropped = true;
3377
- console.error(import_chalk25.default.yellow(`\u26A0 volume ceiling \u2014 ${res.dropped_this_hour} rows dropped this hour; errors keep logging.`));
4656
+ console.error(import_chalk28.default.yellow(`\u26A0 volume ceiling \u2014 ${res.dropped_this_hour} rows dropped this hour; errors keep logging.`));
3378
4657
  }
3379
4658
  }
3380
4659
  };
@@ -3433,13 +4712,13 @@ async function runTailSession(opts) {
3433
4712
  if (!held.length && !heldRowsDropped && !heldNotesDropped) return;
3434
4713
  const rows = held.filter((h) => h.kind === "row").length;
3435
4714
  const total = rows + heldRowsDropped;
3436
- if (total) console.log(import_chalk25.default.dim(`\u2500\u2500\u2500 ${total} request${total === 1 ? "" : "s"} arrived while paused \u2500\u2500\u2500`));
4715
+ if (total) console.log(import_chalk28.default.dim(`\u2500\u2500\u2500 ${total} request${total === 1 ? "" : "s"} arrived while paused \u2500\u2500\u2500`));
3437
4716
  for (const h of held) {
3438
4717
  if (h.kind === "row") printRow(h.row, opts.json);
3439
4718
  else console.error(h.msg);
3440
4719
  }
3441
4720
  if (heldRowsDropped || heldNotesDropped) {
3442
- console.log(import_chalk25.default.dim(`\u2500\u2500\u2500 ${heldRowsDropped} older one${heldRowsDropped === 1 ? "" : "s"} not shown (pause buffer full) \u2014 browse them with \`logs list\` \u2500\u2500\u2500`));
4721
+ console.log(import_chalk28.default.dim(`\u2500\u2500\u2500 ${heldRowsDropped} older one${heldRowsDropped === 1 ? "" : "s"} not shown (pause buffer full) \u2014 browse them with \`logs list\` \u2500\u2500\u2500`));
3443
4722
  }
3444
4723
  held.length = 0;
3445
4724
  heldRowsDropped = 0;
@@ -3453,7 +4732,7 @@ async function runTailSession(opts) {
3453
4732
  activeSocket?.close();
3454
4733
  } catch {
3455
4734
  }
3456
- if (!opts.json) console.log(import_chalk25.default.dim("\nStopped."));
4735
+ if (!opts.json) console.log(import_chalk28.default.dim("\nStopped."));
3457
4736
  process.exit(0);
3458
4737
  }
3459
4738
  function onKeypress(_s, key) {
@@ -3481,17 +4760,17 @@ async function runTailSession(opts) {
3481
4760
  async function openInspector() {
3482
4761
  if (paused) return;
3483
4762
  if (recent.length === 0) {
3484
- console.log(import_chalk25.default.dim(" nothing captured yet \u2014 waiting for a request\u2026"));
4763
+ console.log(import_chalk28.default.dim(" nothing captured yet \u2014 waiting for a request\u2026"));
3485
4764
  return;
3486
4765
  }
3487
4766
  paused = true;
3488
4767
  unbindKeys();
3489
4768
  try {
3490
4769
  const { default: inquirer3 } = await import("inquirer");
3491
- console.log(import_chalk25.default.dim("\n\u2500\u2500\u2500 paused \xB7 still capturing in the background \u2500\u2500\u2500"));
4770
+ console.log(import_chalk28.default.dim("\n\u2500\u2500\u2500 paused \xB7 still capturing in the background \u2500\u2500\u2500"));
3492
4771
  for (; ; ) {
3493
4772
  const choices = recent.slice(-TAIL_INSPECT_CHOICES).reverse().map((r) => ({ name: formatRow(r), value: r.request_id }));
3494
- choices.push({ name: import_chalk25.default.dim("\u2039resume tail\u203A"), value: "__resume__" });
4773
+ choices.push({ name: import_chalk28.default.dim("\u2039resume tail\u203A"), value: "__resume__" });
3495
4774
  const { picked } = await inquirer3.prompt([{
3496
4775
  type: "list",
3497
4776
  name: "picked",
@@ -3502,12 +4781,12 @@ async function runTailSession(opts) {
3502
4781
  if (picked === "__resume__") break;
3503
4782
  const row = recent.find((r) => r.request_id === picked);
3504
4783
  if (row) printDetail(row, opts.detail);
3505
- else console.log(import_chalk25.default.dim(" that request has scrolled out of the tail buffer \u2014 find it with `logs list`.\n"));
4784
+ else console.log(import_chalk28.default.dim(" that request has scrolled out of the tail buffer \u2014 find it with `logs list`.\n"));
3506
4785
  }
3507
4786
  } finally {
3508
4787
  paused = false;
3509
4788
  flushHeld();
3510
- console.log(import_chalk25.default.dim("\u2500\u2500\u2500 resumed \u2500\u2500\u2500"));
4789
+ console.log(import_chalk28.default.dim("\u2500\u2500\u2500 resumed \u2500\u2500\u2500"));
3511
4790
  bindKeys();
3512
4791
  }
3513
4792
  }
@@ -3517,12 +4796,12 @@ async function runTailSession(opts) {
3517
4796
  if (reconnects >= MAX_RECONNECTS) {
3518
4797
  paused = false;
3519
4798
  flushHeld();
3520
- console.error(import_chalk25.default.red(`Connection lost \u2014 giving up after repeated reconnects${lastFailure ? ` (last error: ${lastFailure})` : ""}.`));
4799
+ console.error(import_chalk28.default.red(`Connection lost \u2014 giving up after repeated reconnects${lastFailure ? ` (last error: ${lastFailure})` : ""}.`));
3521
4800
  process.exit(1);
3522
4801
  }
3523
4802
  const delay = Math.min(1e3 * 2 ** reconnects, 15e3);
3524
4803
  reconnects++;
3525
- diag(import_chalk25.default.dim(`disconnected${lastFailure ? ` (${lastFailure})` : ""} \u2014 reconnecting in ${Math.round(delay / 1e3)}s\u2026`));
4804
+ diag(import_chalk28.default.dim(`disconnected${lastFailure ? ` (${lastFailure})` : ""} \u2014 reconnecting in ${Math.round(delay / 1e3)}s\u2026`));
3526
4805
  setTimeout(() => {
3527
4806
  if (!closed) void connect();
3528
4807
  }, delay);
@@ -3533,7 +4812,7 @@ async function runTailSession(opts) {
3533
4812
  url = await opts.mintTicket();
3534
4813
  } catch (err) {
3535
4814
  if (!everConnected) {
3536
- console.error(import_chalk25.default.red(`Could not start tail: ${err.message}`));
4815
+ console.error(import_chalk28.default.red(`Could not start tail: ${err.message}`));
3537
4816
  process.exit(1);
3538
4817
  }
3539
4818
  lastFailure = `ticket mint failed: ${err.message}`;
@@ -3546,7 +4825,7 @@ async function runTailSession(opts) {
3546
4825
  } catch (err) {
3547
4826
  lastFailure = `bad tail URL: ${err.message}`;
3548
4827
  if (!everConnected) {
3549
- console.error(import_chalk25.default.red(`Could not start tail: ${lastFailure}`));
4828
+ console.error(import_chalk28.default.red(`Could not start tail: ${lastFailure}`));
3550
4829
  process.exit(1);
3551
4830
  }
3552
4831
  scheduleReconnect();
@@ -3561,9 +4840,9 @@ async function runTailSession(opts) {
3561
4840
  lastInbound = Date.now();
3562
4841
  lastFailure = "";
3563
4842
  if (isReconnect) {
3564
- diag(import_chalk25.default.dim("reconnected \u2014 requests during the gap were not replayed (browse them with `logs list`)."));
4843
+ diag(import_chalk28.default.dim("reconnected \u2014 requests during the gap were not replayed (browse them with `logs list`)."));
3565
4844
  } else {
3566
- diag(import_chalk25.default.dim(interactive ? "[Enter] inspect a request \xB7 [Ctrl+C] stop\n" : "Ctrl+C to stop."));
4845
+ diag(import_chalk28.default.dim(interactive ? "[Enter] inspect a request \xB7 [Ctrl+C] stop\n" : "Ctrl+C to stop."));
3567
4846
  }
3568
4847
  bindKeys();
3569
4848
  pingTimer = setInterval(() => {
@@ -3590,7 +4869,7 @@ async function runTailSession(opts) {
3590
4869
  return;
3591
4870
  }
3592
4871
  if (frame?.type === "ceiling") {
3593
- diag(import_chalk25.default.yellow(
4872
+ diag(import_chalk28.default.yellow(
3594
4873
  `\u26A0 volume ceiling \u2014 ${Number(frame.dropped_this_hour) || 0} rows dropped this hour; errors keep streaming.`
3595
4874
  ));
3596
4875
  return;
@@ -3670,10 +4949,10 @@ async function fetchPage(fetchWindow3, params, notices) {
3670
4949
  return { rows, nextCursor: res.next_cursor ?? void 0 };
3671
4950
  }
3672
4951
  if (hop >= MAX_EMPTY_HOPS) {
3673
- console.error(import_chalk25.default.yellow("\u26A0 stopped after scanning a long empty span \u2014 older rows may still exist."));
4952
+ console.error(import_chalk28.default.yellow("\u26A0 stopped after scanning a long empty span \u2014 older rows may still exist."));
3674
4953
  return { rows: [], nextCursor: res.next_cursor, fuseTripped: true };
3675
4954
  }
3676
- if (hop === 0) console.error(import_chalk25.default.dim("searching older history\u2026"));
4955
+ if (hop === 0) console.error(import_chalk28.default.dim("searching older history\u2026"));
3677
4956
  cursor = res.next_cursor;
3678
4957
  }
3679
4958
  }
@@ -3713,18 +4992,18 @@ async function runPlainList(opts, notices) {
3713
4992
  }
3714
4993
  }
3715
4994
  if (rows.length === 0) {
3716
- console.log(import_chalk25.default.dim(fuseTripped ? "Nothing found in the scanned span \u2014 older requests may still exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
4995
+ console.log(import_chalk28.default.dim(fuseTripped ? "Nothing found in the scanned span \u2014 older requests may still exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
3717
4996
  return;
3718
4997
  }
3719
4998
  const now = Date.now();
3720
4999
  for (const d of groupIntoDays(rows)) {
3721
- console.log(import_chalk25.default.bold(dayLabel(d.dayMs, now)));
5000
+ console.log(import_chalk28.default.bold(dayLabel(d.dayMs, now)));
3722
5001
  for (const r of d.rows) console.log(` ${formatRow(r)}`);
3723
5002
  console.log("");
3724
5003
  }
3725
5004
  const errs = rows.filter((r) => r.status >= 400).length;
3726
5005
  const tail = fuseTripped ? " \xB7 stopped early (long empty span) \u2014 older requests may still exist" : more ? " \xB7 showing the most recent \u2014 `--json` streams the rest" : "";
3727
- console.log(import_chalk25.default.dim(
5006
+ console.log(import_chalk28.default.dim(
3728
5007
  `${rows.length} request${rows.length === 1 ? "" : "s"} \xB7 ${errs} error${errs === 1 ? "" : "s"}${tail}`
3729
5008
  ));
3730
5009
  }
@@ -3743,7 +5022,7 @@ async function runHistoryBrowser(opts) {
3743
5022
  for (const r of page.rows) console.log(JSON.stringify(r));
3744
5023
  any = any || page.rows.length > 0;
3745
5024
  if (page.fuseTripped || !page.nextCursor) {
3746
- if (!any && !page.fuseTripped) console.error(import_chalk25.default.dim(opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
5025
+ if (!any && !page.fuseTripped) console.error(import_chalk28.default.dim(opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
3747
5026
  return;
3748
5027
  }
3749
5028
  cursor2 = page.nextCursor;
@@ -3764,7 +5043,7 @@ async function runHistoryBrowser(opts) {
3764
5043
  scanRows = first.rows;
3765
5044
  scanCursor = first.nextCursor;
3766
5045
  if (scanRows.length === 0) {
3767
- console.log(import_chalk25.default.dim(first.fuseTripped ? "Nothing found in the scanned span \u2014 older rows may exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
5046
+ console.log(import_chalk28.default.dim(first.fuseTripped ? "Nothing found in the scanned span \u2014 older rows may exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
3768
5047
  return;
3769
5048
  }
3770
5049
  }
@@ -3775,10 +5054,10 @@ async function runHistoryBrowser(opts) {
3775
5054
  const now2 = Date.now();
3776
5055
  const oldestKey = days[days.length - 1]?.key;
3777
5056
  const choices = days.map((d) => ({
3778
- name: `${dayLabel(d.dayMs, now2).padEnd(12)} ${String(d.rows.length).padStart(4)}${(scanCursor !== void 0 || scanFloorUnknown) && d.key === oldestKey ? "+" : ""} requests${d.errors ? import_chalk25.default.red(` ${d.errors} errors`) : ""}`,
5057
+ name: `${dayLabel(d.dayMs, now2).padEnd(12)} ${String(d.rows.length).padStart(4)}${(scanCursor !== void 0 || scanFloorUnknown) && d.key === oldestKey ? "+" : ""} requests${d.errors ? import_chalk28.default.red(` ${d.errors} errors`) : ""}`,
3779
5058
  value: d.key
3780
5059
  }));
3781
- if (scanCursor) choices.push({ name: import_chalk25.default.dim("\u2026 older days"), value: "__older__" });
5060
+ if (scanCursor) choices.push({ name: import_chalk28.default.dim("\u2026 older days"), value: "__older__" });
3782
5061
  const { chosenDay } = await inquirer3.prompt([{
3783
5062
  type: "list",
3784
5063
  name: "chosenDay",
@@ -3798,7 +5077,7 @@ async function runHistoryBrowser(opts) {
3798
5077
  scanCursor = void 0;
3799
5078
  } else {
3800
5079
  scanCursor = more.nextCursor;
3801
- if (more.rows.length === 0 && !scanCursor) console.log(import_chalk25.default.dim("That was everything \u2014 no older requests."));
5080
+ if (more.rows.length === 0 && !scanCursor) console.log(import_chalk28.default.dim("That was everything \u2014 no older requests."));
3802
5081
  }
3803
5082
  continue;
3804
5083
  }
@@ -3820,11 +5099,11 @@ async function runHistoryBrowser(opts) {
3820
5099
  cursor
3821
5100
  }, notices);
3822
5101
  if (page.rows.length === 0 && pageRows.length === 0) {
3823
- console.log(import_chalk25.default.dim(page.fuseTripped ? "Stopped scanning this day (long empty span) \u2014 older rows in it may exist." : "No requests for this day."));
5102
+ console.log(import_chalk28.default.dim(page.fuseTripped ? "Stopped scanning this day (long empty span) \u2014 older rows in it may exist." : "No requests for this day."));
3824
5103
  return;
3825
5104
  }
3826
5105
  if (page.rows.length === 0) {
3827
- console.log(import_chalk25.default.dim(page.fuseTripped ? "Stopped scanning further into this day (long empty span) \u2014 older rows in it may exist." : "That was everything for this day."));
5106
+ console.log(import_chalk28.default.dim(page.fuseTripped ? "Stopped scanning further into this day (long empty span) \u2014 older rows in it may exist." : "That was everything for this day."));
3828
5107
  moreCursor = void 0;
3829
5108
  } else {
3830
5109
  pageRows = page.rows;
@@ -3835,8 +5114,8 @@ async function runHistoryBrowser(opts) {
3835
5114
  name: formatRow(r),
3836
5115
  value: r.request_id
3837
5116
  }));
3838
- if (moreCursor) choices.push({ name: import_chalk25.default.dim("\u2026 load more"), value: "__more__" });
3839
- choices.push({ name: import_chalk25.default.dim("quit"), value: "__quit__" });
5117
+ if (moreCursor) choices.push({ name: import_chalk28.default.dim("\u2026 load more"), value: "__more__" });
5118
+ choices.push({ name: import_chalk28.default.dim("quit"), value: "__quit__" });
3840
5119
  for (; ; ) {
3841
5120
  const { picked } = await inquirer3.prompt([{
3842
5121
  type: "list",
@@ -3886,19 +5165,19 @@ function wrapCells(items, width) {
3886
5165
  ${PANE_INDENT}`);
3887
5166
  }
3888
5167
  function renderHeaders(h) {
3889
- if (!h) return import_chalk25.default.dim("\u2014");
5168
+ if (!h) return import_chalk28.default.dim("\u2014");
3890
5169
  const width = process.stdout.columns || 100;
3891
5170
  if (h.values) {
3892
5171
  const e = Object.entries(h.values);
3893
- if (!e.length) return import_chalk25.default.dim("none");
5172
+ if (!e.length) return import_chalk28.default.dim("none");
3894
5173
  const rank = (k) => {
3895
5174
  const i = HEADER_PRIORITY.indexOf(k.toLowerCase());
3896
5175
  return i === -1 ? NOISE_HEADER.test(k) ? 999 : 500 : i;
3897
5176
  };
3898
- return e.sort((a, b) => rank(a[0]) - rank(b[0])).map(([k, v]) => `${import_chalk25.default.dim(k + ":")} ${v}`).join(`
5177
+ return e.sort((a, b) => rank(a[0]) - rank(b[0])).map(([k, v]) => `${import_chalk28.default.dim(k + ":")} ${v}`).join(`
3899
5178
  ${PANE_INDENT}`);
3900
5179
  }
3901
- if (!h.names?.length) return import_chalk25.default.dim("none");
5180
+ if (!h.names?.length) return import_chalk28.default.dim("none");
3902
5181
  const names = [...h.names];
3903
5182
  const noise = names.filter((n) => NOISE_HEADER.test(n));
3904
5183
  const shown = names.filter((n) => !NOISE_HEADER.test(n)).sort((a, b) => {
@@ -3906,70 +5185,70 @@ ${PANE_INDENT}`);
3906
5185
  const ib = HEADER_PRIORITY.indexOf(b.toLowerCase());
3907
5186
  return (ia === -1 ? 500 : ia) - (ib === -1 ? 500 : ib) || a.localeCompare(b);
3908
5187
  });
3909
- const body = shown.length ? wrapCells(shown, width) : import_chalk25.default.dim("(all forwarding headers)");
5188
+ const body = shown.length ? wrapCells(shown, width) : import_chalk28.default.dim("(all forwarding headers)");
3910
5189
  const tail = noise.length ? `
3911
- ${PANE_INDENT}${import_chalk25.default.dim(`+ ${noise.length} forwarding/client-hint header${noise.length === 1 ? "" : "s"} (cf-*, sec-*)`)}` : "";
3912
- return `${body}${tail} ${import_chalk25.default.dim("(names only)")}`;
5190
+ ${PANE_INDENT}${import_chalk28.default.dim(`+ ${noise.length} forwarding/client-hint header${noise.length === 1 ? "" : "s"} (cf-*, sec-*)`)}` : "";
5191
+ return `${body}${tail} ${import_chalk28.default.dim("(names only)")}`;
3913
5192
  }
3914
5193
  function renderBody(b) {
3915
- if (!b) return import_chalk25.default.dim("\u2014");
5194
+ if (!b) return import_chalk28.default.dim("\u2014");
3916
5195
  const meta = [b.content_type, b.size != null ? `${b.size}B` : null, b.truncated ? "truncated" : null].filter(Boolean).join(" \xB7 ");
3917
- if (b.not_captured) return import_chalk25.default.dim(`not captured (${b.not_captured})${meta ? " \xB7 " + meta : ""}`);
5196
+ if (b.not_captured) return import_chalk28.default.dim(`not captured (${b.not_captured})${meta ? " \xB7 " + meta : ""}`);
3918
5197
  const isShape = b.value === void 0 && b.shape !== void 0;
3919
5198
  const content = b.value !== void 0 ? b.value : b.shape;
3920
5199
  if (content === null || content === void 0 || content === "" || content === "empty") {
3921
- return import_chalk25.default.dim(`empty${meta ? " \xB7 " + meta : ""}`);
5200
+ return import_chalk28.default.dim(`empty${meta ? " \xB7 " + meta : ""}`);
3922
5201
  }
3923
5202
  const text = typeof content === "string" ? content : JSON.stringify(content, null, 2);
3924
- const head = isShape ? import_chalk25.default.dim("shape only (values not captured)\n ") : "";
5203
+ const head = isShape ? import_chalk28.default.dim("shape only (values not captured)\n ") : "";
3925
5204
  return head + text.split("\n").join("\n ");
3926
5205
  }
3927
5206
  function pane(title, tone, view, empty) {
3928
5207
  console.log(` ${tone(title)}`);
3929
5208
  if (empty !== void 0) {
3930
- console.log(` ${import_chalk25.default.dim(empty)}`);
5209
+ console.log(` ${import_chalk28.default.dim(empty)}`);
3931
5210
  return;
3932
5211
  }
3933
5212
  const v = view ?? {};
3934
- if (v.url) console.log(` ${import_chalk25.default.dim("target")} ${v.url}`);
5213
+ if (v.url) console.log(` ${import_chalk28.default.dim("target")} ${v.url}`);
3935
5214
  if (v.status != null) {
3936
- console.log(` ${import_chalk25.default.dim("status")} ${statusColor(v.status)(String(v.status))}${v.status_text ? import_chalk25.default.dim(" " + v.status_text) : ""}`);
5215
+ console.log(` ${import_chalk28.default.dim("status")} ${statusColor(v.status)(String(v.status))}${v.status_text ? import_chalk28.default.dim(" " + v.status_text) : ""}`);
3937
5216
  }
3938
- if (v.raw_path) console.log(` ${import_chalk25.default.dim("path")} ${v.raw_path}`);
5217
+ if (v.raw_path) console.log(` ${import_chalk28.default.dim("path")} ${v.raw_path}`);
3939
5218
  if (v.query && Object.keys(v.query).length) {
3940
- console.log(` ${import_chalk25.default.dim("query")} ${Object.entries(v.query).map(([k, q]) => `${k}=${q}`).join(" ")}`);
5219
+ console.log(` ${import_chalk28.default.dim("query")} ${Object.entries(v.query).map(([k, q]) => `${k}=${q}`).join(" ")}`);
3941
5220
  }
3942
- if (v.jwt !== void 0) console.log(` ${import_chalk25.default.dim("jwt")} ${JSON.stringify(v.jwt)}`);
3943
- console.log(` ${import_chalk25.default.dim("headers")} ${renderHeaders(v.headers)}`);
3944
- console.log(` ${import_chalk25.default.dim("body")} ${renderBody(v.body)}`);
5221
+ if (v.jwt !== void 0) console.log(` ${import_chalk28.default.dim("jwt")} ${JSON.stringify(v.jwt)}`);
5222
+ console.log(` ${import_chalk28.default.dim("headers")} ${renderHeaders(v.headers)}`);
5223
+ console.log(` ${import_chalk28.default.dim("body")} ${renderBody(v.body)}`);
3945
5224
  }
3946
5225
  function printDetail(r, mode = "producer") {
3947
5226
  const v = r.views;
3948
5227
  console.log("");
3949
- console.log(import_chalk25.default.bold(`${r.method} ${r.route}`) + " " + statusColor(r.status)(String(r.status)) + import_chalk25.default.dim(` ${r.duration_ms}ms`));
5228
+ console.log(import_chalk28.default.bold(`${r.method} ${r.route}`) + " " + statusColor(r.status)(String(r.status)) + import_chalk28.default.dim(` ${r.duration_ms}ms`));
3950
5229
  const cost = typeof r.cost_cents === "number" && r.cost_cents > 0 ? ` \xB7 ${r.cost_cents}\xA2` : "";
3951
- console.log(import_chalk25.default.dim(` request_id ${r.request_id}${r.environment ? ` \xB7 env ${r.environment}` : ""}${r.consumer_id ? ` \xB7 consumer ${r.consumer_id}` : ""}${cost}`));
5230
+ console.log(import_chalk28.default.dim(` request_id ${r.request_id}${r.environment ? ` \xB7 env ${r.environment}` : ""}${r.consumer_id ? ` \xB7 consumer ${r.consumer_id}` : ""}${cost}`));
3952
5231
  console.log("");
3953
5232
  if (!v) {
3954
- console.log(import_chalk25.default.dim(" No view detail captured for this request.\n"));
5233
+ console.log(import_chalk28.default.dim(" No view detail captured for this request.\n"));
3955
5234
  return;
3956
5235
  }
3957
- pane("Request (before) \u2014 client \u2192 APIblaze", import_chalk25.default.cyan, v.request);
5236
+ pane("Request (before) \u2014 client \u2192 APIblaze", import_chalk28.default.cyan, v.request);
3958
5237
  if (mode === "producer") {
3959
5238
  pane(
3960
5239
  "Request (after) \u2014 APIblaze \u2192 upstream",
3961
- import_chalk25.default.cyan,
5240
+ import_chalk28.default.cyan,
3962
5241
  v.forwarded_request,
3963
5242
  v.forwarded_request ? void 0 : "Request did not reach an upstream."
3964
5243
  );
3965
5244
  pane(
3966
5245
  "Response (before) \u2014 upstream \u2192 APIblaze",
3967
- import_chalk25.default.magenta,
5246
+ import_chalk28.default.magenta,
3968
5247
  v.upstream_response,
3969
5248
  v.upstream_response ? void 0 : "No upstream response."
3970
5249
  );
3971
5250
  }
3972
- pane("Response (after) \u2014 APIblaze \u2192 client", import_chalk25.default.magenta, v.response);
5251
+ pane("Response (after) \u2014 APIblaze \u2192 client", import_chalk28.default.magenta, v.response);
3973
5252
  console.log("");
3974
5253
  }
3975
5254
 
@@ -4018,7 +5297,7 @@ async function resolve(projectArg, versionArg, opts) {
4018
5297
  return { projectId, projectName: match.projectName, version: version2, tenant: tenant2 };
4019
5298
  }
4020
5299
  function otherPlaneHint() {
4021
- if (loadConsumer()) console.log(import_chalk26.default.dim(" \u2039consumer view: apiblaze consumer logs\u203A"));
5300
+ if (loadConsumer()) console.log(import_chalk29.default.dim(" \u2039consumer view: apiblaze consumer logs\u203A"));
4022
5301
  }
4023
5302
  function fetchWindow(projectId, version2, tenant2) {
4024
5303
  return (params) => {
@@ -4037,8 +5316,8 @@ function fetchWindow(projectId, version2, tenant2) {
4037
5316
  async function runLogsTail(projectArg, versionArg, opts) {
4038
5317
  const { projectId, projectName, version: version2, tenant: tenant2 } = await resolve(projectArg, versionArg, opts);
4039
5318
  if (!opts.json) {
4040
- console.log(import_chalk26.default.bold("API Producer logs") + import_chalk26.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant2}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
4041
- console.log(import_chalk26.default.dim("every caller's requests, with cost and upstream detail"));
5319
+ console.log(import_chalk29.default.bold("API Producer logs") + import_chalk29.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant2}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
5320
+ console.log(import_chalk29.default.dim("every caller's requests, with cost and upstream detail"));
4042
5321
  otherPlaneHint();
4043
5322
  }
4044
5323
  await runTailSession({
@@ -4059,8 +5338,8 @@ async function runLogsTail(projectArg, versionArg, opts) {
4059
5338
  async function runLogsList(projectArg, versionArg, opts) {
4060
5339
  const { projectId, projectName, version: version2, tenant: tenant2 } = await resolve(projectArg, versionArg, opts);
4061
5340
  if (!opts.json) {
4062
- console.log(import_chalk26.default.bold("API Producer logs") + import_chalk26.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant2}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
4063
- console.log(import_chalk26.default.dim("every caller's requests, with cost and upstream detail"));
5341
+ console.log(import_chalk29.default.bold("API Producer logs") + import_chalk29.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant2}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
5342
+ console.log(import_chalk29.default.dim("every caller's requests, with cost and upstream detail"));
4064
5343
  otherPlaneHint();
4065
5344
  console.log("");
4066
5345
  }
@@ -4074,15 +5353,15 @@ async function runLogsList(projectArg, versionArg, opts) {
4074
5353
  }
4075
5354
 
4076
5355
  // src/commands/consumer-logs.ts
4077
- var import_chalk27 = __toESM(require("chalk"));
5356
+ var import_chalk30 = __toESM(require("chalk"));
4078
5357
  init_auth();
4079
5358
  var CONSUMER_LOGS_BASE = process.env.APIBLAZE_CONSUMER_LOGS_BASE || "https://logs.apiblaze.com/consumer";
4080
5359
  function requireConsumer() {
4081
5360
  const c = loadConsumer();
4082
5361
  if (!c) {
4083
- console.error(import_chalk27.default.red("Not logged in as an API Consumer. Run `apiblaze consumer login` first."));
5362
+ console.error(import_chalk30.default.red("Not logged in as an API Consumer. Run `apiblaze consumer login` first."));
4084
5363
  if (loadCredentials()) {
4085
- console.error(import_chalk27.default.dim("You're signed in as an API Producer \u2014 for a proxy's full logs run `apiblaze logs <project>`."));
5364
+ console.error(import_chalk30.default.dim("You're signed in as an API Producer \u2014 for a proxy's full logs run `apiblaze logs <project>`."));
4086
5365
  }
4087
5366
  process.exit(1);
4088
5367
  }
@@ -4113,7 +5392,7 @@ async function consumerLogsFetch(session, suffix, init) {
4113
5392
  return data;
4114
5393
  }
4115
5394
  function otherPlaneHint2() {
4116
- if (loadCredentials()) console.log(import_chalk27.default.dim(" \u2039producer view: apiblaze logs <project>\u203A"));
5395
+ if (loadCredentials()) console.log(import_chalk30.default.dim(" \u2039producer view: apiblaze logs <project>\u203A"));
4117
5396
  }
4118
5397
  function fetchWindow2(session, project) {
4119
5398
  return (params) => {
@@ -4129,8 +5408,8 @@ function fetchWindow2(session, project) {
4129
5408
  async function runConsumerLogsTail(opts) {
4130
5409
  const session = requireConsumer();
4131
5410
  if (!opts.json) {
4132
- console.log(import_chalk27.default.bold("API Consumer logs") + import_chalk27.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
4133
- console.log(import_chalk27.default.dim("cost and upstream details are producer-only and are not sent"));
5411
+ console.log(import_chalk30.default.bold("API Consumer logs") + import_chalk30.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
5412
+ console.log(import_chalk30.default.dim("cost and upstream details are producer-only and are not sent"));
4134
5413
  otherPlaneHint2();
4135
5414
  }
4136
5415
  await runTailSession({
@@ -4148,8 +5427,8 @@ async function runConsumerLogsTail(opts) {
4148
5427
  async function runConsumerLogsList(opts) {
4149
5428
  const session = requireConsumer();
4150
5429
  if (!opts.json) {
4151
- console.log(import_chalk27.default.bold("API Consumer logs") + import_chalk27.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
4152
- console.log(import_chalk27.default.dim("cost and upstream details are producer-only and are not sent"));
5430
+ console.log(import_chalk30.default.bold("API Consumer logs") + import_chalk30.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
5431
+ console.log(import_chalk30.default.dim("cost and upstream details are producer-only and are not sent"));
4153
5432
  otherPlaneHint2();
4154
5433
  console.log("");
4155
5434
  }
@@ -4163,14 +5442,14 @@ async function runConsumerLogsList(opts) {
4163
5442
  }
4164
5443
 
4165
5444
  // src/commands/config.ts
4166
- var import_chalk28 = __toESM(require("chalk"));
4167
- var import_ora8 = __toESM(require("ora"));
5445
+ var import_chalk31 = __toESM(require("chalk"));
5446
+ var import_ora10 = __toESM(require("ora"));
4168
5447
  init_admin();
4169
5448
  init_resolve();
4170
5449
  async function patchConfig(project, opts, body, summary) {
4171
5450
  const { teamId } = await resolveTeam(opts.team);
4172
5451
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
4173
- const spinner = (0, import_ora8.default)(summary + "...").start();
5452
+ const spinner = (0, import_ora10.default)(summary + "...").start();
4174
5453
  try {
4175
5454
  const out = await admin({
4176
5455
  method: "PATCH",
@@ -4187,7 +5466,7 @@ async function patchConfig(project, opts, body, summary) {
4187
5466
  }
4188
5467
  async function runTargetSet(project, opts) {
4189
5468
  if (!opts.url) {
4190
- console.error(import_chalk28.default.red("--url is required."));
5469
+ console.error(import_chalk31.default.red("--url is required."));
4191
5470
  process.exit(1);
4192
5471
  }
4193
5472
  const body = opts.env ? { environments: { [opts.env]: { target: opts.url } } } : { target_url: opts.url };
@@ -4200,45 +5479,45 @@ async function runThrottleSet(project, opts) {
4200
5479
  if (opts.quota !== void 0) throttling.proxyQuota = Number(opts.quota);
4201
5480
  if (opts.period !== void 0) {
4202
5481
  if (!["daily", "weekly", "monthly"].includes(opts.period)) {
4203
- console.error(import_chalk28.default.red("--period must be daily, weekly, or monthly."));
5482
+ console.error(import_chalk31.default.red("--period must be daily, weekly, or monthly."));
4204
5483
  process.exit(1);
4205
5484
  }
4206
5485
  throttling.quotaPeriod = opts.period;
4207
5486
  }
4208
5487
  if (Object.keys(throttling).length === 0) {
4209
- console.error(import_chalk28.default.red("Nothing to set. Pass at least one of --rate, --end-user-rate, --quota, --period."));
5488
+ console.error(import_chalk31.default.red("Nothing to set. Pass at least one of --rate, --end-user-rate, --quota, --period."));
4210
5489
  process.exit(1);
4211
5490
  }
4212
5491
  await patchConfig(project, opts, { throttling }, `Update throttling ${JSON.stringify(throttling)}`);
4213
5492
  }
4214
5493
  async function runRename(project, opts) {
4215
5494
  if (!opts.displayName) {
4216
- console.error(import_chalk28.default.red("--display-name is required."));
5495
+ console.error(import_chalk31.default.red("--display-name is required."));
4217
5496
  process.exit(1);
4218
5497
  }
4219
5498
  await patchConfig(project, opts, { display_name: opts.displayName }, `Rename \u2192 "${opts.displayName}"`);
4220
5499
  }
4221
5500
 
4222
5501
  // src/commands/config-browse.ts
4223
- var import_chalk37 = __toESM(require("chalk"));
4224
- var import_ora16 = __toESM(require("ora"));
5502
+ var import_chalk40 = __toESM(require("chalk"));
5503
+ var import_ora18 = __toESM(require("ora"));
4225
5504
  init_admin();
4226
5505
  init_auth();
4227
5506
  init_resolve();
4228
5507
 
4229
5508
  // src/commands/domain.ts
4230
- var import_chalk29 = __toESM(require("chalk"));
4231
- var import_ora9 = __toESM(require("ora"));
5509
+ var import_chalk32 = __toESM(require("chalk"));
5510
+ var import_ora11 = __toESM(require("ora"));
4232
5511
  init_admin();
4233
5512
  init_resolve();
4234
5513
  async function runDomainAdd(project, opts) {
4235
5514
  if (!opts.domain) {
4236
- console.error(import_chalk29.default.red("--domain is required."));
5515
+ console.error(import_chalk32.default.red("--domain is required."));
4237
5516
  process.exit(1);
4238
5517
  }
4239
5518
  const { teamId } = await resolveTeam(opts.team);
4240
5519
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
4241
- const spinner = (0, import_ora9.default)(`Registering ${opts.domain}...`).start();
5520
+ const spinner = (0, import_ora11.default)(`Registering ${opts.domain}...`).start();
4242
5521
  try {
4243
5522
  const out = await admin({
4244
5523
  method: "POST",
@@ -4252,9 +5531,9 @@ async function runDomainAdd(project, opts) {
4252
5531
  console.log(JSON.stringify(out));
4253
5532
  return;
4254
5533
  }
4255
- if (out?.cnameRecord) console.log(` ${import_chalk29.default.cyan("CNAME")} ${out.cnameRecord.name ?? opts.domain} \u2192 ${out.cnameRecord.value ?? out.cnameRecord.target}`);
4256
- if (out?.dcv) console.log(` ${import_chalk29.default.cyan("TXT")} ${out.dcv.name} = ${out.dcv.value}`);
4257
- if (out?.id) console.log(import_chalk29.default.dim(` domain id: ${out.id}`));
5534
+ if (out?.cnameRecord) console.log(` ${import_chalk32.default.cyan("CNAME")} ${out.cnameRecord.name ?? opts.domain} \u2192 ${out.cnameRecord.value ?? out.cnameRecord.target}`);
5535
+ if (out?.dcv) console.log(` ${import_chalk32.default.cyan("TXT")} ${out.dcv.name} = ${out.dcv.value}`);
5536
+ if (out?.id) console.log(import_chalk32.default.dim(` domain id: ${out.id}`));
4258
5537
  } catch (err) {
4259
5538
  spinner.fail("Domain registration failed.");
4260
5539
  throw err;
@@ -4274,14 +5553,14 @@ async function runDomainList(project, opts) {
4274
5553
  return;
4275
5554
  }
4276
5555
  if (!domains.length) {
4277
- console.log(import_chalk29.default.yellow("No custom domains."));
5556
+ console.log(import_chalk32.default.yellow("No custom domains."));
4278
5557
  return;
4279
5558
  }
4280
- for (const d of domains) console.log(` ${import_chalk29.default.bold(d.hostname)} ${import_chalk29.default.dim(d.status ?? "")} ${import_chalk29.default.dim(d.id ?? "")}`);
5559
+ for (const d of domains) console.log(` ${import_chalk32.default.bold(d.hostname)} ${import_chalk32.default.dim(d.status ?? "")} ${import_chalk32.default.dim(d.id ?? "")}`);
4281
5560
  }
4282
5561
  async function runDomainStatus(project, opts) {
4283
5562
  if (!opts.id) {
4284
- console.error(import_chalk29.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
5563
+ console.error(import_chalk32.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
4285
5564
  process.exit(1);
4286
5565
  }
4287
5566
  const { teamId } = await resolveTeam(opts.team);
@@ -4291,16 +5570,16 @@ async function runDomainStatus(project, opts) {
4291
5570
  path: `/projects/${proj2.projectId}/domains/${encodeURIComponent(opts.id)}/status`,
4292
5571
  summary: `Check custom-domain status`
4293
5572
  });
4294
- console.log(opts.json ? JSON.stringify(out) : ` ${import_chalk29.default.bold(out?.hostname ?? opts.id)}: ${import_chalk29.default.cyan(out?.status ?? "unknown")}`);
5573
+ console.log(opts.json ? JSON.stringify(out) : ` ${import_chalk32.default.bold(out?.hostname ?? opts.id)}: ${import_chalk32.default.cyan(out?.status ?? "unknown")}`);
4295
5574
  }
4296
5575
  async function runDomainRemove(project, opts) {
4297
5576
  if (!opts.id) {
4298
- console.error(import_chalk29.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
5577
+ console.error(import_chalk32.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
4299
5578
  process.exit(1);
4300
5579
  }
4301
5580
  const { teamId } = await resolveTeam(opts.team);
4302
5581
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
4303
- const spinner = (0, import_ora9.default)("Removing domain...").start();
5582
+ const spinner = (0, import_ora11.default)("Removing domain...").start();
4304
5583
  try {
4305
5584
  await admin({
4306
5585
  method: "DELETE",
@@ -4317,7 +5596,7 @@ async function runDomainSetBase(project, opts) {
4317
5596
  const env = opts.env ?? "prod";
4318
5597
  const { teamId } = await resolveTeam(opts.team);
4319
5598
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
4320
- const spinner = (0, import_ora9.default)("Setting base domain...").start();
5599
+ const spinner = (0, import_ora11.default)("Setting base domain...").start();
4321
5600
  try {
4322
5601
  await admin({
4323
5602
  method: "PUT",
@@ -4333,8 +5612,8 @@ async function runDomainSetBase(project, opts) {
4333
5612
  }
4334
5613
 
4335
5614
  // src/commands/tenant.ts
4336
- var import_chalk32 = __toESM(require("chalk"));
4337
- var import_ora12 = __toESM(require("ora"));
5615
+ var import_chalk35 = __toESM(require("chalk"));
5616
+ var import_ora14 = __toESM(require("ora"));
4338
5617
  init_admin();
4339
5618
  init_resolve();
4340
5619
  init_auth();
@@ -4342,20 +5621,20 @@ init_tenant_pick();
4342
5621
  async function runTenantUse(query, opts) {
4343
5622
  const creds = loadCredentials();
4344
5623
  if (!creds) {
4345
- console.error(import_chalk32.default.red("Not logged in. Run `apiblaze login` first."));
5624
+ console.error(import_chalk35.default.red("Not logged in. Run `apiblaze login` first."));
4346
5625
  process.exit(1);
4347
5626
  }
4348
5627
  if (opts.clear) {
4349
5628
  delete creds.activeTenant;
4350
5629
  saveCredentials(creds);
4351
- console.log(import_chalk32.default.green("Tenant scope cleared."));
5630
+ console.log(import_chalk35.default.green("Tenant scope cleared."));
4352
5631
  return;
4353
5632
  }
4354
5633
  const { teamId } = await resolveTeam(opts.team);
4355
5634
  const slug = await pickTenant(teamId, { message: "Scope future commands to which tenant?", initialQuery: query });
4356
5635
  if (!slug) process.exit(1);
4357
5636
  saveCredentials({ ...creds, activeTenant: slug });
4358
- console.log(import_chalk32.default.green(`Tenant scope set to ${import_chalk32.default.bold(slug)}.`) + import_chalk32.default.dim(" (clear with `apiblaze tenant use --clear`)"));
5637
+ console.log(import_chalk35.default.green(`Tenant scope set to ${import_chalk35.default.bold(slug)}.`) + import_chalk35.default.dim(" (clear with `apiblaze tenant use --clear`)"));
4359
5638
  }
4360
5639
  async function runTenantList(opts) {
4361
5640
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -4372,26 +5651,26 @@ async function runTenantList(opts) {
4372
5651
  return;
4373
5652
  }
4374
5653
  if (!tenants.length) {
4375
- console.log(import_chalk32.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
5654
+ console.log(import_chalk35.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
4376
5655
  return;
4377
5656
  }
4378
5657
  for (const t of tenants) {
4379
5658
  const name = typeof t === "string" ? t : t.tenant_name;
4380
- const display = typeof t === "string" ? "" : import_chalk32.default.dim(` ${t.display_name ?? ""}`);
4381
- console.log(` ${import_chalk32.default.bold(name)}${display}`);
5659
+ const display = typeof t === "string" ? "" : import_chalk35.default.dim(` ${t.display_name ?? ""}`);
5660
+ console.log(` ${import_chalk35.default.bold(name)}${display}`);
4382
5661
  }
4383
5662
  const total = out?.total ?? tenants.length;
4384
5663
  if (total > tenants.length) {
4385
- console.log(import_chalk32.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
5664
+ console.log(import_chalk35.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
4386
5665
  }
4387
5666
  }
4388
5667
  async function runTenantCreate(opts) {
4389
5668
  if (!opts.name) {
4390
- console.error(import_chalk32.default.red("--name (display name) is required."));
5669
+ console.error(import_chalk35.default.red("--name (display name) is required."));
4391
5670
  process.exit(1);
4392
5671
  }
4393
5672
  const { teamId } = await resolveTeam(opts.team);
4394
- const spinner = (0, import_ora12.default)("Creating tenant...").start();
5673
+ const spinner = (0, import_ora14.default)("Creating tenant...").start();
4395
5674
  try {
4396
5675
  const out = await admin({
4397
5676
  method: "POST",
@@ -4399,7 +5678,7 @@ async function runTenantCreate(opts) {
4399
5678
  body: { display_name: opts.name, ...opts.slug ? { tenant_name: opts.slug } : {} },
4400
5679
  summary: `Create tenant "${opts.name}"`
4401
5680
  });
4402
- spinner.succeed(`Created tenant ${import_chalk32.default.bold(out?.tenant_name ?? opts.name)}.`);
5681
+ spinner.succeed(`Created tenant ${import_chalk35.default.bold(out?.tenant_name ?? opts.name)}.`);
4403
5682
  if (opts.json) console.log(JSON.stringify(out));
4404
5683
  } catch (err) {
4405
5684
  spinner.fail("Tenant create failed.");
@@ -4408,12 +5687,12 @@ async function runTenantCreate(opts) {
4408
5687
  }
4409
5688
  async function runTenantAttach(project, opts) {
4410
5689
  if (!opts.tenant) {
4411
- console.error(import_chalk32.default.red("--tenant <slug> is required."));
5690
+ console.error(import_chalk35.default.red("--tenant <slug> is required."));
4412
5691
  process.exit(1);
4413
5692
  }
4414
5693
  const { teamId } = await resolveTeam(opts.team);
4415
5694
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
4416
- const spinner = (0, import_ora12.default)("Attaching tenant...").start();
5695
+ const spinner = (0, import_ora14.default)("Attaching tenant...").start();
4417
5696
  try {
4418
5697
  const out = await admin({
4419
5698
  method: "POST",
@@ -4432,15 +5711,15 @@ async function runTenantDelete(slug, opts) {
4432
5711
  const { teamId } = await resolveTeam(opts.team);
4433
5712
  if (!opts.yes && !opts.json) {
4434
5713
  const { default: inquirer3 } = await import("inquirer");
4435
- const { confirm } = await inquirer3.prompt([
5714
+ const { confirm: confirm2 } = await inquirer3.prompt([
4436
5715
  { type: "confirm", name: "confirm", message: `Permanently delete tenant "${slug}" and everything under it? This cannot be undone.`, default: false }
4437
5716
  ]);
4438
- if (!confirm) {
4439
- console.log(import_chalk32.default.dim("Aborted."));
5717
+ if (!confirm2) {
5718
+ console.log(import_chalk35.default.dim("Aborted."));
4440
5719
  return;
4441
5720
  }
4442
5721
  }
4443
- const spinner = (0, import_ora12.default)("Deleting tenant...").start();
5722
+ const spinner = (0, import_ora14.default)("Deleting tenant...").start();
4444
5723
  try {
4445
5724
  await admin({
4446
5725
  method: "DELETE",
@@ -4455,13 +5734,13 @@ async function runTenantDelete(slug, opts) {
4455
5734
  }
4456
5735
  async function runTenantCors(opts) {
4457
5736
  if (!opts.tenant) {
4458
- console.error(import_chalk32.default.red("--tenant <slug> is required."));
5737
+ console.error(import_chalk35.default.red("--tenant <slug> is required."));
4459
5738
  process.exit(1);
4460
5739
  }
4461
5740
  const { teamId } = await resolveTeam(opts.team);
4462
5741
  const origins = (opts.origins ?? "").split(",").map((s) => s.trim()).filter(Boolean);
4463
5742
  const cors = origins.length ? { allowed_origins: origins } : null;
4464
- const spinner = (0, import_ora12.default)("Updating CORS...").start();
5743
+ const spinner = (0, import_ora14.default)("Updating CORS...").start();
4465
5744
  try {
4466
5745
  await admin({
4467
5746
  method: "PUT",
@@ -4477,8 +5756,8 @@ async function runTenantCors(opts) {
4477
5756
  }
4478
5757
 
4479
5758
  // src/commands/tenant-drill.ts
4480
- var import_chalk33 = __toESM(require("chalk"));
4481
- var import_ora13 = __toESM(require("ora"));
5759
+ var import_chalk36 = __toESM(require("chalk"));
5760
+ var import_ora15 = __toESM(require("ora"));
4482
5761
  var import_crypto = require("crypto");
4483
5762
  init_admin();
4484
5763
  init_auth();
@@ -4508,17 +5787,17 @@ async function validScopedTenant(teamId, query) {
4508
5787
  const next = { ...creds };
4509
5788
  delete next.activeTenant;
4510
5789
  saveCredentials2(next);
4511
- console.log(import_chalk33.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
5790
+ console.log(import_chalk36.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
4512
5791
  return void 0;
4513
5792
  }
4514
5793
  async function tenantHome(teamId, tenant2) {
4515
5794
  const { default: inquirer3 } = await import("inquirer");
4516
5795
  const base2 = `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}`;
4517
- console.log(import_chalk33.default.bold(`
5796
+ console.log(import_chalk36.default.bold(`
4518
5797
  Tenant ${tenant2}`));
4519
- console.log(import_chalk33.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
5798
+ console.log(import_chalk36.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
4520
5799
  for (; ; ) {
4521
- const spinner = (0, import_ora13.default)("Reading tenant state...").start();
5800
+ const spinner = (0, import_ora15.default)("Reading tenant state...").start();
4522
5801
  const [iam, cors, emails, issuers, opaque, clients] = await Promise.all([
4523
5802
  admin({ method: "GET", path: `${base2}/iam`, summary: "Read IAM toggle" }).catch(() => null),
4524
5803
  admin({ method: "GET", path: `${base2}/cors`, summary: "Read tenant CORS" }).catch(() => null),
@@ -4532,18 +5811,18 @@ Tenant ${tenant2}`));
4532
5811
  const nClients = Array.isArray(clients) ? clients.length : 0;
4533
5812
  const nOpaque = opaque?.opaque?.endpoint ? 1 : 0;
4534
5813
  const nLogin = nClients + nIssuers + nOpaque;
4535
- const onOff = (b) => b ? import_chalk33.default.green("on") : import_chalk33.default.dim("off");
5814
+ const onOff = (b) => b ? import_chalk36.default.green("on") : import_chalk36.default.dim("off");
4536
5815
  const { pick: pick2 } = await inquirer3.prompt([{
4537
5816
  type: "list",
4538
5817
  name: "pick",
4539
5818
  message: `Tenant ${tenant2}:`,
4540
5819
  pageSize: 12,
4541
5820
  choices: [
4542
- { name: `Login methods (${nLogin}) ${import_chalk33.default.dim("how your consumers sign in")}`, value: "login" },
4543
- { name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk33.default.dim(`identity & key management (iam.apiblaze.com)`)}`, value: "iam" },
4544
- { name: `Portal admins (${nEmails}) ${import_chalk33.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
4545
- new inquirer3.Separator(import_chalk33.default.dim(" Settings")),
4546
- { name: `CORS: ${cors?.cors ? import_chalk33.default.cyan(JSON.stringify(cors.cors)) : import_chalk33.default.dim("(unset)")} ${import_chalk33.default.dim("browser origins allowed to call this tenant")}`, value: "cors" },
5821
+ { name: `Login methods (${nLogin}) ${import_chalk36.default.dim("how your consumers sign in")}`, value: "login" },
5822
+ { name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk36.default.dim(`identity & key management (iam.apiblaze.com)`)}`, value: "iam" },
5823
+ { name: `Portal admins (${nEmails}) ${import_chalk36.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
5824
+ new inquirer3.Separator(import_chalk36.default.dim(" Settings")),
5825
+ { name: `CORS: ${cors?.cors ? import_chalk36.default.cyan(JSON.stringify(cors.cors)) : import_chalk36.default.dim("(unset)")} ${import_chalk36.default.dim("browser origins allowed to call this tenant")}`, value: "cors" },
4547
5826
  { name: "\u2190 Back", value: "back" }
4548
5827
  ]
4549
5828
  }]);
@@ -4556,7 +5835,7 @@ Tenant ${tenant2}`));
4556
5835
  case "iam": {
4557
5836
  const { v } = await inquirer3.prompt([{ type: "confirm", name: "v", message: "Enable Users & groups?", default: !!iam?.iam_enabled }]);
4558
5837
  await admin({ method: "PATCH", path: `${base2}/iam`, body: { enabled: v }, summary: `IAM enforcement \u2192 ${v ? "on" : "off"}` });
4559
- console.log(import_chalk33.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
5838
+ console.log(import_chalk36.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
4560
5839
  break;
4561
5840
  }
4562
5841
  case "cors": {
@@ -4569,11 +5848,11 @@ Tenant ${tenant2}`));
4569
5848
  if (v === "") break;
4570
5849
  const parsed = v === "null" ? null : safeJson(v);
4571
5850
  if (parsed === void 0) {
4572
- console.log(import_chalk33.default.yellow(" Not valid JSON \u2014 unchanged."));
5851
+ console.log(import_chalk36.default.yellow(" Not valid JSON \u2014 unchanged."));
4573
5852
  break;
4574
5853
  }
4575
5854
  await admin({ method: "PUT", path: `${base2}/cors`, body: { cors: parsed }, summary: "Set tenant CORS" });
4576
- console.log(import_chalk33.default.green(" CORS updated."));
5855
+ console.log(import_chalk36.default.green(" CORS updated."));
4577
5856
  break;
4578
5857
  }
4579
5858
  case "emails":
@@ -4585,7 +5864,7 @@ Tenant ${tenant2}`));
4585
5864
  async function loginMethodsMenu(teamId, tenant2, base2) {
4586
5865
  const { default: inquirer3 } = await import("inquirer");
4587
5866
  for (; ; ) {
4588
- const spinner = (0, import_ora13.default)("Loading login methods...").start();
5867
+ const spinner = (0, import_ora15.default)("Loading login methods...").start();
4589
5868
  const [rawClients, rawIssuers, rawOpaque] = await Promise.all([
4590
5869
  admin({ method: "GET", path: `${base2}/app-clients`, summary: "List APIblaze-hosted logins" }).catch(() => []),
4591
5870
  admin({ method: "GET", path: `${base2}/external-issuers`, summary: "List your-own-JWT logins" }).catch(() => null),
@@ -4597,15 +5876,15 @@ async function loginMethodsMenu(teamId, tenant2, base2) {
4597
5876
  const choices = [];
4598
5877
  for (const c of appClients) {
4599
5878
  const nP = (c.providers ?? []).length || c.providers_count || 0;
4600
- choices.push({ name: `${import_chalk33.default.cyan("APIblaze-hosted")} ${import_chalk33.default.bold(c.name ?? c.clientId)} ${import_chalk33.default.dim(`${c.clientId}${nP ? ` \xB7 ${nP} provider${nP === 1 ? "" : "s"}` : import_chalk33.default.yellow(" \xB7 needs a provider")}`)}`, value: { kind: "client", item: c } });
5879
+ choices.push({ name: `${import_chalk36.default.cyan("APIblaze-hosted")} ${import_chalk36.default.bold(c.name ?? c.clientId)} ${import_chalk36.default.dim(`${c.clientId}${nP ? ` \xB7 ${nP} provider${nP === 1 ? "" : "s"}` : import_chalk36.default.yellow(" \xB7 needs a provider")}`)}`, value: { kind: "client", item: c } });
4601
5880
  }
4602
5881
  for (const i of issuers) {
4603
- choices.push({ name: `${import_chalk33.default.cyan("Your own \u2014 JWT ")} ${import_chalk33.default.bold(i.iss)} ${import_chalk33.default.dim(`aud=${i.aud}`)}`, value: { kind: "issuer", item: i } });
5882
+ choices.push({ name: `${import_chalk36.default.cyan("Your own \u2014 JWT ")} ${import_chalk36.default.bold(i.iss)} ${import_chalk36.default.dim(`aud=${i.aud}`)}`, value: { kind: "issuer", item: i } });
4604
5883
  }
4605
5884
  if (opaque?.endpoint) {
4606
- choices.push({ name: `${import_chalk33.default.cyan("Your own \u2014 opaque")} ${import_chalk33.default.bold(opaque.endpoint)}`, value: { kind: "opaque", item: opaque } });
5885
+ choices.push({ name: `${import_chalk36.default.cyan("Your own \u2014 opaque")} ${import_chalk36.default.bold(opaque.endpoint)}`, value: { kind: "opaque", item: opaque } });
4607
5886
  }
4608
- if (!choices.length) console.log(import_chalk33.default.dim("\n No login methods yet \u2014 consumers cannot sign in until you add one."));
5887
+ if (!choices.length) console.log(import_chalk36.default.dim("\n No login methods yet \u2014 consumers cannot sign in until you add one."));
4609
5888
  const { pick: pick2 } = await inquirer3.prompt([{
4610
5889
  type: "list",
4611
5890
  name: "pick",
@@ -4645,9 +5924,9 @@ async function addLoginMethod(teamId, tenant2, base2) {
4645
5924
  message: "How do people log in?",
4646
5925
  pageSize: 8,
4647
5926
  choices: [
4648
- { name: `APIblaze hosted login page ${import_chalk33.default.dim("we host login; pick a provider (GitHub/Google/\u2026) \u2014 easiest")}`, value: "apiblaze" },
4649
- { name: `Your own hosted login \u2014 JWT ${import_chalk33.default.dim("your identity provider issues JWTs; we trust them")}`, value: "jwt" },
4650
- { name: `Your own login \u2014 opaque token ${import_chalk33.default.dim("we validate your opaque tokens via an introspection endpoint")}`, value: "opaque" },
5927
+ { name: `APIblaze hosted login page ${import_chalk36.default.dim("we host login; pick a provider (GitHub/Google/\u2026) \u2014 easiest")}`, value: "apiblaze" },
5928
+ { name: `Your own hosted login \u2014 JWT ${import_chalk36.default.dim("your identity provider issues JWTs; we trust them")}`, value: "jwt" },
5929
+ { name: `Your own login \u2014 opaque token ${import_chalk36.default.dim("we validate your opaque tokens via an introspection endpoint")}`, value: "opaque" },
4651
5930
  { name: "\u2190 Back", value: null }
4652
5931
  ]
4653
5932
  }]);
@@ -4671,8 +5950,8 @@ function safeJson(s) {
4671
5950
  async function emailsMenu(base2, emails) {
4672
5951
  const { default: inquirer3 } = await import("inquirer");
4673
5952
  console.log();
4674
- if (!emails.length) console.log(import_chalk33.default.dim(" No consumer-admin emails."));
4675
- for (const e of emails) console.log(` ${import_chalk33.default.bold(e.email ?? e)} ${import_chalk33.default.dim(e.status ?? "")}`);
5953
+ if (!emails.length) console.log(import_chalk36.default.dim(" No consumer-admin emails."));
5954
+ for (const e of emails) console.log(` ${import_chalk36.default.bold(e.email ?? e)} ${import_chalk36.default.dim(e.status ?? "")}`);
4676
5955
  const { act } = await inquirer3.prompt([{
4677
5956
  type: "list",
4678
5957
  name: "act",
@@ -4687,7 +5966,7 @@ async function emailsMenu(base2, emails) {
4687
5966
  if (act === "add") {
4688
5967
  const { email } = await inquirer3.prompt([{ type: "input", name: "email", message: "Email:", validate: (s) => /.+@.+\..+/.test(s) || "not an email" }]);
4689
5968
  await admin({ method: "POST", path: `${base2}/admin-emails`, body: { email }, summary: `Add consumer-admin ${email}` });
4690
- console.log(import_chalk33.default.green(` ${email} added.`));
5969
+ console.log(import_chalk36.default.green(` ${email} added.`));
4691
5970
  } else {
4692
5971
  const { e } = await inquirer3.prompt([{
4693
5972
  type: "list",
@@ -4697,7 +5976,7 @@ async function emailsMenu(base2, emails) {
4697
5976
  }]);
4698
5977
  if (!e) return;
4699
5978
  await admin({ method: "DELETE", path: `${base2}/admin-emails/${encodeURIComponent(e)}`, summary: `Remove consumer-admin ${e}` });
4700
- console.log(import_chalk33.default.green(` ${e} removed.`));
5979
+ console.log(import_chalk36.default.green(` ${e} removed.`));
4701
5980
  }
4702
5981
  }
4703
5982
  async function addIssuer(base2) {
@@ -4718,19 +5997,19 @@ async function addIssuer(base2) {
4718
5997
  body: { iss: a.iss.trim(), aud: a.aud.trim(), jwks_url: a.jwks.trim() || null, sub_semantics: a.sem, ...claim ? { claim_name: claim } : {} },
4719
5998
  summary: `Add external issuer ${a.iss.trim()}`
4720
5999
  });
4721
- console.log(import_chalk33.default.green(" JWT login method saved."));
6000
+ console.log(import_chalk36.default.green(" JWT login method saved."));
4722
6001
  }
4723
6002
  async function issuerHome(base2, issuer) {
4724
6003
  const { default: inquirer3 } = await import("inquirer");
4725
6004
  console.log(`
4726
- ${import_chalk33.default.bold(issuer.iss)} ${import_chalk33.default.dim(`aud=${issuer.aud} \xB7 ${issuer.sub_semantics ?? ""}`)}`);
6005
+ ${import_chalk36.default.bold(issuer.iss)} ${import_chalk36.default.dim(`aud=${issuer.aud} \xB7 ${issuer.sub_semantics ?? ""}`)}`);
4727
6006
  const { act } = await inquirer3.prompt([{
4728
6007
  type: "list",
4729
6008
  name: "act",
4730
6009
  message: "This JWT login method:",
4731
6010
  choices: [
4732
6011
  { name: "Replace it (re-enter details)", value: "edit" },
4733
- { name: import_chalk33.default.red("Delete it"), value: "rm" },
6012
+ { name: import_chalk36.default.red("Delete it"), value: "rm" },
4734
6013
  { name: "\u2190 Back", value: "back" }
4735
6014
  ]
4736
6015
  }]);
@@ -4746,7 +6025,7 @@ async function issuerHome(base2, issuer) {
4746
6025
  path: `${base2}/external-issuers?iss=${encodeURIComponent(issuer.iss)}&aud=${encodeURIComponent(issuer.aud)}`,
4747
6026
  summary: `Delete issuer ${issuer.iss}`
4748
6027
  });
4749
- console.log(import_chalk33.default.green(" Deleted."));
6028
+ console.log(import_chalk36.default.green(" Deleted."));
4750
6029
  }
4751
6030
  async function setOpaque(base2, cur) {
4752
6031
  const { default: inquirer3 } = await import("inquirer");
@@ -4755,19 +6034,19 @@ async function setOpaque(base2, cur) {
4755
6034
  { type: "list", name: "method", message: "HTTP method:", choices: ["GET", "POST"], default: cur?.method ?? "GET" }
4756
6035
  ]);
4757
6036
  await admin({ method: "PUT", path: `${base2}/opaque`, body: { opaque: { endpoint: a.endpoint, method: a.method } }, summary: "Set opaque validator" });
4758
- console.log(import_chalk33.default.green(" Opaque login method set."));
6037
+ console.log(import_chalk36.default.green(" Opaque login method set."));
4759
6038
  }
4760
6039
  async function opaqueHome(base2, cur) {
4761
6040
  const { default: inquirer3 } = await import("inquirer");
4762
6041
  console.log(`
4763
- ${import_chalk33.default.bold(cur.endpoint)} ${import_chalk33.default.dim(cur.method ?? "GET")}`);
6042
+ ${import_chalk36.default.bold(cur.endpoint)} ${import_chalk36.default.dim(cur.method ?? "GET")}`);
4764
6043
  const { act } = await inquirer3.prompt([{
4765
6044
  type: "list",
4766
6045
  name: "act",
4767
6046
  message: "This opaque login method:",
4768
6047
  choices: [
4769
6048
  { name: "Replace it", value: "edit" },
4770
- { name: import_chalk33.default.red("Delete it"), value: "rm" },
6049
+ { name: import_chalk36.default.red("Delete it"), value: "rm" },
4771
6050
  { name: "\u2190 Back", value: "back" }
4772
6051
  ]
4773
6052
  }]);
@@ -4777,14 +6056,14 @@ async function opaqueHome(base2, cur) {
4777
6056
  return;
4778
6057
  }
4779
6058
  await admin({ method: "PUT", path: `${base2}/opaque`, body: { opaque: null }, summary: "Clear opaque validator" });
4780
- console.log(import_chalk33.default.green(" Deleted."));
6059
+ console.log(import_chalk36.default.green(" Deleted."));
4781
6060
  }
4782
6061
  async function clientHome(base2, summary) {
4783
6062
  const { default: inquirer3 } = await import("inquirer");
4784
6063
  const id = summary.clientId ?? summary.client_id;
4785
6064
  const cBase = `${base2}/app-clients/${encodeURIComponent(id)}`;
4786
6065
  for (; ; ) {
4787
- const spinner = (0, import_ora13.default)("Reading app client...").start();
6066
+ const spinner = (0, import_ora15.default)("Reading app client...").start();
4788
6067
  const c = await admin({ method: "GET", path: cBase, summary: `Read app client ${id}` }).catch(() => summary);
4789
6068
  spinner.stop();
4790
6069
  const cb = c.authorizedCallbackUrls ?? c.authorized_callback_urls ?? [];
@@ -4796,13 +6075,13 @@ async function clientHome(base2, summary) {
4796
6075
  message: `${c.name ?? id}:`,
4797
6076
  pageSize: 12,
4798
6077
  choices: [
4799
- { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk33.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
4800
- { name: `Callback URLs: ${cb.length ? import_chalk33.default.cyan(cb.join(", ")) : import_chalk33.default.dim("(none)")}`, value: "callbacks" },
4801
- { name: `Scopes: ${scopes.length ? import_chalk33.default.cyan(scopes.join(" ")) : import_chalk33.default.dim("(defaults)")}`, value: "scopes" },
6078
+ { name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk36.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
6079
+ { name: `Callback URLs: ${cb.length ? import_chalk36.default.cyan(cb.join(", ")) : import_chalk36.default.dim("(none)")}`, value: "callbacks" },
6080
+ { name: `Scopes: ${scopes.length ? import_chalk36.default.cyan(scopes.join(" ")) : import_chalk36.default.dim("(defaults)")}`, value: "scopes" },
4802
6081
  { name: `Token expiries: access ${c.accessTokenExpiry ?? 3600}s \xB7 id ${c.idTokenExpiry ?? 3600}s \xB7 refresh ${c.refreshTokenExpiry ?? 2592e3}s`, value: "expiries" },
4803
6082
  { name: "Reveal client secret", value: "secret" },
4804
6083
  { name: "Rotate client secret", value: "rotate" },
4805
- { name: import_chalk33.default.red("Delete this app client"), value: "delete" },
6084
+ { name: import_chalk36.default.red("Delete this app client"), value: "delete" },
4806
6085
  { name: "\u2190 Back", value: "back" }
4807
6086
  ]
4808
6087
  }]);
@@ -4815,13 +6094,13 @@ async function clientHome(base2, summary) {
4815
6094
  case "callbacks": {
4816
6095
  const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Callback URLs (comma-separated):", default: cb.join(", ") }]);
4817
6096
  await admin({ method: "PATCH", path: cBase, body: { authorizedCallbackUrls: parseList(v) }, summary: "Update callback URLs" });
4818
- console.log(import_chalk33.default.green(" Callbacks updated."));
6097
+ console.log(import_chalk36.default.green(" Callbacks updated."));
4819
6098
  break;
4820
6099
  }
4821
6100
  case "scopes": {
4822
6101
  const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Scopes (space/comma-separated):", default: scopes.join(" ") }]);
4823
6102
  await admin({ method: "PATCH", path: cBase, body: { scopes: v.split(/[\s,]+/).filter(Boolean) }, summary: "Update scopes" });
4824
- console.log(import_chalk33.default.green(" Scopes updated."));
6103
+ console.log(import_chalk36.default.green(" Scopes updated."));
4825
6104
  break;
4826
6105
  }
4827
6106
  case "expiries": {
@@ -4836,14 +6115,14 @@ async function clientHome(base2, summary) {
4836
6115
  body: { accessTokenExpiry: Number(a.access), idTokenExpiry: Number(a.id), refreshTokenExpiry: Number(a.refresh) },
4837
6116
  summary: "Update token expiries"
4838
6117
  });
4839
- console.log(import_chalk33.default.green(" Expiries updated."));
6118
+ console.log(import_chalk36.default.green(" Expiries updated."));
4840
6119
  break;
4841
6120
  }
4842
6121
  case "secret": {
4843
6122
  const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: "Print the client secret to this terminal?", default: false }]);
4844
6123
  if (!sure) break;
4845
6124
  const s = await admin({ method: "GET", path: `${cBase}/secret`, summary: "Reveal client secret" });
4846
- console.log(` ${import_chalk33.default.bold("client_secret")}: ${import_chalk33.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
6125
+ console.log(` ${import_chalk36.default.bold("client_secret")}: ${import_chalk36.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
4847
6126
  break;
4848
6127
  }
4849
6128
  case "rotate": {
@@ -4851,14 +6130,14 @@ async function clientHome(base2, summary) {
4851
6130
  if (!sure) break;
4852
6131
  const fresh = randomSecret();
4853
6132
  await admin({ method: "PATCH", path: cBase, body: { clientSecret: fresh }, summary: "Rotate client secret" });
4854
- console.log(` New ${import_chalk33.default.bold("client_secret")}: ${import_chalk33.default.green(fresh)} ${import_chalk33.default.dim("(store it now)")}`);
6133
+ console.log(` New ${import_chalk36.default.bold("client_secret")}: ${import_chalk36.default.green(fresh)} ${import_chalk36.default.dim("(store it now)")}`);
4855
6134
  break;
4856
6135
  }
4857
6136
  case "delete": {
4858
6137
  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 }]);
4859
6138
  if (!sure) break;
4860
6139
  await admin({ method: "DELETE", path: cBase, summary: `Delete app client ${id}` });
4861
- console.log(import_chalk33.default.green(" App client deleted."));
6140
+ console.log(import_chalk36.default.green(" App client deleted."));
4862
6141
  return;
4863
6142
  }
4864
6143
  }
@@ -4879,15 +6158,15 @@ var DEFAULT_SCOPES2 = {
4879
6158
  async function providersMenu(cBase, clientLabel) {
4880
6159
  const { default: inquirer3 } = await import("inquirer");
4881
6160
  for (; ; ) {
4882
- const spinner = (0, import_ora13.default)("Loading providers...").start();
6161
+ const spinner = (0, import_ora15.default)("Loading providers...").start();
4883
6162
  const raw = await admin({ method: "GET", path: `${cBase}/providers`, summary: "List login providers" }).catch(() => []);
4884
6163
  spinner.stop();
4885
6164
  const providers = Array.isArray(raw) ? raw : [];
4886
6165
  console.log();
4887
6166
  for (const p of providers) {
4888
- console.log(` ${import_chalk33.default.bold(p.type)} ${import_chalk33.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
6167
+ console.log(` ${import_chalk36.default.bold(p.type)} ${import_chalk36.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
4889
6168
  }
4890
- if (!providers.length) console.log(import_chalk33.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
6169
+ if (!providers.length) console.log(import_chalk36.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
4891
6170
  const { act } = await inquirer3.prompt([{
4892
6171
  type: "list",
4893
6172
  name: "act",
@@ -4945,23 +6224,23 @@ async function providersMenu(cBase, clientLabel) {
4945
6224
  body.targetServerToken = routing;
4946
6225
  }
4947
6226
  await admin({ method: "POST", path: `${cBase}/providers`, body, summary: `Add ${type} login provider` });
4948
- console.log(import_chalk33.default.green(` ${type} provider added.`));
6227
+ console.log(import_chalk36.default.green(` ${type} provider added.`));
4949
6228
  } else {
4950
6229
  const { p } = await inquirer3.prompt([{
4951
6230
  type: "list",
4952
6231
  name: "p",
4953
6232
  message: act === "rm" ? "Remove which provider?" : "Reveal which secret?",
4954
- choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk33.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
6233
+ choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk36.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
4955
6234
  }]);
4956
6235
  if (!p) continue;
4957
6236
  if (act === "rm") {
4958
6237
  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 }]);
4959
6238
  if (!sure) continue;
4960
6239
  await admin({ method: "DELETE", path: `${cBase}/providers/${encodeURIComponent(p.id)}`, summary: `Remove ${p.type} provider` });
4961
- console.log(import_chalk33.default.green(` ${p.type} removed.`));
6240
+ console.log(import_chalk36.default.green(` ${p.type} removed.`));
4962
6241
  } else {
4963
6242
  const s = await admin({ method: "GET", path: `${cBase}/providers/${encodeURIComponent(p.id)}/secret`, summary: `Reveal ${p.type} provider secret` });
4964
- console.log(` ${import_chalk33.default.bold("client_secret")}: ${import_chalk33.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
6243
+ console.log(` ${import_chalk36.default.bold("client_secret")}: ${import_chalk36.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
4965
6244
  }
4966
6245
  }
4967
6246
  }
@@ -4969,8 +6248,8 @@ async function providersMenu(cBase, clientLabel) {
4969
6248
 
4970
6249
  // src/commands/spec.ts
4971
6250
  var fs7 = __toESM(require("fs"));
4972
- var import_chalk34 = __toESM(require("chalk"));
4973
- var import_ora14 = __toESM(require("ora"));
6251
+ var import_chalk37 = __toESM(require("chalk"));
6252
+ var import_ora16 = __toESM(require("ora"));
4974
6253
  init_admin();
4975
6254
  init_api();
4976
6255
  init_resolve();
@@ -4986,19 +6265,19 @@ async function runSpecGet(project, opts) {
4986
6265
  }
4987
6266
  async function runSpecSet(project, opts) {
4988
6267
  if (!opts.file) {
4989
- console.error(import_chalk34.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
6268
+ console.error(import_chalk37.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
4990
6269
  process.exit(1);
4991
6270
  }
4992
6271
  let specContent;
4993
6272
  try {
4994
6273
  specContent = fs7.readFileSync(opts.file, "utf-8");
4995
6274
  } catch {
4996
- console.error(import_chalk34.default.red(`Cannot read file: ${opts.file}`));
6275
+ console.error(import_chalk37.default.red(`Cannot read file: ${opts.file}`));
4997
6276
  process.exit(1);
4998
6277
  }
4999
6278
  const { teamId } = await resolveTeam(opts.team);
5000
6279
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
5001
- const spinner = (0, import_ora14.default)("Uploading spec...").start();
6280
+ const spinner = (0, import_ora16.default)("Uploading spec...").start();
5002
6281
  try {
5003
6282
  const out = await admin({
5004
6283
  method: "POST",
@@ -5022,28 +6301,28 @@ async function runSpecSet(project, opts) {
5022
6301
  function printSpecChangeReport(report, projectName) {
5023
6302
  const r = report.routes;
5024
6303
  if (r) {
5025
- for (const a of r.added) console.log(import_chalk34.default.green(` + ${a}`));
5026
- for (const d of r.removed) console.log(import_chalk34.default.red(` \u2212 ${d}`));
5027
- for (const rn of r.renamed ?? []) console.log(import_chalk34.default.yellow(` ~ ${rn.from} \u2192 ${rn.to}`));
5028
- for (const m of r.modified ?? []) console.log(import_chalk34.default.dim(` \xB1 ${m} (params/schema changed)`));
6304
+ for (const a of r.added) console.log(import_chalk37.default.green(` + ${a}`));
6305
+ for (const d of r.removed) console.log(import_chalk37.default.red(` \u2212 ${d}`));
6306
+ for (const rn of r.renamed ?? []) console.log(import_chalk37.default.yellow(` ~ ${rn.from} \u2192 ${rn.to}`));
6307
+ for (const m of r.modified ?? []) console.log(import_chalk37.default.dim(` \xB1 ${m} (params/schema changed)`));
5029
6308
  }
5030
- if (report.applied?.mcp_regenerated) console.log(import_chalk34.default.dim(" MCP catalogue regenerated."));
5031
- if (report.applied?.candidates_cleared) console.log(import_chalk34.default.dim(` ${report.applied.candidates_cleared} route candidate(s) now documented \u2014 cleared.`));
6309
+ if (report.applied?.mcp_regenerated) console.log(import_chalk37.default.dim(" MCP catalogue regenerated."));
6310
+ if (report.applied?.candidates_cleared) console.log(import_chalk37.default.dim(` ${report.applied.candidates_cleared} route candidate(s) now documented \u2014 cleared.`));
5032
6311
  for (const item of report.attention ?? []) {
5033
- console.log(import_chalk34.default.yellow(` \u26A0 ${item.detail}`));
6312
+ console.log(import_chalk37.default.yellow(` \u26A0 ${item.detail}`));
5034
6313
  if (item.suggestion?.carry_from && item.suggestion.carry_to) {
5035
- console.log(import_chalk34.default.dim(` Fix: apiblaze spec carry ${projectName} --method ${item.suggestion.method} --from "${item.suggestion.carry_from}" --to "${item.suggestion.carry_to}"`));
6314
+ console.log(import_chalk37.default.dim(` Fix: apiblaze spec carry ${projectName} --method ${item.suggestion.method} --from "${item.suggestion.carry_from}" --to "${item.suggestion.carry_to}"`));
5036
6315
  }
5037
6316
  }
5038
6317
  }
5039
6318
  async function runSpecCarry(project, opts) {
5040
6319
  if (!opts.method || !opts.from || !opts.to) {
5041
- console.error(import_chalk34.default.red("--method, --from and --to are required."));
6320
+ console.error(import_chalk37.default.red("--method, --from and --to are required."));
5042
6321
  process.exit(1);
5043
6322
  }
5044
6323
  const { teamId } = await resolveTeam(opts.team);
5045
6324
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
5046
- const spinner = (0, import_ora14.default)(`Carrying rules ${opts.from} \u2192 ${opts.to}...`).start();
6325
+ const spinner = (0, import_ora16.default)(`Carrying rules ${opts.from} \u2192 ${opts.to}...`).start();
5047
6326
  const res = await agentCall(`/projects/${proj2.projectId}/${proj2.apiVersion}/policies/route/carry`, "POST", {
5048
6327
  method: opts.method.toUpperCase(),
5049
6328
  from_resource: opts.from,
@@ -5060,13 +6339,13 @@ async function runSpecCarry(project, opts) {
5060
6339
  }
5061
6340
  async function runSpecDeleteRule(project, opts) {
5062
6341
  if (!opts.method || !opts.route) {
5063
- console.error(import_chalk34.default.red("--method and --route are required."));
6342
+ console.error(import_chalk37.default.red("--method and --route are required."));
5064
6343
  process.exit(1);
5065
6344
  }
5066
6345
  const { teamId } = await resolveTeam(opts.team);
5067
6346
  const proj2 = await resolveProject(teamId, project, opts.apiversion);
5068
6347
  const encoded = opts.route.replace(/\{/g, "%7B").replace(/\}/g, "%7D");
5069
- const spinner = (0, import_ora14.default)(`Deleting rules for ${opts.method.toUpperCase()} ${opts.route}...`).start();
6348
+ const spinner = (0, import_ora16.default)(`Deleting rules for ${opts.method.toUpperCase()} ${opts.route}...`).start();
5070
6349
  const res = await agentCall(
5071
6350
  `/projects/${proj2.projectId}/${proj2.apiVersion}/policies/route/${opts.method.toUpperCase()}${encoded.startsWith("/") ? encoded : `/${encoded}`}`,
5072
6351
  "DELETE"
@@ -5080,14 +6359,14 @@ async function runSpecDeleteRule(project, opts) {
5080
6359
  }
5081
6360
 
5082
6361
  // src/commands/agent.ts
5083
- var import_chalk36 = __toESM(require("chalk"));
5084
- var import_ora15 = __toESM(require("ora"));
6362
+ var import_chalk39 = __toESM(require("chalk"));
6363
+ var import_ora17 = __toESM(require("ora"));
5085
6364
  init_auth();
5086
6365
  init_admin();
5087
6366
  init_resolve();
5088
6367
 
5089
6368
  // src/lib/tools.ts
5090
- var import_chalk35 = __toESM(require("chalk"));
6369
+ var import_chalk38 = __toESM(require("chalk"));
5091
6370
  init_admin();
5092
6371
  init_api();
5093
6372
  init_resolve();
@@ -5107,15 +6386,15 @@ var TOOLS = [
5107
6386
  const key = keys.dev ?? Object.values(keys)[0];
5108
6387
  const url = `https://${a.name}.abz.run/${version2}/dev`;
5109
6388
  const tryIt = buildTryItCurl(url, auth, key);
5110
- const lines = [` ${import_chalk35.default.dim("Proxy URL:")} ${import_chalk35.default.bold(url)}`];
5111
- if (res.devPortal) lines.push(` ${import_chalk35.default.dim("Dev portal:")} ${res.devPortal}`);
6389
+ const lines = [` ${import_chalk38.default.dim("Proxy URL:")} ${import_chalk38.default.bold(url)}`];
6390
+ if (res.devPortal) lines.push(` ${import_chalk38.default.dim("Dev portal:")} ${res.devPortal}`);
5112
6391
  const envs = Object.keys(keys);
5113
6392
  if (envs.length) {
5114
- lines.push("", ` ${import_chalk35.default.bold("API keys")} ${import_chalk35.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
6393
+ lines.push("", ` ${import_chalk38.default.bold("API keys")} ${import_chalk38.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
5115
6394
  const w = Math.max(...envs.map((e) => e.length));
5116
- for (const env of envs) lines.push(` ${import_chalk35.default.cyan(env.padEnd(w))} ${import_chalk35.default.green(keys[env])}`);
6395
+ for (const env of envs) lines.push(` ${import_chalk38.default.cyan(env.padEnd(w))} ${import_chalk38.default.green(keys[env])}`);
5117
6396
  }
5118
- if (tryIt) lines.push("", ` ${import_chalk35.default.dim("Try it:")}`, ` ${import_chalk35.default.cyan(tryIt)}`);
6397
+ if (tryIt) lines.push("", ` ${import_chalk38.default.dim("Try it:")}`, ` ${import_chalk38.default.cyan(tryIt)}`);
5119
6398
  return { ...res, proxy_url: url, keys, ...tryIt ? { try_it: tryIt } : {}, display: lines.join("\n") };
5120
6399
  }
5121
6400
  },
@@ -5271,23 +6550,23 @@ function truncate(value, max = 1500) {
5271
6550
  }
5272
6551
  function printCost(resp) {
5273
6552
  const line = formatBilling(resp.billing);
5274
- if (line) console.log(import_chalk36.default.magenta(` ${line}`) + import_chalk36.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
6553
+ if (line) console.log(import_chalk39.default.magenta(` ${line}`) + import_chalk39.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
5275
6554
  }
5276
6555
  async function runAgent(opts) {
5277
6556
  requireAuth();
5278
6557
  const { teamId, teamName } = await resolveTeam(opts.team);
5279
6558
  const { default: inquirer3 } = await import("inquirer");
5280
- console.log(import_chalk36.default.bold("APIblaze agent") + import_chalk36.default.dim(` \xB7 team ${teamName ?? teamId}`));
5281
- console.log(import_chalk36.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
6559
+ console.log(import_chalk39.default.bold("APIblaze agent") + import_chalk39.default.dim(` \xB7 team ${teamName ?? teamId}`));
6560
+ console.log(import_chalk39.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
5282
6561
  const history = [];
5283
6562
  while (true) {
5284
- const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk36.default.cyan("you") + " \u203A" }]);
6563
+ const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk39.default.cyan("you") + " \u203A" }]);
5285
6564
  const text = (input ?? "").trim();
5286
6565
  if (!text) continue;
5287
6566
  if (["exit", "quit", ":q"].includes(text.toLowerCase())) break;
5288
6567
  history.push({ role: "user", content: text });
5289
6568
  for (let step = 0; step < MAX_TOOL_STEPS; step++) {
5290
- const spinner = (0, import_ora15.default)({ text: "thinking...", color: "magenta" }).start();
6569
+ const spinner = (0, import_ora17.default)({ text: "thinking...", color: "magenta" }).start();
5291
6570
  let resp;
5292
6571
  try {
5293
6572
  resp = await callAgent(history, teamId);
@@ -5295,21 +6574,21 @@ async function runAgent(opts) {
5295
6574
  } catch (err) {
5296
6575
  spinner.stop();
5297
6576
  if (err instanceof ApiError && err.status === 402) {
5298
- console.log(import_chalk36.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
6577
+ console.log(import_chalk39.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
5299
6578
  break;
5300
6579
  }
5301
6580
  throw err;
5302
6581
  }
5303
6582
  history.push({ role: "assistant", content: resp.raw });
5304
6583
  printCost(resp);
5305
- if (resp.reply) console.log(import_chalk36.default.green("agent") + " \u203A " + resp.reply);
6584
+ if (resp.reply) console.log(import_chalk39.default.green("agent") + " \u203A " + resp.reply);
5306
6585
  if (!resp.action) break;
5307
6586
  const tool = findTool(resp.action.tool);
5308
6587
  if (!tool) {
5309
6588
  history.push({ role: "user", content: `TOOL_RESULT ${resp.action.tool}: error \u2014 unknown tool` });
5310
6589
  continue;
5311
6590
  }
5312
- const runSpinner = (0, import_ora15.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
6591
+ const runSpinner = (0, import_ora17.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
5313
6592
  try {
5314
6593
  const result = await tool.run(resp.action.args, { teamId });
5315
6594
  runSpinner.succeed(`${tool.name} \u2713`);
@@ -5327,11 +6606,11 @@ async function runAgent(opts) {
5327
6606
  }
5328
6607
  renderTrace();
5329
6608
  if (step === MAX_TOOL_STEPS - 1) {
5330
- console.log(import_chalk36.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
6609
+ console.log(import_chalk39.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
5331
6610
  }
5332
6611
  }
5333
6612
  }
5334
- console.log(import_chalk36.default.dim("\nBye."));
6613
+ console.log(import_chalk39.default.dim("\nBye."));
5335
6614
  }
5336
6615
 
5337
6616
  // src/commands/config-browse.ts
@@ -5617,11 +6896,11 @@ function dig(blob, dotted) {
5617
6896
  }
5618
6897
  var readSetting = (s, cfg) => s.read ? s.read(cfg) : dig(cfg, s.key);
5619
6898
  function show(v) {
5620
- if (v === void 0) return import_chalk37.default.dim("(unset)");
5621
- if (v === null) return import_chalk37.default.dim("null");
5622
- if (typeof v === "object") return import_chalk37.default.cyan(JSON.stringify(v));
5623
- if (typeof v === "boolean") return v ? import_chalk37.default.green("on") : import_chalk37.default.red("off");
5624
- return import_chalk37.default.cyan(String(v));
6899
+ if (v === void 0) return import_chalk40.default.dim("(unset)");
6900
+ if (v === null) return import_chalk40.default.dim("null");
6901
+ if (typeof v === "object") return import_chalk40.default.cyan(JSON.stringify(v));
6902
+ if (typeof v === "boolean") return v ? import_chalk40.default.green("on") : import_chalk40.default.red("off");
6903
+ return import_chalk40.default.cyan(String(v));
5625
6904
  }
5626
6905
  function parseValue(raw) {
5627
6906
  if (raw === "true") return true;
@@ -5648,7 +6927,7 @@ async function fetchConfigBlob(proj2) {
5648
6927
  }
5649
6928
  async function patchSetting(proj2, s, value, cfg) {
5650
6929
  const body = s.toPatch(value, cfg);
5651
- const spinner = (0, import_ora16.default)(`Set ${s.key}...`).start();
6930
+ const spinner = (0, import_ora18.default)(`Set ${s.key}...`).start();
5652
6931
  try {
5653
6932
  await admin({
5654
6933
  method: "PATCH",
@@ -5663,10 +6942,10 @@ async function patchSetting(proj2, s, value, cfg) {
5663
6942
  }
5664
6943
  }
5665
6944
  var loginFirst = (what) => {
5666
- console.log(import_chalk37.default.yellow(`
6945
+ console.log(import_chalk40.default.yellow(`
5667
6946
  Log in first to ${what}.`));
5668
- console.log(import_chalk37.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
5669
- console.log(import_chalk37.default.dim(" anonymously and want to bring it into your account.\n"));
6947
+ console.log(import_chalk40.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
6948
+ console.log(import_chalk40.default.dim(" anonymously and want to bring it into your account.\n"));
5670
6949
  };
5671
6950
  async function runConfig(project, key, value, opts) {
5672
6951
  const creds = loadCredentials();
@@ -5683,9 +6962,9 @@ async function runConfig(project, key, value, opts) {
5683
6962
  }
5684
6963
  const setting = SETTINGS.find((s) => s.key === key);
5685
6964
  if (!setting) {
5686
- console.error(import_chalk37.default.red(`Unknown setting "${key}".`));
5687
- console.error(import_chalk37.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
5688
- console.error(import_chalk37.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
6965
+ console.error(import_chalk40.default.red(`Unknown setting "${key}".`));
6966
+ console.error(import_chalk40.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
6967
+ console.error(import_chalk40.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
5689
6968
  process.exit(1);
5690
6969
  }
5691
6970
  if (value === void 0) {
@@ -5700,7 +6979,7 @@ async function pickProject(teamId) {
5700
6979
  const { getProjects: getProjects2 } = await Promise.resolve().then(() => (init_api(), api_exports));
5701
6980
  const projects = await getProjects2(teamId).catch(() => []);
5702
6981
  if (!projects.length) {
5703
- console.error(import_chalk37.default.red("No projects in this team. Create one: `npx apiblaze create`."));
6982
+ console.error(import_chalk40.default.red("No projects in this team. Create one: `npx apiblaze create`."));
5704
6983
  process.exit(1);
5705
6984
  }
5706
6985
  const { default: inquirer3 } = await import("inquirer");
@@ -5708,7 +6987,7 @@ async function pickProject(teamId) {
5708
6987
  type: "list",
5709
6988
  name: "picked",
5710
6989
  message: "Which project?",
5711
- choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk37.default.dim("v" + p.apiVersion)}`, value: p }))
6990
+ choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk40.default.dim("v" + p.apiVersion)}`, value: p }))
5712
6991
  }]);
5713
6992
  return { projectId: picked.projectId, projectName: picked.projectName, apiVersion: picked.apiVersion, teamId, tenant: picked.tenant };
5714
6993
  }
@@ -5719,25 +6998,25 @@ function printAll(proj2, cfg, json) {
5719
6998
  console.log(JSON.stringify(out, null, 2));
5720
6999
  return;
5721
7000
  }
5722
- console.log(import_chalk37.default.bold(`
7001
+ console.log(import_chalk40.default.bold(`
5723
7002
  ${proj2.projectName} v${proj2.apiVersion} \u2014 settings
5724
7003
  `));
5725
7004
  for (const group2 of SETTING_GROUPS) {
5726
- console.log(import_chalk37.default.bold(group2));
7005
+ console.log(import_chalk40.default.bold(group2));
5727
7006
  for (const s of SETTINGS.filter((x) => x.group === group2)) {
5728
- console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk37.default.dim(s.desc)}`);
7007
+ console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk40.default.dim(s.desc)}`);
5729
7008
  }
5730
7009
  console.log();
5731
7010
  }
5732
- console.log(import_chalk37.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
7011
+ console.log(import_chalk40.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
5733
7012
  }
5734
7013
  async function discoveryMenu(project) {
5735
7014
  const { default: inquirer3 } = await import("inquirer");
5736
- console.log(import_chalk37.default.bold(`
7015
+ console.log(import_chalk40.default.bold(`
5737
7016
  APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
5738
7017
  `));
5739
- console.log(import_chalk37.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
5740
- console.log(import_chalk37.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
7018
+ console.log(import_chalk40.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
7019
+ console.log(import_chalk40.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
5741
7020
  for (; ; ) {
5742
7021
  const { pick: pick2 } = await inquirer3.prompt([{
5743
7022
  type: "list",
@@ -5745,13 +7024,13 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
5745
7024
  message: "Explore:",
5746
7025
  pageSize: 20,
5747
7026
  choices: [
5748
- new inquirer3.Separator(import_chalk37.default.bold("\u2014 Settings \u2014")),
7027
+ new inquirer3.Separator(import_chalk40.default.bold("\u2014 Settings \u2014")),
5749
7028
  ...SETTING_GROUPS.map((g) => ({
5750
- name: `${g} ${import_chalk37.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
7029
+ name: `${g} ${import_chalk40.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
5751
7030
  value: { kind: "settings", g }
5752
7031
  })),
5753
- new inquirer3.Separator(import_chalk37.default.bold("\u2014 Features \u2014")),
5754
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk37.default.dim(f.desc)}`, value: { kind: "feature", f } })),
7032
+ new inquirer3.Separator(import_chalk40.default.bold("\u2014 Features \u2014")),
7033
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk40.default.dim(f.desc)}`, value: { kind: "feature", f } })),
5755
7034
  new inquirer3.Separator(),
5756
7035
  { name: "Exit", value: { kind: "exit" } }
5757
7036
  ]
@@ -5760,24 +7039,24 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
5760
7039
  if (pick2.kind === "settings") {
5761
7040
  console.log();
5762
7041
  for (const s of SETTINGS.filter((x) => x.group === pick2.g)) {
5763
- console.log(` ${import_chalk37.default.bold(s.label.padEnd(28))} ${import_chalk37.default.dim(s.desc)}`);
5764
- console.log(` ${import_chalk37.default.dim(" key: " + s.key)}`);
7042
+ console.log(` ${import_chalk40.default.bold(s.label.padEnd(28))} ${import_chalk40.default.dim(s.desc)}`);
7043
+ console.log(` ${import_chalk40.default.dim(" key: " + s.key)}`);
5765
7044
  }
5766
7045
  loginFirst("view or change these settings");
5767
7046
  } else {
5768
7047
  const f = pick2.f;
5769
7048
  console.log(`
5770
- ${import_chalk37.default.bold(f.label)} \u2014 ${f.desc}`);
7049
+ ${import_chalk40.default.bold(f.label)} \u2014 ${f.desc}`);
5771
7050
  loginFirst(`use ${f.label.toLowerCase()}`);
5772
7051
  }
5773
7052
  }
5774
7053
  }
5775
7054
  async function navigator(proj2, cfg, opts) {
5776
7055
  const { default: inquirer3 } = await import("inquirer");
5777
- console.log(import_chalk37.default.bold(`
7056
+ console.log(import_chalk40.default.bold(`
5778
7057
  ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
5779
7058
  `));
5780
- console.log(import_chalk37.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
7059
+ console.log(import_chalk40.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
5781
7060
  let blob = cfg;
5782
7061
  for (; ; ) {
5783
7062
  const { pick: pick2 } = await inquirer3.prompt([{
@@ -5786,10 +7065,10 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
5786
7065
  message: "Where to?",
5787
7066
  pageSize: 20,
5788
7067
  choices: [
5789
- new inquirer3.Separator(import_chalk37.default.bold("\u2014 Settings \u2014")),
7068
+ new inquirer3.Separator(import_chalk40.default.bold("\u2014 Settings \u2014")),
5790
7069
  ...SETTING_GROUPS.map((g) => ({ name: g, value: { kind: "settings", g } })),
5791
- new inquirer3.Separator(import_chalk37.default.bold("\u2014 Features \u2014")),
5792
- ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk37.default.dim(f.desc)}`, value: { kind: f.go } })),
7070
+ new inquirer3.Separator(import_chalk40.default.bold("\u2014 Features \u2014")),
7071
+ ...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk40.default.dim(f.desc)}`, value: { kind: f.go } })),
5793
7072
  new inquirer3.Separator(),
5794
7073
  { name: "Show all settings", value: { kind: "list" } },
5795
7074
  { name: "Exit", value: { kind: "exit" } }
@@ -5829,7 +7108,7 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
5829
7108
  }
5830
7109
  }
5831
7110
  } catch (err) {
5832
- console.error(import_chalk37.default.red(` ${err instanceof Error ? err.message : String(err)}`));
7111
+ console.error(import_chalk40.default.red(` ${err instanceof Error ? err.message : String(err)}`));
5833
7112
  }
5834
7113
  }
5835
7114
  }
@@ -5843,7 +7122,7 @@ async function settingsGroup(proj2, cfg, group2) {
5843
7122
  message: group2 + ":",
5844
7123
  pageSize: 16,
5845
7124
  choices: [
5846
- ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk37.default.dim(s2.desc)}`, value: s2 })),
7125
+ ...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk40.default.dim(s2.desc)}`, value: s2 })),
5847
7126
  new inquirer3.Separator(),
5848
7127
  { name: "\u2190 Back", value: null }
5849
7128
  ]
@@ -5861,7 +7140,7 @@ async function settingsGroup(proj2, cfg, group2) {
5861
7140
  } else if (s.type === "number") {
5862
7141
  const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: `${s.label} (number):`, default: readSetting(s, cfg) }]);
5863
7142
  if (v === "" || Number.isNaN(Number(v))) {
5864
- console.log(import_chalk37.default.yellow(" Not a number \u2014 unchanged."));
7143
+ console.log(import_chalk40.default.yellow(" Not a number \u2014 unchanged."));
5865
7144
  continue;
5866
7145
  }
5867
7146
  value = Number(v);
@@ -5942,7 +7221,7 @@ async function buildCondition(phase) {
5942
7221
  const items = [];
5943
7222
  for (; ; ) {
5944
7223
  const a = await inquirer3.prompt([
5945
- { type: "input", name: "source", message: `Condition field ${import_chalk37.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
7224
+ { type: "input", name: "source", message: `Condition field ${import_chalk40.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
5946
7225
  { type: "list", name: "operator", message: "Operator:", choices: [
5947
7226
  "eq",
5948
7227
  "neq",
@@ -5973,7 +7252,7 @@ async function buildCondition(phase) {
5973
7252
  function showCondition(cond) {
5974
7253
  if (!Array.isArray(cond) || !cond.length) return "";
5975
7254
  const s = cond.map((c) => `${c.source} ${c.operator}${c.value !== void 0 ? ` "${c.value}"` : ""}${c.logicOp ? ` ${c.logicOp}` : ""}`).join(" ");
5976
- return import_chalk37.default.dim(` when ${s}`);
7255
+ return import_chalk40.default.dim(` when ${s}`);
5977
7256
  }
5978
7257
  async function transformsMenu(proj2) {
5979
7258
  const { default: inquirer3 } = await import("inquirer");
@@ -5982,12 +7261,12 @@ async function transformsMenu(proj2) {
5982
7261
  const out = await admin({ method: "GET", path: base2, summary: "List transform rules" });
5983
7262
  const rules = out?.rules ?? [];
5984
7263
  console.log();
5985
- if (!rules.length) console.log(import_chalk37.default.dim(" No transform rules yet."));
7264
+ if (!rules.length) console.log(import_chalk40.default.dim(" No transform rules yet."));
5986
7265
  for (const r of rules) {
5987
7266
  const a = r.action ?? {};
5988
7267
  const fns = [...a.source_fns ?? [], ...a.dest_fns ?? []].map((f) => f.fn);
5989
- const what = a.type === "hardcode" ? `${a.destination} = "${a.value}"` : a.type === "remove" ? `remove ${a.field}` : `${a.source} \u2192 ${a.destination}${a.lookup ? " (mapped)" : ""}${fns.length ? import_chalk37.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
5990
- console.log(` ${r.enabled ? import_chalk37.default.green("\u25CF") : import_chalk37.default.dim("\u25CB")} ${import_chalk37.default.bold(r.name)} ${import_chalk37.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
7268
+ 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_chalk40.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
7269
+ console.log(` ${r.enabled ? import_chalk40.default.green("\u25CF") : import_chalk40.default.dim("\u25CB")} ${import_chalk40.default.bold(r.name)} ${import_chalk40.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
5991
7270
  }
5992
7271
  const { act } = await inquirer3.prompt([{
5993
7272
  type: "list",
@@ -5999,7 +7278,7 @@ async function transformsMenu(proj2) {
5999
7278
  { name: "Enable/disable a rule", value: "toggle" },
6000
7279
  { name: "Delete a rule", value: "delete" }
6001
7280
  ] : [],
6002
- { name: import_chalk37.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
7281
+ { name: import_chalk40.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
6003
7282
  { name: "\u2190 Back", value: "back" }
6004
7283
  ]
6005
7284
  }]);
@@ -6012,11 +7291,11 @@ async function transformsMenu(proj2) {
6012
7291
  }]);
6013
7292
  const body = parseValue(raw);
6014
7293
  if (!body || typeof body !== "object" || Array.isArray(body)) {
6015
- console.log(import_chalk37.default.yellow(" Not a JSON object \u2014 skipped."));
7294
+ console.log(import_chalk40.default.yellow(" Not a JSON object \u2014 skipped."));
6016
7295
  continue;
6017
7296
  }
6018
7297
  await admin({ method: "POST", path: base2, body, summary: "Create transform rule (raw JSON)" });
6019
- console.log(import_chalk37.default.green(" Rule created."));
7298
+ console.log(import_chalk40.default.green(" Rule created."));
6020
7299
  continue;
6021
7300
  }
6022
7301
  if (act === "add") {
@@ -6032,7 +7311,7 @@ async function transformsMenu(proj2) {
6032
7311
  { name: "Remove a field", value: "remove" }
6033
7312
  ] }
6034
7313
  ]);
6035
- const fieldHint = import_chalk37.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
7314
+ const fieldHint = import_chalk40.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
6036
7315
  let action2;
6037
7316
  if (ans.kind === "hardcode") {
6038
7317
  const a = await inquirer3.prompt([
@@ -6061,7 +7340,7 @@ async function transformsMenu(proj2) {
6061
7340
  };
6062
7341
  }
6063
7342
  const condition = await buildCondition(ans.phase);
6064
- const spinner = (0, import_ora16.default)("Creating rule...").start();
7343
+ const spinner = (0, import_ora18.default)("Creating rule...").start();
6065
7344
  try {
6066
7345
  await admin({
6067
7346
  method: "POST",
@@ -6079,16 +7358,16 @@ async function transformsMenu(proj2) {
6079
7358
  type: "list",
6080
7359
  name: "rule",
6081
7360
  message: act === "toggle" ? "Which rule?" : "Delete which rule?",
6082
- choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk37.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
7361
+ choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk40.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
6083
7362
  }]);
6084
7363
  if (!rule) continue;
6085
7364
  if (act === "toggle") {
6086
7365
  const flipped = { ...rule, enabled: rule.enabled === false };
6087
7366
  await admin({ method: "PUT", path: `${base2}/${rule.id}`, body: flipped, summary: `${flipped.enabled ? "Enable" : "Disable"} transform "${rule.name}"` });
6088
- console.log(import_chalk37.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
7367
+ console.log(import_chalk40.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
6089
7368
  } else {
6090
7369
  await admin({ method: "DELETE", path: `${base2}/${rule.id}`, summary: `Delete transform "${rule.name}"` });
6091
- console.log(import_chalk37.default.green(` ${rule.name} deleted.`));
7370
+ console.log(import_chalk40.default.green(` ${rule.name} deleted.`));
6092
7371
  }
6093
7372
  }
6094
7373
  }
@@ -6100,9 +7379,9 @@ async function mappingsMenu(proj2) {
6100
7379
  const out = await admin({ method: "GET", path: base2, summary: "List mapping tables" });
6101
7380
  const tables = out?.mappings ?? out?.tables ?? [];
6102
7381
  console.log();
6103
- if (!tables.length) console.log(import_chalk37.default.dim(" No mapping tables yet."));
7382
+ if (!tables.length) console.log(import_chalk40.default.dim(" No mapping tables yet."));
6104
7383
  for (const t of tables) {
6105
- console.log(` ${import_chalk37.default.bold(t.name)} ${import_chalk37.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
7384
+ console.log(` ${import_chalk40.default.bold(t.name)} ${import_chalk40.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
6106
7385
  }
6107
7386
  const { act } = await inquirer3.prompt([{
6108
7387
  type: "list",
@@ -6122,11 +7401,11 @@ async function mappingsMenu(proj2) {
6122
7401
  ]);
6123
7402
  const entries2 = parseValue(a.entries);
6124
7403
  if (!Array.isArray(entries2)) {
6125
- console.log(import_chalk37.default.yellow(" Entries must be a JSON array \u2014 not created."));
7404
+ console.log(import_chalk40.default.yellow(" Entries must be a JSON array \u2014 not created."));
6126
7405
  continue;
6127
7406
  }
6128
7407
  await admin({ method: "POST", path: base2, body: { name: a.name, entries: entries2 }, summary: `Create mapping table "${a.name}"` });
6129
- console.log(import_chalk37.default.green(` Table "${a.name}" created.`));
7408
+ console.log(import_chalk40.default.green(` Table "${a.name}" created.`));
6130
7409
  } else {
6131
7410
  const { table } = await inquirer3.prompt([{
6132
7411
  type: "list",
@@ -6136,7 +7415,7 @@ async function mappingsMenu(proj2) {
6136
7415
  }]);
6137
7416
  if (!table) continue;
6138
7417
  await admin({ method: "DELETE", path: `${base2}/${table.id}`, summary: `Delete mapping table "${table.name}"` });
6139
- console.log(import_chalk37.default.green(` ${table.name} deleted.`));
7418
+ console.log(import_chalk40.default.green(` ${table.name} deleted.`));
6140
7419
  }
6141
7420
  }
6142
7421
  }
@@ -6147,14 +7426,14 @@ async function tenantsMenu(proj2, opts) {
6147
7426
  const out = await admin({ method: "GET", path: base2, summary: "List attached tenants" });
6148
7427
  const tenants = out?.tenants ?? [];
6149
7428
  console.log();
6150
- if (!tenants.length) console.log(import_chalk37.default.dim(" No tenants attached (consumers use the default tenant)."));
6151
- for (const t of tenants) console.log(` ${import_chalk37.default.bold(t.tenant_name ?? t.name)} ${import_chalk37.default.dim(t.display_name ?? "")}`);
7429
+ if (!tenants.length) console.log(import_chalk40.default.dim(" No tenants attached (consumers use the default tenant)."));
7430
+ for (const t of tenants) console.log(` ${import_chalk40.default.bold(t.tenant_name ?? t.name)} ${import_chalk40.default.dim(t.display_name ?? "")}`);
6152
7431
  const { act } = await inquirer3.prompt([{
6153
7432
  type: "list",
6154
7433
  name: "act",
6155
7434
  message: "Tenants:",
6156
7435
  choices: [
6157
- { name: `Manage a tenant\u2026 ${import_chalk37.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
7436
+ { name: `Manage a tenant\u2026 ${import_chalk40.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
6158
7437
  { name: "Attach a tenant to this project", value: "attach" },
6159
7438
  ...tenants.length ? [{ name: "Detach a tenant from this project", value: "detach" }] : [],
6160
7439
  { name: "\u2190 Back", value: "back" }
@@ -6177,7 +7456,7 @@ async function tenantsMenu(proj2, opts) {
6177
7456
  }]);
6178
7457
  if (!t) continue;
6179
7458
  await admin({ method: "DELETE", path: `${base2}/${encodeURIComponent(t.tenant_name ?? t.name)}`, summary: `Detach tenant ${t.tenant_name ?? t.name}` });
6180
- console.log(import_chalk37.default.green(` Detached ${t.tenant_name ?? t.name}.`));
7459
+ console.log(import_chalk40.default.green(` Detached ${t.tenant_name ?? t.name}.`));
6181
7460
  }
6182
7461
  }
6183
7462
  }
@@ -6220,7 +7499,7 @@ async function specMenu(proj2, opts) {
6220
7499
  choices: [
6221
7500
  { name: "Print the stored spec", value: "get" },
6222
7501
  { name: "Refresh the spec from its source", value: "refresh" },
6223
- { name: import_chalk37.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
7502
+ { name: import_chalk40.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
6224
7503
  { name: "\u2190 Back", value: "back" }
6225
7504
  ]
6226
7505
  }]);
@@ -6228,7 +7507,7 @@ async function specMenu(proj2, opts) {
6228
7507
  if (act === "get") await runSpecGet(proj2.projectName, { team: opts.team, apiversion: proj2.apiVersion });
6229
7508
  else if (act === "refresh") {
6230
7509
  await admin({ method: "POST", path: `/projects/${proj2.projectId}/${proj2.apiVersion}/refresh-spec`, summary: "Refresh spec from source" });
6231
- console.log(import_chalk37.default.green(" Spec refresh triggered."));
7510
+ console.log(import_chalk40.default.green(" Spec refresh triggered."));
6232
7511
  } else await runOpenapi(proj2.projectName, proj2.apiVersion);
6233
7512
  }
6234
7513
  async function agentsMenu(proj2, opts) {
@@ -6253,8 +7532,8 @@ async function agentsMenu(proj2, opts) {
6253
7532
  }
6254
7533
 
6255
7534
  // src/commands/group.ts
6256
- var import_chalk38 = __toESM(require("chalk"));
6257
- var import_ora17 = __toESM(require("ora"));
7535
+ var import_chalk41 = __toESM(require("chalk"));
7536
+ var import_ora19 = __toESM(require("ora"));
6258
7537
  init_auth();
6259
7538
  init_admin();
6260
7539
  init_resolve();
@@ -6347,7 +7626,7 @@ async function userByRefOrCreate(t, ref) {
6347
7626
  if (!ref.includes("@")) throw e;
6348
7627
  const created = await t.call("/v1/admin/users", "POST", { email: ref.trim().toLowerCase() });
6349
7628
  if (!created?.abz_sub) throw e;
6350
- console.log(import_chalk38.default.dim(` ${ref} wasn't a user yet \u2014 created.`));
7629
+ console.log(import_chalk41.default.dim(` ${ref} wasn't a user yet \u2014 created.`));
6351
7630
  return { abz_sub: created.abz_sub, email: created.email ?? ref, display_name: null };
6352
7631
  }
6353
7632
  }
@@ -6355,11 +7634,11 @@ async function runGroupList(opts) {
6355
7634
  const t = await resolveTransport(opts);
6356
7635
  const groups = await listGroups(t);
6357
7636
  if (opts.json) return void console.log(JSON.stringify(groups));
6358
- if (!groups.length) return void console.log(import_chalk38.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
6359
- console.log(import_chalk38.default.dim(`Tenant ${t.tenant}:`));
7637
+ if (!groups.length) return void console.log(import_chalk41.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
7638
+ console.log(import_chalk41.default.dim(`Tenant ${t.tenant}:`));
6360
7639
  for (const g of groups) {
6361
- const sealed = g.name === "apiblaze_admins" ? import_chalk38.default.dim(" (admins \u2014 managed by allowlist)") : "";
6362
- console.log(` ${import_chalk38.default.bold(g.name)} ${import_chalk38.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
7640
+ const sealed = g.name === "apiblaze_admins" ? import_chalk41.default.dim(" (admins \u2014 managed by allowlist)") : "";
7641
+ console.log(` ${import_chalk41.default.bold(g.name)} ${import_chalk41.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
6363
7642
  }
6364
7643
  }
6365
7644
  async function runGroupCreate(name, opts) {
@@ -6384,10 +7663,10 @@ async function runGroupCreate(name, opts) {
6384
7663
  }
6385
7664
  }
6386
7665
  }
6387
- const spinner = (0, import_ora17.default)(`Creating group ${name}...`).start();
7666
+ const spinner = (0, import_ora19.default)(`Creating group ${name}...`).start();
6388
7667
  try {
6389
7668
  await t.call("/v1/admin/groups", "POST", { name, admins: [adminSub] });
6390
- spinner.succeed(`Group ${import_chalk38.default.bold(name)} created in ${t.tenant}.`);
7669
+ spinner.succeed(`Group ${import_chalk41.default.bold(name)} created in ${t.tenant}.`);
6391
7670
  } catch (e) {
6392
7671
  spinner.fail("Create failed.");
6393
7672
  throw e;
@@ -6396,10 +7675,10 @@ async function runGroupCreate(name, opts) {
6396
7675
  async function runGroupDelete(name, opts) {
6397
7676
  const t = await resolveTransport(opts);
6398
7677
  const g = await groupByName(t, name);
6399
- const spinner = (0, import_ora17.default)(`Deleting group ${name}...`).start();
7678
+ const spinner = (0, import_ora19.default)(`Deleting group ${name}...`).start();
6400
7679
  try {
6401
7680
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}`, "DELETE");
6402
- spinner.succeed(`Group ${import_chalk38.default.bold(name)} deleted.`);
7681
+ spinner.succeed(`Group ${import_chalk41.default.bold(name)} deleted.`);
6403
7682
  } catch (e) {
6404
7683
  spinner.fail("Delete failed.");
6405
7684
  throw e;
@@ -6412,21 +7691,21 @@ async function runGroupMembers(name, opts) {
6412
7691
  const subs = await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/subgroups`);
6413
7692
  if (opts.json) return void console.log(JSON.stringify({ ...detail, subgroups: subs?.subgroups ?? [] }));
6414
7693
  const members = detail?.members ?? [];
6415
- console.log(import_chalk38.default.bold(`${g.name}`) + import_chalk38.default.dim(` (${t.tenant})`));
6416
- for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk38.default.cyan("group-admin") : import_chalk38.default.dim("member")}`);
6417
- if (!members.length) console.log(import_chalk38.default.dim(" no members"));
7694
+ console.log(import_chalk41.default.bold(`${g.name}`) + import_chalk41.default.dim(` (${t.tenant})`));
7695
+ for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk41.default.cyan("group-admin") : import_chalk41.default.dim("member")}`);
7696
+ if (!members.length) console.log(import_chalk41.default.dim(" no members"));
6418
7697
  const sg = subs?.subgroups ?? [];
6419
- if (sg.length) console.log(import_chalk38.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
7698
+ if (sg.length) console.log(import_chalk41.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
6420
7699
  }
6421
7700
  async function runGroupAddUser(userRef, groupName, opts) {
6422
7701
  const t = await resolveTransport(opts);
6423
7702
  const g = await groupByName(t, groupName);
6424
7703
  const u = await userByRefOrCreate(t, userRef);
6425
7704
  const role = opts.role === "admin" ? "admin" : "member";
6426
- const spinner = (0, import_ora17.default)(`Adding ${label2(u)} to ${g.name}...`).start();
7705
+ const spinner = (0, import_ora19.default)(`Adding ${label2(u)} to ${g.name}...`).start();
6427
7706
  try {
6428
7707
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members`, "POST", { abz_sub: u.abz_sub, role });
6429
- spinner.succeed(`${import_chalk38.default.bold(label2(u))} added to ${import_chalk38.default.bold(g.name)} as ${role}.`);
7708
+ spinner.succeed(`${import_chalk41.default.bold(label2(u))} added to ${import_chalk41.default.bold(g.name)} as ${role}.`);
6430
7709
  } catch (e) {
6431
7710
  spinner.fail("Add failed.");
6432
7711
  throw e;
@@ -6435,10 +7714,10 @@ async function runGroupAddUser(userRef, groupName, opts) {
6435
7714
  async function runGroupRemoveUser(userRef, groupName, opts) {
6436
7715
  const t = await resolveTransport(opts);
6437
7716
  const [g, u] = [await groupByName(t, groupName), await userByRef(t, userRef)];
6438
- const spinner = (0, import_ora17.default)(`Removing ${label2(u)} from ${g.name}...`).start();
7717
+ const spinner = (0, import_ora19.default)(`Removing ${label2(u)} from ${g.name}...`).start();
6439
7718
  try {
6440
7719
  await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members/_?abz_sub=${encodeURIComponent(u.abz_sub)}`, "DELETE");
6441
- spinner.succeed(`${import_chalk38.default.bold(label2(u))} removed from ${import_chalk38.default.bold(g.name)}.`);
7720
+ spinner.succeed(`${import_chalk41.default.bold(label2(u))} removed from ${import_chalk41.default.bold(g.name)}.`);
6442
7721
  } catch (e) {
6443
7722
  spinner.fail("Remove failed.");
6444
7723
  throw e;
@@ -6447,10 +7726,10 @@ async function runGroupRemoveUser(userRef, groupName, opts) {
6447
7726
  async function runGroupAddGroup(childName, parentName, opts) {
6448
7727
  const t = await resolveTransport(opts);
6449
7728
  const [child, parent] = [await groupByName(t, childName), await groupByName(t, parentName)];
6450
- const spinner = (0, import_ora17.default)(`Nesting ${child.name} under ${parent.name}...`).start();
7729
+ const spinner = (0, import_ora19.default)(`Nesting ${child.name} under ${parent.name}...`).start();
6451
7730
  try {
6452
7731
  await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups`, "POST", { child_group_id: child.id });
6453
- spinner.succeed(`${import_chalk38.default.bold(child.name)} is now a subgroup of ${import_chalk38.default.bold(parent.name)}.`);
7732
+ spinner.succeed(`${import_chalk41.default.bold(child.name)} is now a subgroup of ${import_chalk41.default.bold(parent.name)}.`);
6454
7733
  } catch (e) {
6455
7734
  spinner.fail("Nest failed.");
6456
7735
  throw e;
@@ -6459,10 +7738,10 @@ async function runGroupAddGroup(childName, parentName, opts) {
6459
7738
  async function runGroupRemoveGroup(childName, parentName, opts) {
6460
7739
  const t = await resolveTransport(opts);
6461
7740
  const [child, parent] = [await groupByName(t, childName), await groupByName(t, parentName)];
6462
- const spinner = (0, import_ora17.default)(`Un-nesting ${child.name} from ${parent.name}...`).start();
7741
+ const spinner = (0, import_ora19.default)(`Un-nesting ${child.name} from ${parent.name}...`).start();
6463
7742
  try {
6464
7743
  await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups/${encodeURIComponent(child.id)}`, "DELETE");
6465
- spinner.succeed(`${import_chalk38.default.bold(child.name)} un-nested from ${import_chalk38.default.bold(parent.name)}.`);
7744
+ spinner.succeed(`${import_chalk41.default.bold(child.name)} un-nested from ${import_chalk41.default.bold(parent.name)}.`);
6466
7745
  } catch (e) {
6467
7746
  spinner.fail("Un-nest failed.");
6468
7747
  throw e;
@@ -6473,19 +7752,19 @@ async function runGroupUsers(opts) {
6473
7752
  const users = await listUsers(t);
6474
7753
  const observed = await t.call("/v1/admin/observed-identities").catch(() => ({ identities: [] }));
6475
7754
  if (opts.json) return void console.log(JSON.stringify({ users, observed: observed?.identities ?? [] }));
6476
- console.log(import_chalk38.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
6477
- for (const u of users) console.log(` ${label2(u)} ${import_chalk38.default.dim(u.abz_sub)}`);
6478
- if (!users.length) console.log(import_chalk38.default.dim(" no users yet"));
7755
+ console.log(import_chalk41.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
7756
+ for (const u of users) console.log(` ${label2(u)} ${import_chalk41.default.dim(u.abz_sub)}`);
7757
+ if (!users.length) console.log(import_chalk41.default.dim(" no users yet"));
6479
7758
  const fresh = (observed?.identities ?? []).filter((o) => !o.provisioned);
6480
7759
  if (fresh.length) {
6481
- console.log(import_chalk38.default.dim("Seen in traffic (not yet users):"));
6482
- for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk38.default.dim(o.source_label ?? "")}`);
7760
+ console.log(import_chalk41.default.dim("Seen in traffic (not yet users):"));
7761
+ for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk41.default.dim(o.source_label ?? "")}`);
6483
7762
  }
6484
7763
  }
6485
7764
 
6486
7765
  // src/commands/key.ts
6487
- var import_chalk39 = __toESM(require("chalk"));
6488
- var import_ora18 = __toESM(require("ora"));
7766
+ var import_chalk42 = __toESM(require("chalk"));
7767
+ var import_ora20 = __toESM(require("ora"));
6489
7768
  init_caller();
6490
7769
  async function runApikeysMenu(opts) {
6491
7770
  await runKeyList(opts);
@@ -6514,11 +7793,11 @@ async function runKeyList(opts) {
6514
7793
  return;
6515
7794
  }
6516
7795
  if (!keys.length) {
6517
- console.log(import_chalk39.default.yellow("No developer keys."));
7796
+ console.log(import_chalk42.default.yellow("No developer keys."));
6518
7797
  return;
6519
7798
  }
6520
7799
  for (const k of keys) {
6521
- console.log(` ${import_chalk39.default.bold(k.key_id ?? k.id)} ${import_chalk39.default.dim(k.description ?? "")} ${import_chalk39.default.dim(k.expires_at ?? "no expiry")}`);
7800
+ console.log(` ${import_chalk42.default.bold(k.key_id ?? k.id)} ${import_chalk42.default.dim(k.description ?? "")} ${import_chalk42.default.dim(k.expires_at ?? "no expiry")}`);
6522
7801
  }
6523
7802
  }
6524
7803
  async function runKeyMint(opts) {
@@ -6527,7 +7806,7 @@ async function runKeyMint(opts) {
6527
7806
  const body = { role: "consumer-admin" };
6528
7807
  if (opts.desc) body.description = opts.desc;
6529
7808
  if (opts.expiresDays) body.expires_in_seconds = Number(opts.expiresDays) * 24 * 60 * 60;
6530
- const spinner = (0, import_ora18.default)("Minting key...").start();
7809
+ const spinner = (0, import_ora20.default)("Minting key...").start();
6531
7810
  try {
6532
7811
  const out = await producer(caller, {
6533
7812
  method: "POST",
@@ -6540,9 +7819,9 @@ async function runKeyMint(opts) {
6540
7819
  console.log(JSON.stringify(out));
6541
7820
  return;
6542
7821
  }
6543
- console.log(` ${import_chalk39.default.bold("key_id")}: ${out?.key_id}`);
6544
- console.log(` ${import_chalk39.default.bold("key")}: ${import_chalk39.default.green(out?.key)} ${import_chalk39.default.dim("(shown once \u2014 store it now)")}`);
6545
- if (out?.expires_at) console.log(` ${import_chalk39.default.dim("expires:")} ${out.expires_at}`);
7822
+ console.log(` ${import_chalk42.default.bold("key_id")}: ${out?.key_id}`);
7823
+ console.log(` ${import_chalk42.default.bold("key")}: ${import_chalk42.default.green(out?.key)} ${import_chalk42.default.dim("(shown once \u2014 store it now)")}`);
7824
+ if (out?.expires_at) console.log(` ${import_chalk42.default.dim("expires:")} ${out.expires_at}`);
6546
7825
  } catch (err) {
6547
7826
  spinner.fail("Mint failed.");
6548
7827
  throw err;
@@ -6551,7 +7830,7 @@ async function runKeyMint(opts) {
6551
7830
  async function runKeyRevoke(keyId, opts) {
6552
7831
  const caller = requireCaller();
6553
7832
  const { teamId } = await resolveActingTeam(caller, opts.team);
6554
- const spinner = (0, import_ora18.default)("Revoking key...").start();
7833
+ const spinner = (0, import_ora20.default)("Revoking key...").start();
6555
7834
  try {
6556
7835
  await producer(caller, {
6557
7836
  method: "DELETE",
@@ -6569,8 +7848,8 @@ async function runKeyRevoke(keyId, opts) {
6569
7848
  init_iam();
6570
7849
 
6571
7850
  // src/commands/admins.ts
6572
- var import_chalk40 = __toESM(require("chalk"));
6573
- var import_ora19 = __toESM(require("ora"));
7851
+ var import_chalk43 = __toESM(require("chalk"));
7852
+ var import_ora21 = __toESM(require("ora"));
6574
7853
  init_caller();
6575
7854
  function requireTenant(opts) {
6576
7855
  const t = (opts.tenant ?? "").trim();
@@ -6597,20 +7876,20 @@ async function runAdminsList(opts) {
6597
7876
  return;
6598
7877
  }
6599
7878
  if (!admins2.length) {
6600
- console.log(import_chalk40.default.yellow(`No tenant admins for ${tenant2} yet.`));
7879
+ console.log(import_chalk43.default.yellow(`No tenant admins for ${tenant2} yet.`));
6601
7880
  return;
6602
7881
  }
6603
7882
  for (const a of admins2) {
6604
7883
  const email = typeof a === "string" ? a : a.email;
6605
7884
  const flags = [a.active === false ? "pending" : null, a.pinned ? "pinned" : null].filter(Boolean).join(", ");
6606
- console.log(` ${import_chalk40.default.bold(email)}${flags ? import_chalk40.default.dim(` (${flags})`) : ""}`);
7885
+ console.log(` ${import_chalk43.default.bold(email)}${flags ? import_chalk43.default.dim(` (${flags})`) : ""}`);
6607
7886
  }
6608
7887
  }
6609
7888
  async function runAdminsAdd(email, opts) {
6610
7889
  const caller = requireCaller();
6611
7890
  const { teamId } = await resolveActingTeam(caller, opts.team);
6612
7891
  const tenant2 = requireTenant(opts);
6613
- const spinner = opts.json ? null : (0, import_ora19.default)(`Adding ${email} as a tenant admin of ${tenant2}...`).start();
7892
+ const spinner = opts.json ? null : (0, import_ora21.default)(`Adding ${email} as a tenant admin of ${tenant2}...`).start();
6614
7893
  try {
6615
7894
  const out = await producer(caller, {
6616
7895
  method: "POST",
@@ -6618,9 +7897,9 @@ async function runAdminsAdd(email, opts) {
6618
7897
  body: { email },
6619
7898
  summary: `Add ${email} to tenant ${tenant2} admins`
6620
7899
  });
6621
- spinner?.succeed(`${import_chalk40.default.bold(email)} is now a tenant admin of ${import_chalk40.default.bold(tenant2)}.`);
7900
+ spinner?.succeed(`${import_chalk43.default.bold(email)} is now a tenant admin of ${import_chalk43.default.bold(tenant2)}.`);
6622
7901
  if (opts.json) console.log(JSON.stringify(out ?? { ok: true }));
6623
- else console.log(import_chalk40.default.dim(" Reload the Users & Groups widget \u2014 access flips from \u201Cpending\u201D to ready."));
7902
+ else console.log(import_chalk43.default.dim(" Reload the Users & Groups widget \u2014 access flips from \u201Cpending\u201D to ready."));
6624
7903
  } catch (err) {
6625
7904
  spinner?.fail("Add failed.");
6626
7905
  throw err;
@@ -6630,14 +7909,14 @@ async function runAdminsRemove(email, opts) {
6630
7909
  const caller = requireCaller();
6631
7910
  const { teamId } = await resolveActingTeam(caller, opts.team);
6632
7911
  const tenant2 = requireTenant(opts);
6633
- const spinner = opts.json ? null : (0, import_ora19.default)(`Removing ${email} from the tenant admins of ${tenant2}...`).start();
7912
+ const spinner = opts.json ? null : (0, import_ora21.default)(`Removing ${email} from the tenant admins of ${tenant2}...`).start();
6634
7913
  try {
6635
7914
  await producer(caller, {
6636
7915
  method: "DELETE",
6637
7916
  path: `${base(teamId, tenant2)}/${encodeURIComponent(email)}`,
6638
7917
  summary: `Remove ${email} from tenant ${tenant2} admins`
6639
7918
  });
6640
- spinner?.succeed(`Removed ${import_chalk40.default.bold(email)} from the tenant admins of ${import_chalk40.default.bold(tenant2)}.`);
7919
+ spinner?.succeed(`Removed ${import_chalk43.default.bold(email)} from the tenant admins of ${import_chalk43.default.bold(tenant2)}.`);
6641
7920
  } catch (err) {
6642
7921
  spinner?.fail("Remove failed.");
6643
7922
  throw err;
@@ -6645,8 +7924,8 @@ async function runAdminsRemove(email, opts) {
6645
7924
  }
6646
7925
 
6647
7926
  // src/commands/preapprove.ts
6648
- var import_chalk41 = __toESM(require("chalk"));
6649
- var import_ora20 = __toESM(require("ora"));
7927
+ var import_chalk44 = __toESM(require("chalk"));
7928
+ var import_ora22 = __toESM(require("ora"));
6650
7929
 
6651
7930
  // src/lib/preapproval.ts
6652
7931
  init_auth();
@@ -6710,14 +7989,14 @@ async function runPreapprove(who, opts) {
6710
7989
  const rules = await listPreapprovalRules(tenant2);
6711
7990
  if (opts.json) return void console.log(JSON.stringify(rules, null, 2));
6712
7991
  if (!rules.length) {
6713
- console.log(import_chalk41.default.dim(`No pre-approval rules in ${tenant2}. Anyone who signs in can access (unless access is restricted).`));
6714
- console.log(import_chalk41.default.dim(`Add one: apiblaze preapprove someone@acme.com`));
7992
+ console.log(import_chalk44.default.dim(`No pre-approval rules in ${tenant2}. Anyone who signs in can access (unless access is restricted).`));
7993
+ console.log(import_chalk44.default.dim(`Add one: apiblaze preapprove someone@acme.com`));
6715
7994
  return;
6716
7995
  }
6717
- console.log(import_chalk41.default.dim(`Pre-approved for ${import_chalk41.default.bold(tenant2)}:`));
7996
+ console.log(import_chalk44.default.dim(`Pre-approved for ${import_chalk44.default.bold(tenant2)}:`));
6718
7997
  for (const r of rules) {
6719
- const tag = r.kind === "domain" ? import_chalk41.default.cyan("@" + r.value + " (whole domain)") : r.value;
6720
- const grp = r.groups?.length ? import_chalk41.default.dim(` \u2192 groups: ${r.groups.join(", ")}`) : "";
7998
+ const tag = r.kind === "domain" ? import_chalk44.default.cyan("@" + r.value + " (whole domain)") : r.value;
7999
+ const grp = r.groups?.length ? import_chalk44.default.dim(` \u2192 groups: ${r.groups.join(", ")}`) : "";
6721
8000
  console.log(` ${tag}${grp}`);
6722
8001
  }
6723
8002
  return;
@@ -6726,19 +8005,19 @@ async function runPreapprove(who, opts) {
6726
8005
  throw new Error("Who? Pass an email or a domain: `apiblaze preapprove someone@acme.com` (or `apiblaze preapprove --list`).");
6727
8006
  }
6728
8007
  if (opts.remove) {
6729
- const spinner2 = (0, import_ora20.default)(`Removing ${who} from ${tenant2}\u2026`).start();
8008
+ const spinner2 = (0, import_ora22.default)(`Removing ${who} from ${tenant2}\u2026`).start();
6730
8009
  const { removed, value } = await removePreapprovalRule(tenant2, who);
6731
- if (removed) spinner2.succeed(`${import_chalk41.default.bold(value)} is no longer pre-approved for ${tenant2}.`);
6732
- else spinner2.warn(`No pre-approval rule for ${import_chalk41.default.bold(value)} in ${tenant2} \u2014 nothing to remove.`);
8010
+ if (removed) spinner2.succeed(`${import_chalk44.default.bold(value)} is no longer pre-approved for ${tenant2}.`);
8011
+ else spinner2.warn(`No pre-approval rule for ${import_chalk44.default.bold(value)} in ${tenant2} \u2014 nothing to remove.`);
6733
8012
  return;
6734
8013
  }
6735
- const spinner = (0, import_ora20.default)(`Pre-approving ${who} for ${tenant2}\u2026`).start();
8014
+ const spinner = (0, import_ora22.default)(`Pre-approving ${who} for ${tenant2}\u2026`).start();
6736
8015
  try {
6737
8016
  const { kind, value } = await addPreapprovalRule(tenant2, who, opts.group);
6738
8017
  const what = kind === "domain" ? `Anyone @${value}` : value;
6739
- spinner.succeed(`${import_chalk41.default.bold(what)} can now sign in to ${import_chalk41.default.bold(tenant2)}.`);
6740
- if (opts.group?.length) console.log(import_chalk41.default.dim(` They'll join group(s) ${opts.group.join(", ")} on first sign-in.`));
6741
- console.log(import_chalk41.default.dim(` See the full list: apiblaze preapprove --list`));
8018
+ spinner.succeed(`${import_chalk44.default.bold(what)} can now sign in to ${import_chalk44.default.bold(tenant2)}.`);
8019
+ if (opts.group?.length) console.log(import_chalk44.default.dim(` They'll join group(s) ${opts.group.join(", ")} on first sign-in.`));
8020
+ console.log(import_chalk44.default.dim(` See the full list: apiblaze preapprove --list`));
6742
8021
  } catch (err) {
6743
8022
  spinner.fail("Could not add the rule.");
6744
8023
  throw err;
@@ -6749,8 +8028,8 @@ async function runPreapprove(who, opts) {
6749
8028
  var fs9 = __toESM(require("fs"));
6750
8029
  var path6 = __toESM(require("path"));
6751
8030
  var crypto2 = __toESM(require("crypto"));
6752
- var import_chalk43 = __toESM(require("chalk"));
6753
- var import_ora21 = __toESM(require("ora"));
8031
+ var import_chalk46 = __toESM(require("chalk"));
8032
+ var import_ora23 = __toESM(require("ora"));
6754
8033
  var import_yaml2 = require("yaml");
6755
8034
  init_auth();
6756
8035
  init_anon_cred();
@@ -6760,7 +8039,7 @@ init_admin();
6760
8039
  // src/commands/llm.ts
6761
8040
  var fs8 = __toESM(require("fs"));
6762
8041
  var path5 = __toESM(require("path"));
6763
- var import_chalk42 = __toESM(require("chalk"));
8042
+ var import_chalk45 = __toESM(require("chalk"));
6764
8043
  var import_inquirer2 = __toESM(require("inquirer"));
6765
8044
  init_auth();
6766
8045
  var LLM_PATH = path5.join(getApiblazeDir(), "llm.json");
@@ -6804,27 +8083,27 @@ async function runLlmSetKey(keyArg, opts) {
6804
8083
  }
6805
8084
  const existing = loadLlmConfig();
6806
8085
  saveLlmConfig({ key, provider, model: opts.model ?? existing?.model });
6807
- console.log(`${import_chalk42.default.green("\u2713")} Saved ${import_chalk42.default.bold(provider)} key ${maskSecret(key)}`);
6808
- console.log(import_chalk42.default.gray(` Stored locally at ${LLM_PATH} (0600) \u2014 never sent to APIblaze except per chat turn.`));
6809
- if (opts.model) console.log(import_chalk42.default.gray(` Model: ${opts.model}`));
8086
+ console.log(`${import_chalk45.default.green("\u2713")} Saved ${import_chalk45.default.bold(provider)} key ${maskSecret(key)}`);
8087
+ console.log(import_chalk45.default.gray(` Stored locally at ${LLM_PATH} (0600) \u2014 never sent to APIblaze except per chat turn.`));
8088
+ if (opts.model) console.log(import_chalk45.default.gray(` Model: ${opts.model}`));
6810
8089
  }
6811
8090
  async function runLlmShow() {
6812
8091
  const cfg = loadLlmConfig();
6813
8092
  if (!cfg) {
6814
- console.log(import_chalk42.default.gray("No LLM key set. `apiblaze llm set-key sk-...` to add one (optional \u2014 chat works without it)."));
8093
+ console.log(import_chalk45.default.gray("No LLM key set. `apiblaze llm set-key sk-...` to add one (optional \u2014 chat works without it)."));
6815
8094
  return;
6816
8095
  }
6817
- console.log(`Provider: ${import_chalk42.default.bold(cfg.provider)}`);
8096
+ console.log(`Provider: ${import_chalk45.default.bold(cfg.provider)}`);
6818
8097
  console.log(`Key: ${maskSecret(cfg.key)}`);
6819
8098
  if (cfg.model) console.log(`Model: ${cfg.model}`);
6820
- console.log(import_chalk42.default.gray(`Stored at ${LLM_PATH}`));
8099
+ console.log(import_chalk45.default.gray(`Stored at ${LLM_PATH}`));
6821
8100
  }
6822
8101
  async function runLlmClearKey() {
6823
8102
  try {
6824
8103
  fs8.unlinkSync(LLM_PATH);
6825
- console.log(`${import_chalk42.default.green("\u2713")} Removed local LLM key.`);
8104
+ console.log(`${import_chalk45.default.green("\u2713")} Removed local LLM key.`);
6826
8105
  } catch {
6827
- console.log(import_chalk42.default.gray("No LLM key was set."));
8106
+ console.log(import_chalk45.default.gray("No LLM key was set."));
6828
8107
  }
6829
8108
  }
6830
8109
 
@@ -6832,12 +8111,12 @@ async function runLlmClearKey() {
6832
8111
  init_trace();
6833
8112
  init_types();
6834
8113
  function fail4(message, hint) {
6835
- console.error(import_chalk43.default.red(`
8114
+ console.error(import_chalk46.default.red(`
6836
8115
  Error: ${message}`));
6837
- if (hint) console.error(import_chalk43.default.dim(hint));
8116
+ if (hint) console.error(import_chalk46.default.dim(hint));
6838
8117
  process.exit(1);
6839
8118
  }
6840
- function normalizeName2(raw) {
8119
+ function normalizeName3(raw) {
6841
8120
  return (raw || "").toLowerCase().replace(/[^a-z0-9]/g, "");
6842
8121
  }
6843
8122
  function isHttpUrl2(s) {
@@ -6982,7 +8261,7 @@ async function resolveTargetAuth(spec2, opts) {
6982
8261
  "Re-run with --force to provision anyway (configure target auth later with `apiblaze config`),\nor use an api_key / bearer / basic scheme."
6983
8262
  );
6984
8263
  }
6985
- if (sawOAuth) console.log(import_chalk43.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
8264
+ if (sawOAuth) console.log(import_chalk46.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
6986
8265
  return null;
6987
8266
  }
6988
8267
  if (candidates.length === 1 && !noneAllowed) return candidates[0];
@@ -7055,11 +8334,11 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
7055
8334
  const fresh = await validConsumerToken(existing);
7056
8335
  if (fresh) {
7057
8336
  if (fresh.accessToken !== existing.accessToken) saveConsumer({ ...fresh, resource });
7058
- console.log(import_chalk43.default.dim(` Using your consumer session on ${import_chalk43.default.bold(tenant2)}${fresh.email ? ` (${fresh.email})` : ""}.`));
8337
+ console.log(import_chalk46.default.dim(` Using your consumer session on ${import_chalk46.default.bold(tenant2)}${fresh.email ? ` (${fresh.email})` : ""}.`));
7059
8338
  return fresh;
7060
8339
  }
7061
8340
  }
7062
- const spinner = (0, import_ora21.default)(`Finding the login app for ${tenant2}...`).start();
8341
+ const spinner = (0, import_ora23.default)(`Finding the login app for ${tenant2}...`).start();
7063
8342
  const clients = await admin({
7064
8343
  method: "GET",
7065
8344
  path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/app-clients`,
@@ -7074,13 +8353,13 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
7074
8353
  );
7075
8354
  }
7076
8355
  const clientId = pick2.client_id ?? pick2.clientId;
7077
- console.log(`${import_chalk43.default.cyan("\u2192")} This proxy signs consumers in with OAuth \u2014 logging you in to ${import_chalk43.default.bold(tenant2)}...`);
8356
+ console.log(`${import_chalk46.default.cyan("\u2192")} This proxy signs consumers in with OAuth \u2014 logging you in to ${import_chalk46.default.bold(tenant2)}...`);
7078
8357
  const result = await deviceLogin(clientId, "openid email profile offline_access", ({ verificationUri, userCode }) => {
7079
8358
  console.log(`
7080
- Open: ${import_chalk43.default.underline(verificationUri)}`);
7081
- console.log(` Code: ${import_chalk43.default.bold(userCode)}
8359
+ Open: ${import_chalk46.default.underline(verificationUri)}`);
8360
+ console.log(` Code: ${import_chalk46.default.bold(userCode)}
7082
8361
  `);
7083
- console.log(import_chalk43.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
8362
+ console.log(import_chalk46.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
7084
8363
  }, resource);
7085
8364
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
7086
8365
  const creds = {
@@ -7096,7 +8375,7 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
7096
8375
  resource
7097
8376
  };
7098
8377
  saveConsumer(creds);
7099
- console.log(` ${import_chalk43.default.green("\u2714")} Signed in as${creds.email ? ` ${import_chalk43.default.bold(creds.email)}` : " a consumer"} on ${tenant2}.`);
8378
+ console.log(` ${import_chalk46.default.green("\u2714")} Signed in as${creds.email ? ` ${import_chalk46.default.bold(creds.email)}` : " a consumer"} on ${tenant2}.`);
7100
8379
  return creds;
7101
8380
  }
7102
8381
  async function cpPost(anon, path8, body, summary) {
@@ -7111,21 +8390,21 @@ async function provision(spec2, target, opts) {
7111
8390
  const loggedIn = !!loadCredentials();
7112
8391
  const anon = !loggedIn;
7113
8392
  const salt = () => Math.random().toString(36).slice(2, 6);
7114
- let base2 = opts.name ? normalizeName2(opts.name) : "";
8393
+ let base2 = opts.name ? normalizeName3(opts.name) : "";
7115
8394
  if (!base2) {
7116
8395
  try {
7117
8396
  const host = new URL(target).hostname;
7118
- base2 = normalizeName2(host.split(".")[0]);
7119
- if (base2.length < 3) base2 = normalizeName2(host);
8397
+ base2 = normalizeName3(host.split(".")[0]);
8398
+ if (base2.length < 3) base2 = normalizeName3(host);
7120
8399
  } catch {
7121
8400
  }
7122
8401
  }
7123
- if (!base2 && spec2.info && typeof spec2.info.title === "string") base2 = normalizeName2(spec2.info.title);
8402
+ if (!base2 && spec2.info && typeof spec2.info.title === "string") base2 = normalizeName3(spec2.info.title);
7124
8403
  if (!base2 || base2.length < 3) base2 = "apichat";
7125
8404
  let name = opts.name ? base2 : `${base2}${salt()}`;
7126
8405
  const access = anon ? "open" : opts.access === "open" ? "open" : "invite";
7127
8406
  if (anon && opts.access === "invite") {
7128
- console.log(import_chalk43.default.dim(" Note: --access invite needs an account to pre-approve people. Staying open for this anonymous proxy \u2014 run `apiblaze login`, then `apiblaze apichat --access invite`."));
8407
+ console.log(import_chalk46.default.dim(" Note: --access invite needs an account to pre-approve people. Staying open for this anonymous proxy \u2014 run `apiblaze login`, then `apiblaze apichat --access invite`."));
7129
8408
  }
7130
8409
  const DUAL_AUTH = {
7131
8410
  mode: "authenticate",
@@ -7137,7 +8416,7 @@ async function provision(spec2, target, opts) {
7137
8416
  yes: opts.yes,
7138
8417
  json: opts.json
7139
8418
  }) : void 0;
7140
- const spinner = (0, import_ora21.default)("Provisioning an api_key proxy...").start();
8419
+ const spinner = (0, import_ora23.default)("Provisioning an api_key proxy...").start();
7141
8420
  let result;
7142
8421
  for (let attempt = 0; attempt < 4; attempt++) {
7143
8422
  try {
@@ -7224,14 +8503,14 @@ async function provision(spec2, target, opts) {
7224
8503
  try {
7225
8504
  await addPreapprovalRule(tenant2, email);
7226
8505
  } catch {
7227
- console.log(import_chalk43.default.dim(` (Could not auto-approve your email for sign-in \u2014 add it later: apiblaze preapprove ${email})`));
8506
+ console.log(import_chalk46.default.dim(` (Could not auto-approve your email for sign-in \u2014 add it later: apiblaze preapprove ${email})`));
7228
8507
  }
7229
8508
  }
7230
8509
  }
7231
8510
  return { projectId, version: version2, environment, dpKey, mcpHost, proxyUrl, anon, access, tenant: tenant2 };
7232
8511
  }
7233
8512
  async function writeTargetAuth(p, auth, secret) {
7234
- const spinner = (0, import_ora21.default)("Storing target credentials (encrypted)...").start();
8513
+ const spinner = (0, import_ora23.default)("Storing target credentials (encrypted)...").start();
7235
8514
  try {
7236
8515
  await cpPost(
7237
8516
  p.anon,
@@ -7253,7 +8532,7 @@ async function writeTargetAuth(p, auth, secret) {
7253
8532
  }
7254
8533
  }
7255
8534
  async function uploadSpec(p, specText, opts) {
7256
- const spinner = (0, import_ora21.default)("Uploading the spec...").start();
8535
+ const spinner = (0, import_ora23.default)("Uploading the spec...").start();
7257
8536
  let out;
7258
8537
  try {
7259
8538
  out = await cpPost(
@@ -7268,7 +8547,7 @@ async function uploadSpec(p, specText, opts) {
7268
8547
  throw err;
7269
8548
  }
7270
8549
  if (out && out.reused === true) {
7271
- console.log(import_chalk43.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
8550
+ console.log(import_chalk46.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
7272
8551
  } else if (out && out.changed === true && out.previous_spec_hash) {
7273
8552
  const interactive = !!process.stdin.isTTY && !opts.yes;
7274
8553
  if (interactive) {
@@ -7276,12 +8555,12 @@ async function uploadSpec(p, specText, opts) {
7276
8555
  const { go } = await inquirer3.prompt([
7277
8556
  { type: "confirm", name: "go", message: "The spec changed since the last provision \u2014 re-publish the MCP catalogue?", default: true }
7278
8557
  ]);
7279
- if (!go) console.log(import_chalk43.default.dim(" Keeping the existing MCP catalogue."));
8558
+ if (!go) console.log(import_chalk46.default.dim(" Keeping the existing MCP catalogue."));
7280
8559
  }
7281
8560
  }
7282
8561
  }
7283
8562
  async function publishMcp(p, spec2) {
7284
- const spinner = (0, import_ora21.default)("Publishing the MCP catalogue...").start();
8563
+ const spinner = (0, import_ora23.default)("Publishing the MCP catalogue...").start();
7285
8564
  try {
7286
8565
  const url = `https://${p.mcpHost}/${p.version}/${p.environment}/mcp/generate`;
7287
8566
  const res = await fetch(url, {
@@ -7317,15 +8596,15 @@ var revealAuth = false;
7317
8596
  function renderToolEvents(events, cred) {
7318
8597
  for (const e of events ?? []) {
7319
8598
  const ok = typeof e.status === "number" ? e.status < 400 : String(e.status).toLowerCase() === "ok";
7320
- const mark = ok ? import_chalk43.default.green("\u2713") : import_chalk43.default.red("\u2717");
7321
- console.log(` ${mark} ${import_chalk43.default.cyan(e.name)} ${import_chalk43.default.dim(`(${e.status}, ${e.ms}ms)`)}`);
8599
+ const mark = ok ? import_chalk46.default.green("\u2713") : import_chalk46.default.red("\u2717");
8600
+ console.log(` ${mark} ${import_chalk46.default.cyan(e.name)} ${import_chalk46.default.dim(`(${e.status}, ${e.ms}ms)`)}`);
7322
8601
  if (isVerbose() && e.method && e.url) {
7323
- console.log(import_chalk43.default.dim(` curl -sS -X ${e.method} '${e.url}'${cred ? " \\" : ""}`));
8602
+ console.log(import_chalk46.default.dim(` curl -sS -X ${e.method} '${e.url}'${cred ? " \\" : ""}`));
7324
8603
  if (cred) {
7325
8604
  const shown = revealAuth ? cred.value : maskKey(cred.value);
7326
8605
  const keyLine = ` -H '${cred.header}: ${shown}'`;
7327
- const hint = revealAuth ? "" : import_chalk43.default.yellow(" \u2190 /showauth will reveal this");
7328
- console.log(import_chalk43.default.dim(keyLine) + hint);
8606
+ const hint = revealAuth ? "" : import_chalk46.default.yellow(" \u2190 /showauth will reveal this");
8607
+ console.log(import_chalk46.default.dim(keyLine) + hint);
7329
8608
  }
7330
8609
  }
7331
8610
  }
@@ -7346,20 +8625,20 @@ function renderToolResults(delta, events) {
7346
8625
  }
7347
8626
  })();
7348
8627
  const lines = pretty.split("\n");
7349
- console.log(import_chalk43.default.dim(" response:"));
8628
+ console.log(import_chalk46.default.dim(" response:"));
7350
8629
  for (const line of lines.slice(0, cap)) {
7351
- console.log(import_chalk43.default.dim(` ${line}`));
8630
+ console.log(import_chalk46.default.dim(` ${line}`));
7352
8631
  }
7353
- if (lines.length > cap) console.log(import_chalk43.default.dim(` \u2026${lines.length - cap} more lines`));
8632
+ if (lines.length > cap) console.log(import_chalk46.default.dim(` \u2026${lines.length - cap} more lines`));
7354
8633
  }
7355
8634
  }
7356
8635
  function billingLine(billing) {
7357
8636
  if (!billing || typeof billing.cents !== "number") return null;
7358
8637
  if (typeof billing.free_turns_remaining === "number") return null;
7359
8638
  const usd = (billing.cents / 100).toFixed(Math.abs(billing.cents - Math.round(billing.cents)) < 1e-9 ? 2 : 4);
7360
- let line = import_chalk43.default.magenta(` \u{1F4B3} $${usd}`) + import_chalk43.default.dim(billing.model ? ` \xB7 ${billing.model}` : "");
8639
+ let line = import_chalk46.default.magenta(` \u{1F4B3} $${usd}`) + import_chalk46.default.dim(billing.model ? ` \xB7 ${billing.model}` : "");
7361
8640
  if (typeof billing.credits_remaining === "number") {
7362
- line += import_chalk43.default.dim(` \xB7 balance $${(billing.credits_remaining / 100).toFixed(2)}`);
8641
+ line += import_chalk46.default.dim(` \xB7 balance $${(billing.credits_remaining / 100).toFixed(2)}`);
7363
8642
  }
7364
8643
  return line;
7365
8644
  }
@@ -7367,21 +8646,21 @@ function freeBudgetWarning(billing, anon) {
7367
8646
  if (!anon || !billing) return null;
7368
8647
  if (typeof billing.free_turns_remaining === "number") {
7369
8648
  const left2 = billing.free_turns_remaining;
7370
- if (left2 <= 0) return import_chalk43.default.yellow(" Free chats used up \u2014 `npx apiblaze login` (free) to keep going.");
7371
- return import_chalk43.default.dim(` ${left2} free chat${left2 === 1 ? "" : "s"} left \xB7 /login to get more`);
8649
+ if (left2 <= 0) return import_chalk46.default.yellow(" Free chats used up \u2014 `npx apiblaze login` (free) to keep going.");
8650
+ return import_chalk46.default.dim(` ${left2} free chat${left2 === 1 ? "" : "s"} left \xB7 /login to get more`);
7372
8651
  }
7373
8652
  if (typeof billing.free_remaining_cents !== "number") return null;
7374
8653
  const perTurn = Math.max(billing.cents || 0, 0.02);
7375
8654
  const left = Math.floor(billing.free_remaining_cents / perTurn);
7376
8655
  if (left > 8) return null;
7377
- if (left <= 0) return import_chalk43.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
7378
- return import_chalk43.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
8656
+ if (left <= 0) return import_chalk46.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
8657
+ return import_chalk46.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
7379
8658
  }
7380
8659
  function printAssistant(delta) {
7381
8660
  for (let i = delta.length - 1; i >= 0; i--) {
7382
8661
  const m = delta[i];
7383
8662
  if (m && m.role === "assistant" && typeof m.content === "string" && m.content.trim()) {
7384
- console.log("\n" + import_chalk43.default.green("assistant \u203A ") + m.content + "\n");
8663
+ console.log("\n" + import_chalk46.default.green("assistant \u203A ") + m.content + "\n");
7385
8664
  return;
7386
8665
  }
7387
8666
  }
@@ -7391,7 +8670,7 @@ async function replTurn(p, messages, userText) {
7391
8670
  const llm2 = loadLlmConfig();
7392
8671
  const turnId = crypto2.randomUUID();
7393
8672
  for (let round = 0; round < CLIENT_ROUND_CAP; round++) {
7394
- const spinner = (0, import_ora21.default)({ text: round === 0 ? "thinking..." : "working...", color: "magenta" }).start();
8673
+ const spinner = (0, import_ora23.default)({ text: round === 0 ? "thinking..." : "working...", color: "magenta" }).start();
7395
8674
  const body = {
7396
8675
  turn_id: turnId,
7397
8676
  messages,
@@ -7407,7 +8686,7 @@ async function replTurn(p, messages, userText) {
7407
8686
  });
7408
8687
  } catch (err) {
7409
8688
  spinner.fail("Network error.");
7410
- console.log(import_chalk43.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
8689
+ console.log(import_chalk46.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
7411
8690
  return;
7412
8691
  }
7413
8692
  let data = null;
@@ -7427,9 +8706,9 @@ async function replTurn(p, messages, userText) {
7427
8706
  if (res.status === 401) {
7428
8707
  const reason = data && (data.error || data.message) || null;
7429
8708
  const usingKey = !p.consumerAuth;
7430
- console.log(import_chalk43.default.red(` The proxy rejected the request (401)${reason ? `: ${reason}` : "."}`));
8709
+ console.log(import_chalk46.default.red(` The proxy rejected the request (401)${reason ? `: ${reason}` : "."}`));
7431
8710
  console.log(
7432
- import_chalk43.default.dim(
8711
+ import_chalk46.default.dim(
7433
8712
  usingKey ? " Sent an API key. If the key was revoked, re-run `apiblaze apichat` to re-provision." : " Sent your consumer OAuth token. Re-run `apiblaze apichat` to sign in again."
7434
8713
  )
7435
8714
  );
@@ -7437,7 +8716,7 @@ async function replTurn(p, messages, userText) {
7437
8716
  }
7438
8717
  if (!res.ok || !data) {
7439
8718
  const err = data && data.error || `HTTP ${res.status}`;
7440
- console.log(import_chalk43.default.red(` Chat error: ${err}`));
8719
+ console.log(import_chalk46.default.red(` Chat error: ${err}`));
7441
8720
  return;
7442
8721
  }
7443
8722
  if (Array.isArray(data.delta)) {
@@ -7458,25 +8737,25 @@ async function replTurn(p, messages, userText) {
7458
8737
  if (warn) console.log(warn);
7459
8738
  if (!data.continue) return;
7460
8739
  }
7461
- console.log(import_chalk43.default.dim(" (stopped after several tool rounds \u2014 ask again to continue)"));
8740
+ console.log(import_chalk46.default.dim(" (stopped after several tool rounds \u2014 ask again to continue)"));
7462
8741
  }
7463
8742
  function renderUpsell(p, upsell) {
7464
8743
  const loggedIn = !!loadCredentials();
7465
8744
  if (upsell.reason === "CAPPED" && !loggedIn) {
7466
- console.log("\n" + import_chalk43.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
7467
- console.log(import_chalk43.default.dim(" (or `/login` right here \u2014 your chat is preserved \u2014 or `apiblaze llm set-key` for your own model key.)"));
8745
+ console.log("\n" + import_chalk46.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
8746
+ console.log(import_chalk46.default.dim(" (or `/login` right here \u2014 your chat is preserved \u2014 or `apiblaze llm set-key` for your own model key.)"));
7468
8747
  console.log();
7469
8748
  return;
7470
8749
  }
7471
- console.log("\n" + import_chalk43.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
8750
+ console.log("\n" + import_chalk46.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
7472
8751
  if (upsell.reason === "INSUFFICIENT" || upsell.reason === "BREAKER" || upsell.reason === "CAPPED" || upsell.reason === "QUOTA" || upsell.reason === "PROXY_CAP" || upsell.reason === "PAUSED" || upsell.reason === "BYO_REQUIRED") {
7473
8752
  if (!loggedIn) {
7474
- console.log(import_chalk43.default.dim(" Options: `/login` for more free chats and requests, or `apiblaze llm set-key` to bring your own model key."));
8753
+ console.log(import_chalk46.default.dim(" Options: `/login` for more free chats and requests, or `apiblaze llm set-key` to bring your own model key."));
7475
8754
  } else {
7476
- console.log(import_chalk43.default.dim(" Options: top up your wallet, or `apiblaze llm set-key` to bring your own model key (bypasses platform limits)."));
8755
+ console.log(import_chalk46.default.dim(" Options: top up your wallet, or `apiblaze llm set-key` to bring your own model key (bypasses platform limits)."));
7477
8756
  }
7478
8757
  } else if (upsell.reason === "INFLIGHT") {
7479
- console.log(import_chalk43.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
8758
+ console.log(import_chalk46.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
7480
8759
  }
7481
8760
  console.log();
7482
8761
  }
@@ -7569,9 +8848,9 @@ async function openServerProxy(project) {
7569
8848
  let consumerAuth = false;
7570
8849
  if (acceptsApiKey) {
7571
8850
  if (!dpKey) {
7572
- console.log(import_chalk43.default.dim(` Minting an API key for tenant ${import_chalk43.default.bold(tenant2)} to query project ${import_chalk43.default.bold(project.projectName)}\u2026`));
8851
+ console.log(import_chalk46.default.dim(` Minting an API key for tenant ${import_chalk46.default.bold(tenant2)} to query project ${import_chalk46.default.bold(project.projectName)}\u2026`));
7573
8852
  dpKey = await mintDurableProxyKey(project.teamId, tenant2);
7574
- console.log(` ${import_chalk43.default.green("\u2714")} API key: ${import_chalk43.default.dim(maskKey(dpKey))}`);
8853
+ console.log(` ${import_chalk46.default.green("\u2714")} API key: ${import_chalk46.default.dim(maskKey(dpKey))}`);
7575
8854
  }
7576
8855
  } else {
7577
8856
  consumerAuth = true;
@@ -7590,7 +8869,7 @@ async function openServerProxy(project) {
7590
8869
  // Reusing an owned proxy: logged-in apichat doors default to invite-only.
7591
8870
  access: "invite"
7592
8871
  };
7593
- const spinner = (0, import_ora21.default)("Preparing the chat\u2026").start();
8872
+ const spinner = (0, import_ora23.default)("Preparing the chat\u2026").start();
7594
8873
  try {
7595
8874
  const raw = await admin({
7596
8875
  method: "GET",
@@ -7600,9 +8879,9 @@ async function openServerProxy(project) {
7600
8879
  const spec2 = raw && (raw.spec ?? raw);
7601
8880
  spinner.stop();
7602
8881
  if (!spec2 || !(spec2.paths || spec2.openapi)) {
7603
- console.log(import_chalk43.default.yellow(" This proxy has no OpenAPI spec yet \u2014 chat will have no tools. Build one with `apiblaze agent openapi`."));
8882
+ console.log(import_chalk46.default.yellow(" This proxy has no OpenAPI spec yet \u2014 chat will have no tools. Build one with `apiblaze agent openapi`."));
7604
8883
  } else {
7605
- console.log(import_chalk43.default.dim(" Using the proxy's existing MCP catalogue (`apiblaze mcp` to rebuild it)."));
8884
+ console.log(import_chalk46.default.dim(" Using the proxy's existing MCP catalogue (`apiblaze mcp` to rebuild it)."));
7606
8885
  }
7607
8886
  } catch (err) {
7608
8887
  spinner.fail("Could not open the proxy.");
@@ -7658,7 +8937,7 @@ async function noArgsMenu(opts) {
7658
8937
  const me = loadCredentials()?.apiblazeUserId;
7659
8938
  const saved = loadApichats().filter((a) => a.anon ? true : a.ownerUserId !== void 0 && a.ownerUserId === me);
7660
8939
  const choices = saved.map((a) => ({
7661
- name: `Chat with ${import_chalk43.default.bold(a.name)} ${import_chalk43.default.dim(`(${a.target})${a.messages && a.messages.length ? ` \xB7 ${a.messages.length} msgs` : ""}`)}`,
8940
+ name: `Chat with ${import_chalk46.default.bold(a.name)} ${import_chalk46.default.dim(`(${a.target})${a.messages && a.messages.length ? ` \xB7 ${a.messages.length} msgs` : ""}`)}`,
7662
8941
  value: { type: "existing", a }
7663
8942
  }));
7664
8943
  const creds = loadCredentials();
@@ -7668,14 +8947,14 @@ async function noArgsMenu(opts) {
7668
8947
  const proxies = (await getProjects(creds.teamId)).filter((pr) => !savedIds.has(pr.projectId));
7669
8948
  for (const pr of proxies) {
7670
8949
  choices.push({
7671
- name: `Chat with ${import_chalk43.default.bold(pr.projectName)} ${import_chalk43.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
8950
+ name: `Chat with ${import_chalk46.default.bold(pr.projectName)} ${import_chalk46.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
7672
8951
  value: { type: "server", project: pr }
7673
8952
  });
7674
8953
  }
7675
8954
  } catch {
7676
8955
  }
7677
8956
  }
7678
- choices.push({ name: import_chalk43.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
8957
+ choices.push({ name: import_chalk46.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
7679
8958
  const { pick: pick2 } = await inquirer3.prompt([
7680
8959
  { type: "list", name: "pick", message: "What would you like to do?", choices }
7681
8960
  ]);
@@ -7778,36 +9057,36 @@ async function noArgsMenu(opts) {
7778
9057
  async function runRepl(p, initialMessages) {
7779
9058
  const { default: inquirer3 } = await import("inquirer");
7780
9059
  const messages = initialMessages && initialMessages.length ? initialMessages.slice() : [];
7781
- console.log("\n" + import_chalk43.default.cyan.bold("Chat with your API") + import_chalk43.default.dim(` \xB7 ${p.mcpHost}`));
7782
- if (messages.length) console.log(import_chalk43.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
9060
+ console.log("\n" + import_chalk46.default.cyan.bold("Chat with your API") + import_chalk46.default.dim(` \xB7 ${p.mcpHost}`));
9061
+ if (messages.length) console.log(import_chalk46.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
7783
9062
  const llm2 = loadLlmConfig();
7784
9063
  console.log(
7785
- import_chalk43.default.dim(
9064
+ import_chalk46.default.dim(
7786
9065
  llm2 ? `Using your local ${llm2.provider} key for the model. Type a question, or /exit. /login /claim manage your workspace.` : "Ask a question in plain English. /exit to quit \xB7 /login for more free chats \xB7 /claim to keep this workspace \xB7 `apiblaze llm set-key` for BYO models."
7787
9066
  )
7788
9067
  );
7789
9068
  for (; ; ) {
7790
- const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk43.default.green("you \u203A") }]);
9069
+ const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk46.default.green("you \u203A") }]);
7791
9070
  const text = (input ?? "").trim();
7792
9071
  if (!text) continue;
7793
9072
  if (["/exit", "/quit", "exit", "quit", ":q"].includes(text.toLowerCase())) break;
7794
9073
  if (text === "/login") {
7795
9074
  try {
7796
9075
  await runLogin();
7797
- console.log(import_chalk43.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
9076
+ console.log(import_chalk46.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
7798
9077
  } catch (err) {
7799
- console.log(import_chalk43.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9078
+ console.log(import_chalk46.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
7800
9079
  }
7801
9080
  continue;
7802
9081
  }
7803
9082
  if (text === "/claim") {
7804
9083
  const justLoggedIn = !loadCredentials();
7805
9084
  if (justLoggedIn) {
7806
- console.log(import_chalk43.default.dim(" Logging in to claim your workspace\u2026"));
9085
+ console.log(import_chalk46.default.dim(" Logging in to claim your workspace\u2026"));
7807
9086
  try {
7808
9087
  await runLogin();
7809
9088
  } catch (err) {
7810
- console.log(import_chalk43.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9089
+ console.log(import_chalk46.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
7811
9090
  continue;
7812
9091
  }
7813
9092
  if (!loadCredentials()) continue;
@@ -7818,30 +9097,30 @@ async function runRepl(p, initialMessages) {
7818
9097
  p.mcpHost = p.mcpHost.replace(".mcp.tryabz.run", ".mcp.abz.run");
7819
9098
  p.anon = false;
7820
9099
  claimApichat(p, loadCredentials()?.apiblazeUserId);
7821
- console.log(import_chalk43.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
9100
+ console.log(import_chalk46.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
7822
9101
  }
7823
9102
  } catch (err) {
7824
- console.log(import_chalk43.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
9103
+ console.log(import_chalk46.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
7825
9104
  }
7826
9105
  continue;
7827
9106
  }
7828
9107
  if (text === "/showauth") {
7829
9108
  revealAuth = !revealAuth;
7830
- console.log(import_chalk43.default.dim(revealAuth ? " The real API key will be shown in the next call's curl. /showauth again to re-mask." : " API key re-masked."));
9109
+ console.log(import_chalk46.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."));
7831
9110
  continue;
7832
9111
  }
7833
9112
  if (text.startsWith("/")) {
7834
- console.log(import_chalk43.default.dim(" Commands: /login /claim /showauth /exit"));
9113
+ console.log(import_chalk46.default.dim(" Commands: /login /claim /showauth /exit"));
7835
9114
  continue;
7836
9115
  }
7837
9116
  await replTurn(p, messages, text);
7838
9117
  saveTranscript(p, messages);
7839
9118
  }
7840
- console.log(import_chalk43.default.dim("\nBye."));
9119
+ console.log(import_chalk46.default.dim("\nBye."));
7841
9120
  }
7842
9121
  async function runApichat(opts) {
7843
9122
  setVerbose(opts.verbose !== false);
7844
- console.log(import_chalk43.default.bold("\napichat \u2014 turn any API into a chat\n"));
9123
+ console.log(import_chalk46.default.bold("\napichat \u2014 turn any API into a chat\n"));
7845
9124
  if (!opts.openapispec && !opts.target) {
7846
9125
  if (!process.stdin.isTTY) {
7847
9126
  fail4("No spec source. Pass --openapispec <file|url> or --target <url>.", GENERATOR_HINT);
@@ -7854,7 +9133,7 @@ async function runApichat(opts) {
7854
9133
  }
7855
9134
  const { spec: spec2, sourceUrl } = await loadSpec(opts);
7856
9135
  const target = resolveTarget(spec2, opts, sourceUrl);
7857
- console.log(` ${import_chalk43.default.dim("Target:")} ${import_chalk43.default.bold(target)}`);
9136
+ console.log(` ${import_chalk46.default.dim("Target:")} ${import_chalk46.default.bold(target)}`);
7858
9137
  const auth = await resolveTargetAuth(spec2, opts);
7859
9138
  if (auth && !process.stdin.isTTY && !opts.targetAuthEnv) {
7860
9139
  fail4(
@@ -7863,7 +9142,7 @@ async function runApichat(opts) {
7863
9142
  );
7864
9143
  }
7865
9144
  const p = await provision(spec2, target, opts);
7866
- console.log(` ${import_chalk43.default.dim("Proxy: ")} ${import_chalk43.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
9145
+ console.log(` ${import_chalk46.default.dim("Proxy: ")} ${import_chalk46.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
7867
9146
  upsertApichat({
7868
9147
  name: p.projectId,
7869
9148
  target,
@@ -7883,38 +9162,38 @@ async function runApichat(opts) {
7883
9162
  const secret = await captureTargetSecret(auth, opts);
7884
9163
  if (secret) await writeTargetAuth(p, auth, secret);
7885
9164
  } else {
7886
- console.log(import_chalk43.default.dim(" Target auth: none required."));
9165
+ console.log(import_chalk46.default.dim(" Target auth: none required."));
7887
9166
  }
7888
9167
  const specText = JSON.stringify(spec2);
7889
9168
  await uploadSpec(p, specText, opts);
7890
9169
  const mcpUrl = await publishMcp(p, spec2);
7891
9170
  console.log();
7892
- if (p.proxyUrl) console.log(` ${import_chalk43.default.green("\u2713")} proxy ${import_chalk43.default.bold(p.proxyUrl)}`);
9171
+ if (p.proxyUrl) console.log(` ${import_chalk46.default.green("\u2713")} proxy ${import_chalk46.default.bold(p.proxyUrl)}`);
7893
9172
  if (mcpUrl) {
7894
- console.log(` ${import_chalk43.default.green("\u2713")} mcp ${import_chalk43.default.bold(mcpUrl)}`);
9173
+ console.log(` ${import_chalk46.default.green("\u2713")} mcp ${import_chalk46.default.bold(mcpUrl)}`);
7895
9174
  if (p.access === "invite") {
7896
- console.log(import_chalk43.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: invite \u2014 only you + emails you pre-approve"));
7897
- console.log(import_chalk43.default.dim(` Let others in: apiblaze preapprove someone@company.com${p.tenant ? ` --tenant ${p.tenant}` : ""} (or re-run with --access open)`));
9175
+ console.log(import_chalk46.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: invite \u2014 only you + emails you pre-approve"));
9176
+ console.log(import_chalk46.default.dim(` Let others in: apiblaze preapprove someone@company.com${p.tenant ? ` --tenant ${p.tenant}` : ""} (or re-run with --access open)`));
7898
9177
  } else {
7899
- console.log(import_chalk43.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: open \u2014 anyone who signs in can call this API"));
9178
+ console.log(import_chalk46.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: open \u2014 anyone who signs in can call this API"));
7900
9179
  }
7901
9180
  }
7902
9181
  if (p.anon) {
7903
- console.log(import_chalk43.default.dim("\n Anonymous workspace \u2014 /claim inside the chat to log in and keep it beyond 30 days."));
9182
+ console.log(import_chalk46.default.dim("\n Anonymous workspace \u2014 /claim inside the chat to log in and keep it beyond 30 days."));
7904
9183
  }
7905
9184
  await runRepl(p);
7906
9185
  }
7907
9186
 
7908
9187
  // src/commands/consumer.ts
7909
- var import_chalk44 = __toESM(require("chalk"));
7910
- var import_ora22 = __toESM(require("ora"));
9188
+ var import_chalk47 = __toESM(require("chalk"));
9189
+ var import_ora24 = __toESM(require("ora"));
7911
9190
  init_admin();
7912
9191
  init_resolve();
7913
9192
  var DEFAULT_SCOPE = "openid email profile offline_access";
7914
- var APIKEYS_BASE = process.env.APIBLAZE_APIKEYS_BASE || "https://apikeys.apiblaze.com";
9193
+ var APIKEYS_BASE2 = process.env.APIBLAZE_APIKEYS_BASE || "https://apikeys.apiblaze.com";
7915
9194
  async function consumerFetch(creds, suffix, init) {
7916
9195
  const fresh = await validConsumerToken(creds) ?? creds;
7917
- const res = await fetch(`${APIKEYS_BASE}${suffix}`, {
9196
+ const res = await fetch(`${APIKEYS_BASE2}${suffix}`, {
7918
9197
  ...init,
7919
9198
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${fresh.accessToken}`, ...init?.headers ?? {} }
7920
9199
  });
@@ -7928,7 +9207,7 @@ async function consumerFetch(creds, suffix, init) {
7928
9207
  function requireConsumer2() {
7929
9208
  const c = loadConsumer();
7930
9209
  if (!c) {
7931
- console.error(import_chalk44.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
9210
+ console.error(import_chalk47.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
7932
9211
  process.exit(1);
7933
9212
  }
7934
9213
  return c;
@@ -7939,7 +9218,7 @@ async function runConsumerLogin(opts) {
7939
9218
  let clientId = opts.client;
7940
9219
  if (clientId) {
7941
9220
  if (!tenant2) {
7942
- console.error(import_chalk44.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
9221
+ console.error(import_chalk47.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
7943
9222
  process.exit(1);
7944
9223
  }
7945
9224
  } else {
@@ -7951,24 +9230,24 @@ async function runConsumerLogin(opts) {
7951
9230
  if (!picked) process.exit(1);
7952
9231
  tenant2 = picked;
7953
9232
  }
7954
- const s2 = (0, import_ora22.default)("Finding the login app...").start();
9233
+ const s2 = (0, import_ora24.default)("Finding the login app...").start();
7955
9234
  const clients = await admin({ method: "GET", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/app-clients`, summary: `List app clients for ${tenant2}` }).catch(() => []);
7956
9235
  s2.stop();
7957
9236
  const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
7958
9237
  const pick2 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
7959
9238
  if (!pick2) {
7960
- console.error(import_chalk44.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
9239
+ console.error(import_chalk47.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
7961
9240
  process.exit(1);
7962
9241
  }
7963
9242
  clientId = pick2.client_id ?? pick2.clientId;
7964
9243
  }
7965
- console.log(`${import_chalk44.default.cyan("\u2192")} Logging in to ${import_chalk44.default.bold(tenant2)} as a consumer...`);
9244
+ console.log(`${import_chalk47.default.cyan("\u2192")} Logging in to ${import_chalk47.default.bold(tenant2)} as a consumer...`);
7966
9245
  const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
7967
9246
  console.log(`
7968
- Open: ${import_chalk44.default.underline(verificationUri)}`);
7969
- console.log(` Code: ${import_chalk44.default.bold(userCode)}
9247
+ Open: ${import_chalk47.default.underline(verificationUri)}`);
9248
+ console.log(` Code: ${import_chalk47.default.bold(userCode)}
7970
9249
  `);
7971
- console.log(import_chalk44.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
9250
+ console.log(import_chalk47.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
7972
9251
  });
7973
9252
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
7974
9253
  const creds = {
@@ -7983,7 +9262,7 @@ async function runConsumerLogin(opts) {
7983
9262
  obtainedAt: Date.now()
7984
9263
  };
7985
9264
  saveConsumer(creds);
7986
- console.log(import_chalk44.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
9265
+ console.log(import_chalk47.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
7987
9266
  }
7988
9267
  async function runConsumerTokens(opts) {
7989
9268
  const creds = requireConsumer2();
@@ -7996,29 +9275,29 @@ async function runConsumerTokens(opts) {
7996
9275
  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));
7997
9276
  return;
7998
9277
  }
7999
- console.log(`${import_chalk44.default.cyan("Consumer")} ${import_chalk44.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk44.default.bold(fresh.tenant)}
9278
+ console.log(`${import_chalk47.default.cyan("Consumer")} ${import_chalk47.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk47.default.bold(fresh.tenant)}
8000
9279
  `);
8001
- console.log(`${import_chalk44.default.bold("access_token")} ${import_chalk44.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
9280
+ console.log(`${import_chalk47.default.bold("access_token")} ${import_chalk47.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
8002
9281
  ${fresh.accessToken}
8003
9282
  `);
8004
- if (fresh.idToken) console.log(`${import_chalk44.default.bold("id_token")} ${import_chalk44.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
9283
+ if (fresh.idToken) console.log(`${import_chalk47.default.bold("id_token")} ${import_chalk47.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
8005
9284
  ${fresh.idToken}
8006
9285
  `);
8007
- if (fresh.refreshToken) console.log(`${import_chalk44.default.bold("refresh_token")}
9286
+ if (fresh.refreshToken) console.log(`${import_chalk47.default.bold("refresh_token")}
8008
9287
  ${fresh.refreshToken}
8009
9288
  `);
8010
- console.log(import_chalk44.default.dim("These are your own tokens \u2014 keep them secret."));
9289
+ console.log(import_chalk47.default.dim("These are your own tokens \u2014 keep them secret."));
8011
9290
  }
8012
9291
  async function runConsumerApikeys(opts) {
8013
9292
  const creds = requireConsumer2();
8014
9293
  const { default: inquirer3 } = await import("inquirer");
8015
- const spinner = (0, import_ora22.default)("Loading your API keys...").start();
9294
+ const spinner = (0, import_ora24.default)("Loading your API keys...").start();
8016
9295
  const list = await consumerFetch(creds, "/apikeys");
8017
9296
  const revealed = await consumerFetch(list.creds, "/apikeys/reveal").catch(() => ({ status: 0, data: null, creds: list.creds }));
8018
9297
  spinner.stop();
8019
9298
  if (list.status >= 400) {
8020
- console.error(import_chalk44.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
8021
- if (list.status === 401) console.error(import_chalk44.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
9299
+ console.error(import_chalk47.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
9300
+ if (list.status === 401) console.error(import_chalk47.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
8022
9301
  process.exit(1);
8023
9302
  }
8024
9303
  const keys = list.data?.keys ?? [];
@@ -8026,16 +9305,16 @@ async function runConsumerApikeys(opts) {
8026
9305
  if (opts.json) {
8027
9306
  console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
8028
9307
  } else if (!keys.length) {
8029
- console.log(import_chalk44.default.yellow("No API keys yet."));
9308
+ console.log(import_chalk47.default.yellow("No API keys yet."));
8030
9309
  } else {
8031
9310
  for (const k of keys) {
8032
9311
  const clear = revealMap[k.environment]?.key;
8033
- const shown = clear ? import_chalk44.default.green(clear) : import_chalk44.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
8034
- const exp = k.expires_at ? import_chalk44.default.dim(`exp ${k.expires_at}`) : import_chalk44.default.dim("no expiry");
8035
- console.log(` ${import_chalk44.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk44.default.dim(k.description ?? "")}`);
9312
+ const shown = clear ? import_chalk47.default.green(clear) : import_chalk47.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
9313
+ const exp = k.expires_at ? import_chalk47.default.dim(`exp ${k.expires_at}`) : import_chalk47.default.dim("no expiry");
9314
+ console.log(` ${import_chalk47.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk47.default.dim(k.description ?? "")}`);
8036
9315
  }
8037
9316
  if (Object.keys(revealMap).length === 0 && keys.some((k) => !k.expires_at)) {
8038
- console.log(import_chalk44.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
9317
+ console.log(import_chalk47.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
8039
9318
  }
8040
9319
  }
8041
9320
  if (opts.json) return;
@@ -8049,7 +9328,7 @@ async function runConsumerApikeys(opts) {
8049
9328
  const body = { environment: answers.environment };
8050
9329
  if (answers.description) body.description = answers.description;
8051
9330
  if (answers.expiresDays) body.expires_in_seconds = Number(answers.expiresDays) * 86400;
8052
- const s2 = (0, import_ora22.default)("Creating key...").start();
9331
+ const s2 = (0, import_ora24.default)("Creating key...").start();
8053
9332
  const created = await consumerFetch(list.creds, "/apikeys", { method: "POST", body: JSON.stringify(body) });
8054
9333
  if (created.status >= 400) {
8055
9334
  s2.fail(`Create failed (${created.status}): ${created.data?.error ?? ""}`);
@@ -8057,13 +9336,13 @@ async function runConsumerApikeys(opts) {
8057
9336
  }
8058
9337
  s2.succeed("Key created.");
8059
9338
  const key = created.data?.key ?? created.data?.fullKey;
8060
- if (key) console.log(` ${import_chalk44.default.green(key)} ${import_chalk44.default.dim("(shown once \u2014 store it now)")}`);
8061
- else console.log(import_chalk44.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
9339
+ if (key) console.log(` ${import_chalk47.default.green(key)} ${import_chalk47.default.dim("(shown once \u2014 store it now)")}`);
9340
+ else console.log(import_chalk47.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
8062
9341
  }
8063
9342
 
8064
9343
  // src/commands/sidecar.ts
8065
- var import_chalk45 = __toESM(require("chalk"));
8066
- var import_ora23 = __toESM(require("ora"));
9344
+ var import_chalk48 = __toESM(require("chalk"));
9345
+ var import_ora25 = __toESM(require("ora"));
8067
9346
  var fs10 = __toESM(require("fs"));
8068
9347
  var path7 = __toESM(require("path"));
8069
9348
  init_admin();
@@ -8105,18 +9384,18 @@ function upsertEnvLocal(root, token) {
8105
9384
  }
8106
9385
  function installSidecarPackage(root) {
8107
9386
  if (fs10.existsSync(path7.join(root, "node_modules", "apiblaze", "package.json"))) {
8108
- console.log(` ${import_chalk45.default.green("\u2713")} apiblaze package already installed`);
9387
+ console.log(` ${import_chalk48.default.green("\u2713")} apiblaze package already installed`);
8109
9388
  return;
8110
9389
  }
8111
9390
  const has = (f) => fs10.existsSync(path7.join(root, f));
8112
9391
  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" };
8113
- const spinner = (0, import_ora23.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
9392
+ const spinner = (0, import_ora25.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
8114
9393
  try {
8115
9394
  const { execSync } = require("child_process");
8116
9395
  execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
8117
9396
  spinner.succeed("Installed apiblaze (the sidecar runtime).");
8118
9397
  } catch {
8119
- spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk45.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk45.default.cyan("npm run dev")}.`);
9398
+ spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk48.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk48.default.cyan("npm run dev")}.`);
8120
9399
  }
8121
9400
  }
8122
9401
  function readEnvKey(root) {
@@ -8255,7 +9534,7 @@ async function runAnonymousInit(root, router, opts) {
8255
9534
  const { sidecarInitAnonymous: sidecarInitAnonymous2 } = await Promise.resolve().then(() => (init_api(), api_exports));
8256
9535
  const { saveAnonCred: saveAnonCred2, clearAnonCred: clearAnonCred2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
8257
9536
  if (opts.newSession) clearAnonCred2();
8258
- const spinner = (0, import_ora23.default)("Setting up a sidecar (no login needed)...").start();
9537
+ const spinner = (0, import_ora25.default)("Setting up a sidecar (no login needed)...").start();
8259
9538
  let out;
8260
9539
  try {
8261
9540
  out = await sidecarInitAnonymous2();
@@ -8267,29 +9546,29 @@ async function runAnonymousInit(root, router, opts) {
8267
9546
  if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
8268
9547
  const envState = upsertEnvLocal(root, out.token);
8269
9548
  ensureGitignored(root);
8270
- console.log(` ${import_chalk45.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
8271
- console.log(` ${import_chalk45.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
9549
+ console.log(` ${import_chalk48.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
9550
+ console.log(` ${import_chalk48.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
8272
9551
  installSidecarPackage(root);
8273
9552
  let inspectorPath = null;
8274
9553
  if (!opts.noInspector) {
8275
9554
  inspectorPath = generateInspector(root, router);
8276
- if (inspectorPath) console.log(` ${import_chalk45.default.green("\u2713")} inspector at ${inspectorPath}`);
9555
+ if (inspectorPath) console.log(` ${import_chalk48.default.green("\u2713")} inspector at ${inspectorPath}`);
8277
9556
  }
8278
9557
  console.log("");
8279
- console.log(import_chalk45.default.bold("Done (no account needed). What happens next:"));
8280
- console.log(` 1. ${import_chalk45.default.cyan("npm run dev")} and use your app.`);
9558
+ console.log(import_chalk48.default.bold("Done (no account needed). What happens next:"));
9559
+ console.log(` 1. ${import_chalk48.default.cyan("npm run dev")} and use your app.`);
8281
9560
  console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
8282
- console.log(` ${import_chalk45.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
9561
+ console.log(` ${import_chalk48.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
8283
9562
  console.log("");
8284
- console.log(import_chalk45.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
8285
- console.log(` ${import_chalk45.default.cyan("apiblaze login")} then ${import_chalk45.default.cyan("apiblaze claim")} ${import_chalk45.default.dim("(no code needed here)")}`);
8286
- console.log(import_chalk45.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
9563
+ console.log(import_chalk48.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
9564
+ console.log(` ${import_chalk48.default.cyan("apiblaze login")} then ${import_chalk48.default.cyan("apiblaze claim")} ${import_chalk48.default.dim("(no code needed here)")}`);
9565
+ console.log(import_chalk48.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
8287
9566
  }
8288
9567
  async function runSidecar(opts) {
8289
9568
  const root = path7.resolve(opts.dir ?? process.cwd());
8290
9569
  const detected = detectNextProject(root);
8291
9570
  if (!detected.found) {
8292
- console.log(import_chalk45.default.yellow(`No Next.js project detected in ${root}.`));
9571
+ console.log(import_chalk48.default.yellow(`No Next.js project detected in ${root}.`));
8293
9572
  console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
8294
9573
  return;
8295
9574
  }
@@ -8300,10 +9579,10 @@ async function runSidecar(opts) {
8300
9579
  if (!loadCredentials()) {
8301
9580
  upsertEnvLocal(root, readEnvKey(root));
8302
9581
  ensureGitignored(root);
8303
- console.log(` ${import_chalk45.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
8304
- console.log(` ${import_chalk45.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
9582
+ console.log(` ${import_chalk48.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
9583
+ console.log(` ${import_chalk48.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
8305
9584
  installSidecarPackage(root);
8306
- console.log(import_chalk45.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
9585
+ console.log(import_chalk48.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
8307
9586
  return;
8308
9587
  }
8309
9588
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -8312,7 +9591,7 @@ async function runSidecar(opts) {
8312
9591
  const mustMint = !existingKey || opts.rotate || switchingTeam;
8313
9592
  let token = existingKey ?? "";
8314
9593
  if (mustMint) {
8315
- const spinner = (0, import_ora23.default)(existingKey ? "Re-establishing the sidecar (minting a fresh invoke key)..." : "Setting up the sidecar (tenant + non-expiring invoke key)...").start();
9594
+ const spinner = (0, import_ora25.default)(existingKey ? "Re-establishing the sidecar (minting a fresh invoke key)..." : "Setting up the sidecar (tenant + non-expiring invoke key)...").start();
8316
9595
  try {
8317
9596
  const out = await admin({
8318
9597
  method: "POST",
@@ -8326,39 +9605,39 @@ async function runSidecar(opts) {
8326
9605
  throw err;
8327
9606
  }
8328
9607
  } else {
8329
- console.log(import_chalk45.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
9608
+ console.log(import_chalk48.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
8330
9609
  }
8331
9610
  const envState = upsertEnvLocal(root, token);
8332
9611
  ensureGitignored(root);
8333
- console.log(` ${import_chalk45.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
9612
+ console.log(` ${import_chalk48.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
8334
9613
  const wireState = wireInstrumentation(root);
8335
- console.log(` ${import_chalk45.default.green("\u2713")} instrumentation.ts ${wireState}`);
9614
+ console.log(` ${import_chalk48.default.green("\u2713")} instrumentation.ts ${wireState}`);
8336
9615
  installSidecarPackage(root);
8337
9616
  let inspectorPath = null;
8338
9617
  if (!opts.noInspector) {
8339
9618
  inspectorPath = generateInspector(root, detected.router);
8340
- if (inspectorPath) console.log(` ${import_chalk45.default.green("\u2713")} inspector at ${inspectorPath}`);
9619
+ if (inspectorPath) console.log(` ${import_chalk48.default.green("\u2713")} inspector at ${inspectorPath}`);
8341
9620
  }
8342
9621
  console.log("");
8343
- console.log(import_chalk45.default.bold("Done. What happens next:"));
8344
- console.log(` 1. ${import_chalk45.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
8345
- console.log(` 2. The origins your app calls appear as ${import_chalk45.default.bold("candidates")} \u2014 list them: ${import_chalk45.default.cyan("apiblaze sidecar")}`);
8346
- console.log(` 3. Approve the ones to route: ${import_chalk45.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
9622
+ console.log(import_chalk48.default.bold("Done. What happens next:"));
9623
+ console.log(` 1. ${import_chalk48.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
9624
+ console.log(` 2. The origins your app calls appear as ${import_chalk48.default.bold("candidates")} \u2014 list them: ${import_chalk48.default.cyan("apiblaze sidecar")}`);
9625
+ console.log(` 3. Approve the ones to route: ${import_chalk48.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
8347
9626
  console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
8348
- if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk45.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path7.dirname(inspectorPath)} before shipping)`);
8349
- if (switchingTeam) console.log(import_chalk45.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
9627
+ if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk48.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path7.dirname(inspectorPath)} before shipping)`);
9628
+ if (switchingTeam) console.log(import_chalk48.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
8350
9629
  console.log("");
8351
- console.log(import_chalk45.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
8352
- console.log(import_chalk45.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
8353
- console.log(import_chalk45.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
9630
+ console.log(import_chalk48.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
9631
+ console.log(import_chalk48.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
9632
+ console.log(import_chalk48.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
8354
9633
  console.log("");
8355
- console.log(import_chalk45.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
8356
- console.log(import_chalk45.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
9634
+ console.log(import_chalk48.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
9635
+ console.log(import_chalk48.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
8357
9636
  }
8358
9637
 
8359
9638
  // src/commands/origins.ts
8360
- var import_chalk46 = __toESM(require("chalk"));
8361
- var import_ora24 = __toESM(require("ora"));
9639
+ var import_chalk49 = __toESM(require("chalk"));
9640
+ var import_ora26 = __toESM(require("ora"));
8362
9641
  init_admin();
8363
9642
  init_resolve();
8364
9643
  init_auth();
@@ -8368,7 +9647,7 @@ async function runOriginsList(opts) {
8368
9647
  if (!loadCredentials()) {
8369
9648
  const cred = loadAnonCred();
8370
9649
  if (!cred) {
8371
- console.log(import_chalk46.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
9650
+ console.log(import_chalk49.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
8372
9651
  return;
8373
9652
  }
8374
9653
  out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
@@ -8386,30 +9665,30 @@ async function runOriginsList(opts) {
8386
9665
  }
8387
9666
  const routed = out.routed ?? [];
8388
9667
  const candidates = out.candidates ?? [];
8389
- console.log(import_chalk46.default.bold(`
9668
+ console.log(import_chalk49.default.bold(`
8390
9669
  Routed through APIblaze (${routed.length})`));
8391
- if (!routed.length) console.log(import_chalk46.default.dim(" none yet"));
8392
- for (const r of routed) console.log(` ${import_chalk46.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk46.default.dim(`\u2192 ${r.project_id}`)}`);
8393
- console.log(import_chalk46.default.bold(`
9670
+ if (!routed.length) console.log(import_chalk49.default.dim(" none yet"));
9671
+ for (const r of routed) console.log(` ${import_chalk49.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk49.default.dim(`\u2192 ${r.project_id}`)}`);
9672
+ console.log(import_chalk49.default.bold(`
8394
9673
  Candidates \u2014 going direct, not yet approved (${candidates.length})`));
8395
- if (!candidates.length) console.log(import_chalk46.default.dim(" none \u2014 run your app to discover the origins it calls"));
9674
+ if (!candidates.length) console.log(import_chalk49.default.dim(" none \u2014 run your app to discover the origins it calls"));
8396
9675
  for (const c of candidates) {
8397
- console.log(` ${import_chalk46.default.yellow("\u25CB")} ${c.origin} ${import_chalk46.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
9676
+ console.log(` ${import_chalk49.default.yellow("\u25CB")} ${c.origin} ${import_chalk49.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
8398
9677
  }
8399
9678
  if (candidates.length) {
8400
- console.log(import_chalk46.default.dim(`
9679
+ console.log(import_chalk49.default.dim(`
8401
9680
  Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
8402
- console.log(import_chalk46.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
9681
+ console.log(import_chalk49.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
8403
9682
  }
8404
9683
  }
8405
9684
  async function runOriginsApprove(origin, opts) {
8406
9685
  if (!loadCredentials()) {
8407
9686
  const cred = loadAnonCred();
8408
9687
  if (!cred) {
8409
- console.error(import_chalk46.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
9688
+ console.error(import_chalk49.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
8410
9689
  process.exit(1);
8411
9690
  }
8412
- const spinner2 = (0, import_ora24.default)(`Approving ${origin} (anonymous)...`).start();
9691
+ const spinner2 = (0, import_ora26.default)(`Approving ${origin} (anonymous)...`).start();
8413
9692
  try {
8414
9693
  const out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/approve`, { method: "POST", body: JSON.stringify({ origin }) });
8415
9694
  spinner2.succeed(`Approved ${origin} \u2192 proxy ${out.project_id}. Routing within ~5 min.`);
@@ -8420,7 +9699,7 @@ async function runOriginsApprove(origin, opts) {
8420
9699
  return;
8421
9700
  }
8422
9701
  const { teamId } = await resolveTeam(opts.team);
8423
- const spinner = (0, import_ora24.default)(`Approving ${origin}...`).start();
9702
+ const spinner = (0, import_ora26.default)(`Approving ${origin}...`).start();
8424
9703
  try {
8425
9704
  const out = await admin({
8426
9705
  method: "POST",
@@ -8437,7 +9716,7 @@ async function runOriginsApprove(origin, opts) {
8437
9716
  }
8438
9717
  async function runOriginsDeny(origin, opts) {
8439
9718
  const { teamId } = await resolveTeam(opts.team);
8440
- const spinner = (0, import_ora24.default)(`Dismissing ${origin}...`).start();
9719
+ const spinner = (0, import_ora26.default)(`Dismissing ${origin}...`).start();
8441
9720
  try {
8442
9721
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/dismiss`, body: { origin }, summary: `Dismiss sidecar origin ${origin}` });
8443
9722
  spinner.succeed(`Dismissed ${origin}. It won't be suggested again.`);
@@ -8448,7 +9727,7 @@ async function runOriginsDeny(origin, opts) {
8448
9727
  }
8449
9728
  async function runOriginsRemove(origin, opts) {
8450
9729
  const { teamId } = await resolveTeam(opts.team);
8451
- const spinner = (0, import_ora24.default)(`Removing the proxy for ${origin}...`).start();
9730
+ const spinner = (0, import_ora26.default)(`Removing the proxy for ${origin}...`).start();
8452
9731
  try {
8453
9732
  await admin({ method: "POST", path: `/teams/${encodeURIComponent(teamId)}/sidecar/remove`, body: { origin }, summary: `Un-route sidecar origin ${origin}` });
8454
9733
  spinner.succeed(`Removed ${origin}. Your app will stop routing it (goes direct) within ~5 min.`);
@@ -8459,7 +9738,7 @@ async function runOriginsRemove(origin, opts) {
8459
9738
  }
8460
9739
 
8461
9740
  // src/commands/op.ts
8462
- var import_chalk47 = __toESM(require("chalk"));
9741
+ var import_chalk50 = __toESM(require("chalk"));
8463
9742
  init_auth();
8464
9743
  init_trace();
8465
9744
  init_types();
@@ -8492,82 +9771,82 @@ function printResidue(report, applied) {
8492
9771
  const up = report?.upstash ?? {};
8493
9772
  const fga = report?.fga ?? {};
8494
9773
  const ghosts = report?.ghosts ?? {};
8495
- console.log(import_chalk47.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
8496
- console.log(import_chalk47.default.bold("\n Upstash"));
9774
+ console.log(import_chalk50.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
9775
+ console.log(import_chalk50.default.bold("\n Upstash"));
8497
9776
  const orphans = up.orphans ?? [];
8498
- if (orphans.length === 0) console.log(import_chalk47.default.green(" no orphaned keys"));
8499
- for (const o of orphans) console.log(` ${import_chalk47.default.yellow(o.key)} ${import_chalk47.default.dim(`\u2014 ${o.reason}`)}`);
8500
- console.log(import_chalk47.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
9777
+ if (orphans.length === 0) console.log(import_chalk50.default.green(" no orphaned keys"));
9778
+ for (const o of orphans) console.log(` ${import_chalk50.default.yellow(o.key)} ${import_chalk50.default.dim(`\u2014 ${o.reason}`)}`);
9779
+ console.log(import_chalk50.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
8501
9780
  if (up.anon_wallet_detail) {
8502
9781
  const d = up.anon_wallet_detail;
8503
- console.log(import_chalk47.default.dim(` anon wallets: ${d.count} ($${(d.total_cents / 100).toFixed(2)}), ${d.no_ttl} with NO TTL${d.no_ttl ? " \u26A0" : " (all self-expire)"}`));
9782
+ console.log(import_chalk50.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)"}`));
8504
9783
  }
8505
9784
  if (up.keyspace_census) {
8506
9785
  const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
8507
- console.log(import_chalk47.default.dim(` keyspace: ${census}`));
9786
+ console.log(import_chalk50.default.dim(` keyspace: ${census}`));
8508
9787
  }
8509
- if (up.unknown?.length) console.log(import_chalk47.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
8510
- if (applied) console.log(` ${import_chalk47.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
8511
- for (const e of up.errors ?? []) console.log(import_chalk47.default.red(` error: ${e}`));
8512
- console.log(import_chalk47.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
9788
+ if (up.unknown?.length) console.log(import_chalk50.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
9789
+ if (applied) console.log(` ${import_chalk50.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
9790
+ for (const e of up.errors ?? []) console.log(import_chalk50.default.red(` error: ${e}`));
9791
+ console.log(import_chalk50.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
8513
9792
  if (applied) {
8514
9793
  const swept = fga?.swept ?? [];
8515
- if (swept.length === 0) console.log(import_chalk47.default.green(" no orphaned stores"));
9794
+ if (swept.length === 0) console.log(import_chalk50.default.green(" no orphaned stores"));
8516
9795
  for (const s of swept) {
8517
9796
  console.log(
8518
- ` ${import_chalk47.default.yellow(s.store_id)} ${import_chalk47.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
9797
+ ` ${import_chalk50.default.yellow(s.store_id)} ${import_chalk50.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
8519
9798
  );
8520
9799
  }
8521
- if (fga?.remaining) console.log(import_chalk47.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
9800
+ if (fga?.remaining) console.log(import_chalk50.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
8522
9801
  const st = fga?.side_tables;
8523
- if (st) console.log(import_chalk47.default.dim(` Neon side-tables purged: ${st.soft_deleted_stores} store records, ${st.orphan_models} models, ${st.orphan_changelog} changelog rows${st.error ? ` (${st.error})` : ""}`));
9802
+ if (st) console.log(import_chalk50.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})` : ""}`));
8524
9803
  } else {
8525
9804
  const fgaOrphans = fga?.orphans ?? [];
8526
- if (fgaOrphans.length === 0) console.log(import_chalk47.default.green(" no orphaned stores"));
9805
+ if (fgaOrphans.length === 0) console.log(import_chalk50.default.green(" no orphaned stores"));
8527
9806
  for (const s of fgaOrphans) {
8528
9807
  const src = s.in_openfga ? "live in OpenFGA" : "Neon tuples only";
8529
- console.log(` ${import_chalk47.default.yellow(s.store_id)} ${import_chalk47.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
9808
+ console.log(` ${import_chalk50.default.yellow(s.store_id)} ${import_chalk50.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
8530
9809
  }
8531
- console.log(import_chalk47.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
9810
+ console.log(import_chalk50.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
8532
9811
  const st = fga?.side_tables;
8533
- if (st) console.log(import_chalk47.default.dim(` Neon side-table residue: ${st.soft_deleted_stores} soft-deleted store records, ${st.orphan_models} orphan models, ${st.orphan_changelog} orphan changelog rows`));
9812
+ if (st) console.log(import_chalk50.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`));
8534
9813
  }
8535
- for (const e of fga?.errors ?? []) console.log(import_chalk47.default.red(` error: ${e}`));
8536
- console.log(import_chalk47.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
9814
+ for (const e of fga?.errors ?? []) console.log(import_chalk50.default.red(` error: ${e}`));
9815
+ console.log(import_chalk50.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
8537
9816
  if (applied) {
8538
- if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk47.default.green(" no ghost tuples"));
8539
- else console.log(` ${import_chalk47.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk47.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
9817
+ if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk50.default.green(" no ghost tuples"));
9818
+ else console.log(` ${import_chalk50.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk50.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
8540
9819
  } else {
8541
9820
  const n = ghosts?.ghost_count ?? 0;
8542
- if (n === 0) console.log(import_chalk47.default.green(` no ghost tuples ${import_chalk47.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
9821
+ if (n === 0) console.log(import_chalk50.default.green(` no ghost tuples ${import_chalk50.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
8543
9822
  else {
8544
- console.log(import_chalk47.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
9823
+ console.log(import_chalk50.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
8545
9824
  for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
8546
- console.log(import_chalk47.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
9825
+ console.log(import_chalk50.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
8547
9826
  }
8548
- if (n > 20) console.log(import_chalk47.default.dim(` \u2026 and ${n - 20} more`));
9827
+ if (n > 20) console.log(import_chalk50.default.dim(` \u2026 and ${n - 20} more`));
8549
9828
  }
8550
9829
  }
8551
- for (const e of ghosts?.errors ?? []) console.log(import_chalk47.default.red(` error: ${e}`));
9830
+ for (const e of ghosts?.errors ?? []) console.log(import_chalk50.default.red(` error: ${e}`));
8552
9831
  console.log();
8553
9832
  }
8554
9833
  async function runOp(sub, opts = {}) {
8555
9834
  if (!loadCredentials()) {
8556
- console.log(import_chalk47.default.dim("Not logged in. Run `apiblaze login`."));
9835
+ console.log(import_chalk50.default.dim("Not logged in. Run `apiblaze login`."));
8557
9836
  return;
8558
9837
  }
8559
9838
  if (!isOperatorLogin()) {
8560
- console.log(import_chalk47.default.dim("`apiblaze op` is only available to platform operators."));
9839
+ console.log(import_chalk50.default.dim("`apiblaze op` is only available to platform operators."));
8561
9840
  return;
8562
9841
  }
8563
9842
  switch (sub) {
8564
9843
  case void 0:
8565
9844
  case "menu": {
8566
- console.log(import_chalk47.default.bold("\nOperator menu"));
8567
- console.log(` ${import_chalk47.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
8568
- console.log(` ${import_chalk47.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk47.default.dim("-y to skip")})`);
8569
- console.log(` ${import_chalk47.default.cyan("apiblaze op credits")} list credit wallets`);
8570
- console.log(import_chalk47.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
9845
+ console.log(import_chalk50.default.bold("\nOperator menu"));
9846
+ console.log(` ${import_chalk50.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
9847
+ console.log(` ${import_chalk50.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk50.default.dim("-y to skip")})`);
9848
+ console.log(` ${import_chalk50.default.cyan("apiblaze op credits")} list credit wallets`);
9849
+ console.log(import_chalk50.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
8571
9850
  `));
8572
9851
  return;
8573
9852
  }
@@ -8586,17 +9865,17 @@ async function runOp(sub, opts = {}) {
8586
9865
  const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
8587
9866
  printResidue(report, false);
8588
9867
  if (nUp + nFga + nGhost + nSide === 0) {
8589
- console.log(import_chalk47.default.green("Nothing to sweep."));
9868
+ console.log(import_chalk50.default.green("Nothing to sweep."));
8590
9869
  return;
8591
9870
  }
8592
9871
  if (!opts.yes) {
8593
9872
  const readline3 = await import("readline/promises");
8594
9873
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
8595
9874
  const answer = await rl.question(
8596
- import_chalk47.default.red(`Delete ${nUp} Upstash key(s) + ${nFga} OpenFGA store(s) + ${nGhost} ghost tuple(s) + ${nSide} Neon side-table row(s)? Type 'sweep' to confirm: `)
9875
+ import_chalk50.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: `)
8597
9876
  );
8598
9877
  rl.close();
8599
- if (answer.trim() !== "sweep") return void console.log(import_chalk47.default.dim("Aborted."));
9878
+ if (answer.trim() !== "sweep") return void console.log(import_chalk50.default.dim("Aborted."));
8600
9879
  }
8601
9880
  const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
8602
9881
  if (opts.json) return void console.log(JSON.stringify(result, null, 2));
@@ -8607,15 +9886,15 @@ async function runOp(sub, opts = {}) {
8607
9886
  const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list credit wallets" });
8608
9887
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
8609
9888
  const accounts = data?.accounts ?? [];
8610
- if (accounts.length === 0) return void console.log(import_chalk47.default.dim("No credit wallets."));
9889
+ if (accounts.length === 0) return void console.log(import_chalk50.default.dim("No credit wallets."));
8611
9890
  for (const a of accounts) {
8612
9891
  const bal = typeof a.balance_cents === "number" ? `$${(a.balance_cents / 100).toFixed(2)}` : "?";
8613
- console.log(` ${import_chalk47.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk47.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk47.default.dim(" \u2014 anon") : ""}`);
9892
+ console.log(` ${import_chalk50.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk50.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk50.default.dim(" \u2014 anon") : ""}`);
8614
9893
  }
8615
9894
  return;
8616
9895
  }
8617
9896
  default:
8618
- console.log(import_chalk47.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
9897
+ console.log(import_chalk50.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
8619
9898
  }
8620
9899
  }
8621
9900
 
@@ -8678,7 +9957,7 @@ program.command("dev").description("Put your localhost behind a public URL (dev
8678
9957
  try {
8679
9958
  const resolved = parseInt(port ?? opts.port, 10);
8680
9959
  if (Number.isNaN(resolved)) {
8681
- console.error(import_chalk48.default.red(`Invalid port: ${port ?? opts.port}`));
9960
+ console.error(import_chalk51.default.red(`Invalid port: ${port ?? opts.port}`));
8682
9961
  process.exit(1);
8683
9962
  }
8684
9963
  await runDev({ port: resolved, project: opts.project, yes: opts.yes, captureFile: opts.captureFile, newSession: opts.newSession });
@@ -8727,6 +10006,11 @@ program.command("projects").description("List the projects in your team").action
8727
10006
  process.exit(1);
8728
10007
  }
8729
10008
  });
10009
+ program.command("search").description("Find a published recipe \u2014 a whole working proxy someone else set up").argument("[query]", "Words to match against a recipe name or summary").option("--limit <n>", "Maximum results (default 25)").option("--json", "Output machine-readable JSON").action(action((query, opts) => runRecipeSearch(query, opts)));
10010
+ program.command("show").description("Read a recipe before you install it (upstreams, questions, transforms, spec)").argument("<recipe>", "Recipe name, e.g. @julien/gmail or @julien/gmail@2").option("--settings", "Print the settings section").option("--auth", "Print the auth section (login provider, key types)").option("--transforms", "Print the transform rules and mapping tables").option("--openapi", "Print the OpenAPI document").option("--json", "Output machine-readable JSON").action(action((recipe, opts) => runRecipeShow(recipe, opts)));
10011
+ program.command("install").description("Create a proxy from a recipe, with your own credentials").argument("<recipe>", "Recipe name, e.g. @julien/gmail or @julien/gmail@2 to pin a revision").option("--as <name>", "Proxy name (skips the name prompt)").option("--into <proxy>", "Reinstall over an existing proxy \u2014 replaces its settings, transforms and spec").option("--team <id|name>", "Team the proxy is created in (you are asked when you belong to several)").option("--apiversion <v>", "API version of the proxy named by --into").option("-y, --yes", "Skip the routine prompts (installs WITHOUT anything needing consent)").action(action((recipe, opts) => runRecipeInstall(recipe, opts)));
10012
+ program.command("publish").description("Publish one of your proxies as a recipe others can install").argument("<project>", "Project name or id (see `apiblaze projects`)").option("--as <name>", "Recipe name. Defaults to your GitHub handle + the proxy name; pass `pokedex` for just the name, or `@acme/pokedex` to set both").option("--private", "Only your team can see or install it (default is public)").option("--tenant <slug>", "Which tenant's auth setup the recipe carries (asked when a proxy has several)").option("--display-name <text>", "Human-readable title").option("--summary <text>", "One-line description shown in search").option("--license <id>", "Licence identifier, e.g. MIT").option("--team <id|name>", "Team the project is in (defaults to active team)").option("--apiversion <v>", "API version to publish (defaults to the first match)").option("-y, --yes", "Skip routine confirmations (never accepts scanner findings)").option("--json", "Output machine-readable JSON").action(action((project, opts) => runRecipePublish(project, opts)));
10013
+ program.command("withdraw").description("Permanently delete one published recipe revision").argument("<recipe>", "Recipe revision, e.g. @julien/gmail@3").option("--team <id|name>", "Team that published it (defaults to active team)").option("--json", "Output machine-readable JSON").action(action((recipe, opts) => runRecipeWithdraw(recipe, opts)));
8730
10014
  program.command("delete").description("Delete a proxy and everything under it (asks first)").argument("<project>", "Project name or id (see `apiblaze projects`)").argument("[version]", "API version (defaults to the first match)").option("--team <id|name>", "Team the project is in (defaults to active team)").option("-y, --yes", "Skip the confirmation prompt").option("--json", "Output machine-readable JSON").action(action((project, version2, opts) => runDelete(project, version2, opts)));
8731
10015
  program.command("export").description("Export config and data for migration out of APIblaze (Kong, ...)").argument("<project>", "Project name or id (see `apiblaze projects`)").argument("[version]", "API version (defaults to the first match)").option("--kong", "Produce a runnable Kong OSS bundle (decK config + plugins + docker-compose)").option("--data", "Plain data export (default)").option("--secrets", "Include decrypted producer-supplied secrets (member role; audit-logged)").option("--keys <mode>", "API-key export: hashes (default, consumers keep keys) | mint | none").option("--no-consumers", "Skip the end-user lane (users, groups, keys)").option("-o, --out <file>", "Output zip path").option("--team <id|name>", "Team the project is in (defaults to active team)").action(action((project, version2, opts) => runExport(project, version2, { ...opts, noConsumers: opts.consumers === false })));
8732
10016
  var logs = program.command("logs").description("API Producer view \u2014 stream this proxy's requests from EVERY caller live (see `apiblaze logs list` to browse past days)").argument("<project>", "Project name or id (see `apiblaze projects`)").argument("[version]", "API version (defaults to the first match)").option("--tenant <slug>", "Tenant to tail (auto when one is attached; prompted otherwise)").option("--errors-only", "Only show 4xx/5xx responses").option("--json", "Emit raw NDJSON rows (pipe into jq)").option("--team <id|name>", "Team the project is in (defaults to active team)").action(action((project, version2, opts) => runLogsTail(project, version2, opts)));
@@ -8782,6 +10066,7 @@ spec.command("delete-rule").description("Delete the saved rules for a route (e.g
8782
10066
  var HELP_GROUPS = [
8783
10067
  { title: "Chat", commands: ["apichat", "agent"] },
8784
10068
  { title: "Setup", commands: ["login", "create", "init", "sidecar", "dev", "claim", "team", "whoami", "logout"] },
10069
+ { title: "Recipes \u2014 install a working setup, or publish yours", commands: ["search", "show", "install", "publish", "withdraw"] },
8785
10070
  { title: "Control plane commands", commands: ["config", "projects", "logs", "tenant", "group", "admins", "iam", "identified", "preapprove", "rule", "domain", "delete", "target", "throttle", "rename", "spec", "export"] },
8786
10071
  { title: "Data plane commands", commands: [
8787
10072
  { parent: "consumer", sub: "login" },
@@ -8802,7 +10087,7 @@ function groupedCommandHelp() {
8802
10087
  const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
8803
10088
  return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
8804
10089
  }).filter(Boolean).join("\n");
8805
- return `${import_chalk48.default.bold(g.title)}
10090
+ return `${import_chalk51.default.bold(g.title)}
8806
10091
  ${rows}`;
8807
10092
  }).join("\n\n");
8808
10093
  }
@@ -8826,6 +10111,9 @@ Examples:
8826
10111
  $ npx apiblaze agent # just chat
8827
10112
  $ npx apiblaze create --target https://api.example.com # one-line API
8828
10113
  $ npx apiblaze create --openapi https://pokeapi.co/openapi.yaml # build it from a spec URL
10114
+ $ npx apiblaze search gmail # find a recipe (no login needed)
10115
+ $ npx apiblaze install @julien/gmail # someone's whole working setup, your credentials
10116
+ $ npx apiblaze publish mygmail # share yours back, as @yourgithubhandle/mygmail
8829
10117
  $ npx apiblaze dev 3000 # localhost \u2192 public URL
8830
10118
  $ npx apiblaze throttle myapi --rate 50 --verbose # configure + show the API call
8831
10119
  $ npx apiblaze consumer login # act as a consumer of your API
@@ -8837,14 +10125,14 @@ async function recoverStaleTeam() {
8837
10125
  const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
8838
10126
  const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
8839
10127
  if (!linked) {
8840
- console.error(import_chalk48.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
10128
+ console.error(import_chalk51.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
8841
10129
  return;
8842
10130
  }
8843
10131
  if (linked.teamId === creds.teamId) return;
8844
10132
  const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
8845
10133
  delete next.activeTenant;
8846
10134
  saveCredentials(next);
8847
- console.error(import_chalk48.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk48.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
10135
+ console.error(import_chalk51.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk51.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
8848
10136
  } catch {
8849
10137
  }
8850
10138
  }
@@ -8852,16 +10140,16 @@ async function printError(err) {
8852
10140
  if (err instanceof ApiError) {
8853
10141
  const data = err.body;
8854
10142
  const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
8855
- console.error(import_chalk48.default.red(`
10143
+ console.error(import_chalk51.default.red(`
8856
10144
  API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
8857
10145
  if (err.status === 403 || err.status === 404) {
8858
10146
  await recoverStaleTeam();
8859
10147
  }
8860
10148
  } else if (err instanceof Error) {
8861
- console.error(import_chalk48.default.red(`
10149
+ console.error(import_chalk51.default.red(`
8862
10150
  Error: ${err.message}`));
8863
10151
  } else {
8864
- console.error(import_chalk48.default.red("\nUnknown error"));
10152
+ console.error(import_chalk51.default.red("\nUnknown error"));
8865
10153
  }
8866
10154
  }
8867
10155
  program.parse(process.argv);