apiblaze 0.1.9 → 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 +151 -76
  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", {
@@ -677,7 +678,7 @@ function normalizeName(raw) {
677
678
  }
678
679
  function isHttpUrl(s) {
679
680
  try {
680
- const u = new URL(s.trim());
681
+ const u = new URL((s || "").trim());
681
682
  return u.protocol === "http:" || u.protocol === "https:";
682
683
  } catch {
683
684
  return false;
@@ -695,78 +696,144 @@ function stripTenantFromPortal(devPortal) {
695
696
  return devPortal;
696
697
  }
697
698
  }
698
- 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 = {}) {
699
705
  const creds = loadCredentials();
700
706
  if (!creds) {
701
- console.error(import_chalk5.default.red("Not logged in. Run `apiblaze login` first."));
702
- 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
+ }
703
728
  }
704
- console.log(import_chalk5.default.bold("\nCreate an API proxy\n"));
705
- const { default: inquirer2 } = await import("inquirer");
729
+ if (!opts.json) console.log(import_chalk5.default.bold("\nCreate an API proxy\n"));
706
730
  let name = "";
707
- for (; ; ) {
708
- const { rawName } = await inquirer2.prompt([{
709
- type: "input",
710
- name: "rawName",
711
- message: "Proxy name (your API will live at <name>.apiblaze.com):",
712
- transformer: (v) => normalizeName(v)
713
- }]);
714
- name = normalizeName(rawName);
715
- if (name.length < 3) {
716
- console.log(import_chalk5.default.yellow(" Name must be at least 3 characters (letters and digits only).\n"));
717
- 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}` : ""}.`);
718
737
  }
719
- const spinner2 = (0, import_ora5.default)("Checking availability...").start();
720
- try {
721
- const check = await checkProxyName(name);
722
- spinner2.stop();
723
- if (!check.canUseProjectName || !check.canUseApiVersion) {
724
- const why = check.message ? ` \u2014 ${check.message}` : "";
725
- console.log(import_chalk5.default.yellow(` "${name}" is not available${why}. Try another.
726
- `));
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"));
727
750
  continue;
728
751
  }
729
- } catch {
730
- spinner2.stop();
731
- console.log(import_chalk5.default.dim(" (could not verify availability; continuing)"));
732
- }
733
- 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`)}
734
766
  `);
735
- break;
767
+ break;
768
+ }
769
+ } else {
770
+ fail("--name is required in non-interactive mode.");
736
771
  }
737
772
  let targetUrl = "";
738
- for (; ; ) {
739
- const { url } = await inquirer2.prompt([{
740
- type: "input",
741
- name: "url",
742
- 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
743
802
  }]);
744
- if (!isHttpUrl(url)) {
745
- console.log(import_chalk5.default.yellow(" Enter a valid http(s) URL.\n"));
746
- continue;
803
+ if (!ok) {
804
+ console.log(import_chalk5.default.yellow("Cancelled."));
805
+ return;
747
806
  }
748
- targetUrl = url.trim();
749
- break;
750
807
  }
751
- console.log(`${import_chalk5.default.cyan("\u2192")} Auth: ${import_chalk5.default.bold("API key")} \u2014 consumers send an X-API-Key header
752
- `);
753
- 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;
754
809
  let result;
755
810
  try {
756
- result = await createProxy({ name, target_url: targetUrl, auth_type: "api_key" });
757
- 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!"));
758
813
  } catch (err) {
759
- spinner.fail("Failed to create proxy.");
814
+ spinner?.fail("Failed to create proxy.");
760
815
  throw err;
761
816
  }
762
817
  const version = result.api_version || "1.0.0";
763
818
  const keys = result.api_keys ?? {};
764
819
  const adminKey = keys.dev ?? Object.values(keys)[0];
765
- console.log();
766
- console.log(` ${import_chalk5.default.dim("Proxy URL: ")} ${import_chalk5.default.bold(`https://${name}.apiblaze.com/${version}/dev`)}`);
767
- if (result.devPortal) {
768
- 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;
769
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)}`);
770
837
  if (adminKey) {
771
838
  console.log();
772
839
  console.log(` ${import_chalk5.default.dim("Consumer admin API key (dev):")}`);
@@ -784,38 +851,46 @@ async function runCreate() {
784
851
  var import_chalk6 = __toESM(require("chalk"));
785
852
  init_auth();
786
853
  init_api();
787
- async function runTeam() {
854
+ function fail2(message) {
855
+ console.error(import_chalk6.default.red(`Error: ${message}`));
856
+ process.exit(1);
857
+ }
858
+ async function runTeam(arg) {
788
859
  const creds = loadCredentials();
789
860
  if (!creds) {
790
- console.error(import_chalk6.default.red("Not logged in. Run `apiblaze login` first."));
791
- process.exit(1);
861
+ fail2("Not logged in. Run `apiblaze login` first.");
792
862
  }
793
863
  const teams = await getTeams().catch(() => []);
794
864
  if (teams.length === 0) {
795
- console.log(import_chalk6.default.yellow("No teams found for your account."));
796
- return;
797
- }
798
- let teamId;
799
- let teamName;
800
- if (teams.length === 1) {
801
- teamId = teams[0].teamId;
802
- teamName = teams[0].name;
803
- console.log(`${import_chalk6.default.cyan("\u2192")} You only have one team: ${import_chalk6.default.bold(teamName)}`);
804
- } else {
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) {
805
879
  const { default: inquirer2 } = await import("inquirer");
806
- const { chosen } = await inquirer2.prompt([{
880
+ const { picked } = await inquirer2.prompt([{
807
881
  type: "list",
808
- name: "chosen",
882
+ name: "picked",
809
883
  message: "Switch to which team?",
810
884
  default: creds.teamId,
811
885
  choices: teams.map((t) => ({ name: t.name, value: t.teamId }))
812
886
  }]);
813
- teamId = chosen;
814
- teamName = teams.find((t) => t.teamId === chosen)?.name;
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(", ")}.`);
815
890
  }
816
- saveCredentials({ ...creds, teamId, teamName });
891
+ saveCredentials({ ...creds, teamId: chosen.teamId, teamName: chosen.name });
817
892
  console.log(import_chalk6.default.green(`
818
- \u2714 Active team: ${import_chalk6.default.bold(teamName ?? teamId)}`));
893
+ \u2714 Active team: ${import_chalk6.default.bold(chosen.name)}`));
819
894
  }
820
895
 
821
896
  // src/index.ts
@@ -829,17 +904,17 @@ program.command("login").description("Authenticate with APIblaze").action(async
829
904
  process.exit(1);
830
905
  }
831
906
  });
832
- 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) => {
833
908
  try {
834
- await runCreate();
909
+ await runCreate(opts);
835
910
  } catch (err) {
836
911
  printError(err);
837
912
  process.exit(1);
838
913
  }
839
914
  });
840
- program.command("team").description("Switch the active team").action(async () => {
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) => {
841
916
  try {
842
- await runTeam();
917
+ await runTeam(team);
843
918
  } catch (err) {
844
919
  printError(err);
845
920
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.1.9",
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",