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.
- package/dist/{chunk-WEG3ISRS.js → chunk-HUN2MRZO.js} +43 -21
- package/dist/index.cjs +166 -69
- package/dist/index.d.cts +23 -6
- package/dist/index.d.ts +23 -6
- package/dist/index.js +124 -49
- package/dist/{tui-KEHUQT7G.js → tui-TJXEPR3U.js} +2 -2
- package/package.json +2 -2
- package/src/cli/starCli.tsx +13 -9
- package/src/index.ts +2 -1
- package/src/logger.ts +64 -31
- package/src/remote_management/handler.ts +23 -9
- package/src/remote_management/remote_schema.ts +3 -3
- package/src/tui/sections/URLsSection.tsx +1 -1
- package/src/tunnel_manager/TunnelManager.ts +61 -23
- package/src/utils/parseArgs.ts +42 -0
- package/src/utils/printer.ts +9 -14
|
@@ -11,21 +11,24 @@ function getLogger() {
|
|
|
11
11
|
return _logger;
|
|
12
12
|
}
|
|
13
13
|
var logger = getLogger();
|
|
14
|
-
function
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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}]
|
|
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
|
|
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
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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}]
|
|
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
|
|
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
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
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
|
|
888
|
-
|
|
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
|
|
892
|
-
|
|
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
|
-
|
|
897
|
-
console.log(chalk.blue(message));
|
|
915
|
+
console.log(this.chalk.blue(message));
|
|
898
916
|
}
|
|
899
917
|
static async startSpinner(message) {
|
|
900
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
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
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
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.
|
|
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,
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
2466
|
-
const
|
|
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:
|
|
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
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|