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.
- package/dist/index.js +183 -61
- 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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
701
|
-
|
|
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
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
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
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
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
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
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
|
-
|
|
767
|
+
break;
|
|
768
|
+
}
|
|
769
|
+
} else {
|
|
770
|
+
fail("--name is required in non-interactive mode.");
|
|
735
771
|
}
|
|
736
772
|
let targetUrl = "";
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
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 (!
|
|
744
|
-
console.log(import_chalk5.default.yellow("
|
|
745
|
-
|
|
803
|
+
if (!ok) {
|
|
804
|
+
console.log(import_chalk5.default.yellow("Cancelled."));
|
|
805
|
+
return;
|
|
746
806
|
}
|
|
747
|
-
targetUrl = url.trim();
|
|
748
|
-
break;
|
|
749
807
|
}
|
|
750
|
-
|
|
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:
|
|
756
|
-
spinner
|
|
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
|
|
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
|
-
|
|
765
|
-
|
|
766
|
-
if (
|
|
767
|
-
|
|
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
|
|
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(
|
|
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(
|
|
944
|
+
console.error(import_chalk7.default.red(`
|
|
823
945
|
Error: ${err.message}`));
|
|
824
946
|
} else {
|
|
825
|
-
console.error(
|
|
947
|
+
console.error(import_chalk7.default.red("\nUnknown error"));
|
|
826
948
|
}
|
|
827
949
|
}
|
|
828
950
|
program.parse(process.argv);
|