apiblaze 0.1.10 → 0.1.12
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 +81 -61
- package/package.json +2 -4
package/dist/index.js
CHANGED
|
@@ -150,8 +150,11 @@ async function putDevTunnel(payload) {
|
|
|
150
150
|
body: JSON.stringify(payload)
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
|
-
async function deleteDevTunnel() {
|
|
154
|
-
return apiFetch("/api/cli/dev-tunnel", {
|
|
153
|
+
async function deleteDevTunnel(restore) {
|
|
154
|
+
return apiFetch("/api/cli/dev-tunnel", {
|
|
155
|
+
method: "DELETE",
|
|
156
|
+
body: JSON.stringify({ restore })
|
|
157
|
+
});
|
|
155
158
|
}
|
|
156
159
|
var DASHBOARD_BASE;
|
|
157
160
|
var init_api = __esm({
|
|
@@ -405,9 +408,7 @@ function killCloudflared(proc) {
|
|
|
405
408
|
}
|
|
406
409
|
|
|
407
410
|
// src/lib/traffic.ts
|
|
408
|
-
var import_ws = __toESM(require("ws"));
|
|
409
411
|
var import_chalk2 = __toESM(require("chalk"));
|
|
410
|
-
init_auth();
|
|
411
412
|
var METHOD_COLORS = {
|
|
412
413
|
GET: import_chalk2.default.cyan,
|
|
413
414
|
POST: import_chalk2.default.green,
|
|
@@ -439,35 +440,51 @@ function formatLogLine(entry) {
|
|
|
439
440
|
const ts = now.toTimeString().slice(0, 8);
|
|
440
441
|
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)})`)}`;
|
|
441
442
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
443
|
+
|
|
444
|
+
// src/lib/proxy-logger.ts
|
|
445
|
+
var import_http = __toESM(require("http"));
|
|
446
|
+
var import_net = __toESM(require("net"));
|
|
447
|
+
function startPassthroughProxy(targetPort, onEntry) {
|
|
448
|
+
return new Promise((resolve, reject) => {
|
|
449
|
+
const server = import_http.default.createServer((req, res) => {
|
|
450
|
+
const start = Date.now();
|
|
451
|
+
const method = req.method ?? "GET";
|
|
452
|
+
const path3 = req.url ?? "/";
|
|
453
|
+
const proxyReq = import_http.default.request(
|
|
454
|
+
{ host: "127.0.0.1", port: targetPort, method, path: path3, headers: req.headers },
|
|
455
|
+
(proxyRes) => {
|
|
456
|
+
onEntry({ method, path: path3, status: proxyRes.statusCode ?? 0, latency: Date.now() - start });
|
|
457
|
+
res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
|
|
458
|
+
proxyRes.pipe(res);
|
|
459
|
+
}
|
|
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);
|
|
455
467
|
});
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
468
|
+
server.on("upgrade", (req, clientSocket, head) => {
|
|
469
|
+
const upstream = import_net.default.connect(targetPort, "127.0.0.1", () => {
|
|
470
|
+
const headerLines = Object.entries(req.headers).map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(", ") : v}`).join("\r\n");
|
|
471
|
+
upstream.write(`${req.method} ${req.url} HTTP/1.1\r
|
|
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());
|
|
463
481
|
});
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
482
|
+
server.on("error", reject);
|
|
483
|
+
server.listen(0, "127.0.0.1", () => {
|
|
484
|
+
const { port } = server.address();
|
|
485
|
+
resolve({ port, close: () => server.close() });
|
|
467
486
|
});
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
return connect();
|
|
487
|
+
});
|
|
471
488
|
}
|
|
472
489
|
|
|
473
490
|
// src/commands/dev.ts
|
|
@@ -552,60 +569,58 @@ Tunneling ${selectedTargets.length} project(s) to localhost:${options.port}
|
|
|
552
569
|
`)
|
|
553
570
|
);
|
|
554
571
|
await ensureCloudflared();
|
|
572
|
+
const logger = await startPassthroughProxy(options.port, (entry) => {
|
|
573
|
+
console.log(formatLogLine(entry));
|
|
574
|
+
});
|
|
555
575
|
let cfProcess;
|
|
556
576
|
let tunnelUrl;
|
|
557
577
|
{
|
|
558
578
|
const spinner = (0, import_ora3.default)("Starting Cloudflare tunnel...").start();
|
|
559
579
|
try {
|
|
560
|
-
({ process: cfProcess, tunnelUrl } = await spawnCloudflared(
|
|
580
|
+
({ process: cfProcess, tunnelUrl } = await spawnCloudflared(logger.port));
|
|
561
581
|
spinner.succeed(`Tunnel active: ${import_chalk3.default.bold.cyan(tunnelUrl)}`);
|
|
562
582
|
} catch (err) {
|
|
563
583
|
spinner.fail("Failed to start cloudflared tunnel.");
|
|
584
|
+
logger.close();
|
|
564
585
|
throw err;
|
|
565
586
|
}
|
|
566
587
|
}
|
|
588
|
+
let restore = [];
|
|
567
589
|
{
|
|
568
590
|
const spinner = (0, import_ora3.default)("Registering tunnel with APIblaze...").start();
|
|
569
|
-
let wsUrl;
|
|
570
591
|
try {
|
|
571
592
|
const result = await putDevTunnel({
|
|
572
593
|
tunnelUrl,
|
|
573
594
|
targets: selectedTargets.map((t) => ({ projectId: t.projectId, tenantId: t.tenantId }))
|
|
574
595
|
});
|
|
575
|
-
|
|
596
|
+
restore = result.restore ?? [];
|
|
576
597
|
spinner.succeed("Tunnel registered. Proxying traffic.");
|
|
577
598
|
} catch (err) {
|
|
578
599
|
spinner.fail("Failed to register tunnel.");
|
|
600
|
+
logger.close();
|
|
579
601
|
killCloudflared(cfProcess);
|
|
580
602
|
throw err;
|
|
581
603
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
isCleaningUp = true;
|
|
593
|
-
console.log(import_chalk3.default.gray("\n\nShutting down..."));
|
|
594
|
-
try {
|
|
595
|
-
ws.close();
|
|
596
|
-
} catch {
|
|
597
|
-
}
|
|
598
|
-
await deleteDevTunnel().catch(() => {
|
|
599
|
-
});
|
|
600
|
-
killCloudflared(cfProcess);
|
|
601
|
-
console.log(import_chalk3.default.green("Tunnel stopped."));
|
|
602
|
-
process.exit(0);
|
|
603
|
-
}
|
|
604
|
-
process.on("SIGINT", () => void cleanup());
|
|
605
|
-
process.on("SIGTERM", () => void cleanup());
|
|
606
|
-
await new Promise(() => {
|
|
604
|
+
}
|
|
605
|
+
console.log("\n" + import_chalk3.default.gray("\u2500".repeat(60)));
|
|
606
|
+
console.log(import_chalk3.default.bold("Live traffic") + import_chalk3.default.gray(" (Ctrl+C to stop)"));
|
|
607
|
+
console.log(import_chalk3.default.gray("\u2500".repeat(60)) + "\n");
|
|
608
|
+
let isCleaningUp = false;
|
|
609
|
+
async function cleanup() {
|
|
610
|
+
if (isCleaningUp) return;
|
|
611
|
+
isCleaningUp = true;
|
|
612
|
+
console.log(import_chalk3.default.gray("\n\nShutting down..."));
|
|
613
|
+
await deleteDevTunnel(restore).catch(() => {
|
|
607
614
|
});
|
|
615
|
+
logger.close();
|
|
616
|
+
killCloudflared(cfProcess);
|
|
617
|
+
console.log(import_chalk3.default.green("Tunnel stopped."));
|
|
618
|
+
process.exit(0);
|
|
608
619
|
}
|
|
620
|
+
process.on("SIGINT", () => void cleanup());
|
|
621
|
+
process.on("SIGTERM", () => void cleanup());
|
|
622
|
+
await new Promise(() => {
|
|
623
|
+
});
|
|
609
624
|
}
|
|
610
625
|
|
|
611
626
|
// src/commands/projects.ts
|
|
@@ -895,7 +910,7 @@ async function runTeam(arg) {
|
|
|
895
910
|
|
|
896
911
|
// src/index.ts
|
|
897
912
|
var program = new import_commander.Command();
|
|
898
|
-
program.name("apiblaze").description("APIblaze dev tunnel CLI").version("0.1.
|
|
913
|
+
program.name("apiblaze").description("APIblaze dev tunnel CLI").version("0.1.11");
|
|
899
914
|
program.command("login").description("Authenticate with APIblaze").action(async () => {
|
|
900
915
|
try {
|
|
901
916
|
await runLogin();
|
|
@@ -928,9 +943,14 @@ program.command("projects").description("List the projects in your team").action
|
|
|
928
943
|
process.exit(1);
|
|
929
944
|
}
|
|
930
945
|
});
|
|
931
|
-
program.command("dev").description("Start a dev tunnel for your localhost projects").option("-p, --port <number>", "Local port to tunnel", "3000").action(async (opts) => {
|
|
946
|
+
program.command("dev").description("Start a dev tunnel for your localhost projects").argument("[port]", "Local port to tunnel (positional; overrides --port)").option("-p, --port <number>", "Local port to tunnel", "3000").action(async (port, opts) => {
|
|
932
947
|
try {
|
|
933
|
-
|
|
948
|
+
const resolved = parseInt(port ?? opts.port, 10);
|
|
949
|
+
if (Number.isNaN(resolved)) {
|
|
950
|
+
console.error(import_chalk7.default.red(`Invalid port: ${port ?? opts.port}`));
|
|
951
|
+
process.exit(1);
|
|
952
|
+
}
|
|
953
|
+
await runDev({ port: resolved });
|
|
934
954
|
} catch (err) {
|
|
935
955
|
printError(err);
|
|
936
956
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apiblaze",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Dev tunnel CLI for APIblaze — route localhost projects through Cloudflare tunnels",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"apiblaze",
|
|
@@ -32,13 +32,11 @@
|
|
|
32
32
|
"chalk": "^4.1.2",
|
|
33
33
|
"commander": "^11.1.0",
|
|
34
34
|
"inquirer": "^8.2.6",
|
|
35
|
-
"ora": "^5.4.1"
|
|
36
|
-
"ws": "^8.17.0"
|
|
35
|
+
"ora": "^5.4.1"
|
|
37
36
|
},
|
|
38
37
|
"devDependencies": {
|
|
39
38
|
"@types/inquirer": "^8.2.10",
|
|
40
39
|
"@types/node": "^20.0.0",
|
|
41
|
-
"@types/ws": "^8.5.10",
|
|
42
40
|
"tsup": "^8.0.0",
|
|
43
41
|
"typescript": "^5.4.0"
|
|
44
42
|
}
|