apiblaze 0.14.0 → 0.15.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 +40 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -534,16 +534,33 @@ async function pickTenant(teamId, opts = {}) {
534
534
  }
535
535
  async function createTenantInline(teamId) {
536
536
  const { default: inquirer2 } = await import("inquirer");
537
- const { display } = await inquirer2.prompt([{ type: "input", name: "display", message: "Display name for the new tenant:", validate: (s) => !!s.trim() || "required" }]);
538
- const out = await admin({
539
- method: "POST",
540
- path: `/teams/${encodeURIComponent(teamId)}/tenants`,
541
- body: { display_name: display.trim() },
542
- summary: `Create tenant "${display.trim()}"`
543
- });
544
- const slug = out?.tenant_name ?? out?.tenant?.tenant_name;
545
- console.log(import_chalk22.default.green(` Tenant ${import_chalk22.default.bold(slug)} created.`));
546
- return slug;
537
+ for (; ; ) {
538
+ const { name } = await inquirer2.prompt([{
539
+ type: "input",
540
+ name: "name",
541
+ message: `Tenant name ${import_chalk22.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
542
+ validate: (s) => /^[a-z0-9]+$/.test(s.trim()) ? true : "lowercase letters and numbers only"
543
+ }]);
544
+ const slugInput = name.trim();
545
+ try {
546
+ const out = await admin({
547
+ method: "POST",
548
+ path: `/teams/${encodeURIComponent(teamId)}/tenants`,
549
+ body: { tenant_name: slugInput, display_name: slugInput },
550
+ summary: `Create tenant "${slugInput}"`
551
+ });
552
+ const slug = out?.tenant_name ?? out?.tenant?.tenant_name ?? slugInput;
553
+ console.log(import_chalk22.default.green(` Tenant ${import_chalk22.default.bold(slug)} created.`));
554
+ return slug;
555
+ } catch (err) {
556
+ const msg = err instanceof Error ? err.message : String(err);
557
+ if (/taken|unique|exists|reserved|conflict/i.test(msg)) {
558
+ console.log(import_chalk22.default.yellow(` "${slugInput}" is not available (tenant names are global): ${msg}`));
559
+ continue;
560
+ }
561
+ throw err;
562
+ }
563
+ }
547
564
  }
548
565
  var import_chalk22, import_ora8, PAGE;
549
566
  var init_tenant_pick = __esm({
@@ -562,7 +579,7 @@ var import_commander = require("commander");
562
579
  var import_chalk34 = __toESM(require("chalk"));
563
580
 
564
581
  // package.json
565
- var version = "0.14.0";
582
+ var version = "0.15.1";
566
583
 
567
584
  // src/index.ts
568
585
  init_types();
@@ -3136,22 +3153,26 @@ async function clientsMenu(teamId, tenant2, base) {
3136
3153
  if (pick2 === " back") return;
3137
3154
  if (pick2 === " create") {
3138
3155
  const projects = await getProjects(teamId).catch(() => []);
3139
- if (!projects.length) {
3140
- console.log(import_chalk24.default.yellow(" No projects in this team \u2014 create a proxy first."));
3141
- continue;
3142
- }
3143
3156
  const a = await inquirer2.prompt([
3144
3157
  { type: "input", name: "name", message: "Client name:", validate: (s) => !!s.trim() || "required" },
3145
- { type: "list", name: "proj", message: "For which project?", choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk24.default.dim("v" + p.apiVersion)}`, value: p })) },
3158
+ ...projects.length ? [{
3159
+ type: "list",
3160
+ name: "proj",
3161
+ message: "Reference a project? (adds its portal/MCP token audiences)",
3162
+ choices: [
3163
+ ...projects.map((p) => ({ name: `${p.projectName} ${import_chalk24.default.dim("v" + p.apiVersion)}`, value: p })),
3164
+ { name: import_chalk24.default.dim("Skip \u2014 tenant-only client"), value: null }
3165
+ ]
3166
+ }] : [],
3146
3167
  { type: "input", name: "callbacks", message: "Callback URLs (comma-separated, empty = none):" }
3147
3168
  ]);
3169
+ if (!projects.length) console.log(import_chalk24.default.dim(" (no projects in this team yet \u2014 creating a tenant-only client; you can reference a project later)"));
3148
3170
  const created = await admin({
3149
3171
  method: "POST",
3150
3172
  path: `${base}/app-clients`,
3151
3173
  body: {
3152
3174
  name: a.name.trim(),
3153
- projectName: a.proj.projectName,
3154
- apiVersion: a.proj.apiVersion,
3175
+ ...a.proj ? { projectName: a.proj.projectName, apiVersion: a.proj.apiVersion } : {},
3155
3176
  ...a.callbacks.trim() ? { authorizedCallbackUrls: parseList(a.callbacks) } : {}
3156
3177
  },
3157
3178
  summary: `Create app client "${a.name.trim()}"`
@@ -5350,7 +5371,7 @@ var tenant = program.command("tenant").description("Manage tenants \u2014 bare c
5350
5371
  tenant.command("manage").description("Browse & edit one tenant: settings, login app clients, providers, issuers (search-first picker)").argument("[query]", "Search by tenant name/display name (omit to use your tenant scope or pick)").option("--tenant <slug>", "Exact tenant slug (skips the picker)").option("--team <id|name>", "Team (defaults to active team)").action(action((query, opts) => runTenantManage(query, opts)));
5351
5372
  tenant.command("use").description("Set the sticky tenant scope for future commands (search-first; --clear to unset)").argument("[query]", "Search by tenant name/display name").option("--clear", "Clear the tenant scope").option("--team <id|name>", "Team (defaults to active team)").action(action((query, opts) => runTenantUse(query, opts)));
5352
5373
  tenant.command("list").description("List tenants in your team (--q searches server-side)").option("--q <search>", "Filter by tenant name or display name").option("--limit <n>", "Page size (max 200)").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Output machine-readable JSON").action(action((opts) => runTenantList(opts)));
5353
- tenant.command("create").description("Create a tenant in your team").requiredOption("--name <display>", "Display name").option("--slug <tenant_name>", "Explicit tenant slug (generated if omitted)").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Output machine-readable JSON").action(action((opts) => runTenantCreate(opts)));
5374
+ tenant.command("create").description("Create a tenant in your team (tenant names are lowercase alphanumeric and globally unique)").requiredOption("--name <name>", "Tenant name \u2014 becomes the slug ({name}.portal.apiblaze.com) unless --slug overrides; also the display label").option("--slug <tenant_name>", "Explicit tenant slug when it should differ from --name").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Output machine-readable JSON").action(action((opts) => runTenantCreate(opts)));
5354
5375
  tenant.command("attach").description("Attach a tenant to a proxy").argument("<project>", "Project name or id").requiredOption("--tenant <slug>", "Tenant slug to attach").option("--auth-config <id>", "Auth config id to bind").option("--team <id|name>", "Team the project is in").option("--apiversion <version>", "API version").option("--json", "Output machine-readable JSON").action(action((project, opts) => runTenantAttach(project, opts)));
5355
5376
  tenant.command("delete").description("Delete a tenant (full cascade)").argument("<slug>", "Tenant slug to delete").option("--team <id|name>", "Team (defaults to active team)").option("-y, --yes", "Skip the confirmation prompt").action(action((slug, opts) => runTenantDelete(slug, opts)));
5356
5377
  tenant.command("cors").description("Set the CORS allow-list for a tenant").requiredOption("--tenant <slug>", "Tenant slug").option("--origins <list>", 'Comma-separated origins (or "*"); empty clears').option("--team <id|name>", "Team (defaults to active team)").action(action((opts) => runTenantCors(opts)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "description": "APIblaze CLI + sidecar — manage API proxies, run dev tunnels, and route a Next.js app's egress through APIblaze with one command",
5
5
  "keywords": [
6
6
  "apiblaze",