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.
Files changed (2) hide show
  1. package/dist/index.js +81 -61
  2. 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", { method: "DELETE" });
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
- function connectTrafficStream(wsUrl, onEntry) {
443
- const token = getAccessToken();
444
- let ws;
445
- let reconnectCount = 0;
446
- const MAX_RECONNECTS = 3;
447
- function connect() {
448
- ws = new import_ws.default(wsUrl, { headers: { Authorization: `Bearer ${token}` } });
449
- ws.on("message", (data) => {
450
- try {
451
- const entry = JSON.parse(data.toString());
452
- onEntry(entry);
453
- } catch {
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
- ws.on("close", () => {
457
- if (reconnectCount < MAX_RECONNECTS) {
458
- reconnectCount++;
459
- setTimeout(() => connect(), 2e3);
460
- } else {
461
- console.warn(import_chalk2.default.yellow("\nTraffic stream disconnected. Stop and restart `apiblaze dev` to reconnect."));
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
- ws.on("error", (err) => {
465
- console.warn(import_chalk2.default.yellow(`
466
- Traffic stream error: ${err.message}`));
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
- return ws;
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(options.port));
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
- wsUrl = result.wsUrl;
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
- let ws;
583
- console.log("\n" + import_chalk3.default.gray("\u2500".repeat(60)));
584
- console.log(import_chalk3.default.bold("Live traffic") + import_chalk3.default.gray(" (Ctrl+C to stop)"));
585
- console.log(import_chalk3.default.gray("\u2500".repeat(60)) + "\n");
586
- ws = connectTrafficStream(wsUrl, (entry) => {
587
- console.log(formatLogLine(entry));
588
- });
589
- let isCleaningUp = false;
590
- async function cleanup() {
591
- if (isCleaningUp) return;
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.0");
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
- await runDev({ port: parseInt(opts.port, 10) });
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.10",
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
  }