pinggy 0.4.4 → 0.4.6

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.cjs CHANGED
@@ -116,6 +116,11 @@ var init_printer = __esm({
116
116
  const def = this.errorDefinitions.find((d) => d.match(err));
117
117
  const msg = def.message(err);
118
118
  console.error(import_picocolors2.default.red(import_picocolors2.default.bold("\u2716 Error:")), import_picocolors2.default.red(msg));
119
+ }
120
+ static fatal(err) {
121
+ const def = this.errorDefinitions.find((d) => d.match(err));
122
+ const msg = def.message(err);
123
+ console.error(import_picocolors2.default.red(import_picocolors2.default.bold("\u2716 Fatal Error:")), import_picocolors2.default.red(msg));
119
124
  process.exit(1);
120
125
  }
121
126
  static red(message) {
@@ -254,7 +259,9 @@ function enablePackageLogging(opts) {
254
259
  return applyLoggingConfig(opts ?? {});
255
260
  }
256
261
  function enableLoggingByLogLevelInSdk(loglevel, logFilePath) {
257
- if (!loglevel) return;
262
+ if (!loglevel) {
263
+ return;
264
+ }
258
265
  const l = loglevel.toUpperCase();
259
266
  if (loglevel === "DEBUG") {
260
267
  import_pinggy.pinggy.setDebugLogging(true, import_pinggy.LogLevel.DEBUG, logFilePath);
@@ -430,7 +437,9 @@ var init_TunnelManager = __esm({
430
437
  */
431
438
  async startTunnel(tunnelId) {
432
439
  const managed = this.tunnelsByTunnelId.get(tunnelId);
433
- if (!managed) throw new Error(`Tunnel with id "${tunnelId}" not found`);
440
+ if (!managed) {
441
+ throw new Error(`Tunnel with id "${tunnelId}" not found`);
442
+ }
434
443
  logger.info("Starting tunnel", { tunnelId });
435
444
  let urls;
436
445
  try {
@@ -478,7 +487,9 @@ var init_TunnelManager = __esm({
478
487
  */
479
488
  stopTunnel(tunnelId) {
480
489
  const managed = this.tunnelsByTunnelId.get(tunnelId);
481
- if (!managed) throw new Error(`Tunnel "${tunnelId}" not found`);
490
+ if (!managed) {
491
+ throw new Error(`Tunnel "${tunnelId}" not found`);
492
+ }
482
493
  logger.info("Stopping tunnel", { tunnelId, configId: managed.configId });
483
494
  try {
484
495
  managed.instance.stop();
@@ -659,12 +670,16 @@ var init_TunnelManager = __esm({
659
670
  getTunnelInstance(configId, tunnelId) {
660
671
  if (configId) {
661
672
  const managed = this.tunnelsByConfigId.get(configId);
662
- if (!managed) throw new Error(`Tunnel "${configId}" not found`);
673
+ if (!managed) {
674
+ throw new Error(`Tunnel "${configId}" not found`);
675
+ }
663
676
  return managed.instance;
664
677
  }
665
678
  if (tunnelId) {
666
679
  const managed = this.tunnelsByTunnelId.get(tunnelId);
667
- if (!managed) throw new Error(`Tunnel "${tunnelId}" not found`);
680
+ if (!managed) {
681
+ throw new Error(`Tunnel "${tunnelId}" not found`);
682
+ }
668
683
  return managed.instance;
669
684
  }
670
685
  throw new Error(`Either configId or tunnelId must be provided`);
@@ -843,12 +858,16 @@ var init_TunnelManager = __esm({
843
858
  getManagedTunnel(configId, tunnelId) {
844
859
  if (configId) {
845
860
  const managed = this.tunnelsByConfigId.get(configId);
846
- if (!managed) throw new Error(`Tunnel "${configId}" not found`);
861
+ if (!managed) {
862
+ throw new Error(`Tunnel "${configId}" not found`);
863
+ }
847
864
  return managed;
848
865
  }
849
866
  if (tunnelId) {
850
867
  const managed = this.tunnelsByTunnelId.get(tunnelId);
851
- if (!managed) throw new Error(`Tunnel "${tunnelId}" not found`);
868
+ if (!managed) {
869
+ throw new Error(`Tunnel "${tunnelId}" not found`);
870
+ }
852
871
  return managed;
853
872
  }
854
873
  throw new Error(`Either configId or tunnelId must be provided`);
@@ -1237,7 +1256,9 @@ var init_TunnelManager = __esm({
1237
1256
  notifyPollingErrorListeners(tunnelId, errorMsg) {
1238
1257
  try {
1239
1258
  const listeners = this.tunnelPollingErrorListeners.get(tunnelId);
1240
- if (!listeners) return;
1259
+ if (!listeners) {
1260
+ return;
1261
+ }
1241
1262
  for (const [id, listener] of listeners) {
1242
1263
  try {
1243
1264
  listener(tunnelId, errorMsg);
@@ -1252,7 +1273,9 @@ var init_TunnelManager = __esm({
1252
1273
  notifyErrorListeners(tunnelId, errorMsg, isFatal) {
1253
1274
  try {
1254
1275
  const listeners = this.tunnelErrorListeners.get(tunnelId);
1255
- if (!listeners) return;
1276
+ if (!listeners) {
1277
+ return;
1278
+ }
1256
1279
  for (const [id, listener] of listeners) {
1257
1280
  try {
1258
1281
  listener(tunnelId, errorMsg, isFatal);
@@ -1301,7 +1324,9 @@ var init_TunnelManager = __esm({
1301
1324
  managedTunnel.stoppedAt = (/* @__PURE__ */ new Date()).toISOString();
1302
1325
  }
1303
1326
  const listeners = this.tunnelDisconnectListeners.get(tunnelId);
1304
- if (!listeners) return;
1327
+ if (!listeners) {
1328
+ return;
1329
+ }
1305
1330
  for (const [id, listener] of listeners) {
1306
1331
  try {
1307
1332
  listener(tunnelId, error, messages);
@@ -1329,7 +1354,9 @@ var init_TunnelManager = __esm({
1329
1354
  try {
1330
1355
  logger.info("Tunnel will reconnect", { tunnelId, error, messages });
1331
1356
  const listeners = this.tunnelWillReconnectListeners.get(tunnelId);
1332
- if (!listeners) return;
1357
+ if (!listeners) {
1358
+ return;
1359
+ }
1333
1360
  for (const [id, listener] of listeners) {
1334
1361
  try {
1335
1362
  listener(tunnelId, error, messages);
@@ -1357,7 +1384,9 @@ var init_TunnelManager = __esm({
1357
1384
  try {
1358
1385
  logger.info("Tunnel reconnecting", { tunnelId, retryCnt });
1359
1386
  const listeners = this.tunnelReconnectingListeners.get(tunnelId);
1360
- if (!listeners) return;
1387
+ if (!listeners) {
1388
+ return;
1389
+ }
1361
1390
  for (const [id, listener] of listeners) {
1362
1391
  try {
1363
1392
  listener(tunnelId, retryCnt);
@@ -1435,7 +1464,9 @@ var init_TunnelManager = __esm({
1435
1464
  managedTunnel.stoppedAt = (/* @__PURE__ */ new Date()).toISOString();
1436
1465
  }
1437
1466
  const listeners = this.tunnelReconnectionFailedListeners.get(tunnelId);
1438
- if (!listeners) return;
1467
+ if (!listeners) {
1468
+ return;
1469
+ }
1439
1470
  for (const [id, listener] of listeners) {
1440
1471
  try {
1441
1472
  listener(tunnelId, retryCnt);
@@ -1459,7 +1490,9 @@ var init_TunnelManager = __esm({
1459
1490
  try {
1460
1491
  logger.debug("Error in Tunnel Worker", { tunnelId, errorMessage: error.message });
1461
1492
  const listeners = this.tunnelWorkerErrorListeners.get(tunnelId);
1462
- if (!listeners) return;
1493
+ if (!listeners) {
1494
+ return;
1495
+ }
1463
1496
  for (const [id, listener] of listeners) {
1464
1497
  try {
1465
1498
  listener(tunnelId, error);
@@ -1945,6 +1978,7 @@ var init_handler = __esm({
1945
1978
  "use strict";
1946
1979
  init_cjs_shims();
1947
1980
  init_types();
1981
+ init_logger();
1948
1982
  init_TunnelManager();
1949
1983
  init_remote_schema();
1950
1984
  TunnelOperations = class {
@@ -1967,6 +2001,26 @@ var init_handler = __esm({
1967
2001
  }
1968
2002
  return status;
1969
2003
  }
2004
+ // --- Placeholder response ---
2005
+ buildPendingTunnelResponse(tunnelid, tunnelConfig, configid, tunnelName, serve) {
2006
+ return {
2007
+ tunnelid,
2008
+ remoteurls: [],
2009
+ tunnelconfig: pinggyOptionsToTunnelConfig(tunnelConfig, configid, tunnelName, false, void 0, serve),
2010
+ status: this.buildStatus(tunnelid, "starting" /* Starting */, "" /* NoError */),
2011
+ stats: newStats()
2012
+ };
2013
+ }
2014
+ buildPendingTunnelResponseV2(tunnelid, tunnelConfig, configFromCli, configid, tunnelName, serve) {
2015
+ return {
2016
+ tunnelid,
2017
+ remoteurls: [],
2018
+ tunnelconfig: pinggyOptionsToTunnelConfigV1(tunnelConfig, configFromCli),
2019
+ status: this.buildStatus(tunnelid, "starting" /* Starting */, "" /* NoError */),
2020
+ stats: newStats(),
2021
+ greetmsg: ""
2022
+ };
2023
+ }
1970
2024
  // --- Helper to construct TunnelResponse ---
1971
2025
  async buildTunnelResponse(tunnelid, tunnelConfig, configid, tunnelName, serve) {
1972
2026
  const [status, stats, tlsInfo, greetMsg, remoteurls] = await Promise.all([
@@ -2007,10 +2061,10 @@ var init_handler = __esm({
2007
2061
  });
2008
2062
  }
2009
2063
  // --- Operations ---
2010
- async handleStart(config) {
2064
+ async handleStart(config, noWait = false) {
2011
2065
  try {
2012
2066
  const opts = tunnelConfigToPinggyOptions(config);
2013
- const { tunnelid, instance, tunnelName, serve, tunnelConfig } = await this.tunnelManager.createTunnel({
2067
+ const managed = await this.tunnelManager.createTunnel({
2014
2068
  ...opts,
2015
2069
  configId: config.configid,
2016
2070
  name: config.configname,
@@ -2018,36 +2072,52 @@ var init_handler = __esm({
2018
2072
  serve: config.serve
2019
2073
  }
2020
2074
  });
2021
- await this.tunnelManager.startTunnel(tunnelid);
2075
+ const { tunnelid, tunnelName, serve, tunnelConfig } = managed;
2076
+ const startPromise = this.tunnelManager.startTunnel(tunnelid);
2077
+ if (noWait) {
2078
+ startPromise.catch((err) => {
2079
+ logger.error("No-wait startTunnel failed", { tunnelid, err: String(err) });
2080
+ });
2081
+ return this.buildPendingTunnelResponse(tunnelid, tunnelConfig, config.configid, tunnelName, serve);
2082
+ }
2083
+ await startPromise;
2022
2084
  const tunnelPconfig = await this.tunnelManager.getTunnelConfig("", tunnelid);
2023
- const resp = this.buildTunnelResponse(tunnelid, tunnelPconfig, config.configid, tunnelName, serve);
2024
- return resp;
2085
+ return this.buildTunnelResponse(tunnelid, tunnelPconfig, config.configid, tunnelName, serve);
2025
2086
  } catch (err) {
2026
2087
  return this.error(ErrorCode.ErrorStartingTunnel, err, "Unknown error occurred while starting tunnel");
2027
2088
  }
2028
2089
  }
2029
- async handleStartV2(config) {
2090
+ async handleStartV2(config, noWait = false) {
2030
2091
  try {
2031
- const { tunnelid, instance, serve } = await this.tunnelManager.createTunnel(config);
2092
+ const managed = await this.tunnelManager.createTunnel(config);
2093
+ const { tunnelid, serve, tunnelConfig } = managed;
2032
2094
  await this.tunnelManager.startTunnel(tunnelid);
2033
2095
  const tunnelPconfig = await this.tunnelManager.getTunnelConfig("", tunnelid);
2034
- const resp = this.buildTunnelResponseV2(tunnelid, tunnelPconfig, config, config.configId, config.name, config.serve);
2035
- return resp;
2096
+ return this.buildTunnelResponseV2(tunnelid, tunnelPconfig, config, config.configId, config.name, config.serve);
2036
2097
  } catch (err) {
2037
2098
  return this.error(ErrorCode.ErrorStartingTunnel, err, "Unknown error occurred while starting tunnel");
2038
2099
  }
2039
2100
  }
2040
- async handleUpdateConfig(config) {
2101
+ async handleUpdateConfig(config, noWait = false) {
2041
2102
  try {
2042
2103
  const opts = tunnelConfigToPinggyOptions(config);
2043
- const tunnel = await this.tunnelManager.updateConfig({
2104
+ const updateOpts = {
2044
2105
  ...opts,
2045
2106
  configId: config.configid,
2046
2107
  name: config.configname,
2047
2108
  optional: {
2048
2109
  serve: config.serve
2049
2110
  }
2050
- });
2111
+ };
2112
+ if (noWait) {
2113
+ const existing = this.tunnelManager.getManagedTunnel(config.configid);
2114
+ if (!existing.tunnelConfig) throw new Error("Invalid tunnel state before configuration update");
2115
+ this.tunnelManager.updateConfig(updateOpts).catch((err) => {
2116
+ logger.error("No-wait updateConfig failed", { configid: config.configid, err: String(err) });
2117
+ });
2118
+ return this.buildPendingTunnelResponse(existing.tunnelid, existing.tunnelConfig, config.configid, existing.tunnelName, existing.serve);
2119
+ }
2120
+ const tunnel = await this.tunnelManager.updateConfig(updateOpts);
2051
2121
  if (!tunnel.instance || !tunnel.tunnelConfig)
2052
2122
  throw new Error("Invalid tunnel state after configuration update");
2053
2123
  return this.buildTunnelResponse(tunnel.tunnelid, tunnel.tunnelConfig, config.configid, tunnel.tunnelName, tunnel.serve);
@@ -2055,8 +2125,17 @@ var init_handler = __esm({
2055
2125
  return this.error(ErrorCode.InternalServerError, err, "Failed to update tunnel configuration");
2056
2126
  }
2057
2127
  }
2058
- async handleUpdateConfigV2(config) {
2128
+ async handleUpdateConfigV2(config, noWait = false) {
2059
2129
  try {
2130
+ if (noWait) {
2131
+ const existing = this.tunnelManager.getManagedTunnel(config.configId);
2132
+ console.log(existing);
2133
+ if (!existing.tunnelConfig) throw new Error("Invalid tunnel state before configuration update");
2134
+ this.tunnelManager.updateConfig(config).catch((err) => {
2135
+ logger.error("No-wait updateConfigV2 failed", { configId: config.configId, err: String(err) });
2136
+ });
2137
+ return this.buildPendingTunnelResponseV2(existing.tunnelid, existing.tunnelConfig, config, config.configId, existing.tunnelName, existing.serve);
2138
+ }
2060
2139
  const tunnel = await this.tunnelManager.updateConfig(config);
2061
2140
  if (!tunnel.instance || !tunnel.tunnelConfig)
2062
2141
  throw new Error("Invalid tunnel state after configuration update");
@@ -2143,8 +2222,16 @@ var init_handler = __esm({
2143
2222
  return this.error(ErrorCode.TunnelNotFound, err, "Failed to get tunnel information");
2144
2223
  }
2145
2224
  }
2146
- async handleRestart(tunnelid) {
2225
+ async handleRestart(tunnelid, noWait = false) {
2147
2226
  try {
2227
+ if (noWait) {
2228
+ const managed2 = this.tunnelManager.getManagedTunnel("", tunnelid);
2229
+ if (!managed2?.tunnelConfig) throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
2230
+ this.tunnelManager.restartTunnel(tunnelid).catch((err) => {
2231
+ logger.error("No-wait restartTunnel failed", { tunnelid, err: String(err) });
2232
+ });
2233
+ return this.buildPendingTunnelResponse(tunnelid, managed2.tunnelConfig, managed2.configId, managed2.tunnelName, managed2.serve);
2234
+ }
2148
2235
  await this.tunnelManager.restartTunnel(tunnelid);
2149
2236
  const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
2150
2237
  if (!managed?.tunnelConfig) throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
@@ -2463,7 +2550,7 @@ var init_websocket_handlers = __esm({
2463
2550
  const dc = StartSchema.parse(raw);
2464
2551
  queuedConfig = dc.tunnelConfig;
2465
2552
  remoteManagementWebSocketPrinter.queueStart(dc.tunnelConfig);
2466
- const result = await this.tunnelHandler.handleStart(dc.tunnelConfig);
2553
+ const result = await this.tunnelHandler.handleStart(dc.tunnelConfig, true);
2467
2554
  remoteManagementWebSocketPrinter.handleStartResult(dc.tunnelConfig, result);
2468
2555
  return this.wrapResponse(result, req);
2469
2556
  } catch (e) {
@@ -2484,7 +2571,7 @@ var init_websocket_handlers = __esm({
2484
2571
  const dc = StartV2Schema.parse(raw);
2485
2572
  queuedConfig = dc.tunnelConfig;
2486
2573
  remoteManagementWebSocketPrinter.queueStart(dc.tunnelConfig);
2487
- const result = await this.tunnelHandler.handleStartV2(dc.tunnelConfig);
2574
+ const result = await this.tunnelHandler.handleStartV2(dc.tunnelConfig, true);
2488
2575
  remoteManagementWebSocketPrinter.handleStartResult(dc.tunnelConfig, result);
2489
2576
  return this.wrapResponse(result, req);
2490
2577
  } catch (e) {
@@ -2533,7 +2620,7 @@ var init_websocket_handlers = __esm({
2533
2620
  try {
2534
2621
  const dc = RestartSchema.parse(raw);
2535
2622
  remoteManagementWebSocketPrinter.printRestartRequested(dc.tunnelID);
2536
- const result = await this.tunnelHandler.handleRestart(dc.tunnelID);
2623
+ const result = await this.tunnelHandler.handleRestart(dc.tunnelID, true);
2537
2624
  remoteManagementWebSocketPrinter.handleRestartResult(dc.tunnelID, result);
2538
2625
  return this.wrapResponse(result, req);
2539
2626
  } catch (e) {
@@ -2548,7 +2635,7 @@ var init_websocket_handlers = __esm({
2548
2635
  async handleUpdateConfigReq(req, raw) {
2549
2636
  try {
2550
2637
  const dc = UpdateConfigSchema.parse(raw);
2551
- const result = await this.tunnelHandler.handleUpdateConfig(dc.tunnelConfig);
2638
+ const result = await this.tunnelHandler.handleUpdateConfig(dc.tunnelConfig, true);
2552
2639
  return this.wrapResponse(result, req);
2553
2640
  } catch (e) {
2554
2641
  if (e instanceof import_zod2.default.ZodError) {
@@ -2562,7 +2649,7 @@ var init_websocket_handlers = __esm({
2562
2649
  async handleUpdateConfigV2Req(req, raw) {
2563
2650
  try {
2564
2651
  const dc = UpdateConfigV2Schema.parse(raw);
2565
- const result = await this.tunnelHandler.handleUpdateConfigV2(dc.tunnelConfig);
2652
+ const result = await this.tunnelHandler.handleUpdateConfigV2(dc.tunnelConfig, true);
2566
2653
  return this.wrapResponse(result, req);
2567
2654
  } catch (e) {
2568
2655
  if (e instanceof import_zod2.default.ZodError) {
@@ -2758,9 +2845,14 @@ async function initiateRemoteManagement(remoteManagementConfig) {
2758
2845
  try {
2759
2846
  await handleWebSocketConnection(wsUrl, wsHost, remoteManagementConfig.apiKey);
2760
2847
  } catch (error) {
2848
+ if (error instanceof RemoteManagementUnauthorizedError) {
2849
+ throw error;
2850
+ }
2761
2851
  logger.warn("Remote management connection error", { error: String(error) });
2762
2852
  }
2763
- if (_stopRequested) break;
2853
+ if (_stopRequested) {
2854
+ break;
2855
+ }
2764
2856
  printer_default.warn(`Remote management disconnected. Reconnecting in ${RECONNECT_SLEEP_MS / 1e3} seconds...`);
2765
2857
  logger.info("Reconnecting to remote management after disconnect");
2766
2858
  await sleep(RECONNECT_SLEEP_MS);
@@ -2769,22 +2861,34 @@ async function initiateRemoteManagement(remoteManagementConfig) {
2769
2861
  logger.info("Remote management stopped.");
2770
2862
  return getRemoteManagementState();
2771
2863
  }
2772
- async function handleWebSocketConnection(wsUrl, wsHost, token) {
2773
- return new Promise((resolve) => {
2864
+ async function handleWebSocketConnection(wsUrl, wsHost, token, onOpenCallback) {
2865
+ return new Promise((resolve, reject) => {
2774
2866
  const ws = new import_ws.default(wsUrl, {
2775
2867
  headers: { Authorization: `Bearer ${token}` }
2776
2868
  });
2777
2869
  currentWs = ws;
2778
2870
  let heartbeat = null;
2779
2871
  let firstMessage = true;
2780
- const cleanup = () => {
2781
- if (heartbeat) clearInterval(heartbeat);
2872
+ let settled = false;
2873
+ const cleanup = (err) => {
2874
+ if (settled) {
2875
+ return;
2876
+ }
2877
+ settled = true;
2878
+ if (heartbeat) {
2879
+ clearInterval(heartbeat);
2880
+ }
2782
2881
  currentWs = null;
2783
- resolve();
2882
+ if (err) {
2883
+ reject(err);
2884
+ } else {
2885
+ resolve();
2886
+ }
2784
2887
  };
2785
2888
  ws.once("open", () => {
2786
2889
  printer_default.success(`Connected to ${wsHost}`);
2787
2890
  setRemoteManagementState({ status: RemoteManagementStatus.Running, errorMessage: "" });
2891
+ onOpenCallback?.();
2788
2892
  heartbeat = setInterval(() => {
2789
2893
  if (ws.readyState === import_ws.default.OPEN) ws.ping();
2790
2894
  }, PING_INTERVAL_MS);
@@ -2812,13 +2916,14 @@ async function handleWebSocketConnection(wsUrl, wsHost, token) {
2812
2916
  ws.on("unexpected-response", (_, res) => {
2813
2917
  if (res.statusCode === 401) {
2814
2918
  setRemoteManagementState({ status: RemoteManagementStatus.NotRunning, errorMessage: `HTTP ${res.statusCode}` });
2815
- printer_default.error("Unauthorized. Please enter a valid token.");
2816
2919
  logger.error("Unauthorized (401) on remote management connect");
2920
+ cleanup(new RemoteManagementUnauthorizedError());
2817
2921
  ws.close();
2818
2922
  } else {
2819
2923
  logger.warn("Unexpected HTTP response ", { statusCode: res.statusCode });
2820
2924
  printer_default.warn(`Unexpected HTTP ${res.statusCode}. Retrying...`);
2821
2925
  cleanup();
2926
+ ws.close();
2822
2927
  }
2823
2928
  });
2824
2929
  ws.on("close", (code, reason) => {
@@ -2830,7 +2935,7 @@ async function handleWebSocketConnection(wsUrl, wsHost, token) {
2830
2935
  ws.on("error", (err) => {
2831
2936
  setRemoteManagementState({ status: RemoteManagementStatus.Error, errorMessage: err.message });
2832
2937
  logger.warn("WebSocket error", { error: err.message });
2833
- printer_default.error(err);
2938
+ printer_default.warn(err.message);
2834
2939
  cleanup();
2835
2940
  });
2836
2941
  });
@@ -2860,6 +2965,58 @@ async function closeRemoteManagement(timeoutMs = 1e4) {
2860
2965
  return getRemoteManagementState();
2861
2966
  }
2862
2967
  }
2968
+ function startRemoteManagement(remoteManagementConfig) {
2969
+ if (!remoteManagementConfig.apiKey || remoteManagementConfig.apiKey.trim().length === 0) {
2970
+ return Promise.reject(new Error("Remote management token is required"));
2971
+ }
2972
+ const wsUrl = remoteManagementConfig.serverUrl;
2973
+ const wsHost = extractHostname(wsUrl);
2974
+ logger.info("Remote management mode enabled.");
2975
+ _stopRequested = false;
2976
+ return new Promise((resolve, reject) => {
2977
+ let firstSettled = false;
2978
+ const settleOnce = (err) => {
2979
+ if (firstSettled) {
2980
+ return;
2981
+ }
2982
+ firstSettled = true;
2983
+ if (err) {
2984
+ reject(err);
2985
+ } else {
2986
+ resolve(getRemoteManagementState());
2987
+ }
2988
+ };
2989
+ const runLoop = async () => {
2990
+ const sigintHandler = () => {
2991
+ _stopRequested = true;
2992
+ };
2993
+ process.once("SIGINT", sigintHandler);
2994
+ while (!_stopRequested) {
2995
+ logger.info("Connecting to remote management", { wsUrl });
2996
+ setRemoteManagementState({ status: RemoteManagementStatus.Connecting, errorMessage: "" });
2997
+ try {
2998
+ await handleWebSocketConnection(wsUrl, wsHost, remoteManagementConfig.apiKey, () => settleOnce());
2999
+ } catch (error) {
3000
+ if (error instanceof RemoteManagementUnauthorizedError) {
3001
+ settleOnce(error);
3002
+ process.removeListener("SIGINT", sigintHandler);
3003
+ return;
3004
+ }
3005
+ settleOnce();
3006
+ logger.warn("Remote management connection error", { error: String(error) });
3007
+ }
3008
+ if (_stopRequested) {
3009
+ break;
3010
+ }
3011
+ logger.info("Reconnecting to remote management after disconnect");
3012
+ await sleep(RECONNECT_SLEEP_MS);
3013
+ }
3014
+ process.removeListener("SIGINT", sigintHandler);
3015
+ logger.info("Remote management stopped.");
3016
+ };
3017
+ runLoop().catch((err) => settleOnce(err instanceof Error ? err : new Error(String(err))));
3018
+ });
3019
+ }
2863
3020
  function getRemoteManagementState() {
2864
3021
  return _remoteManagementState;
2865
3022
  }
@@ -2869,7 +3026,7 @@ function setRemoteManagementState(state, errorMessage) {
2869
3026
  errorMessage: errorMessage || ""
2870
3027
  };
2871
3028
  }
2872
- var import_ws, RECONNECT_SLEEP_MS, PING_INTERVAL_MS, _remoteManagementState, _stopRequested, currentWs;
3029
+ var import_ws, RECONNECT_SLEEP_MS, PING_INTERVAL_MS, RemoteManagementUnauthorizedError, _remoteManagementState, _stopRequested, currentWs;
2873
3030
  var init_remoteManagement = __esm({
2874
3031
  "src/remote_management/remoteManagement.ts"() {
2875
3032
  "use strict";
@@ -2881,6 +3038,12 @@ var init_remoteManagement = __esm({
2881
3038
  init_types();
2882
3039
  RECONNECT_SLEEP_MS = 5e3;
2883
3040
  PING_INTERVAL_MS = 3e4;
3041
+ RemoteManagementUnauthorizedError = class extends Error {
3042
+ constructor() {
3043
+ super("Unauthorized. Please enter a valid token.");
3044
+ this.name = "RemoteManagementUnauthorizedError";
3045
+ }
3046
+ };
2884
3047
  _remoteManagementState = {
2885
3048
  status: "NOT_RUNNING",
2886
3049
  errorMessage: ""
@@ -3154,6 +3317,19 @@ var init_extendedOptions = __esm({
3154
3317
  });
3155
3318
 
3156
3319
  // src/cli/buildConfig.ts
3320
+ function removeIPv6Brackets(ip) {
3321
+ if (ip.startsWith("[") && ip.endsWith("]")) {
3322
+ return ip.slice(1, -1);
3323
+ }
3324
+ return ip;
3325
+ }
3326
+ function isValidServerAddress(host) {
3327
+ const normalized = removeIPv6Brackets(host.trim());
3328
+ if (!normalized) {
3329
+ return false;
3330
+ }
3331
+ return domainRegex.test(normalized) || (0, import_net2.isIP)(normalized) !== 0;
3332
+ }
3157
3333
  function isKeyword(str) {
3158
3334
  return KEYWORDS.has(str.toLowerCase());
3159
3335
  }
@@ -3163,10 +3339,12 @@ function parseUserAndDomain(str) {
3163
3339
  let server;
3164
3340
  let qrCode;
3165
3341
  let forceFlag;
3166
- if (!str) return { token, type, server, qrCode, forceFlag };
3342
+ if (!str) {
3343
+ return { token, type, server, qrCode, forceFlag };
3344
+ }
3167
3345
  if (str.includes("@")) {
3168
3346
  const [user, domain] = str.split("@", 2);
3169
- if (domainRegex.test(domain)) {
3347
+ if (isValidServerAddress(domain)) {
3170
3348
  let processKeyword2 = function(keyword) {
3171
3349
  if ([import_pinggy4.TunnelType.Http, import_pinggy4.TunnelType.Tcp, import_pinggy4.TunnelType.Tls, import_pinggy4.TunnelType.Udp, import_pinggy4.TunnelType.TlsTcp].includes(keyword)) {
3172
3350
  type = keyword;
@@ -3202,7 +3380,7 @@ function parseUserAndDomain(str) {
3202
3380
  }
3203
3381
  }
3204
3382
  }
3205
- } else if (domainRegex.test(str)) {
3383
+ } else if (isValidServerAddress(str)) {
3206
3384
  server = str;
3207
3385
  }
3208
3386
  return { token, type, server, qrCode, forceFlag };
@@ -3216,21 +3394,39 @@ function parseUsers(positionalArgs, explicitToken) {
3216
3394
  let remaining = [...positionalArgs];
3217
3395
  if (typeof explicitToken === "string") {
3218
3396
  const parsed = parseUserAndDomain(explicitToken);
3219
- if (parsed.server) server = parsed.server;
3220
- if (parsed.type) type = parsed.type;
3221
- if (parsed.token) token = parsed.token;
3222
- if (parsed.forceFlag) forceFlag = true;
3223
- if (parsed.qrCode) qrCode = true;
3397
+ if (parsed.server) {
3398
+ server = parsed.server;
3399
+ }
3400
+ if (parsed.type) {
3401
+ type = parsed.type;
3402
+ }
3403
+ if (parsed.token) {
3404
+ token = parsed.token;
3405
+ }
3406
+ if (parsed.forceFlag) {
3407
+ forceFlag = true;
3408
+ }
3409
+ if (parsed.qrCode) {
3410
+ qrCode = true;
3411
+ }
3224
3412
  }
3225
3413
  if (remaining.length > 0) {
3226
3414
  const first = remaining[0];
3227
3415
  const parsed = parseUserAndDomain(first);
3228
3416
  if (parsed.server) {
3229
3417
  server = parsed.server;
3230
- if (parsed.type) type = parsed.type;
3231
- if (parsed.token) token = parsed.token;
3232
- if (parsed.forceFlag) forceFlag = true;
3233
- if (parsed.qrCode) qrCode = true;
3418
+ if (parsed.type) {
3419
+ type = parsed.type;
3420
+ }
3421
+ if (parsed.token) {
3422
+ token = parsed.token;
3423
+ }
3424
+ if (parsed.forceFlag) {
3425
+ forceFlag = true;
3426
+ }
3427
+ if (parsed.qrCode) {
3428
+ qrCode = true;
3429
+ }
3234
3430
  remaining = remaining.slice(1);
3235
3431
  }
3236
3432
  }
@@ -3243,7 +3439,9 @@ function parseType(finalConfig, values, inferredType) {
3243
3439
  }
3244
3440
  }
3245
3441
  function parseLocalPort(finalConfig, values) {
3246
- if (typeof values.localport !== "string") return null;
3442
+ if (typeof values.localport !== "string") {
3443
+ return null;
3444
+ }
3247
3445
  let lp = values.localport.trim();
3248
3446
  let isHttps = false;
3249
3447
  if (lp.startsWith("https://")) {
@@ -3273,15 +3471,11 @@ function parseLocalPort(finalConfig, values) {
3273
3471
  }
3274
3472
  return null;
3275
3473
  }
3276
- function removeIPv6Brackets(ip) {
3277
- if (ip.startsWith("[") && ip.endsWith("]")) {
3278
- return ip.slice(1, -1);
3279
- }
3280
- return ip;
3281
- }
3282
3474
  function isValidHostAddress(host) {
3283
3475
  const normalized = removeIPv6Brackets(host.trim());
3284
- if (normalized.length === 0) return false;
3476
+ if (normalized.length === 0) {
3477
+ return false;
3478
+ }
3285
3479
  return normalized === "localhost" || (0, import_net2.isIP)(normalized) !== 0;
3286
3480
  }
3287
3481
  function ipv6SafeSplitColon(s) {
@@ -3324,7 +3518,9 @@ function parseDefaultForwarding(forwarding) {
3324
3518
  }
3325
3519
  function parseAdditionalForwarding(forwarding) {
3326
3520
  const toPort = (v) => {
3327
- if (!v) return null;
3521
+ if (!v) {
3522
+ return null;
3523
+ }
3328
3524
  const n = parseInt(v, 10);
3329
3525
  return Number.isNaN(n) ? null : n;
3330
3526
  };
@@ -3336,7 +3532,7 @@ function parseAdditionalForwarding(forwarding) {
3336
3532
  }
3337
3533
  const firstPart = parsed[0];
3338
3534
  const [hostPart] = firstPart.split("@");
3339
- let protocol = "http";
3535
+ let protocol = import_pinggy4.TunnelType.Http;
3340
3536
  let remoteDomainRaw;
3341
3537
  let remotePort = 0;
3342
3538
  if (hostPart.includes("//")) {
@@ -3350,7 +3546,7 @@ function parseAdditionalForwarding(forwarding) {
3350
3546
  return new Error("invalid forwarding address format");
3351
3547
  }
3352
3548
  remoteDomainRaw = domainAndPort[0];
3353
- if (!remoteDomainRaw || !domainRegex.test(remoteDomainRaw)) {
3549
+ if (!remoteDomainRaw || !isValidServerAddress(remoteDomainRaw)) {
3354
3550
  return new Error("invalid remote domain");
3355
3551
  }
3356
3552
  const parsedRemotePort = toPort(domainAndPort[1]);
@@ -3366,10 +3562,10 @@ function parseAdditionalForwarding(forwarding) {
3366
3562
  }
3367
3563
  } else {
3368
3564
  remoteDomainRaw = hostPart;
3369
- if (!domainRegex.test(remoteDomainRaw)) {
3565
+ if (!isValidServerAddress(remoteDomainRaw)) {
3370
3566
  return new Error("invalid remote domain");
3371
3567
  }
3372
- protocol = "http";
3568
+ protocol = import_pinggy4.TunnelType.Http;
3373
3569
  remotePort = 0;
3374
3570
  }
3375
3571
  const localDomain = removeIPv6Brackets(parsed[2] || "localhost");
@@ -3403,7 +3599,9 @@ function parseReverseTunnelAddr(finalConfig, values, primaryType) {
3403
3599
  });
3404
3600
  } else if (slicedForwarding.length === 4) {
3405
3601
  const parsed = parseAdditionalForwarding(forwarding);
3406
- if (parsed instanceof Error) return parsed;
3602
+ if (parsed instanceof Error) {
3603
+ return parsed;
3604
+ }
3407
3605
  forwardingData.push(parsed);
3408
3606
  } else {
3409
3607
  return new Error(
@@ -3415,7 +3613,9 @@ function parseReverseTunnelAddr(finalConfig, values, primaryType) {
3415
3613
  return null;
3416
3614
  }
3417
3615
  function parseLocalTunnelAddr(finalConfig, values) {
3418
- if (!Array.isArray(values.L) || values.L.length === 0) return null;
3616
+ if (!Array.isArray(values.L) || values.L.length === 0) {
3617
+ return null;
3618
+ }
3419
3619
  const firstL = values.L[0];
3420
3620
  const parts = ipv6SafeSplitColon(firstL);
3421
3621
  let debuggerHost = "localhost";
@@ -3439,7 +3639,9 @@ function parseLocalTunnelAddr(finalConfig, values) {
3439
3639
  }
3440
3640
  function parseDebugger(finalConfig, values) {
3441
3641
  let dbg = values.debugger;
3442
- if (typeof dbg !== "string") return;
3642
+ if (typeof dbg !== "string") {
3643
+ return;
3644
+ }
3443
3645
  dbg = dbg.startsWith(":") ? dbg.slice(1) : dbg;
3444
3646
  const d = parseInt(dbg, 10);
3445
3647
  if (!Number.isNaN(d) && isValidPort(d)) {
@@ -3498,7 +3700,9 @@ function isSaveConfOption(values) {
3498
3700
  }
3499
3701
  function parseServe(finalConfig, values) {
3500
3702
  const sv = values.serve;
3501
- if (typeof sv !== "string" || sv.trim().length === 0) return null;
3703
+ if (typeof sv !== "string" || sv.trim().length === 0) {
3704
+ return null;
3705
+ }
3502
3706
  finalConfig.optional.serve = sv;
3503
3707
  return null;
3504
3708
  }
@@ -3539,7 +3743,7 @@ async function buildFinalConfig(values, positionals) {
3539
3743
  // Apply loaded config on top of defaults
3540
3744
  configId: getRandomId(),
3541
3745
  token: token || (configFromFile?.token || (typeof values.token === "string" ? values.token : "")),
3542
- serverAddress: server || (configFromFile?.serverAddress || defaultOptions.serverAddress),
3746
+ serverAddress: server ? removeIPv6Brackets(server) : configFromFile?.serverAddress || defaultOptions.serverAddress,
3543
3747
  isQRCode: qrCode || (configFromFile?.isQRCode || false),
3544
3748
  autoReconnect: configFromFile?.autoReconnect ? configFromFile.autoReconnect : defaultOptions.autoReconnect,
3545
3749
  optional: {
@@ -3550,18 +3754,32 @@ async function buildFinalConfig(values, positionals) {
3550
3754
  type = parseType(finalConfig, values, type);
3551
3755
  parseToken(finalConfig, token || values.token);
3552
3756
  const dbgErr = parseDebugger(finalConfig, values);
3553
- if (dbgErr instanceof Error) throw dbgErr;
3757
+ if (dbgErr instanceof Error) {
3758
+ throw dbgErr;
3759
+ }
3554
3760
  const lpErr = parseLocalPort(finalConfig, values);
3555
- if (lpErr instanceof Error) throw lpErr;
3761
+ if (lpErr instanceof Error) {
3762
+ throw lpErr;
3763
+ }
3556
3764
  const rErr = parseReverseTunnelAddr(finalConfig, values, type);
3557
- if (rErr instanceof Error) throw rErr;
3765
+ if (rErr instanceof Error) {
3766
+ throw rErr;
3767
+ }
3558
3768
  const lErr = parseLocalTunnelAddr(finalConfig, values);
3559
- if (lErr instanceof Error) throw lErr;
3769
+ if (lErr instanceof Error) {
3770
+ throw lErr;
3771
+ }
3560
3772
  const serveErr = parseServe(finalConfig, values);
3561
- if (serveErr instanceof Error) throw serveErr;
3773
+ if (serveErr instanceof Error) {
3774
+ throw serveErr;
3775
+ }
3562
3776
  const autoReconnectErr = parseAutoReconnect(finalConfig, values);
3563
- if (autoReconnectErr instanceof Error) throw autoReconnectErr;
3564
- if (forceFlag || values.force) finalConfig.force = true;
3777
+ if (autoReconnectErr instanceof Error) {
3778
+ throw autoReconnectErr;
3779
+ }
3780
+ if (forceFlag || values.force) {
3781
+ finalConfig.force = true;
3782
+ }
3565
3783
  parseArgs(finalConfig, remainingPositionals);
3566
3784
  storeJson(finalConfig, saveconf);
3567
3785
  return finalConfig;
@@ -3589,7 +3807,7 @@ var init_buildConfig = __esm({
3589
3807
  "force",
3590
3808
  "qr"
3591
3809
  ]);
3592
- VALID_PROTOCOLS = ["http", "tcp", "udp", "tls"];
3810
+ VALID_PROTOCOLS = [import_pinggy4.TunnelType.Http, import_pinggy4.TunnelType.Tcp, import_pinggy4.TunnelType.Udp, import_pinggy4.TunnelType.Tls, import_pinggy4.TunnelType.TlsTcp];
3593
3811
  }
3594
3812
  });
3595
3813
 
@@ -3598,15 +3816,26 @@ function isAttachedReverseOrLocalFlag(arg) {
3598
3816
  return /^-[RL].+/.test(arg);
3599
3817
  }
3600
3818
  function shouldMergeReverseOrLocalFragment(current, next) {
3601
- if (next.startsWith("-")) return false;
3602
- if (next.startsWith(".")) return true;
3819
+ if (next.startsWith("-")) {
3820
+ return false;
3821
+ }
3822
+ if (next.startsWith(".")) {
3823
+ return true;
3824
+ }
3603
3825
  const body = current.slice(2);
3604
- if (body.endsWith(":")) return true;
3605
- if (body.includes("//") && !body.includes(":")) return true;
3826
+ if (body.endsWith(":")) {
3827
+ return true;
3828
+ }
3829
+ if (body.includes("//") && !body.includes(":")) {
3830
+ return true;
3831
+ }
3606
3832
  return false;
3607
3833
  }
3608
3834
  function preprocessWindowsArgs(args) {
3609
- if (os2.platform() !== "win32") return args;
3835
+ if (os2.platform() !== "win32") {
3836
+ return args;
3837
+ }
3838
+ ;
3610
3839
  const out = [];
3611
3840
  let i = 0;
3612
3841
  while (i < args.length) {
@@ -3693,13 +3922,12 @@ var init_getFreePort = __esm({
3693
3922
  async function createQrCodes(urls) {
3694
3923
  const codes = [];
3695
3924
  for (const url of urls) {
3696
- const qr = await import_qrcode.default.toString(url, {
3697
- type: "terminal",
3698
- small: true,
3699
- margin: 0,
3925
+ const raw = await import_qrcode.default.toString(url, {
3926
+ type: "utf8",
3927
+ margin: 2,
3700
3928
  errorCorrectionLevel: "L"
3701
3929
  });
3702
- codes.push(qr);
3930
+ codes.push(raw);
3703
3931
  }
3704
3932
  return codes;
3705
3933
  }
@@ -3717,6 +3945,7 @@ function getTuiConfig() {
3717
3945
  return {
3718
3946
  maxRequestPairs: defaultTuiConfig.maxRequestPairs,
3719
3947
  visibleRequestCount: defaultTuiConfig.visibleRequestCount,
3948
+ visibleUrlCount: defaultTuiConfig.visibleUrlCount,
3720
3949
  viewportScrollMargin: defaultTuiConfig.viewportScrollMargin,
3721
3950
  inactivityHttpSelectorTimeoutMs: defaultTuiConfig.inactivityHttpSelectorTimeoutMs
3722
3951
  };
@@ -3729,6 +3958,7 @@ var init_config = __esm({
3729
3958
  defaultTuiConfig = {
3730
3959
  maxRequestPairs: 100,
3731
3960
  visibleRequestCount: 10,
3961
+ visibleUrlCount: 7,
3732
3962
  viewportScrollMargin: 2,
3733
3963
  inactivityHttpSelectorTimeoutMs: 1e4
3734
3964
  };
@@ -3969,7 +4199,7 @@ function createFullUI(screen, urls, greet, tunnelConfig) {
3969
4199
  width: "100%-2",
3970
4200
  height: `100%-${lowerSectionTop + 6}`
3971
4201
  });
3972
- const isQrCodeRequested = tunnelConfig?.qrCode || false;
4202
+ const isQrCodeRequested = tunnelConfig?.isQRCode || false;
3973
4203
  const requestsBox = import_blessed.default.box({
3974
4204
  parent: lowerSection,
3975
4205
  top: 0,
@@ -4129,8 +4359,24 @@ var init_utils = __esm({
4129
4359
  // src/tui/blessed/components/DisplayUpdaters.ts
4130
4360
  function updateUrlsDisplay(urlsBox, screen, urls, currentQrIndex) {
4131
4361
  if (!urlsBox) return;
4132
- let content = "{green-fg}{bold}Public URLs{/bold}{/green-fg}\n";
4133
- urls.forEach((url, index) => {
4362
+ const config = getTuiConfig();
4363
+ const { visibleUrlCount } = config;
4364
+ let viewportStart = 0;
4365
+ if (urls.length > visibleUrlCount) {
4366
+ viewportStart = Math.max(0, Math.min(
4367
+ currentQrIndex - Math.floor(visibleUrlCount / 2),
4368
+ urls.length - visibleUrlCount
4369
+ ));
4370
+ }
4371
+ const viewportEnd = Math.min(viewportStart + visibleUrlCount, urls.length);
4372
+ const visibleUrls = urls.slice(viewportStart, viewportEnd);
4373
+ let content = "{green-fg}{bold}Public URLs{/bold}{/green-fg}";
4374
+ if (viewportStart > 0) {
4375
+ content += ` {gray-fg}\u2191 ${viewportStart} more{/gray-fg}`;
4376
+ }
4377
+ content += "\n";
4378
+ visibleUrls.forEach((url, i) => {
4379
+ const index = viewportStart + i;
4134
4380
  const isSelected = index === currentQrIndex;
4135
4381
  const prefix = isSelected ? "\u2192 " : "\u2022 ";
4136
4382
  const color = isSelected ? "yellow" : "magenta";
@@ -4142,6 +4388,11 @@ function updateUrlsDisplay(urlsBox, screen, urls, currentQrIndex) {
4142
4388
  `;
4143
4389
  }
4144
4390
  });
4391
+ const itemsBelow = urls.length - viewportEnd;
4392
+ if (itemsBelow > 0) {
4393
+ content += `{gray-fg}\u2193 ${itemsBelow} more{/gray-fg}
4394
+ `;
4395
+ }
4145
4396
  urlsBox.setContent(content);
4146
4397
  screen.render();
4147
4398
  }
@@ -4854,7 +5105,7 @@ var init_TunnelTui = __esm({
4854
5105
  }
4855
5106
  }
4856
5107
  async generateQrCodes() {
4857
- if (this.tunnelConfig?.qrCode && this.urls.length > 0) {
5108
+ if (this.tunnelConfig?.isQRCode && this.urls.length > 0) {
4858
5109
  this.qrCodes = await createQrCodes(this.urls);
4859
5110
  this.updateQrCodeDisplay();
4860
5111
  }
@@ -5091,7 +5342,7 @@ async function startCli(finalConfig, manager) {
5091
5342
  });
5092
5343
  }
5093
5344
  manager2.registerWorkerErrorListner(tunnel.tunnelid, (_tunnelid, error) => {
5094
- printer_default.error(`${error.message}`);
5345
+ printer_default.fatal(`${error.message}`);
5095
5346
  });
5096
5347
  await manager2.startTunnel(tunnel.tunnelid);
5097
5348
  printer_default.stopSpinnerSuccess(" Connected to Pinggy");
@@ -5216,7 +5467,7 @@ async function startCli(finalConfig, manager) {
5216
5467
  }
5217
5468
  } catch (err) {
5218
5469
  printer_default.stopSpinnerFail("Failed to connect");
5219
- printer_default.error(err.message || "Unknown error");
5470
+ printer_default.fatal(err.message || "Unknown error");
5220
5471
  throw err;
5221
5472
  }
5222
5473
  }
@@ -5244,6 +5495,7 @@ var init_starCli = __esm({
5244
5495
  // src/main.ts
5245
5496
  var main_exports = {};
5246
5497
  __export(main_exports, {
5498
+ RemoteManagementUnauthorizedError: () => RemoteManagementUnauthorizedError,
5247
5499
  TunnelManager: () => TunnelManager,
5248
5500
  TunnelOperations: () => TunnelOperations,
5249
5501
  closeRemoteManagement: () => closeRemoteManagement,
@@ -5273,9 +5525,8 @@ async function main() {
5273
5525
  }
5274
5526
  const parseResult = await parseRemoteManagement(values);
5275
5527
  if (parseResult?.ok === false) {
5276
- printer_default.error(parseResult.error);
5277
5528
  logger.error("Failed to initiate remote management:", parseResult.error);
5278
- process.exit(1);
5529
+ printer_default.fatal(parseResult.error);
5279
5530
  }
5280
5531
  logger.debug("Building final config from CLI values and positionals", { values, positionals });
5281
5532
  const finalConfig = await buildFinalConfig(values, positionals);
@@ -5283,7 +5534,7 @@ async function main() {
5283
5534
  await startCli(finalConfig, manager);
5284
5535
  } catch (error) {
5285
5536
  logger.error("Unhandled error in CLI:", error);
5286
- printer_default.error(error);
5537
+ printer_default.fatal(error);
5287
5538
  }
5288
5539
  }
5289
5540
  var import_url2, import_process, import_fs5, currentFile, entryFile;
@@ -5323,6 +5574,7 @@ var init_main = __esm({
5323
5574
  // src/index.ts
5324
5575
  var index_exports = {};
5325
5576
  __export(index_exports, {
5577
+ RemoteManagementUnauthorizedError: () => RemoteManagementUnauthorizedError,
5326
5578
  TunnelErrorCodeType: () => TunnelErrorCodeType,
5327
5579
  TunnelManager: () => TunnelManager,
5328
5580
  TunnelOperations: () => TunnelOperations,
@@ -5331,7 +5583,8 @@ __export(index_exports, {
5331
5583
  closeRemoteManagement: () => closeRemoteManagement,
5332
5584
  enablePackageLogging: () => enablePackageLogging,
5333
5585
  getRemoteManagementState: () => getRemoteManagementState,
5334
- initiateRemoteManagement: () => initiateRemoteManagement
5586
+ initiateRemoteManagement: () => initiateRemoteManagement,
5587
+ startRemoteManagement: () => startRemoteManagement
5335
5588
  });
5336
5589
  module.exports = __toCommonJS(index_exports);
5337
5590
  init_cjs_shims();
@@ -5437,11 +5690,11 @@ async function verifyAndLoad() {
5437
5690
  await Promise.resolve().then(() => (init_main(), main_exports));
5438
5691
  }
5439
5692
  verifyAndLoad().catch((err) => {
5440
- printer_default.error(`Failed to start CLI:, ${err}`);
5441
- process.exit(1);
5693
+ printer_default.fatal(`Failed to start CLI:, ${err}`);
5442
5694
  });
5443
5695
  // Annotate the CommonJS export names for ESM import in node:
5444
5696
  0 && (module.exports = {
5697
+ RemoteManagementUnauthorizedError,
5445
5698
  TunnelErrorCodeType,
5446
5699
  TunnelManager,
5447
5700
  TunnelOperations,
@@ -5450,5 +5703,6 @@ verifyAndLoad().catch((err) => {
5450
5703
  closeRemoteManagement,
5451
5704
  enablePackageLogging,
5452
5705
  getRemoteManagementState,
5453
- initiateRemoteManagement
5706
+ initiateRemoteManagement,
5707
+ startRemoteManagement
5454
5708
  });