pinggy 0.1.6 → 0.1.7

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.
@@ -11,21 +11,24 @@ function getLogger() {
11
11
  return _logger;
12
12
  }
13
13
  var logger = getLogger();
14
- function configureLogger(values, silent = false) {
15
- const levelStr = values.loglevel || void 0;
16
- const filePath = values.logfile || process.env.PINGGY_LOG_FILE || void 0;
17
- const printlog = values.v || values.vvv || void 0;
18
- const source = values.vvv ?? false;
19
- if (values.vv || values.vvv || levelStr) {
20
- enableLoggingByLogLevel(levelStr);
14
+ function applyLoggingConfig(cfg) {
15
+ const {
16
+ level,
17
+ filePath,
18
+ stdout = false,
19
+ source = false,
20
+ silent = false,
21
+ enableSdkLog = false
22
+ } = cfg;
23
+ if (enableSdkLog) {
24
+ enableLoggingByLogLevelInSdk(level ?? "info", filePath);
21
25
  }
22
26
  if (filePath) {
23
27
  const dir = path.dirname(filePath);
24
28
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
25
29
  }
26
30
  const transports = [];
27
- const stdoutEnabled = printlog === true || (process.env.PINGGY_LOG_STDOUT || "").toLowerCase() === "true";
28
- if (stdoutEnabled) {
31
+ if (stdout) {
29
32
  transports.push(
30
33
  new winston.transports.Console({
31
34
  format: winston.format.combine(
@@ -33,7 +36,7 @@ function configureLogger(values, silent = false) {
33
36
  winston.format.timestamp(),
34
37
  winston.format.printf(({ level: level2, message, timestamp, ...meta }) => {
35
38
  const srcLabel = source ? "[CLI] " : "";
36
- return `${timestamp} ${srcLabel}[${level2}] ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ""}`;
39
+ return `${timestamp} ${srcLabel}[${level2}] ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ""}`;
37
40
  })
38
41
  )
39
42
  })
@@ -44,7 +47,6 @@ function configureLogger(values, silent = false) {
44
47
  new winston.transports.File({
45
48
  filename: filePath,
46
49
  format: winston.format.combine(
47
- winston.format.colorize(),
48
50
  winston.format.timestamp(),
49
51
  winston.format.printf(({ level: level2, message, timestamp, ...meta }) => {
50
52
  return `${timestamp} [${level2}] ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ""}`;
@@ -53,27 +55,47 @@ function configureLogger(values, silent = false) {
53
55
  })
54
56
  );
55
57
  }
56
- const level = (levelStr || process.env.PINGGY_LOG_LEVEL || "info").toLowerCase();
57
58
  const log = getLogger();
58
59
  log.clear();
59
60
  for (const t of transports) {
60
61
  log.add(t);
61
62
  }
62
- log.level = level;
63
- log.silent = transports.length === 0 || silent === true;
63
+ log.level = (level || process.env.PINGGY_LOG_LEVEL || "info").toLowerCase();
64
+ log.silent = silent || transports.length === 0;
64
65
  return log;
65
66
  }
66
- function enableLoggingByLogLevel(loglevel) {
67
- if (loglevel === "DEBUG" || loglevel === "debug") {
68
- pinggy.setDebugLogging(true, LogLevel.DEBUG);
69
- } else if (loglevel === "ERROR" || loglevel === "error") {
70
- pinggy.setDebugLogging(true, LogLevel.ERROR);
67
+ function configureLogger(values, silent = false) {
68
+ const level = values.loglevel || void 0;
69
+ const filePath = values.logfile || process.env.PINGGY_LOG_FILE || void 0;
70
+ const stdout = values.v || values.vvv || void 0;
71
+ const source = values.vvv ?? false;
72
+ const enableSdkLog = values.vv || values.vvv;
73
+ return applyLoggingConfig({
74
+ level,
75
+ filePath,
76
+ stdout,
77
+ source,
78
+ silent,
79
+ enableSdkLog
80
+ });
81
+ }
82
+ function enablePackageLogging(opts) {
83
+ return applyLoggingConfig(opts ?? {});
84
+ }
85
+ function enableLoggingByLogLevelInSdk(loglevel, logFilePath) {
86
+ if (!loglevel) return;
87
+ const l = loglevel.toUpperCase();
88
+ if (loglevel === "DEBUG") {
89
+ pinggy.setDebugLogging(true, LogLevel.DEBUG, logFilePath);
90
+ } else if (loglevel === "ERROR") {
91
+ pinggy.setDebugLogging(true, LogLevel.ERROR, logFilePath);
71
92
  } else {
72
- pinggy.setDebugLogging(true, LogLevel.INFO);
93
+ pinggy.setDebugLogging(true, LogLevel.INFO, logFilePath);
73
94
  }
74
95
  }
75
96
 
76
97
  export {
77
98
  logger,
78
- configureLogger
99
+ configureLogger,
100
+ enablePackageLogging
79
101
  };
package/dist/index.cjs CHANGED
@@ -48,21 +48,24 @@ function getLogger() {
48
48
  }
49
49
  return _logger;
50
50
  }
51
- function configureLogger(values, silent = false) {
52
- const levelStr = values.loglevel || void 0;
53
- const filePath = values.logfile || process.env.PINGGY_LOG_FILE || void 0;
54
- const printlog = values.v || values.vvv || void 0;
55
- const source = values.vvv ?? false;
56
- if (values.vv || values.vvv || levelStr) {
57
- enableLoggingByLogLevel(levelStr);
51
+ function applyLoggingConfig(cfg) {
52
+ const {
53
+ level,
54
+ filePath,
55
+ stdout = false,
56
+ source = false,
57
+ silent = false,
58
+ enableSdkLog = false
59
+ } = cfg;
60
+ if (enableSdkLog) {
61
+ enableLoggingByLogLevelInSdk(level ?? "info", filePath);
58
62
  }
59
63
  if (filePath) {
60
64
  const dir = import_path.default.dirname(filePath);
61
65
  if (!import_fs.default.existsSync(dir)) import_fs.default.mkdirSync(dir, { recursive: true });
62
66
  }
63
67
  const transports = [];
64
- const stdoutEnabled = printlog === true || (process.env.PINGGY_LOG_STDOUT || "").toLowerCase() === "true";
65
- if (stdoutEnabled) {
68
+ if (stdout) {
66
69
  transports.push(
67
70
  new import_winston.default.transports.Console({
68
71
  format: import_winston.default.format.combine(
@@ -70,7 +73,7 @@ function configureLogger(values, silent = false) {
70
73
  import_winston.default.format.timestamp(),
71
74
  import_winston.default.format.printf(({ level: level2, message, timestamp, ...meta }) => {
72
75
  const srcLabel = source ? "[CLI] " : "";
73
- return `${timestamp} ${srcLabel}[${level2}] ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ""}`;
76
+ return `${timestamp} ${srcLabel}[${level2}] ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ""}`;
74
77
  })
75
78
  )
76
79
  })
@@ -81,7 +84,6 @@ function configureLogger(values, silent = false) {
81
84
  new import_winston.default.transports.File({
82
85
  filename: filePath,
83
86
  format: import_winston.default.format.combine(
84
- import_winston.default.format.colorize(),
85
87
  import_winston.default.format.timestamp(),
86
88
  import_winston.default.format.printf(({ level: level2, message, timestamp, ...meta }) => {
87
89
  return `${timestamp} [${level2}] ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ""}`;
@@ -90,23 +92,42 @@ function configureLogger(values, silent = false) {
90
92
  })
91
93
  );
92
94
  }
93
- const level = (levelStr || process.env.PINGGY_LOG_LEVEL || "info").toLowerCase();
94
95
  const log = getLogger();
95
96
  log.clear();
96
97
  for (const t of transports) {
97
98
  log.add(t);
98
99
  }
99
- log.level = level;
100
- log.silent = transports.length === 0 || silent === true;
100
+ log.level = (level || process.env.PINGGY_LOG_LEVEL || "info").toLowerCase();
101
+ log.silent = silent || transports.length === 0;
101
102
  return log;
102
103
  }
103
- function enableLoggingByLogLevel(loglevel) {
104
- if (loglevel === "DEBUG" || loglevel === "debug") {
105
- import_pinggy.pinggy.setDebugLogging(true, import_pinggy.LogLevel.DEBUG);
106
- } else if (loglevel === "ERROR" || loglevel === "error") {
107
- import_pinggy.pinggy.setDebugLogging(true, import_pinggy.LogLevel.ERROR);
104
+ function configureLogger(values, silent = false) {
105
+ const level = values.loglevel || void 0;
106
+ const filePath = values.logfile || process.env.PINGGY_LOG_FILE || void 0;
107
+ const stdout = values.v || values.vvv || void 0;
108
+ const source = values.vvv ?? false;
109
+ const enableSdkLog = values.vv || values.vvv;
110
+ return applyLoggingConfig({
111
+ level,
112
+ filePath,
113
+ stdout,
114
+ source,
115
+ silent,
116
+ enableSdkLog
117
+ });
118
+ }
119
+ function enablePackageLogging(opts) {
120
+ return applyLoggingConfig(opts ?? {});
121
+ }
122
+ function enableLoggingByLogLevelInSdk(loglevel, logFilePath) {
123
+ if (!loglevel) return;
124
+ const l = loglevel.toUpperCase();
125
+ if (loglevel === "DEBUG") {
126
+ import_pinggy.pinggy.setDebugLogging(true, import_pinggy.LogLevel.DEBUG, logFilePath);
127
+ } else if (loglevel === "ERROR") {
128
+ import_pinggy.pinggy.setDebugLogging(true, import_pinggy.LogLevel.ERROR, logFilePath);
108
129
  } else {
109
- import_pinggy.pinggy.setDebugLogging(true, import_pinggy.LogLevel.INFO);
130
+ import_pinggy.pinggy.setDebugLogging(true, import_pinggy.LogLevel.INFO, logFilePath);
110
131
  }
111
132
  }
112
133
  var import_winston, import_fs, import_path, import_pinggy, _logger, logger;
@@ -305,7 +326,7 @@ var init_URLsSection = __esm({
305
326
  isCopied && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { color: "greenBright", children: " [Copied!]" })
306
327
  ]
307
328
  },
308
- url
329
+ `url-${url}-${index}`
309
330
  );
310
331
  })
311
332
  ] });
@@ -825,7 +846,8 @@ var init_tui = __esm({
825
846
  var index_exports = {};
826
847
  __export(index_exports, {
827
848
  TunnelManager: () => TunnelManager,
828
- TunnelOperations: () => TunnelOperations
849
+ TunnelOperations: () => TunnelOperations,
850
+ enablePackageLogging: () => enablePackageLogging
829
851
  });
830
852
  module.exports = __toCommonJS(index_exports);
831
853
  init_cjs_shims();
@@ -877,28 +899,23 @@ var _CLIPrinter = class _CLIPrinter {
877
899
  static print(message, ...args) {
878
900
  console.log(message, ...args);
879
901
  }
880
- static async error(err) {
881
- const chalk = this.chalk;
902
+ static error(err) {
882
903
  const def = this.errorDefinitions.find((d) => d.match(err));
883
904
  const msg = def.message(err);
884
- console.error(chalk.redBright("\u2716 Error:"), chalk.red(msg));
905
+ console.error(this.chalk.redBright("\u2716 Error:"), this.chalk.red(msg));
885
906
  process.exit(1);
886
907
  }
887
- static async warn(message) {
888
- const chalk = this.chalk;
889
- console.warn(chalk.yellowBright("\u26A0 Warning:"), chalk.yellow(message));
908
+ static warn(message) {
909
+ console.warn(this.chalk.yellowBright("\u26A0 Warning:"), this.chalk.yellow(message));
890
910
  }
891
- static async success(message) {
892
- const chalk = this.chalk;
893
- console.log(chalk.greenBright("\u2714 Success:"), chalk.green(message));
911
+ static success(message) {
912
+ console.log(this.chalk.greenBright(" \u2714 Success:"), this.chalk.green(message));
894
913
  }
895
914
  static async info(message) {
896
- const chalk = this.chalk;
897
- console.log(chalk.blue(message));
915
+ console.log(this.chalk.blue(message));
898
916
  }
899
917
  static async startSpinner(message) {
900
- const ora = this.ora;
901
- this.spinner = ora({ text: message, color: "cyan" }).start();
918
+ this.spinner = this.ora({ text: message, color: "cyan" }).start();
902
919
  }
903
920
  static stopSpinnerSuccess(message) {
904
921
  this.spinner?.succeed(message);
@@ -993,7 +1010,8 @@ var TunnelManager = class _TunnelManager {
993
1010
  tunnelConfig: config,
994
1011
  additionalForwarding,
995
1012
  serve: config.serve,
996
- warnings: []
1013
+ warnings: [],
1014
+ isStopped: false
997
1015
  };
998
1016
  this.setupStatsCallback(tunnelid, managed);
999
1017
  this.setupErrorCallback(tunnelid, managed);
@@ -1062,7 +1080,15 @@ var TunnelManager = class _TunnelManager {
1062
1080
  }
1063
1081
  this.tunnelStats.delete(tunnelId);
1064
1082
  this.tunnelStatsListeners.delete(tunnelId);
1065
- logger.info("Tunnel stopped", { tunnelId });
1083
+ this.tunnelStats.delete(tunnelId);
1084
+ this.tunnelStatsListeners.delete(tunnelId);
1085
+ this.tunnelErrorListeners.delete(tunnelId);
1086
+ this.tunnelDisconnectListeners.delete(tunnelId);
1087
+ this.tunnelWorkerErrorListeners.delete(tunnelId);
1088
+ managed.serveWorker = null;
1089
+ managed.warnings = managed.warnings ?? [];
1090
+ managed.isStopped = true;
1091
+ logger.info("Tunnel stopped", { tunnelId, configId: managed.configid });
1066
1092
  return { configid: managed.configid, tunnelid: managed.tunnelid };
1067
1093
  } catch (error) {
1068
1094
  logger.error("Failed to stop tunnel", { tunnelId, error });
@@ -1073,28 +1099,40 @@ var TunnelManager = class _TunnelManager {
1073
1099
  * Get all public URLs for a tunnel
1074
1100
  */
1075
1101
  async getTunnelUrls(tunnelId) {
1076
- const managed = this.tunnelsByTunnelId.get(tunnelId);
1077
- if (!managed) {
1078
- logger.error(`Tunnel "${tunnelId}" not found when fetching URLs`);
1079
- throw new Error(`Tunnel "${tunnelId}" not found`);
1102
+ try {
1103
+ const managed = this.tunnelsByTunnelId.get(tunnelId);
1104
+ if (!managed || managed.isStopped) {
1105
+ logger.error(`Tunnel "${tunnelId}" not found when fetching URLs`);
1106
+ return [];
1107
+ }
1108
+ const urls = await managed.instance.urls();
1109
+ logger.debug("Queried tunnel URLs", { tunnelId, urls });
1110
+ return urls;
1111
+ } catch (error) {
1112
+ logger.error("Error fetching tunnel URLs", { tunnelId, error });
1113
+ throw error;
1080
1114
  }
1081
- const urls = await managed.instance.urls();
1082
- logger.debug("Queried tunnel URLs", { tunnelId, urls });
1083
- return urls;
1084
1115
  }
1085
1116
  /**
1086
1117
  * Get all TunnelStatus currently managed by this TunnelManager
1087
1118
  * @returns An array of all TunnelStatus objects
1088
1119
  */
1089
1120
  async getAllTunnels() {
1090
- const tunnelList = await Promise.all(Array.from(this.tunnelsByTunnelId.values()).map(async (tunnel) => ({
1091
- tunnelid: tunnel.tunnelid,
1092
- configid: tunnel.configid,
1093
- tunnelName: tunnel.tunnelName,
1094
- tunnelConfig: tunnel.tunnelConfig,
1095
- remoteurls: await this.getTunnelUrls(tunnel.tunnelid)
1096
- })));
1097
- return tunnelList;
1121
+ try {
1122
+ const tunnelList = await Promise.all(Array.from(this.tunnelsByTunnelId.values()).map(async (tunnel) => {
1123
+ return {
1124
+ tunnelid: tunnel.tunnelid,
1125
+ configid: tunnel.configid,
1126
+ tunnelName: tunnel.tunnelName,
1127
+ tunnelConfig: tunnel.tunnelConfig,
1128
+ remoteurls: !tunnel.isStopped ? await this.getTunnelUrls(tunnel.tunnelid) : []
1129
+ };
1130
+ }));
1131
+ return tunnelList;
1132
+ } catch (err) {
1133
+ logger.error("Error fetching tunnels", { error: err });
1134
+ return [];
1135
+ }
1098
1136
  }
1099
1137
  /**
1100
1138
  * Get status of a tunnel
@@ -1105,6 +1143,9 @@ var TunnelManager = class _TunnelManager {
1105
1143
  logger.error(`Tunnel "${tunnelId}" not found when fetching status`);
1106
1144
  throw new Error(`Tunnel "${tunnelId}" not found`);
1107
1145
  }
1146
+ if (managed.isStopped) {
1147
+ return "exited";
1148
+ }
1108
1149
  const status = await managed.instance.getStatus();
1109
1150
  logger.debug("Queried tunnel status", { tunnelId, status });
1110
1151
  return status;
@@ -1316,6 +1357,10 @@ var TunnelManager = class _TunnelManager {
1316
1357
  return null;
1317
1358
  }
1318
1359
  try {
1360
+ if (managed.isStopped) {
1361
+ logger.debug(`Tunnel "${tunnelId}" is stopped. No greet message available.`);
1362
+ return null;
1363
+ }
1319
1364
  const messages = await managed.instance.getGreetMessage();
1320
1365
  if (Array.isArray(messages)) {
1321
1366
  return messages.join(" ");
@@ -1460,6 +1505,10 @@ var TunnelManager = class _TunnelManager {
1460
1505
  return false;
1461
1506
  }
1462
1507
  try {
1508
+ if (managed.isStopped) {
1509
+ logger.debug(`Tunnel "${tunnelId}" is stopped. Cannot fetch local server TLS info`);
1510
+ return false;
1511
+ }
1463
1512
  const tlsInfo = await managed.instance.getLocalServerTls();
1464
1513
  if (tlsInfo) {
1465
1514
  return tlsInfo;
@@ -1572,12 +1621,14 @@ var TunnelManager = class _TunnelManager {
1572
1621
  updateStats(tunnelId, rawUsage) {
1573
1622
  try {
1574
1623
  const normalizedStats = this.normalizeStats(rawUsage);
1575
- this.tunnelStats.set(tunnelId, normalizedStats);
1624
+ const existingStats = this.tunnelStats.get(tunnelId) || [];
1625
+ const updatedStats = [...existingStats, normalizedStats];
1626
+ this.tunnelStats.set(tunnelId, updatedStats);
1576
1627
  const tunnelListeners = this.tunnelStatsListeners.get(tunnelId);
1577
1628
  if (tunnelListeners) {
1578
1629
  for (const [listenerId, listener] of tunnelListeners) {
1579
1630
  try {
1580
- listener(tunnelId, normalizedStats);
1631
+ listener(tunnelId, updatedStats);
1581
1632
  } catch (error) {
1582
1633
  logger.warn("Error in stats listener callback", { listenerId, tunnelId, error });
1583
1634
  }
@@ -2299,7 +2350,7 @@ var HeaderModificationSchema = import_zod.z.object({
2299
2350
  type: import_zod.z.enum(["add", "remove", "update"])
2300
2351
  });
2301
2352
  var TunnelConfigSchema = import_zod.z.object({
2302
- allowpreflight: import_zod.z.boolean(),
2353
+ allowPreflight: import_zod.z.boolean(),
2303
2354
  autoreconnect: import_zod.z.boolean(),
2304
2355
  basicauth: import_zod.z.array(import_zod.z.object({ username: import_zod.z.string(), password: import_zod.z.string() })).nullable(),
2305
2356
  bearerauth: import_zod.z.string().nullable(),
@@ -2353,7 +2404,7 @@ function tunnelConfigToPinggyOptions(config) {
2353
2404
  xForwardedFor: !!config.xff,
2354
2405
  httpsOnly: config.httpsOnly,
2355
2406
  originalRequestUrl: config.fullRequestUrl,
2356
- allowPreflight: config.allowpreflight,
2407
+ allowPreflight: config.allowPreflight,
2357
2408
  reverseProxy: config.noReverseProxy,
2358
2409
  force: config.force,
2359
2410
  optional: {
@@ -2366,7 +2417,7 @@ function pinggyOptionsToTunnelConfig(opts, configid, configName, localserverTls,
2366
2417
  const tunnelType = Array.isArray(opts.tunnelType) ? opts.tunnelType[0] : opts.tunnelType ?? "http";
2367
2418
  const parsedTokens = opts.bearerTokenAuth ? Array.isArray(opts.bearerTokenAuth) ? opts.bearerTokenAuth : JSON.parse(opts.bearerTokenAuth) : [];
2368
2419
  return {
2369
- allowpreflight: opts.allowPreflight ?? false,
2420
+ allowPreflight: opts.allowPreflight ?? false,
2370
2421
  autoreconnect: true,
2371
2422
  basicauth: opts.basicAuth && Object.keys(opts.basicAuth).length ? opts.basicAuth : null,
2372
2423
  bearerauth: parsedTokens.length ? parsedTokens.join(",") : null,
@@ -2460,21 +2511,25 @@ var TunnelOperations = class {
2460
2511
  async handleList() {
2461
2512
  try {
2462
2513
  const tunnels = await this.tunnelManager.getAllTunnels();
2514
+ if (tunnels.length === 0) {
2515
+ return [];
2516
+ }
2463
2517
  return Promise.all(
2464
2518
  tunnels.map(async (t) => {
2465
- const stats = this.tunnelManager.getTunnelStats(t.tunnelid) ?? newStats();
2466
- const [status, config, tlsInfo, greetMsg] = await Promise.all([
2519
+ const rawStats = this.tunnelManager.getTunnelStats(t.tunnelid);
2520
+ const stats = rawStats ?? newStats();
2521
+ const [status, tlsInfo, greetMsg] = await Promise.all([
2467
2522
  this.tunnelManager.getTunnelStatus(t.tunnelid),
2468
- this.tunnelManager.getTunnelConfig("", t.tunnelid),
2469
2523
  this.tunnelManager.getLocalserverTlsInfo(t.tunnelid),
2470
2524
  this.tunnelManager.getTunnelGreetMessage(t.tunnelid)
2471
2525
  ]);
2526
+ const tunnelConfig = pinggyOptionsToTunnelConfig(t.tunnelConfig, t.configid, t.tunnelName, tlsInfo, greetMsg);
2472
2527
  return {
2473
2528
  tunnelid: t.tunnelid,
2474
2529
  remoteurls: t.remoteurls,
2475
2530
  status: newStatus(status, "" /* NoError */, ""),
2476
2531
  stats,
2477
- tunnelconfig: pinggyOptionsToTunnelConfig(config, t.configid, t.tunnelName, tlsInfo, greetMsg)
2532
+ tunnelconfig: tunnelConfig
2478
2533
  };
2479
2534
  })
2480
2535
  );
@@ -2511,6 +2566,12 @@ var TunnelOperations = class {
2511
2566
  return this.error(ErrorCode.TunnelNotFound, err, "Failed to restart tunnel");
2512
2567
  }
2513
2568
  }
2569
+ handleRegisterStatsListener(tunnelid, listener) {
2570
+ this.tunnelManager.registerStatsListener(tunnelid, listener);
2571
+ }
2572
+ handleUnregisterStatsListener(tunnelid, listnerId) {
2573
+ this.tunnelManager.deregisterStatsListener(tunnelid, listnerId);
2574
+ }
2514
2575
  };
2515
2576
 
2516
2577
  // src/remote_management/websocket_handlers.ts
@@ -2777,8 +2838,37 @@ async function initiateRemoteManagement(token, manage) {
2777
2838
  // src/utils/parseArgs.ts
2778
2839
  init_cjs_shims();
2779
2840
  var import_util2 = require("util");
2841
+ var os = __toESM(require("os"), 1);
2842
+ function isInlineColonFlag(arg) {
2843
+ return /^-([RL])[A-Za-z0-9._-]*:?$/.test(arg);
2844
+ }
2845
+ function preprocessWindowsArgs(args) {
2846
+ if (os.platform() !== "win32") return args;
2847
+ const out = [];
2848
+ let i = 0;
2849
+ while (i < args.length) {
2850
+ const arg = args[i];
2851
+ if (isInlineColonFlag(arg)) {
2852
+ if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
2853
+ let merged = arg + args[i + 1];
2854
+ i += 2;
2855
+ out.push(merged);
2856
+ continue;
2857
+ }
2858
+ out.push(arg);
2859
+ i++;
2860
+ continue;
2861
+ }
2862
+ out.push(arg);
2863
+ i++;
2864
+ }
2865
+ return out;
2866
+ }
2780
2867
  function parseCliArgs(options) {
2868
+ const rawArgs = process.argv.slice(2);
2869
+ const processedArgs = preprocessWindowsArgs(rawArgs);
2781
2870
  const parsed = (0, import_util2.parseArgs)({
2871
+ args: processedArgs,
2782
2872
  options,
2783
2873
  allowPositionals: true
2784
2874
  });
@@ -2907,6 +2997,7 @@ async function startCli(finalConfig, manager) {
2907
2997
  const { withFullScreen } = await import("fullscreen-ink");
2908
2998
  const { default: TunnelTui2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
2909
2999
  const React3 = await import("react");
3000
+ const isTTYEnabled = process.stdin.isTTY;
2910
3001
  const TunnelTuiWrapper = ({ finalConfig: finalConfig2, urls, greet }) => {
2911
3002
  const [disconnectInfo, setDisconnectInfo] = React3.useState(null);
2912
3003
  React3.useEffect(() => {
@@ -2936,13 +3027,17 @@ async function startCli(finalConfig, manager) {
2936
3027
  )
2937
3028
  );
2938
3029
  activeTui = tui;
2939
- try {
2940
- await tui.start();
2941
- await tui.waitUntilExit();
2942
- } catch (e) {
2943
- logger.warn("TUI error", e);
2944
- } finally {
2945
- activeTui = null;
3030
+ if (isTTYEnabled) {
3031
+ try {
3032
+ await tui.start();
3033
+ await tui.waitUntilExit();
3034
+ } catch (e) {
3035
+ logger.warn("TUI error", e);
3036
+ } finally {
3037
+ activeTui = null;
3038
+ }
3039
+ } else {
3040
+ printer_default.warn("Unable to initiate the TUI: your terminal does not support the required input mode.");
2946
3041
  }
2947
3042
  }
2948
3043
  } catch (err) {
@@ -2956,6 +3051,7 @@ async function startCli(finalConfig, manager) {
2956
3051
  var import_url = require("url");
2957
3052
  var import_process = require("process");
2958
3053
  var import_fs3 = require("fs");
3054
+ init_logger();
2959
3055
  async function main() {
2960
3056
  try {
2961
3057
  const { values, positionals, hasAnyArgs } = parseCliArgs(cliOptions);
@@ -3004,5 +3100,6 @@ if (entryFile && entryFile === currentFile) {
3004
3100
  // Annotate the CommonJS export names for ESM import in node:
3005
3101
  0 && (module.exports = {
3006
3102
  TunnelManager,
3007
- TunnelOperations
3103
+ TunnelOperations,
3104
+ enablePackageLogging
3008
3105
  });
package/dist/index.d.cts CHANGED
@@ -2,6 +2,7 @@
2
2
  import { PinggyOptions, TunnelInstance, TunnelUsageType, TunnelType } from '@pinggy/pinggy';
3
3
  import { Worker } from 'node:worker_threads';
4
4
  import { z } from 'zod';
5
+ import winston from 'winston';
5
6
 
6
7
  interface AdditionalForwarding {
7
8
  remoteDomain?: string;
@@ -73,6 +74,7 @@ interface ManagedTunnel {
73
74
  serveWorker?: Worker | null;
74
75
  warnings?: Warning[];
75
76
  serve?: string;
77
+ isStopped?: boolean;
76
78
  }
77
79
  interface TunnelList {
78
80
  tunnelid: string;
@@ -81,7 +83,7 @@ interface TunnelList {
81
83
  tunnelConfig: PinggyOptions;
82
84
  remoteurls: string[];
83
85
  }
84
- type StatsListener = (tunnelId: string, stats: TunnelUsageType) => void;
86
+ type StatsListener = (tunnelId: string, stats: TunnelUsageType[]) => void;
85
87
  type ErrorListener = (tunnelId: string, errorMsg: string, isFatal: boolean) => void;
86
88
  type DisconnectListener = (tunnelId: string, error: string, messages: string[]) => void;
87
89
  type TunnelWorkerErrorListner = (tunnelid: string, error: Error) => void;
@@ -112,7 +114,7 @@ interface ITunnelManager {
112
114
  }): Promise<ManagedTunnel>;
113
115
  getManagedTunnel(configId?: string, tunnelId?: string): ManagedTunnel;
114
116
  getTunnelGreetMessage(tunnelId: string): Promise<string | null>;
115
- getTunnelStats(tunnelId: string): TunnelUsageType | null;
117
+ getTunnelStats(tunnelId: string): TunnelUsageType[] | null;
116
118
  registerStatsListener(tunnelId: string, listener: StatsListener): Promise<string>;
117
119
  registerErrorListener(tunnelId: string, listener: ErrorListener): Promise<string>;
118
120
  registerWorkerErrorListner(tunnelId: string, listener: TunnelWorkerErrorListner): void;
@@ -244,7 +246,7 @@ declare class TunnelManager implements ITunnelManager {
244
246
  */
245
247
  getManagedTunnel(configId?: string, tunnelId?: string): ManagedTunnel;
246
248
  getTunnelGreetMessage(tunnelId: string): Promise<string | null>;
247
- getTunnelStats(tunnelId: string): TunnelUsageType | null;
249
+ getTunnelStats(tunnelId: string): TunnelUsageType[] | null;
248
250
  /**
249
251
  * Registers a listener function to receive tunnel statistics updates.
250
252
  * The listener will be called whenever any tunnel's stats are updated.
@@ -289,7 +291,7 @@ declare class TunnelManager implements ITunnelManager {
289
291
  }
290
292
 
291
293
  declare const TunnelConfigSchema: z.ZodObject<{
292
- allowpreflight: z.ZodBoolean;
294
+ allowPreflight: z.ZodBoolean;
293
295
  autoreconnect: z.ZodBoolean;
294
296
  basicauth: z.ZodNullable<z.ZodArray<z.ZodObject<{
295
297
  username: z.ZodString;
@@ -341,7 +343,7 @@ interface TunnelResponse {
341
343
  remoteurls: string[];
342
344
  tunnelconfig: TunnelConfig;
343
345
  status: Status;
344
- stats: TunnelUsageType;
346
+ stats: TunnelUsageType[];
345
347
  }
346
348
  interface TunnelHandler {
347
349
  handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
@@ -350,6 +352,8 @@ interface TunnelHandler {
350
352
  handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
351
353
  handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
352
354
  handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
355
+ handleRegisterStatsListener(tunnelid: string, listener: (tunnelId: string, stats: TunnelUsageType[]) => void): void;
356
+ handleUnregisterStatsListener(tunnelid: string, listnerId: string): void;
353
357
  }
354
358
  declare class TunnelOperations implements TunnelHandler {
355
359
  private tunnelManager;
@@ -362,6 +366,19 @@ declare class TunnelOperations implements TunnelHandler {
362
366
  handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
363
367
  handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
364
368
  handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
369
+ handleRegisterStatsListener(tunnelid: string, listener: (tunnelId: string, stats: TunnelUsageType[]) => void): void;
370
+ handleUnregisterStatsListener(tunnelid: string, listnerId: string): void;
365
371
  }
366
372
 
367
- export { TunnelManager, TunnelOperations, type TunnelResponse };
373
+ interface BaseLogConfig {
374
+ level?: string;
375
+ filePath?: string;
376
+ stdout?: boolean;
377
+ source?: boolean;
378
+ silent?: boolean;
379
+ enableSdkLog?: boolean;
380
+ }
381
+ type BaseLogConfigType = BaseLogConfig;
382
+ declare function enablePackageLogging(opts?: BaseLogConfigType): winston.Logger;
383
+
384
+ export { TunnelManager, TunnelOperations, type TunnelResponse, enablePackageLogging };