apiblaze 0.1.6 → 0.1.8

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 +142 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -87,6 +87,8 @@ var init_auth = __esm({
87
87
  // src/lib/api.ts
88
88
  var api_exports = {};
89
89
  __export(api_exports, {
90
+ checkProxyName: () => checkProxyName,
91
+ createProxy: () => createProxy,
90
92
  deleteDevTunnel: () => deleteDevTunnel,
91
93
  getLocalhostTargets: () => getLocalhostTargets,
92
94
  getProjects: () => getProjects,
@@ -132,6 +134,15 @@ async function getLocalhostTargets(teamId) {
132
134
  async function getProjects(teamId) {
133
135
  return apiFetch(`/api/cli/projects?team_id=${encodeURIComponent(teamId)}`);
134
136
  }
137
+ async function checkProxyName(name) {
138
+ return apiFetch(`/api/cli/check-name?name=${encodeURIComponent(name)}`);
139
+ }
140
+ async function createProxy(payload) {
141
+ return apiFetch("/api/cli/create-proxy", {
142
+ method: "POST",
143
+ body: JSON.stringify(payload)
144
+ });
145
+ }
135
146
  async function putDevTunnel(payload) {
136
147
  return apiFetch("/api/cli/dev-tunnel", {
137
148
  method: "PUT",
@@ -153,7 +164,7 @@ var init_api = __esm({
153
164
 
154
165
  // src/index.ts
155
166
  var import_commander = require("commander");
156
- var import_chalk5 = __toESM(require("chalk"));
167
+ var import_chalk6 = __toESM(require("chalk"));
157
168
  init_types();
158
169
 
159
170
  // src/commands/login.ts
@@ -231,7 +242,7 @@ async function runLogin() {
231
242
  });
232
243
  spinner.succeed(import_chalk.default.green("Authorized!"));
233
244
  if (githubHandle) {
234
- console.log(`${import_chalk.default.cyan("\u2192")} Logged in as ${import_chalk.default.bold("@" + githubHandle)}${apiblazeUserId ? import_chalk.default.dim(` (${apiblazeUserId})`) : ""}`);
245
+ console.log(`${import_chalk.default.cyan("\u2192")} Logged in as ${import_chalk.default.bold("@" + githubHandle)}`);
235
246
  }
236
247
  let teamId = defaultTeamId ?? void 0;
237
248
  let teamName;
@@ -607,9 +618,7 @@ async function runProjects() {
607
618
  process.exit(1);
608
619
  }
609
620
  if (creds.githubHandle) {
610
- console.log(
611
- `${import_chalk4.default.cyan("\u2192")} Logged in as ${import_chalk4.default.bold("@" + creds.githubHandle)}` + (creds.apiblazeUserId ? import_chalk4.default.dim(` (${creds.apiblazeUserId})`) : "")
612
- );
621
+ console.log(`${import_chalk4.default.cyan("\u2192")} Logged in as ${import_chalk4.default.bold("@" + creds.githubHandle)}`);
613
622
  }
614
623
  let teamId = creds.teamId;
615
624
  let teamName = creds.teamName;
@@ -634,7 +643,7 @@ async function runProjects() {
634
643
  console.error(import_chalk4.default.red("No team found. Run `apiblaze login` to set up your team."));
635
644
  process.exit(1);
636
645
  }
637
- console.log(`${import_chalk4.default.cyan("\u2192")} Team: ${import_chalk4.default.bold(teamName ?? teamId)} ${import_chalk4.default.dim(teamId)}
646
+ console.log(`${import_chalk4.default.cyan("\u2192")} Team: ${import_chalk4.default.bold(teamName ?? teamId)}
638
647
  `);
639
648
  const spinner = (0, import_ora4.default)("Fetching projects...").start();
640
649
  let projects;
@@ -649,12 +658,125 @@ async function runProjects() {
649
658
  console.log(import_chalk4.default.yellow("No projects found for this team."));
650
659
  return;
651
660
  }
661
+ const width = Math.max(...projects.map((p) => p.projectName.length));
652
662
  for (const p of projects) {
653
- console.log(`${import_chalk4.default.bold(p.projectName)} ${import_chalk4.default.dim(p.projectId)}`);
654
- console.log(` ${import_chalk4.default.dim("version:")} ${p.apiVersion} ${import_chalk4.default.dim("team:")} ${p.teamId}`);
663
+ console.log(` ${import_chalk4.default.bold(p.projectName.padEnd(width))} ${import_chalk4.default.dim("v" + p.apiVersion)}`);
655
664
  }
656
665
  console.log(import_chalk4.default.dim(`
657
- ${projects.length} project(s).`));
666
+ ${projects.length} project${projects.length === 1 ? "" : "s"}`));
667
+ }
668
+
669
+ // src/commands/create.ts
670
+ var import_chalk5 = __toESM(require("chalk"));
671
+ var import_ora5 = __toESM(require("ora"));
672
+ init_auth();
673
+ init_api();
674
+ function normalizeName(raw) {
675
+ return (raw || "").toLowerCase().replace(/[^a-z0-9]/g, "");
676
+ }
677
+ function isHttpUrl(s) {
678
+ try {
679
+ const u = new URL(s.trim());
680
+ return u.protocol === "http:" || u.protocol === "https:";
681
+ } catch {
682
+ return false;
683
+ }
684
+ }
685
+ function stripTenantFromPortal(devPortal) {
686
+ try {
687
+ const u = new URL(devPortal);
688
+ const dot = u.hostname.indexOf(".");
689
+ if (dot < 0) return devPortal;
690
+ const product = u.hostname.slice(0, dot).split("-")[0];
691
+ u.hostname = `${product}${u.hostname.slice(dot)}`;
692
+ return u.toString();
693
+ } catch {
694
+ return devPortal;
695
+ }
696
+ }
697
+ async function runCreate() {
698
+ const creds = loadCredentials();
699
+ if (!creds) {
700
+ console.error(import_chalk5.default.red("Not logged in. Run `apiblaze login` first."));
701
+ process.exit(1);
702
+ }
703
+ console.log(import_chalk5.default.bold("\nCreate an API proxy\n"));
704
+ const { default: inquirer2 } = await import("inquirer");
705
+ let name = "";
706
+ for (; ; ) {
707
+ const { rawName } = await inquirer2.prompt([{
708
+ type: "input",
709
+ name: "rawName",
710
+ message: "Proxy name (your API will live at <name>.apiblaze.com):",
711
+ transformer: (v) => normalizeName(v)
712
+ }]);
713
+ name = normalizeName(rawName);
714
+ if (name.length < 3) {
715
+ console.log(import_chalk5.default.yellow(" Name must be at least 3 characters (letters and digits only).\n"));
716
+ continue;
717
+ }
718
+ const spinner2 = (0, import_ora5.default)("Checking availability...").start();
719
+ try {
720
+ const check = await checkProxyName(name);
721
+ spinner2.stop();
722
+ if (!check.canUseProjectName || !check.canUseApiVersion) {
723
+ const why = check.message ? ` \u2014 ${check.message}` : "";
724
+ console.log(import_chalk5.default.yellow(` "${name}" is not available${why}. Try another.
725
+ `));
726
+ continue;
727
+ }
728
+ } catch {
729
+ spinner2.stop();
730
+ console.log(import_chalk5.default.dim(" (could not verify availability; continuing)"));
731
+ }
732
+ console.log(`${import_chalk5.default.cyan("\u2192")} Your API will live at ${import_chalk5.default.bold(`https://${name}.apiblaze.com`)}
733
+ `);
734
+ break;
735
+ }
736
+ let targetUrl = "";
737
+ for (; ; ) {
738
+ const { url } = await inquirer2.prompt([{
739
+ type: "input",
740
+ name: "url",
741
+ message: "Target URL to forward requests to (e.g. https://httpbin.org):"
742
+ }]);
743
+ if (!isHttpUrl(url)) {
744
+ console.log(import_chalk5.default.yellow(" Enter a valid http(s) URL.\n"));
745
+ continue;
746
+ }
747
+ targetUrl = url.trim();
748
+ break;
749
+ }
750
+ console.log(`${import_chalk5.default.cyan("\u2192")} Auth: ${import_chalk5.default.bold("API key")} \u2014 consumers send an X-API-Key header
751
+ `);
752
+ const spinner = (0, import_ora5.default)("Creating proxy (tenant, keys, dev portal)...").start();
753
+ let result;
754
+ try {
755
+ result = await createProxy({ name, target_url: targetUrl, auth_type: "api_key" });
756
+ spinner.succeed(import_chalk5.default.green("Proxy created!"));
757
+ } catch (err) {
758
+ spinner.fail("Failed to create proxy.");
759
+ throw err;
760
+ }
761
+ const version = result.api_version || "1.0.0";
762
+ const keys = result.api_keys ?? {};
763
+ const adminKey = keys.dev ?? Object.values(keys)[0];
764
+ console.log();
765
+ console.log(` ${import_chalk5.default.dim("Proxy URL: ")} ${import_chalk5.default.bold(`https://${name}.apiblaze.com/${version}/dev`)}`);
766
+ if (result.devPortal) {
767
+ console.log(` ${import_chalk5.default.dim("Dev portal:")} ${import_chalk5.default.bold(stripTenantFromPortal(result.devPortal))}`);
768
+ }
769
+ if (adminKey) {
770
+ console.log();
771
+ console.log(` ${import_chalk5.default.dim("Consumer admin API key (dev):")}`);
772
+ console.log(` ${import_chalk5.default.bold.green(adminKey)}`);
773
+ console.log(import_chalk5.default.dim("\n Save this now \u2014 send it as the X-API-Key header. It may not be shown again."));
774
+ const otherEnvs = Object.keys(keys).filter((e) => e !== "dev");
775
+ if (otherEnvs.length) {
776
+ console.log(import_chalk5.default.dim(` (Separate keys were also created for: ${otherEnvs.join(", ")}.)`));
777
+ }
778
+ }
779
+ console.log();
658
780
  }
659
781
 
660
782
  // src/index.ts
@@ -668,6 +790,14 @@ program.command("login").description("Authenticate with APIblaze").action(async
668
790
  process.exit(1);
669
791
  }
670
792
  });
793
+ program.command("create").description("Create a new API proxy").action(async () => {
794
+ try {
795
+ await runCreate();
796
+ } catch (err) {
797
+ printError(err);
798
+ process.exit(1);
799
+ }
800
+ });
671
801
  program.command("projects").description("List the projects in your team").action(async () => {
672
802
  try {
673
803
  await runProjects();
@@ -686,13 +816,13 @@ program.command("dev").description("Start a dev tunnel for your localhost projec
686
816
  });
687
817
  function printError(err) {
688
818
  if (err instanceof ApiError) {
689
- console.error(import_chalk5.default.red(`
819
+ console.error(import_chalk6.default.red(`
690
820
  API error (${err.status}): ${err.message}`));
691
821
  } else if (err instanceof Error) {
692
- console.error(import_chalk5.default.red(`
822
+ console.error(import_chalk6.default.red(`
693
823
  Error: ${err.message}`));
694
824
  } else {
695
- console.error(import_chalk5.default.red("\nUnknown error"));
825
+ console.error(import_chalk6.default.red("\nUnknown error"));
696
826
  }
697
827
  }
698
828
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Dev tunnel CLI for APIblaze — route localhost projects through Cloudflare tunnels",
5
5
  "keywords": [
6
6
  "apiblaze",