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/{chunk-HUN2MRZO.js → chunk-3RTRUYNW.js} +3 -1
- package/dist/{chunk-MBN3YBO4.js → chunk-STEISST3.js} +203 -41
- package/dist/index.cjs +357 -103
- package/dist/index.d.cts +20 -11
- package/dist/index.d.ts +20 -11
- package/dist/index.js +10 -7
- package/dist/{main-PFPDXIRG.js → main-XKFFUSKJ.js} +148 -59
- package/dist/workers/file_serve_worker.js +1 -1
- package/package.json +3 -2
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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)
|
|
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
|
-
|
|
2781
|
-
|
|
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
|
-
|
|
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.
|
|
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)
|
|
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 (
|
|
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 (
|
|
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)
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
if (parsed.
|
|
3223
|
-
|
|
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)
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
if (parsed.
|
|
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")
|
|
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)
|
|
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)
|
|
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 =
|
|
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 || !
|
|
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 (!
|
|
3565
|
+
if (!isValidServerAddress(remoteDomainRaw)) {
|
|
3370
3566
|
return new Error("invalid remote domain");
|
|
3371
3567
|
}
|
|
3372
|
-
protocol =
|
|
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)
|
|
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)
|
|
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")
|
|
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)
|
|
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
|
|
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)
|
|
3757
|
+
if (dbgErr instanceof Error) {
|
|
3758
|
+
throw dbgErr;
|
|
3759
|
+
}
|
|
3554
3760
|
const lpErr = parseLocalPort(finalConfig, values);
|
|
3555
|
-
if (lpErr instanceof Error)
|
|
3761
|
+
if (lpErr instanceof Error) {
|
|
3762
|
+
throw lpErr;
|
|
3763
|
+
}
|
|
3556
3764
|
const rErr = parseReverseTunnelAddr(finalConfig, values, type);
|
|
3557
|
-
if (rErr instanceof Error)
|
|
3765
|
+
if (rErr instanceof Error) {
|
|
3766
|
+
throw rErr;
|
|
3767
|
+
}
|
|
3558
3768
|
const lErr = parseLocalTunnelAddr(finalConfig, values);
|
|
3559
|
-
if (lErr instanceof Error)
|
|
3769
|
+
if (lErr instanceof Error) {
|
|
3770
|
+
throw lErr;
|
|
3771
|
+
}
|
|
3560
3772
|
const serveErr = parseServe(finalConfig, values);
|
|
3561
|
-
if (serveErr instanceof Error)
|
|
3773
|
+
if (serveErr instanceof Error) {
|
|
3774
|
+
throw serveErr;
|
|
3775
|
+
}
|
|
3562
3776
|
const autoReconnectErr = parseAutoReconnect(finalConfig, values);
|
|
3563
|
-
if (autoReconnectErr instanceof Error)
|
|
3564
|
-
|
|
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 = [
|
|
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("-"))
|
|
3602
|
-
|
|
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(":"))
|
|
3605
|
-
|
|
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")
|
|
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
|
|
3697
|
-
type: "
|
|
3698
|
-
|
|
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(
|
|
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?.
|
|
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
|
-
|
|
4133
|
-
|
|
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?.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
});
|