@shipers-dev/multi 0.12.1 → 0.13.0

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 +63 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -16272,7 +16272,7 @@ import { join as join4, dirname as dirname3 } from "path";
16272
16272
  // package.json
16273
16273
  var package_default = {
16274
16274
  name: "@shipers-dev/multi",
16275
- version: "0.12.1",
16275
+ version: "0.13.0",
16276
16276
  type: "module",
16277
16277
  bin: {
16278
16278
  "multi-agent": "./dist/index.js"
@@ -16715,7 +16715,7 @@ async function cmdConnect(apiUrl, config2) {
16715
16715
  try {
16716
16716
  writeFileSync4(PORT_PATH, String(port));
16717
16717
  } catch {}
16718
- let tunnel = await startTunnel(port);
16718
+ let tunnel = await startTunnel(port, log);
16719
16719
  if (!tunnel) {
16720
16720
  log("\u274C cloudflared did not emit a tunnel URL \u2014 is `cloudflared` installed? (`brew install cloudflared`)");
16721
16721
  try {
@@ -16785,7 +16785,7 @@ async function cmdConnect(apiUrl, config2) {
16785
16785
  old?.child.kill();
16786
16786
  } catch {}
16787
16787
  for (let attempt = 1;alive; attempt++) {
16788
- const next = await startTunnel(port);
16788
+ const next = await startTunnel(port, log);
16789
16789
  if (next) {
16790
16790
  tunnel = next;
16791
16791
  log(`\u2601\uFE0F Tunnel up: ${tunnel.url}`);
@@ -16854,21 +16854,77 @@ async function cmdConnect(apiUrl, config2) {
16854
16854
  }
16855
16855
  }
16856
16856
  }
16857
- async function startTunnel(port) {
16857
+ async function startTunnel(port, log2 = () => {}) {
16858
+ const named = process.env.MULTI_TUNNEL_NAME?.trim();
16859
+ const hostname3 = process.env.MULTI_TUNNEL_HOSTNAME?.trim();
16860
+ if (named) {
16861
+ if (!hostname3) {
16862
+ log2("\u274C MULTI_TUNNEL_NAME set but MULTI_TUNNEL_HOSTNAME missing \u2014 set the public hostname routed to this tunnel");
16863
+ return null;
16864
+ }
16865
+ const args = ["tunnel", "--no-autoupdate", "--url", `http://127.0.0.1:${port}`, "run", named];
16866
+ const child2 = Bun.spawn(["cloudflared", ...args], { stdout: "pipe", stderr: "pipe", stdin: "ignore" });
16867
+ const ok = await waitNamedTunnelReady(child2.stderr);
16868
+ if (!ok.ready) {
16869
+ try {
16870
+ child2.kill();
16871
+ } catch {}
16872
+ if (ok.tail) {
16873
+ const lines = ok.tail.split(`
16874
+ `).filter(Boolean).slice(-6);
16875
+ for (const l of lines)
16876
+ log2(` cloudflared: ${l}`);
16877
+ }
16878
+ return null;
16879
+ }
16880
+ const url3 = hostname3.startsWith("http") ? hostname3.replace(/\/+$/, "") : `https://${hostname3}`;
16881
+ return { child: child2, url: url3 };
16882
+ }
16858
16883
  const child = Bun.spawn(["cloudflared", "tunnel", "--no-autoupdate", "--url", `http://127.0.0.1:${port}`], {
16859
16884
  stdout: "pipe",
16860
16885
  stderr: "pipe",
16861
16886
  stdin: "ignore"
16862
16887
  });
16863
- const url2 = await parseTunnelUrl(child.stderr);
16888
+ const { url: url2, tail } = await parseTunnelUrl(child.stderr);
16864
16889
  if (!url2) {
16865
16890
  try {
16866
16891
  child.kill();
16867
16892
  } catch {}
16893
+ if (tail) {
16894
+ const lines = tail.split(`
16895
+ `).filter(Boolean).slice(-6);
16896
+ for (const l of lines)
16897
+ log2(` cloudflared: ${l}`);
16898
+ }
16868
16899
  return null;
16869
16900
  }
16870
16901
  return { child, url: url2 };
16871
16902
  }
16903
+ async function waitNamedTunnelReady(stream2) {
16904
+ const reader = stream2.getReader();
16905
+ const dec = new TextDecoder;
16906
+ const deadline = Date.now() + 30000;
16907
+ let buf = "";
16908
+ while (Date.now() < deadline) {
16909
+ const { value, done } = await reader.read();
16910
+ if (done)
16911
+ break;
16912
+ buf += dec.decode(value, { stream: true });
16913
+ if (/Registered tunnel connection|Connection [a-z0-9-]+ registered/i.test(buf)) {
16914
+ (async () => {
16915
+ try {
16916
+ while (true) {
16917
+ const { done: done2 } = await reader.read();
16918
+ if (done2)
16919
+ break;
16920
+ }
16921
+ } catch {}
16922
+ })();
16923
+ return { ready: true, tail: buf };
16924
+ }
16925
+ }
16926
+ return { ready: false, tail: buf };
16927
+ }
16872
16928
  async function probeTunnel(url2) {
16873
16929
  try {
16874
16930
  const ctrl = new AbortController;
@@ -16934,10 +16990,10 @@ async function parseTunnelUrl(stream2) {
16934
16990
  }
16935
16991
  } catch {}
16936
16992
  })();
16937
- return m[1];
16993
+ return { url: m[1], tail: buf };
16938
16994
  }
16939
16995
  }
16940
- return null;
16996
+ return { url: null, tail: buf };
16941
16997
  }
16942
16998
  async function markStopped(apiUrl, issueId, reason) {
16943
16999
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipers-dev/multi",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "multi-agent": "./dist/index.js"