apiblaze 0.1.8 → 0.1.10

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 +183 -61
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -134,8 +134,9 @@ async function getLocalhostTargets(teamId) {
134
134
  async function getProjects(teamId) {
135
135
  return apiFetch(`/api/cli/projects?team_id=${encodeURIComponent(teamId)}`);
136
136
  }
137
- async function checkProxyName(name) {
138
- return apiFetch(`/api/cli/check-name?name=${encodeURIComponent(name)}`);
137
+ async function checkProxyName(name, teamId) {
138
+ const q = teamId ? `&team_id=${encodeURIComponent(teamId)}` : "";
139
+ return apiFetch(`/api/cli/check-name?name=${encodeURIComponent(name)}${q}`);
139
140
  }
140
141
  async function createProxy(payload) {
141
142
  return apiFetch("/api/cli/create-proxy", {
@@ -164,7 +165,7 @@ var init_api = __esm({
164
165
 
165
166
  // src/index.ts
166
167
  var import_commander = require("commander");
167
- var import_chalk6 = __toESM(require("chalk"));
168
+ var import_chalk7 = __toESM(require("chalk"));
168
169
  init_types();
169
170
 
170
171
  // src/commands/login.ts
@@ -189,12 +190,13 @@ async function runLogin() {
189
190
  throw new Error(`Failed to start login: ${codeRes.status}`);
190
191
  }
191
192
  const deviceAuth = await codeRes.json();
193
+ const loginUrl = deviceAuth.verification_uri_complete ?? deviceAuth.verification_uri;
192
194
  console.log(`${import_chalk.default.cyan("\u2192")} Open this URL in your browser to confirm login:`);
193
- console.log(` ${import_chalk.default.bold.underline(deviceAuth.verification_uri)}
195
+ console.log(` ${import_chalk.default.bold.underline(loginUrl)}
194
196
  `);
195
197
  console.log(`${import_chalk.default.cyan("\u2192")} Your code: ${import_chalk.default.bold(deviceAuth.user_code)}
196
198
  `);
197
- openBrowser(deviceAuth.verification_uri_complete ?? deviceAuth.verification_uri);
199
+ openBrowser(loginUrl);
198
200
  const spinner = (0, import_ora.default)("Waiting for authorization in browser...").start();
199
201
  let accessToken;
200
202
  let pollInterval = (deviceAuth.interval ?? 5) * 1e3;
@@ -676,7 +678,7 @@ function normalizeName(raw) {
676
678
  }
677
679
  function isHttpUrl(s) {
678
680
  try {
679
- const u = new URL(s.trim());
681
+ const u = new URL((s || "").trim());
680
682
  return u.protocol === "http:" || u.protocol === "https:";
681
683
  } catch {
682
684
  return false;
@@ -694,78 +696,144 @@ function stripTenantFromPortal(devPortal) {
694
696
  return devPortal;
695
697
  }
696
698
  }
697
- async function runCreate() {
699
+ function fail(message) {
700
+ console.error(import_chalk5.default.red(`Error: ${message}`));
701
+ process.exit(1);
702
+ }
703
+ var VALID_AUTH = ["api_key", "none", "oauth"];
704
+ async function runCreate(opts = {}) {
698
705
  const creds = loadCredentials();
699
706
  if (!creds) {
700
- console.error(import_chalk5.default.red("Not logged in. Run `apiblaze login` first."));
701
- process.exit(1);
707
+ fail("Not logged in. Run `apiblaze login` first.");
708
+ }
709
+ const interactive = !!process.stdin.isTTY && !opts.json;
710
+ const auth = (opts.auth ?? "api_key").toLowerCase();
711
+ if (!VALID_AUTH.includes(auth)) {
712
+ fail(`Invalid --auth "${auth}". Use one of: ${VALID_AUTH.join(", ")}.`);
713
+ }
714
+ let teamId = creds.teamId;
715
+ if (opts.team) {
716
+ if (opts.team.startsWith("team_")) {
717
+ teamId = opts.team;
718
+ } else {
719
+ const teams = await getTeams().catch(() => []);
720
+ const match = teams.find(
721
+ (t) => t.teamId === opts.team || t.name.toLowerCase() === opts.team.toLowerCase()
722
+ );
723
+ if (!match) {
724
+ fail(`Team "${opts.team}" not found. Run \`apiblaze team\` to see your teams.`);
725
+ }
726
+ teamId = match.teamId;
727
+ }
702
728
  }
703
- console.log(import_chalk5.default.bold("\nCreate an API proxy\n"));
704
- const { default: inquirer2 } = await import("inquirer");
729
+ if (!opts.json) console.log(import_chalk5.default.bold("\nCreate an API proxy\n"));
705
730
  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;
731
+ if (opts.name !== void 0) {
732
+ name = normalizeName(opts.name);
733
+ if (name.length < 3) fail("Proxy name must be at least 3 characters (letters and digits only).");
734
+ const check = await checkProxyName(name, teamId).catch(() => null);
735
+ if (check && (!check.canUseProjectName || !check.canUseApiVersion)) {
736
+ fail(`Proxy name "${name}" is not available${check.message ? ` \u2014 ${check.message}` : ""}.`);
717
737
  }
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
- `));
738
+ } else if (interactive) {
739
+ const { default: inquirer2 } = await import("inquirer");
740
+ for (; ; ) {
741
+ const { rawName } = await inquirer2.prompt([{
742
+ type: "input",
743
+ name: "rawName",
744
+ message: "Proxy name (your API will live at <name>.apiblaze.com):",
745
+ transformer: (v) => normalizeName(v)
746
+ }]);
747
+ name = normalizeName(rawName);
748
+ if (name.length < 3) {
749
+ console.log(import_chalk5.default.yellow(" Name must be at least 3 characters (letters and digits only).\n"));
726
750
  continue;
727
751
  }
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`)}
752
+ const spinner2 = (0, import_ora5.default)("Checking availability...").start();
753
+ try {
754
+ const check = await checkProxyName(name, teamId);
755
+ spinner2.stop();
756
+ if (!check.canUseProjectName || !check.canUseApiVersion) {
757
+ console.log(import_chalk5.default.yellow(` "${name}" is not available${check.message ? ` \u2014 ${check.message}` : ""}. Try another.
758
+ `));
759
+ continue;
760
+ }
761
+ } catch {
762
+ spinner2.stop();
763
+ console.log(import_chalk5.default.dim(" (could not verify availability; continuing)"));
764
+ }
765
+ console.log(`${import_chalk5.default.cyan("\u2192")} Your API will live at ${import_chalk5.default.bold(`https://${name}.apiblaze.com`)}
733
766
  `);
734
- break;
767
+ break;
768
+ }
769
+ } else {
770
+ fail("--name is required in non-interactive mode.");
735
771
  }
736
772
  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):"
773
+ if (opts.target !== void 0) {
774
+ if (!isHttpUrl(opts.target)) fail("--target must be a valid http(s) URL.");
775
+ targetUrl = opts.target.trim();
776
+ } else if (interactive) {
777
+ const { default: inquirer2 } = await import("inquirer");
778
+ for (; ; ) {
779
+ const { url } = await inquirer2.prompt([{
780
+ type: "input",
781
+ name: "url",
782
+ message: "Target URL to forward requests to (e.g. https://httpbin.org):"
783
+ }]);
784
+ if (!isHttpUrl(url)) {
785
+ console.log(import_chalk5.default.yellow(" Enter a valid http(s) URL.\n"));
786
+ continue;
787
+ }
788
+ targetUrl = url.trim();
789
+ break;
790
+ }
791
+ } else {
792
+ fail("--target is required in non-interactive mode.");
793
+ }
794
+ if (interactive && !opts.yes) {
795
+ const { default: inquirer2 } = await import("inquirer");
796
+ console.log(`${import_chalk5.default.cyan("\u2192")} Auth: ${import_chalk5.default.bold(auth)}${auth === "api_key" ? " \u2014 consumers send an X-API-Key header" : ""}`);
797
+ const { ok } = await inquirer2.prompt([{
798
+ type: "confirm",
799
+ name: "ok",
800
+ message: `Create proxy "${name}" \u2192 ${targetUrl}?`,
801
+ default: true
742
802
  }]);
743
- if (!isHttpUrl(url)) {
744
- console.log(import_chalk5.default.yellow(" Enter a valid http(s) URL.\n"));
745
- continue;
803
+ if (!ok) {
804
+ console.log(import_chalk5.default.yellow("Cancelled."));
805
+ return;
746
806
  }
747
- targetUrl = url.trim();
748
- break;
749
807
  }
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();
808
+ const spinner = !opts.json ? (0, import_ora5.default)("Creating proxy (tenant, keys, dev portal)...").start() : null;
753
809
  let result;
754
810
  try {
755
- result = await createProxy({ name, target_url: targetUrl, auth_type: "api_key" });
756
- spinner.succeed(import_chalk5.default.green("Proxy created!"));
811
+ result = await createProxy({ name, target_url: targetUrl, auth_type: auth, team_id: teamId });
812
+ spinner?.succeed(import_chalk5.default.green("Proxy created!"));
757
813
  } catch (err) {
758
- spinner.fail("Failed to create proxy.");
814
+ spinner?.fail("Failed to create proxy.");
759
815
  throw err;
760
816
  }
761
817
  const version = result.api_version || "1.0.0";
762
818
  const keys = result.api_keys ?? {};
763
819
  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))}`);
820
+ const proxyUrl = `https://${name}.apiblaze.com/${version}/dev`;
821
+ const devPortal = result.devPortal ? stripTenantFromPortal(result.devPortal) : void 0;
822
+ if (opts.json) {
823
+ process.stdout.write(JSON.stringify({
824
+ project_id: result.project_id,
825
+ api_version: version,
826
+ proxy_url: proxyUrl,
827
+ dev_portal: devPortal,
828
+ api_key: adminKey,
829
+ api_keys: keys,
830
+ team_id: teamId
831
+ }) + "\n");
832
+ return;
768
833
  }
834
+ console.log();
835
+ console.log(` ${import_chalk5.default.dim("Proxy URL: ")} ${import_chalk5.default.bold(proxyUrl)}`);
836
+ if (devPortal) console.log(` ${import_chalk5.default.dim("Dev portal:")} ${import_chalk5.default.bold(devPortal)}`);
769
837
  if (adminKey) {
770
838
  console.log();
771
839
  console.log(` ${import_chalk5.default.dim("Consumer admin API key (dev):")}`);
@@ -779,6 +847,52 @@ async function runCreate() {
779
847
  console.log();
780
848
  }
781
849
 
850
+ // src/commands/team.ts
851
+ var import_chalk6 = __toESM(require("chalk"));
852
+ init_auth();
853
+ init_api();
854
+ function fail2(message) {
855
+ console.error(import_chalk6.default.red(`Error: ${message}`));
856
+ process.exit(1);
857
+ }
858
+ async function runTeam(arg) {
859
+ const creds = loadCredentials();
860
+ if (!creds) {
861
+ fail2("Not logged in. Run `apiblaze login` first.");
862
+ }
863
+ const teams = await getTeams().catch(() => []);
864
+ if (teams.length === 0) {
865
+ fail2("No teams found for your account.");
866
+ }
867
+ let chosen;
868
+ if (arg) {
869
+ chosen = teams.find(
870
+ (t) => t.teamId === arg || t.name.toLowerCase() === arg.toLowerCase()
871
+ );
872
+ if (!chosen) {
873
+ fail2(`Team "${arg}" not found. Available: ${teams.map((t) => t.name).join(", ")}.`);
874
+ }
875
+ } else if (teams.length === 1) {
876
+ chosen = teams[0];
877
+ console.log(`${import_chalk6.default.cyan("\u2192")} You only have one team: ${import_chalk6.default.bold(chosen.name)}`);
878
+ } else if (process.stdin.isTTY) {
879
+ const { default: inquirer2 } = await import("inquirer");
880
+ const { picked } = await inquirer2.prompt([{
881
+ type: "list",
882
+ name: "picked",
883
+ message: "Switch to which team?",
884
+ default: creds.teamId,
885
+ choices: teams.map((t) => ({ name: t.name, value: t.teamId }))
886
+ }]);
887
+ chosen = teams.find((t) => t.teamId === picked);
888
+ } else {
889
+ fail2(`Specify a team: \`apiblaze team <name|id>\`. Available: ${teams.map((t) => t.name).join(", ")}.`);
890
+ }
891
+ saveCredentials({ ...creds, teamId: chosen.teamId, teamName: chosen.name });
892
+ console.log(import_chalk6.default.green(`
893
+ \u2714 Active team: ${import_chalk6.default.bold(chosen.name)}`));
894
+ }
895
+
782
896
  // src/index.ts
783
897
  var program = new import_commander.Command();
784
898
  program.name("apiblaze").description("APIblaze dev tunnel CLI").version("0.1.0");
@@ -790,9 +904,17 @@ program.command("login").description("Authenticate with APIblaze").action(async
790
904
  process.exit(1);
791
905
  }
792
906
  });
793
- program.command("create").description("Create a new API proxy").action(async () => {
907
+ program.command("create").description("Create a new API proxy").option("--name <name>", "Proxy name (becomes <name>.apiblaze.com)").option("--target <url>", "Target URL to forward requests to").option("--team <id|name>", "Team to create under (defaults to your active team)").option("--auth <type>", "Auth type: api_key | none | oauth", "api_key").option("-y, --yes", "Skip the confirmation prompt").option("--json", "Output machine-readable JSON (non-interactive)").action(async (opts) => {
908
+ try {
909
+ await runCreate(opts);
910
+ } catch (err) {
911
+ printError(err);
912
+ process.exit(1);
913
+ }
914
+ });
915
+ program.command("team").description("Switch the active team").argument("[team]", "Team name or id to switch to (omit to choose interactively)").action(async (team) => {
794
916
  try {
795
- await runCreate();
917
+ await runTeam(team);
796
918
  } catch (err) {
797
919
  printError(err);
798
920
  process.exit(1);
@@ -816,13 +938,13 @@ program.command("dev").description("Start a dev tunnel for your localhost projec
816
938
  });
817
939
  function printError(err) {
818
940
  if (err instanceof ApiError) {
819
- console.error(import_chalk6.default.red(`
941
+ console.error(import_chalk7.default.red(`
820
942
  API error (${err.status}): ${err.message}`));
821
943
  } else if (err instanceof Error) {
822
- console.error(import_chalk6.default.red(`
944
+ console.error(import_chalk7.default.red(`
823
945
  Error: ${err.message}`));
824
946
  } else {
825
- console.error(import_chalk6.default.red("\nUnknown error"));
947
+ console.error(import_chalk7.default.red("\nUnknown error"));
826
948
  }
827
949
  }
828
950
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Dev tunnel CLI for APIblaze — route localhost projects through Cloudflare tunnels",
5
5
  "keywords": [
6
6
  "apiblaze",