apiblaze 0.1.12 → 0.1.16
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 +164 -199
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -69,9 +69,6 @@ function getAccessToken() {
|
|
|
69
69
|
}
|
|
70
70
|
return creds.accessToken;
|
|
71
71
|
}
|
|
72
|
-
function getApiblazeDir() {
|
|
73
|
-
return APIBLAZE_DIR;
|
|
74
|
-
}
|
|
75
72
|
var fs, os, path, APIBLAZE_DIR, CREDENTIALS_PATH;
|
|
76
73
|
var init_auth = __esm({
|
|
77
74
|
"src/lib/auth.ts"() {
|
|
@@ -95,9 +92,9 @@ __export(api_exports, {
|
|
|
95
92
|
getTeams: () => getTeams,
|
|
96
93
|
putDevTunnel: () => putDevTunnel
|
|
97
94
|
});
|
|
98
|
-
async function apiFetch(
|
|
95
|
+
async function apiFetch(path2, options = {}) {
|
|
99
96
|
const token = getAccessToken();
|
|
100
|
-
const url = `${DASHBOARD_BASE}${
|
|
97
|
+
const url = `${DASHBOARD_BASE}${path2}`;
|
|
101
98
|
const res = await fetch(url, {
|
|
102
99
|
...options,
|
|
103
100
|
headers: {
|
|
@@ -169,6 +166,11 @@ var init_api = __esm({
|
|
|
169
166
|
// src/index.ts
|
|
170
167
|
var import_commander = require("commander");
|
|
171
168
|
var import_chalk7 = __toESM(require("chalk"));
|
|
169
|
+
|
|
170
|
+
// package.json
|
|
171
|
+
var version = "0.1.16";
|
|
172
|
+
|
|
173
|
+
// src/index.ts
|
|
172
174
|
init_types();
|
|
173
175
|
|
|
174
176
|
// src/commands/login.ts
|
|
@@ -288,125 +290,11 @@ ${import_chalk.default.cyan("\u2192")} Team: ${import_chalk.default.bold(teamNam
|
|
|
288
290
|
|
|
289
291
|
// src/commands/dev.ts
|
|
290
292
|
var import_chalk3 = __toESM(require("chalk"));
|
|
291
|
-
var
|
|
293
|
+
var import_ora2 = __toESM(require("ora"));
|
|
292
294
|
var import_inquirer = __toESM(require("inquirer"));
|
|
293
295
|
init_auth();
|
|
294
296
|
init_api();
|
|
295
297
|
|
|
296
|
-
// src/lib/cloudflared.ts
|
|
297
|
-
var fs2 = __toESM(require("fs"));
|
|
298
|
-
var path2 = __toESM(require("path"));
|
|
299
|
-
var readline = __toESM(require("readline"));
|
|
300
|
-
var import_child_process = require("child_process");
|
|
301
|
-
var import_ora2 = __toESM(require("ora"));
|
|
302
|
-
init_auth();
|
|
303
|
-
var TUNNEL_URL_RE = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/;
|
|
304
|
-
var DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
305
|
-
var TUNNEL_START_TIMEOUT_MS = 3e4;
|
|
306
|
-
function getCloudflaredFilename() {
|
|
307
|
-
const platform = process.platform;
|
|
308
|
-
const arch = process.arch;
|
|
309
|
-
if (platform === "darwin" && arch === "arm64") return "cloudflared-darwin-arm64";
|
|
310
|
-
if (platform === "darwin" && arch === "x64") return "cloudflared-darwin-amd64";
|
|
311
|
-
if (platform === "linux" && arch === "arm64") return "cloudflared-linux-arm64";
|
|
312
|
-
if (platform === "linux" && arch === "x64") return "cloudflared-linux-amd64";
|
|
313
|
-
if (platform === "win32" && arch === "x64") return "cloudflared-windows-amd64.exe";
|
|
314
|
-
throw new Error(`Unsupported platform: ${platform} ${arch}`);
|
|
315
|
-
}
|
|
316
|
-
function getCloudflaredBinPath() {
|
|
317
|
-
const filename = process.platform === "win32" ? "cloudflared.exe" : "cloudflared";
|
|
318
|
-
return path2.join(getApiblazeDir(), "bin", filename);
|
|
319
|
-
}
|
|
320
|
-
function isExecutable(filePath) {
|
|
321
|
-
try {
|
|
322
|
-
fs2.accessSync(filePath, fs2.constants.X_OK);
|
|
323
|
-
return true;
|
|
324
|
-
} catch {
|
|
325
|
-
return false;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
async function downloadCloudflared(binPath) {
|
|
329
|
-
const filename = getCloudflaredFilename();
|
|
330
|
-
const url = `https://github.com/cloudflare/cloudflared/releases/latest/download/${filename}`;
|
|
331
|
-
const res = await fetch(url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS) });
|
|
332
|
-
if (!res.ok || !res.body) {
|
|
333
|
-
throw new Error(`Failed to download cloudflared: ${res.status} ${res.statusText}`);
|
|
334
|
-
}
|
|
335
|
-
fs2.mkdirSync(path2.dirname(binPath), { recursive: true });
|
|
336
|
-
const tmpPath = `${binPath}.tmp`;
|
|
337
|
-
const writer = fs2.createWriteStream(tmpPath);
|
|
338
|
-
const reader = res.body.getReader();
|
|
339
|
-
try {
|
|
340
|
-
while (true) {
|
|
341
|
-
const { done, value } = await reader.read();
|
|
342
|
-
if (done) break;
|
|
343
|
-
await new Promise((resolve, reject) => {
|
|
344
|
-
writer.write(value, (err) => err ? reject(err) : resolve());
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
} finally {
|
|
348
|
-
reader.releaseLock();
|
|
349
|
-
}
|
|
350
|
-
await new Promise((resolve, reject) => {
|
|
351
|
-
writer.end((err) => err ? reject(err) : resolve());
|
|
352
|
-
});
|
|
353
|
-
fs2.renameSync(tmpPath, binPath);
|
|
354
|
-
if (process.platform !== "win32") {
|
|
355
|
-
fs2.chmodSync(binPath, 493);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
async function ensureCloudflared() {
|
|
359
|
-
const binPath = getCloudflaredBinPath();
|
|
360
|
-
if (fs2.existsSync(binPath) && isExecutable(binPath)) {
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
const spinner = (0, import_ora2.default)("Downloading cloudflared...").start();
|
|
364
|
-
try {
|
|
365
|
-
await downloadCloudflared(binPath);
|
|
366
|
-
spinner.succeed("cloudflared downloaded.");
|
|
367
|
-
} catch (err) {
|
|
368
|
-
spinner.fail("Failed to download cloudflared.");
|
|
369
|
-
throw err;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
function spawnCloudflared(port) {
|
|
373
|
-
return new Promise((resolve, reject) => {
|
|
374
|
-
const binPath = getCloudflaredBinPath();
|
|
375
|
-
const proc = (0, import_child_process.spawn)(binPath, ["tunnel", "--url", `http://localhost:${port}`], {
|
|
376
|
-
stdio: ["ignore", "ignore", "pipe"]
|
|
377
|
-
});
|
|
378
|
-
const timer = setTimeout(() => {
|
|
379
|
-
proc.kill();
|
|
380
|
-
reject(new Error("Timed out waiting for cloudflared tunnel URL (30s). Is something already running on the port?"));
|
|
381
|
-
}, TUNNEL_START_TIMEOUT_MS);
|
|
382
|
-
const rl = readline.createInterface({ input: proc.stderr });
|
|
383
|
-
rl.on("line", (line) => {
|
|
384
|
-
const match = line.match(TUNNEL_URL_RE);
|
|
385
|
-
if (match) {
|
|
386
|
-
clearTimeout(timer);
|
|
387
|
-
rl.close();
|
|
388
|
-
resolve({ process: proc, tunnelUrl: match[0] });
|
|
389
|
-
}
|
|
390
|
-
});
|
|
391
|
-
proc.on("error", (err) => {
|
|
392
|
-
clearTimeout(timer);
|
|
393
|
-
reject(new Error(`Failed to start cloudflared: ${err.message}`));
|
|
394
|
-
});
|
|
395
|
-
proc.on("exit", (code) => {
|
|
396
|
-
clearTimeout(timer);
|
|
397
|
-
if (code !== null && code !== 0) {
|
|
398
|
-
reject(new Error(`cloudflared exited with code ${code}`));
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
function killCloudflared(proc) {
|
|
404
|
-
try {
|
|
405
|
-
proc.kill("SIGTERM");
|
|
406
|
-
} catch {
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
298
|
// src/lib/traffic.ts
|
|
411
299
|
var import_chalk2 = __toESM(require("chalk"));
|
|
412
300
|
var METHOD_COLORS = {
|
|
@@ -441,50 +329,136 @@ function formatLogLine(entry) {
|
|
|
441
329
|
return `${import_chalk2.default.gray(`[${ts}]`)} ${colorMethod(entry.method)} ${import_chalk2.default.white(entry.path)} ${import_chalk2.default.gray("\u2192")} ${colorStatus(entry.status)} ${import_chalk2.default.gray(`(${colorLatency(entry.latency)})`)}`;
|
|
442
330
|
}
|
|
443
331
|
|
|
444
|
-
// src/lib/
|
|
445
|
-
var
|
|
446
|
-
var
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
332
|
+
// src/lib/tunnel-client.ts
|
|
333
|
+
var import_ws = __toESM(require("ws"));
|
|
334
|
+
var CHUNK_BYTES = 512 * 1024;
|
|
335
|
+
var PING_INTERVAL_MS = 6e4;
|
|
336
|
+
var MAX_RECONNECT_DELAY_MS = 15e3;
|
|
337
|
+
var STRIP_HEADERS = /* @__PURE__ */ new Set([
|
|
338
|
+
"host",
|
|
339
|
+
"content-length",
|
|
340
|
+
"connection",
|
|
341
|
+
"keep-alive",
|
|
342
|
+
"transfer-encoding",
|
|
343
|
+
"upgrade",
|
|
344
|
+
"proxy-connection",
|
|
345
|
+
"expect"
|
|
346
|
+
]);
|
|
347
|
+
function stripHeaders(headers) {
|
|
348
|
+
const out = {};
|
|
349
|
+
for (const key of Object.keys(headers)) {
|
|
350
|
+
if (!STRIP_HEADERS.has(key.toLowerCase())) out[key] = headers[key];
|
|
351
|
+
}
|
|
352
|
+
return out;
|
|
353
|
+
}
|
|
354
|
+
function startTunnelClient(opts) {
|
|
355
|
+
const target = `http://127.0.0.1:${opts.localPort}`;
|
|
356
|
+
const inflight = /* @__PURE__ */ new Map();
|
|
357
|
+
let ws = null;
|
|
358
|
+
let closed = false;
|
|
359
|
+
let reconnects = 0;
|
|
360
|
+
let pingTimer;
|
|
361
|
+
function connect() {
|
|
362
|
+
const url = `${opts.connectUrl}?project=${encodeURIComponent(opts.projectId)}&token=${encodeURIComponent(opts.token)}`;
|
|
363
|
+
const socket = new import_ws.default(url);
|
|
364
|
+
ws = socket;
|
|
365
|
+
socket.on("open", () => {
|
|
366
|
+
reconnects = 0;
|
|
367
|
+
opts.onStatus?.("connected");
|
|
368
|
+
pingTimer = setInterval(() => {
|
|
369
|
+
try {
|
|
370
|
+
socket.send("ping");
|
|
371
|
+
} catch {
|
|
459
372
|
}
|
|
460
|
-
);
|
|
461
|
-
proxyReq.on("error", () => {
|
|
462
|
-
onEntry({ method, path: path3, status: 502, latency: Date.now() - start });
|
|
463
|
-
if (!res.headersSent) res.writeHead(502);
|
|
464
|
-
res.end();
|
|
465
|
-
});
|
|
466
|
-
req.pipe(proxyReq);
|
|
373
|
+
}, PING_INTERVAL_MS);
|
|
467
374
|
});
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
${headerLines}\r
|
|
473
|
-
\r
|
|
474
|
-
`);
|
|
475
|
-
if (head && head.length) upstream.write(head);
|
|
476
|
-
upstream.pipe(clientSocket);
|
|
477
|
-
clientSocket.pipe(upstream);
|
|
478
|
-
});
|
|
479
|
-
upstream.on("error", () => clientSocket.destroy());
|
|
480
|
-
clientSocket.on("error", () => upstream.destroy());
|
|
375
|
+
socket.on("message", (data) => handleFrame(socket, data.toString()));
|
|
376
|
+
socket.on("close", () => {
|
|
377
|
+
if (pingTimer) clearInterval(pingTimer);
|
|
378
|
+
if (!closed) scheduleReconnect();
|
|
481
379
|
});
|
|
482
|
-
|
|
483
|
-
server.listen(0, "127.0.0.1", () => {
|
|
484
|
-
const { port } = server.address();
|
|
485
|
-
resolve({ port, close: () => server.close() });
|
|
380
|
+
socket.on("error", () => {
|
|
486
381
|
});
|
|
487
|
-
}
|
|
382
|
+
}
|
|
383
|
+
function scheduleReconnect() {
|
|
384
|
+
const delay = Math.min(1e3 * 2 ** reconnects, MAX_RECONNECT_DELAY_MS);
|
|
385
|
+
reconnects++;
|
|
386
|
+
opts.onStatus?.(`disconnected \u2014 reconnecting in ${Math.round(delay / 1e3)}s`);
|
|
387
|
+
setTimeout(() => {
|
|
388
|
+
if (!closed) connect();
|
|
389
|
+
}, delay);
|
|
390
|
+
}
|
|
391
|
+
function handleFrame(socket, raw) {
|
|
392
|
+
let frame;
|
|
393
|
+
try {
|
|
394
|
+
frame = JSON.parse(raw);
|
|
395
|
+
} catch {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (frame.type === "req") {
|
|
399
|
+
inflight.set(frame.id, {
|
|
400
|
+
method: frame.method,
|
|
401
|
+
path: frame.path,
|
|
402
|
+
headers: frame.headers ?? {},
|
|
403
|
+
chunks: [],
|
|
404
|
+
start: Date.now()
|
|
405
|
+
});
|
|
406
|
+
if (frame.bodyLen === 0) finish(socket, frame.id);
|
|
407
|
+
} else if (frame.type === "chunk") {
|
|
408
|
+
const f = inflight.get(frame.id);
|
|
409
|
+
if (!f) return;
|
|
410
|
+
f.chunks.push(Buffer.from(frame.data ?? "", "base64"));
|
|
411
|
+
if (frame.final) finish(socket, frame.id);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
function finish(socket, id) {
|
|
415
|
+
const f = inflight.get(id);
|
|
416
|
+
if (!f) return;
|
|
417
|
+
inflight.delete(id);
|
|
418
|
+
void forward(socket, id, f);
|
|
419
|
+
}
|
|
420
|
+
async function forward(socket, id, f) {
|
|
421
|
+
const body = Buffer.concat(f.chunks);
|
|
422
|
+
const init = { method: f.method, headers: stripHeaders(f.headers) };
|
|
423
|
+
if (body.length) init.body = body;
|
|
424
|
+
let status = 502;
|
|
425
|
+
try {
|
|
426
|
+
const resp = await fetch(target + f.path, init);
|
|
427
|
+
status = resp.status;
|
|
428
|
+
const buf = Buffer.from(await resp.arrayBuffer());
|
|
429
|
+
const headers = {};
|
|
430
|
+
resp.headers.forEach((value, key) => {
|
|
431
|
+
if (!STRIP_HEADERS.has(key.toLowerCase())) headers[key] = value;
|
|
432
|
+
});
|
|
433
|
+
send(socket, { id, type: "res", status, headers, bodyLen: buf.length });
|
|
434
|
+
for (let off = 0, seq = 0; off < buf.length; off += CHUNK_BYTES) {
|
|
435
|
+
const slice = buf.subarray(off, Math.min(off + CHUNK_BYTES, buf.length));
|
|
436
|
+
send(socket, { id, type: "chunk", seq: seq++, data: slice.toString("base64"), final: off + CHUNK_BYTES >= buf.length });
|
|
437
|
+
}
|
|
438
|
+
} catch (err) {
|
|
439
|
+
const code = err?.cause?.code;
|
|
440
|
+
const message = code === "ECONNREFUSED" || code === "ECONNRESET" || code === "ENOTFOUND" || code === "EHOSTUNREACH" ? `No local server reachable at ${target} \u2014 is your dev server running on port ${opts.localPort}?` : err?.cause?.message || err?.message || String(err);
|
|
441
|
+
send(socket, { id, type: "err", message });
|
|
442
|
+
}
|
|
443
|
+
opts.onEntry({ method: f.method, path: f.path, status, latency: Date.now() - f.start });
|
|
444
|
+
}
|
|
445
|
+
function send(socket, frame) {
|
|
446
|
+
try {
|
|
447
|
+
socket.send(JSON.stringify(frame));
|
|
448
|
+
} catch {
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
connect();
|
|
452
|
+
return {
|
|
453
|
+
close() {
|
|
454
|
+
closed = true;
|
|
455
|
+
if (pingTimer) clearInterval(pingTimer);
|
|
456
|
+
try {
|
|
457
|
+
ws?.close();
|
|
458
|
+
} catch {
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
};
|
|
488
462
|
}
|
|
489
463
|
|
|
490
464
|
// src/commands/dev.ts
|
|
@@ -519,7 +493,7 @@ async function runDev(options) {
|
|
|
519
493
|
}
|
|
520
494
|
let targets;
|
|
521
495
|
{
|
|
522
|
-
const spinner = (0,
|
|
496
|
+
const spinner = (0, import_ora2.default)("Fetching your localhost projects...").start();
|
|
523
497
|
try {
|
|
524
498
|
targets = await getLocalhostTargets(teamId);
|
|
525
499
|
spinner.stop();
|
|
@@ -529,8 +503,8 @@ async function runDev(options) {
|
|
|
529
503
|
}
|
|
530
504
|
}
|
|
531
505
|
if (targets.length === 0) {
|
|
532
|
-
console.log(import_chalk3.default.yellow("No projects found with
|
|
533
|
-
console.log("Set a project's upstream target to localhost in your APIblaze dashboard, then try again.");
|
|
506
|
+
console.log(import_chalk3.default.yellow("No projects found with an internal target."));
|
|
507
|
+
console.log("Set a project's upstream target to localhost or a private IP in your APIblaze dashboard, then try again.");
|
|
534
508
|
process.exit(0);
|
|
535
509
|
}
|
|
536
510
|
let selectedTargets;
|
|
@@ -538,7 +512,7 @@ async function runDev(options) {
|
|
|
538
512
|
const { confirmed } = await import_inquirer.default.prompt([{
|
|
539
513
|
type: "confirm",
|
|
540
514
|
name: "confirmed",
|
|
541
|
-
message: `Found 1 project
|
|
515
|
+
message: `Found 1 project with an internal target \u2014 tunnel "${import_chalk3.default.bold(targets[0].projectName)}" (${targets[0].tenantName})?`,
|
|
542
516
|
default: true
|
|
543
517
|
}]);
|
|
544
518
|
if (!confirmed) {
|
|
@@ -550,11 +524,11 @@ async function runDev(options) {
|
|
|
550
524
|
const { chosen } = await import_inquirer.default.prompt([{
|
|
551
525
|
type: "checkbox",
|
|
552
526
|
name: "chosen",
|
|
553
|
-
message: `Found ${targets.length} projects
|
|
527
|
+
message: `Found ${targets.length} projects with an internal target \u2014 pick which to tunnel (space to select, a for all):`,
|
|
554
528
|
choices: targets.map((t) => ({
|
|
555
529
|
name: `${import_chalk3.default.bold(t.projectName)} (${t.tenantName}) \u2014 ${t.target}`,
|
|
556
530
|
value: t,
|
|
557
|
-
checked:
|
|
531
|
+
checked: false
|
|
558
532
|
}))
|
|
559
533
|
}]);
|
|
560
534
|
if (chosen.length === 0) {
|
|
@@ -568,40 +542,32 @@ async function runDev(options) {
|
|
|
568
542
|
Tunneling ${selectedTargets.length} project(s) to localhost:${options.port}
|
|
569
543
|
`)
|
|
570
544
|
);
|
|
571
|
-
await ensureCloudflared();
|
|
572
|
-
const logger = await startPassthroughProxy(options.port, (entry) => {
|
|
573
|
-
console.log(formatLogLine(entry));
|
|
574
|
-
});
|
|
575
|
-
let cfProcess;
|
|
576
|
-
let tunnelUrl;
|
|
577
|
-
{
|
|
578
|
-
const spinner = (0, import_ora3.default)("Starting Cloudflare tunnel...").start();
|
|
579
|
-
try {
|
|
580
|
-
({ process: cfProcess, tunnelUrl } = await spawnCloudflared(logger.port));
|
|
581
|
-
spinner.succeed(`Tunnel active: ${import_chalk3.default.bold.cyan(tunnelUrl)}`);
|
|
582
|
-
} catch (err) {
|
|
583
|
-
spinner.fail("Failed to start cloudflared tunnel.");
|
|
584
|
-
logger.close();
|
|
585
|
-
throw err;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
545
|
let restore = [];
|
|
546
|
+
let connect;
|
|
589
547
|
{
|
|
590
|
-
const spinner = (0,
|
|
548
|
+
const spinner = (0, import_ora2.default)("Registering tunnel with APIblaze...").start();
|
|
591
549
|
try {
|
|
592
550
|
const result = await putDevTunnel({
|
|
593
|
-
tunnelUrl,
|
|
594
551
|
targets: selectedTargets.map((t) => ({ projectId: t.projectId, tenantId: t.tenantId }))
|
|
595
552
|
});
|
|
596
553
|
restore = result.restore ?? [];
|
|
597
|
-
|
|
554
|
+
connect = result.connect;
|
|
555
|
+
spinner.succeed("Tunnel registered.");
|
|
598
556
|
} catch (err) {
|
|
599
557
|
spinner.fail("Failed to register tunnel.");
|
|
600
|
-
logger.close();
|
|
601
|
-
killCloudflared(cfProcess);
|
|
602
558
|
throw err;
|
|
603
559
|
}
|
|
604
560
|
}
|
|
561
|
+
const clients = connect.projects.map(
|
|
562
|
+
(projectId) => startTunnelClient({
|
|
563
|
+
connectUrl: connect.url,
|
|
564
|
+
token: connect.token,
|
|
565
|
+
projectId,
|
|
566
|
+
localPort: options.port,
|
|
567
|
+
onEntry: (entry) => console.log(formatLogLine(entry)),
|
|
568
|
+
onStatus: (status) => console.log(import_chalk3.default.gray(`[${projectId}] ${status}`))
|
|
569
|
+
})
|
|
570
|
+
);
|
|
605
571
|
console.log("\n" + import_chalk3.default.gray("\u2500".repeat(60)));
|
|
606
572
|
console.log(import_chalk3.default.bold("Live traffic") + import_chalk3.default.gray(" (Ctrl+C to stop)"));
|
|
607
573
|
console.log(import_chalk3.default.gray("\u2500".repeat(60)) + "\n");
|
|
@@ -610,10 +576,9 @@ Tunneling ${selectedTargets.length} project(s) to localhost:${options.port}
|
|
|
610
576
|
if (isCleaningUp) return;
|
|
611
577
|
isCleaningUp = true;
|
|
612
578
|
console.log(import_chalk3.default.gray("\n\nShutting down..."));
|
|
579
|
+
for (const client of clients) client.close();
|
|
613
580
|
await deleteDevTunnel(restore).catch(() => {
|
|
614
581
|
});
|
|
615
|
-
logger.close();
|
|
616
|
-
killCloudflared(cfProcess);
|
|
617
582
|
console.log(import_chalk3.default.green("Tunnel stopped."));
|
|
618
583
|
process.exit(0);
|
|
619
584
|
}
|
|
@@ -625,7 +590,7 @@ Tunneling ${selectedTargets.length} project(s) to localhost:${options.port}
|
|
|
625
590
|
|
|
626
591
|
// src/commands/projects.ts
|
|
627
592
|
var import_chalk4 = __toESM(require("chalk"));
|
|
628
|
-
var
|
|
593
|
+
var import_ora3 = __toESM(require("ora"));
|
|
629
594
|
init_auth();
|
|
630
595
|
init_api();
|
|
631
596
|
async function runProjects() {
|
|
@@ -662,7 +627,7 @@ async function runProjects() {
|
|
|
662
627
|
}
|
|
663
628
|
console.log(`${import_chalk4.default.cyan("\u2192")} Team: ${import_chalk4.default.bold(teamName ?? teamId)}
|
|
664
629
|
`);
|
|
665
|
-
const spinner = (0,
|
|
630
|
+
const spinner = (0, import_ora3.default)("Fetching projects...").start();
|
|
666
631
|
let projects;
|
|
667
632
|
try {
|
|
668
633
|
projects = await getProjects(teamId);
|
|
@@ -685,7 +650,7 @@ ${projects.length} project${projects.length === 1 ? "" : "s"}`));
|
|
|
685
650
|
|
|
686
651
|
// src/commands/create.ts
|
|
687
652
|
var import_chalk5 = __toESM(require("chalk"));
|
|
688
|
-
var
|
|
653
|
+
var import_ora4 = __toESM(require("ora"));
|
|
689
654
|
init_auth();
|
|
690
655
|
init_api();
|
|
691
656
|
function normalizeName(raw) {
|
|
@@ -764,7 +729,7 @@ async function runCreate(opts = {}) {
|
|
|
764
729
|
console.log(import_chalk5.default.yellow(" Name must be at least 3 characters (letters and digits only).\n"));
|
|
765
730
|
continue;
|
|
766
731
|
}
|
|
767
|
-
const spinner2 = (0,
|
|
732
|
+
const spinner2 = (0, import_ora4.default)("Checking availability...").start();
|
|
768
733
|
try {
|
|
769
734
|
const check = await checkProxyName(name, teamId);
|
|
770
735
|
spinner2.stop();
|
|
@@ -820,7 +785,7 @@ async function runCreate(opts = {}) {
|
|
|
820
785
|
return;
|
|
821
786
|
}
|
|
822
787
|
}
|
|
823
|
-
const spinner = !opts.json ? (0,
|
|
788
|
+
const spinner = !opts.json ? (0, import_ora4.default)("Creating proxy (tenant, keys, dev portal)...").start() : null;
|
|
824
789
|
let result;
|
|
825
790
|
try {
|
|
826
791
|
result = await createProxy({ name, target_url: targetUrl, auth_type: auth, team_id: teamId });
|
|
@@ -829,15 +794,15 @@ async function runCreate(opts = {}) {
|
|
|
829
794
|
spinner?.fail("Failed to create proxy.");
|
|
830
795
|
throw err;
|
|
831
796
|
}
|
|
832
|
-
const
|
|
797
|
+
const version2 = result.api_version || "1.0.0";
|
|
833
798
|
const keys = result.api_keys ?? {};
|
|
834
799
|
const adminKey = keys.dev ?? Object.values(keys)[0];
|
|
835
|
-
const proxyUrl = `https://${name}.apiblaze.com/${
|
|
800
|
+
const proxyUrl = `https://${name}.apiblaze.com/${version2}/dev`;
|
|
836
801
|
const devPortal = result.devPortal ? stripTenantFromPortal(result.devPortal) : void 0;
|
|
837
802
|
if (opts.json) {
|
|
838
803
|
process.stdout.write(JSON.stringify({
|
|
839
804
|
project_id: result.project_id,
|
|
840
|
-
api_version:
|
|
805
|
+
api_version: version2,
|
|
841
806
|
proxy_url: proxyUrl,
|
|
842
807
|
dev_portal: devPortal,
|
|
843
808
|
api_key: adminKey,
|
|
@@ -910,7 +875,7 @@ async function runTeam(arg) {
|
|
|
910
875
|
|
|
911
876
|
// src/index.ts
|
|
912
877
|
var program = new import_commander.Command();
|
|
913
|
-
program.name("apiblaze").description("APIblaze dev tunnel CLI").version(
|
|
878
|
+
program.name("apiblaze").description("APIblaze dev tunnel CLI").version(version);
|
|
914
879
|
program.command("login").description("Authenticate with APIblaze").action(async () => {
|
|
915
880
|
try {
|
|
916
881
|
await runLogin();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apiblaze",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Dev tunnel CLI for APIblaze — route localhost projects through
|
|
3
|
+
"version": "0.1.16",
|
|
4
|
+
"description": "Dev tunnel CLI for APIblaze — route localhost projects through your APIblaze endpoints",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"apiblaze",
|
|
7
7
|
"dev-tunnel",
|
|
@@ -32,11 +32,13 @@
|
|
|
32
32
|
"chalk": "^4.1.2",
|
|
33
33
|
"commander": "^11.1.0",
|
|
34
34
|
"inquirer": "^8.2.6",
|
|
35
|
-
"ora": "^5.4.1"
|
|
35
|
+
"ora": "^5.4.1",
|
|
36
|
+
"ws": "^8.17.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@types/inquirer": "^8.2.10",
|
|
39
40
|
"@types/node": "^20.0.0",
|
|
41
|
+
"@types/ws": "^8.5.10",
|
|
40
42
|
"tsup": "^8.0.0",
|
|
41
43
|
"typescript": "^5.4.0"
|
|
42
44
|
}
|