apiblaze 0.1.4 → 0.1.5
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 +145 -88
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -89,12 +89,13 @@ var api_exports = {};
|
|
|
89
89
|
__export(api_exports, {
|
|
90
90
|
deleteDevTunnel: () => deleteDevTunnel,
|
|
91
91
|
getLocalhostTargets: () => getLocalhostTargets,
|
|
92
|
+
getProjects: () => getProjects,
|
|
92
93
|
getTeams: () => getTeams,
|
|
93
94
|
putDevTunnel: () => putDevTunnel
|
|
94
95
|
});
|
|
95
96
|
async function apiFetch(path3, options = {}) {
|
|
96
97
|
const token = getAccessToken();
|
|
97
|
-
const url = `${
|
|
98
|
+
const url = `${DASHBOARD_BASE}${path3}`;
|
|
98
99
|
const res = await fetch(url, {
|
|
99
100
|
...options,
|
|
100
101
|
headers: {
|
|
@@ -118,132 +119,116 @@ async function apiFetch(path3, options = {}) {
|
|
|
118
119
|
return res.json();
|
|
119
120
|
}
|
|
120
121
|
async function getTeams() {
|
|
121
|
-
return apiFetch("/
|
|
122
|
+
return apiFetch("/api/cli/teams");
|
|
122
123
|
}
|
|
123
124
|
async function getLocalhostTargets(teamId) {
|
|
124
|
-
return apiFetch(`/
|
|
125
|
+
return apiFetch(`/api/cli/localhost-targets?team_id=${encodeURIComponent(teamId)}`);
|
|
126
|
+
}
|
|
127
|
+
async function getProjects(teamId) {
|
|
128
|
+
return apiFetch(`/api/cli/projects?team_id=${encodeURIComponent(teamId)}`);
|
|
125
129
|
}
|
|
126
130
|
async function putDevTunnel(payload) {
|
|
127
|
-
return apiFetch("/dev-tunnel", {
|
|
131
|
+
return apiFetch("/api/cli/dev-tunnel", {
|
|
128
132
|
method: "PUT",
|
|
129
133
|
body: JSON.stringify(payload)
|
|
130
134
|
});
|
|
131
135
|
}
|
|
132
136
|
async function deleteDevTunnel() {
|
|
133
|
-
return apiFetch("/dev-tunnel", { method: "DELETE" });
|
|
137
|
+
return apiFetch("/api/cli/dev-tunnel", { method: "DELETE" });
|
|
134
138
|
}
|
|
135
|
-
var
|
|
139
|
+
var DASHBOARD_BASE;
|
|
136
140
|
var init_api = __esm({
|
|
137
141
|
"src/lib/api.ts"() {
|
|
138
142
|
"use strict";
|
|
139
143
|
init_auth();
|
|
140
144
|
init_types();
|
|
141
|
-
|
|
145
|
+
DASHBOARD_BASE = "https://dashboard.apiblaze.com";
|
|
142
146
|
}
|
|
143
147
|
});
|
|
144
148
|
|
|
145
149
|
// src/index.ts
|
|
146
150
|
var import_commander = require("commander");
|
|
147
|
-
var
|
|
151
|
+
var import_chalk5 = __toESM(require("chalk"));
|
|
148
152
|
init_types();
|
|
149
153
|
|
|
150
154
|
// src/commands/login.ts
|
|
151
155
|
var import_chalk = __toESM(require("chalk"));
|
|
152
156
|
var import_ora = __toESM(require("ora"));
|
|
153
|
-
var crypto = __toESM(require("crypto"));
|
|
154
157
|
init_auth();
|
|
155
158
|
init_api();
|
|
156
|
-
var
|
|
157
|
-
var CLIENT_ID = "emdE4-Pt9LGOAXL5MA1zEQ";
|
|
158
|
-
var SCOPE = "openid email profile offline_access";
|
|
159
|
-
function generateCodeVerifier() {
|
|
160
|
-
return crypto.randomBytes(32).toString("base64url");
|
|
161
|
-
}
|
|
162
|
-
function generateCodeChallenge(verifier) {
|
|
163
|
-
return crypto.createHash("sha256").update(verifier).digest("base64url");
|
|
164
|
-
}
|
|
159
|
+
var DASHBOARD_BASE2 = "https://dashboard.apiblaze.com";
|
|
165
160
|
function openBrowser(url) {
|
|
166
161
|
const { exec } = require("child_process");
|
|
167
162
|
const cmd = process.platform === "darwin" ? `open "${url}"` : process.platform === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
|
|
168
163
|
exec(cmd);
|
|
169
164
|
}
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
174
|
-
body: new URLSearchParams({
|
|
175
|
-
client_id: CLIENT_ID,
|
|
176
|
-
scope: SCOPE,
|
|
177
|
-
code_challenge: codeChallenge,
|
|
178
|
-
code_challenge_method: "S256"
|
|
179
|
-
})
|
|
180
|
-
});
|
|
181
|
-
if (!res.ok) {
|
|
182
|
-
const body = await res.text();
|
|
183
|
-
throw new Error(`Failed to start device flow: ${res.status} ${body}`);
|
|
184
|
-
}
|
|
185
|
-
return res.json();
|
|
165
|
+
function decodeJWTPayload(token) {
|
|
166
|
+
const part = token.split(".")[1];
|
|
167
|
+
return JSON.parse(Buffer.from(part, "base64url").toString());
|
|
186
168
|
}
|
|
187
|
-
async function
|
|
188
|
-
|
|
189
|
-
|
|
169
|
+
async function runLogin() {
|
|
170
|
+
console.log(import_chalk.default.bold("\nLogging in to APIblaze...\n"));
|
|
171
|
+
const codeRes = await fetch(`${DASHBOARD_BASE2}/api/device/code`, { method: "POST" });
|
|
172
|
+
if (!codeRes.ok) {
|
|
173
|
+
throw new Error(`Failed to start login: ${codeRes.status}`);
|
|
174
|
+
}
|
|
175
|
+
const deviceAuth = await codeRes.json();
|
|
176
|
+
console.log(`${import_chalk.default.cyan("\u2192")} Open this URL in your browser to confirm login:`);
|
|
177
|
+
console.log(` ${import_chalk.default.bold.underline(deviceAuth.verification_uri)}
|
|
178
|
+
`);
|
|
179
|
+
console.log(`${import_chalk.default.cyan("\u2192")} Your code: ${import_chalk.default.bold(deviceAuth.user_code)}
|
|
180
|
+
`);
|
|
181
|
+
openBrowser(deviceAuth.verification_uri_complete ?? deviceAuth.verification_uri);
|
|
182
|
+
const spinner = (0, import_ora.default)("Waiting for authorization in browser...").start();
|
|
183
|
+
let accessToken;
|
|
184
|
+
let pollInterval = (deviceAuth.interval ?? 5) * 1e3;
|
|
190
185
|
while (true) {
|
|
191
186
|
await new Promise((r) => setTimeout(r, pollInterval));
|
|
192
|
-
const
|
|
187
|
+
const tokenRes = await fetch(`${DASHBOARD_BASE2}/api/device/token`, {
|
|
193
188
|
method: "POST",
|
|
194
|
-
headers: { "Content-Type": "application/
|
|
195
|
-
body:
|
|
196
|
-
grant_type: DEVICE_GRANT,
|
|
197
|
-
device_code: deviceCode,
|
|
198
|
-
client_id: CLIENT_ID,
|
|
199
|
-
code_verifier: codeVerifier
|
|
200
|
-
})
|
|
189
|
+
headers: { "Content-Type": "application/json" },
|
|
190
|
+
body: JSON.stringify({ device_code: deviceAuth.device_code })
|
|
201
191
|
});
|
|
202
|
-
const body = await
|
|
203
|
-
if (
|
|
204
|
-
|
|
192
|
+
const body = await tokenRes.json();
|
|
193
|
+
if (body.access_token) {
|
|
194
|
+
accessToken = body.access_token;
|
|
195
|
+
break;
|
|
205
196
|
}
|
|
206
197
|
if (body.error === "authorization_pending") {
|
|
207
198
|
continue;
|
|
208
199
|
} else if (body.error === "slow_down") {
|
|
209
200
|
pollInterval += 5e3;
|
|
210
201
|
} else if (body.error === "expired_token") {
|
|
202
|
+
spinner.fail("Login failed.");
|
|
211
203
|
throw new Error("Device code expired. Run `apiblaze login` again.");
|
|
212
204
|
} else if (body.error === "access_denied") {
|
|
205
|
+
spinner.fail("Login failed.");
|
|
213
206
|
throw new Error("Login was denied or cancelled.");
|
|
214
207
|
} else {
|
|
208
|
+
spinner.fail("Login failed.");
|
|
215
209
|
throw new Error(`Unexpected error during login: ${body.error ?? "unknown"}`);
|
|
216
210
|
}
|
|
217
211
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
const verifyUrl = deviceAuth.verification_uri_complete ?? deviceAuth.verification_uri;
|
|
225
|
-
console.log(`${import_chalk.default.cyan("\u2192")} Open this URL in your browser to confirm login:`);
|
|
226
|
-
console.log(` ${import_chalk.default.bold.underline(verifyUrl)}
|
|
227
|
-
`);
|
|
228
|
-
console.log(`${import_chalk.default.cyan("\u2192")} Your code: ${import_chalk.default.bold(deviceAuth.user_code)}
|
|
229
|
-
`);
|
|
230
|
-
openBrowser(verifyUrl);
|
|
231
|
-
const spinner = (0, import_ora.default)("Waiting for authorization in browser...").start();
|
|
232
|
-
let token;
|
|
233
|
-
try {
|
|
234
|
-
token = await pollForToken(deviceAuth.device_code, codeVerifier, deviceAuth.interval);
|
|
235
|
-
} catch (err) {
|
|
236
|
-
spinner.fail("Login failed.");
|
|
237
|
-
throw err;
|
|
238
|
-
}
|
|
212
|
+
const jwtPayload = decodeJWTPayload(accessToken);
|
|
213
|
+
const expiresAt = jwtPayload.exp * 1e3;
|
|
214
|
+
const apiblazeUserId = jwtPayload.sub;
|
|
215
|
+
const githubHandle = jwtPayload.handle;
|
|
216
|
+
const email = jwtPayload.email;
|
|
217
|
+
const defaultTeamId = jwtPayload.defaultTeamId;
|
|
239
218
|
saveCredentials({
|
|
240
|
-
accessToken
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
219
|
+
accessToken,
|
|
220
|
+
expiresAt,
|
|
221
|
+
tokenType: "Bearer",
|
|
222
|
+
apiblazeUserId,
|
|
223
|
+
githubHandle,
|
|
224
|
+
email,
|
|
225
|
+
teamId: defaultTeamId ?? void 0
|
|
244
226
|
});
|
|
245
227
|
spinner.succeed(import_chalk.default.green("Authorized!"));
|
|
246
|
-
|
|
228
|
+
if (githubHandle) {
|
|
229
|
+
console.log(`${import_chalk.default.cyan("\u2192")} Logged in as ${import_chalk.default.bold("@" + githubHandle)}${apiblazeUserId ? import_chalk.default.dim(` (${apiblazeUserId})`) : ""}`);
|
|
230
|
+
}
|
|
231
|
+
let teamId = defaultTeamId ?? void 0;
|
|
247
232
|
let teamName;
|
|
248
233
|
try {
|
|
249
234
|
const teams = await getTeams();
|
|
@@ -253,7 +238,7 @@ async function runLogin() {
|
|
|
253
238
|
teamId = teams[0].teamId;
|
|
254
239
|
teamName = teams[0].name;
|
|
255
240
|
console.log(`
|
|
256
|
-
${import_chalk.default.cyan("\u2192")}
|
|
241
|
+
${import_chalk.default.cyan("\u2192")} Team: ${import_chalk.default.bold(teamName)}`);
|
|
257
242
|
} else {
|
|
258
243
|
const { default: inquirer2 } = await import("inquirer");
|
|
259
244
|
const { chosen } = await inquirer2.prompt([{
|
|
@@ -267,16 +252,16 @@ ${import_chalk.default.cyan("\u2192")} Using team: ${import_chalk.default.bold(t
|
|
|
267
252
|
}
|
|
268
253
|
} catch {
|
|
269
254
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
255
|
+
saveCredentials({
|
|
256
|
+
accessToken,
|
|
257
|
+
expiresAt,
|
|
258
|
+
tokenType: "Bearer",
|
|
259
|
+
apiblazeUserId,
|
|
260
|
+
githubHandle,
|
|
261
|
+
email,
|
|
262
|
+
teamId,
|
|
263
|
+
teamName
|
|
264
|
+
});
|
|
280
265
|
console.log(import_chalk.default.green("\n\u2714 Logged in successfully!"));
|
|
281
266
|
}
|
|
282
267
|
|
|
@@ -605,6 +590,70 @@ Tunneling ${selectedTargets.length} project(s) to localhost:${options.port}
|
|
|
605
590
|
}
|
|
606
591
|
}
|
|
607
592
|
|
|
593
|
+
// src/commands/projects.ts
|
|
594
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
595
|
+
var import_ora4 = __toESM(require("ora"));
|
|
596
|
+
init_auth();
|
|
597
|
+
init_api();
|
|
598
|
+
async function runProjects() {
|
|
599
|
+
const creds = loadCredentials();
|
|
600
|
+
if (!creds) {
|
|
601
|
+
console.error(import_chalk4.default.red("Not logged in. Run `apiblaze login` first."));
|
|
602
|
+
process.exit(1);
|
|
603
|
+
}
|
|
604
|
+
if (creds.githubHandle) {
|
|
605
|
+
console.log(
|
|
606
|
+
`${import_chalk4.default.cyan("\u2192")} Logged in as ${import_chalk4.default.bold("@" + creds.githubHandle)}` + (creds.apiblazeUserId ? import_chalk4.default.dim(` (${creds.apiblazeUserId})`) : "")
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
let teamId;
|
|
610
|
+
let teamName;
|
|
611
|
+
const teams = await getTeams().catch(() => []);
|
|
612
|
+
if (teams.length === 0) {
|
|
613
|
+
teamId = creds.teamId;
|
|
614
|
+
teamName = creds.teamName;
|
|
615
|
+
} else if (teams.length === 1) {
|
|
616
|
+
teamId = teams[0].teamId;
|
|
617
|
+
teamName = teams[0].name;
|
|
618
|
+
} else {
|
|
619
|
+
const { default: inquirer2 } = await import("inquirer");
|
|
620
|
+
const { chosen } = await inquirer2.prompt([{
|
|
621
|
+
type: "list",
|
|
622
|
+
name: "chosen",
|
|
623
|
+
message: "Which team?",
|
|
624
|
+
default: creds.teamId,
|
|
625
|
+
choices: teams.map((t) => ({ name: t.name, value: t.teamId }))
|
|
626
|
+
}]);
|
|
627
|
+
teamId = chosen;
|
|
628
|
+
teamName = teams.find((t) => t.teamId === chosen)?.name;
|
|
629
|
+
}
|
|
630
|
+
if (!teamId) {
|
|
631
|
+
console.error(import_chalk4.default.red("No team found. Run `apiblaze login` to set up your team."));
|
|
632
|
+
process.exit(1);
|
|
633
|
+
}
|
|
634
|
+
console.log(`${import_chalk4.default.cyan("\u2192")} Team: ${import_chalk4.default.bold(teamName ?? teamId)} ${import_chalk4.default.dim(teamId)}
|
|
635
|
+
`);
|
|
636
|
+
const spinner = (0, import_ora4.default)("Fetching projects...").start();
|
|
637
|
+
let projects;
|
|
638
|
+
try {
|
|
639
|
+
projects = await getProjects(teamId);
|
|
640
|
+
spinner.stop();
|
|
641
|
+
} catch (err) {
|
|
642
|
+
spinner.fail("Failed to fetch projects.");
|
|
643
|
+
throw err;
|
|
644
|
+
}
|
|
645
|
+
if (projects.length === 0) {
|
|
646
|
+
console.log(import_chalk4.default.yellow("No projects found for this team."));
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
for (const p of projects) {
|
|
650
|
+
console.log(`${import_chalk4.default.bold(p.projectName)} ${import_chalk4.default.dim(p.projectId)}`);
|
|
651
|
+
console.log(` ${import_chalk4.default.dim("version:")} ${p.apiVersion} ${import_chalk4.default.dim("team:")} ${p.teamId}`);
|
|
652
|
+
}
|
|
653
|
+
console.log(import_chalk4.default.dim(`
|
|
654
|
+
${projects.length} project(s).`));
|
|
655
|
+
}
|
|
656
|
+
|
|
608
657
|
// src/index.ts
|
|
609
658
|
var program = new import_commander.Command();
|
|
610
659
|
program.name("apiblaze").description("APIblaze dev tunnel CLI").version("0.1.0");
|
|
@@ -616,6 +665,14 @@ program.command("login").description("Authenticate with APIblaze").action(async
|
|
|
616
665
|
process.exit(1);
|
|
617
666
|
}
|
|
618
667
|
});
|
|
668
|
+
program.command("projects").description("List the projects in your team").action(async () => {
|
|
669
|
+
try {
|
|
670
|
+
await runProjects();
|
|
671
|
+
} catch (err) {
|
|
672
|
+
printError(err);
|
|
673
|
+
process.exit(1);
|
|
674
|
+
}
|
|
675
|
+
});
|
|
619
676
|
program.command("dev").description("Start a dev tunnel for your localhost projects").option("-p, --port <number>", "Local port to tunnel", "3000").action(async (opts) => {
|
|
620
677
|
try {
|
|
621
678
|
await runDev({ port: parseInt(opts.port, 10) });
|
|
@@ -626,13 +683,13 @@ program.command("dev").description("Start a dev tunnel for your localhost projec
|
|
|
626
683
|
});
|
|
627
684
|
function printError(err) {
|
|
628
685
|
if (err instanceof ApiError) {
|
|
629
|
-
console.error(
|
|
686
|
+
console.error(import_chalk5.default.red(`
|
|
630
687
|
API error (${err.status}): ${err.message}`));
|
|
631
688
|
} else if (err instanceof Error) {
|
|
632
|
-
console.error(
|
|
689
|
+
console.error(import_chalk5.default.red(`
|
|
633
690
|
Error: ${err.message}`));
|
|
634
691
|
} else {
|
|
635
|
-
console.error(
|
|
692
|
+
console.error(import_chalk5.default.red("\nUnknown error"));
|
|
636
693
|
}
|
|
637
694
|
}
|
|
638
695
|
program.parse(process.argv);
|