pinggy 0.3.8 → 0.3.10
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/README.md +2 -1
- package/dist/{chunk-65R2GMKQ.js → chunk-MBN3YBO4.js} +756 -182
- package/dist/index.cjs +860 -252
- package/dist/index.d.cts +112 -75
- package/dist/index.d.ts +112 -75
- package/dist/index.js +2 -2
- package/dist/{main-2QDG7PWL.js → main-VCUAV22W.js} +51 -32
- package/jest.config.cjs +13 -0
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -118,6 +118,9 @@ var init_printer = __esm({
|
|
|
118
118
|
console.error(import_picocolors2.default.red(import_picocolors2.default.bold("\u2716 Error:")), import_picocolors2.default.red(msg));
|
|
119
119
|
process.exit(1);
|
|
120
120
|
}
|
|
121
|
+
static red(message) {
|
|
122
|
+
return import_picocolors2.default.red(message);
|
|
123
|
+
}
|
|
121
124
|
static warn(message) {
|
|
122
125
|
console.warn(import_picocolors2.default.yellow(import_picocolors2.default.bold("\u26A0 Warning:")), import_picocolors2.default.yellow(message));
|
|
123
126
|
}
|
|
@@ -146,7 +149,7 @@ var init_printer = __esm({
|
|
|
146
149
|
message: (err) => {
|
|
147
150
|
const match = /Unknown option '(.+?)'/.exec(err.message);
|
|
148
151
|
const option = match ? match[1] : "(unknown)";
|
|
149
|
-
return `Unknown option '${option}'. Please check your command or use pinggy
|
|
152
|
+
return `Unknown option '${option}'. Please check your command or use pinggy -h for guidance.`;
|
|
150
153
|
}
|
|
151
154
|
},
|
|
152
155
|
{
|
|
@@ -283,22 +286,32 @@ function isValidPort(p) {
|
|
|
283
286
|
return Number.isInteger(p) && p > 0 && p < 65536;
|
|
284
287
|
}
|
|
285
288
|
function getVersion() {
|
|
286
|
-
|
|
289
|
+
try {
|
|
290
|
+
const packageJsonPath = (0, import_path3.join)(__dirname, "../package.json");
|
|
291
|
+
const pkg = JSON.parse((0, import_fs3.readFileSync)(packageJsonPath, "utf-8"));
|
|
292
|
+
return pkg.version ?? "";
|
|
293
|
+
} catch (error) {
|
|
294
|
+
printer_default.error("Error reading version info");
|
|
295
|
+
return "";
|
|
296
|
+
}
|
|
287
297
|
}
|
|
288
|
-
var
|
|
298
|
+
var import_fs3, import_crypto, import_url, import_path3, __filename2, __dirname;
|
|
289
299
|
var init_util = __esm({
|
|
290
300
|
"src/utils/util.ts"() {
|
|
291
301
|
"use strict";
|
|
292
302
|
init_cjs_shims();
|
|
293
|
-
|
|
303
|
+
import_fs3 = require("fs");
|
|
294
304
|
import_crypto = require("crypto");
|
|
295
|
-
|
|
296
|
-
|
|
305
|
+
import_url = require("url");
|
|
306
|
+
import_path3 = require("path");
|
|
307
|
+
init_printer();
|
|
308
|
+
__filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
|
|
309
|
+
__dirname = (0, import_path3.dirname)(__filename2);
|
|
297
310
|
}
|
|
298
311
|
});
|
|
299
312
|
|
|
300
313
|
// src/tunnel_manager/TunnelManager.ts
|
|
301
|
-
var import_pinggy2, import_node_path, import_node_worker_threads, import_node_url,
|
|
314
|
+
var import_pinggy2, import_node_path, import_node_worker_threads, import_node_url, __filename3, __dirname2, TunnelManager;
|
|
302
315
|
var init_TunnelManager = __esm({
|
|
303
316
|
"src/tunnel_manager/TunnelManager.ts"() {
|
|
304
317
|
"use strict";
|
|
@@ -310,8 +323,8 @@ var init_TunnelManager = __esm({
|
|
|
310
323
|
import_node_url = require("url");
|
|
311
324
|
init_printer();
|
|
312
325
|
init_util();
|
|
313
|
-
|
|
314
|
-
|
|
326
|
+
__filename3 = (0, import_node_url.fileURLToPath)(importMetaUrl);
|
|
327
|
+
__dirname2 = import_node_path.default.dirname(__filename3);
|
|
315
328
|
TunnelManager = class _TunnelManager {
|
|
316
329
|
constructor() {
|
|
317
330
|
this.tunnelsByTunnelId = /* @__PURE__ */ new Map();
|
|
@@ -319,6 +332,7 @@ var init_TunnelManager = __esm({
|
|
|
319
332
|
this.tunnelStats = /* @__PURE__ */ new Map();
|
|
320
333
|
this.tunnelStatsListeners = /* @__PURE__ */ new Map();
|
|
321
334
|
this.tunnelErrorListeners = /* @__PURE__ */ new Map();
|
|
335
|
+
this.tunnelPollingErrorListeners = /* @__PURE__ */ new Map();
|
|
322
336
|
this.tunnelDisconnectListeners = /* @__PURE__ */ new Map();
|
|
323
337
|
this.tunnelWorkerErrorListeners = /* @__PURE__ */ new Map();
|
|
324
338
|
this.tunnelStartListeners = /* @__PURE__ */ new Map();
|
|
@@ -335,12 +349,9 @@ var init_TunnelManager = __esm({
|
|
|
335
349
|
}
|
|
336
350
|
/**
|
|
337
351
|
* Creates a new managed tunnel instance with the given configuration.
|
|
338
|
-
*
|
|
352
|
+
* Optionally builds the config with forwarding rules based on buildConfig flag.
|
|
339
353
|
*
|
|
340
354
|
* @param config - The tunnel configuration options
|
|
341
|
-
* @param config.configid - Unique identifier for the tunnel configuration
|
|
342
|
-
* @param config.tunnelid - Optional custom tunnel identifier. If not provided, a random UUID will be generated
|
|
343
|
-
* @param config.additionalForwarding - Optional array of additional forwarding configurations
|
|
344
355
|
*
|
|
345
356
|
* @throws {Error} When configId is invalid or empty
|
|
346
357
|
* @throws {Error} When a tunnel with the given configId already exists
|
|
@@ -349,24 +360,19 @@ var init_TunnelManager = __esm({
|
|
|
349
360
|
* status information, and statistics
|
|
350
361
|
*/
|
|
351
362
|
async createTunnel(config) {
|
|
352
|
-
const {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
throw new Error(`Tunnel with configId "${configid}" already exists`);
|
|
363
|
+
const { configId, tunnelid: requestedTunnelId, tunnelName, name, serve } = config;
|
|
364
|
+
const tunnelid = requestedTunnelId || getRandomId();
|
|
365
|
+
const autoReconnect = config.autoReconnect || false;
|
|
366
|
+
if (!configId || typeof configId !== "string" || configId.trim() === "") {
|
|
367
|
+
throw new Error("configId is required and must be a non-empty string");
|
|
358
368
|
}
|
|
359
|
-
const tunnelid = config.tunnelid || getRandomId();
|
|
360
|
-
const configWithForwarding = this.buildPinggyConfig(config, additionalForwarding);
|
|
361
369
|
return this._createTunnelWithProcessedConfig({
|
|
362
|
-
|
|
370
|
+
configId,
|
|
363
371
|
tunnelid,
|
|
364
|
-
tunnelName,
|
|
372
|
+
tunnelName: tunnelName || name,
|
|
365
373
|
originalConfig: config,
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
serve: config.serve,
|
|
369
|
-
autoReconnect: config.autoReconnect !== void 0 ? config.autoReconnect : false
|
|
374
|
+
serve,
|
|
375
|
+
autoReconnect
|
|
370
376
|
});
|
|
371
377
|
}
|
|
372
378
|
/**
|
|
@@ -380,7 +386,8 @@ var init_TunnelManager = __esm({
|
|
|
380
386
|
async _createTunnelWithProcessedConfig(params) {
|
|
381
387
|
let instance;
|
|
382
388
|
try {
|
|
383
|
-
instance
|
|
389
|
+
logger.debug("Creating tunnel instance with processed config", params.originalConfig);
|
|
390
|
+
instance = await import_pinggy2.pinggy.createTunnel(params.originalConfig);
|
|
384
391
|
} catch (e) {
|
|
385
392
|
logger.error("Error creating tunnel instance:", e);
|
|
386
393
|
throw e;
|
|
@@ -388,25 +395,25 @@ var init_TunnelManager = __esm({
|
|
|
388
395
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
389
396
|
const managed = {
|
|
390
397
|
tunnelid: params.tunnelid,
|
|
391
|
-
|
|
398
|
+
configId: params.configId,
|
|
392
399
|
tunnelName: params.tunnelName,
|
|
393
400
|
instance,
|
|
394
401
|
tunnelConfig: params.originalConfig,
|
|
395
|
-
configWithForwarding: params.configWithForwarding,
|
|
396
|
-
additionalForwarding: params.additionalForwarding,
|
|
397
402
|
serve: params.serve,
|
|
398
403
|
warnings: [],
|
|
399
404
|
isStopped: false,
|
|
400
405
|
createdAt: now,
|
|
401
406
|
startedAt: null,
|
|
402
407
|
stoppedAt: null,
|
|
403
|
-
autoReconnect: params.autoReconnect
|
|
408
|
+
autoReconnect: params.autoReconnect,
|
|
409
|
+
lastError: {}
|
|
404
410
|
};
|
|
405
411
|
instance.setTunnelEstablishedCallback(({}) => {
|
|
406
412
|
managed.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
407
413
|
});
|
|
408
414
|
this.setupStatsCallback(params.tunnelid, managed);
|
|
409
415
|
this.setupErrorCallback(params.tunnelid, managed);
|
|
416
|
+
this.setupTunnelPollingErrorCallback(params.tunnelid, managed);
|
|
410
417
|
this.setupDisconnectCallback(params.tunnelid, managed);
|
|
411
418
|
this.setupWillReconnectCallback(params.tunnelid, managed);
|
|
412
419
|
this.setupReconnectingCallback(params.tunnelid, managed);
|
|
@@ -414,44 +421,10 @@ var init_TunnelManager = __esm({
|
|
|
414
421
|
this.setupReconnectionFailedCallback(params.tunnelid, managed);
|
|
415
422
|
this.setUpTunnelWorkerErrorCallback(params.tunnelid, managed);
|
|
416
423
|
this.tunnelsByTunnelId.set(params.tunnelid, managed);
|
|
417
|
-
this.tunnelsByConfigId.set(params.
|
|
418
|
-
logger.info("Tunnel created", {
|
|
424
|
+
this.tunnelsByConfigId.set(params.configId, managed);
|
|
425
|
+
logger.info("Tunnel created", { configId: params.configId, tunnelId: params.tunnelid });
|
|
419
426
|
return managed;
|
|
420
427
|
}
|
|
421
|
-
/**
|
|
422
|
-
* Builds the Pinggy configuration by merging the default forwarding rule
|
|
423
|
-
* with additional forwarding rules from additionalForwarding array.
|
|
424
|
-
*
|
|
425
|
-
* @param config - The base Pinggy configuration
|
|
426
|
-
* @param additionalForwarding - Optional array of additional forwarding rules
|
|
427
|
-
* @returns Modified PinggyOptions
|
|
428
|
-
*/
|
|
429
|
-
buildPinggyConfig(config, additionalForwarding) {
|
|
430
|
-
const forwardingRules = [];
|
|
431
|
-
if (config.forwarding) {
|
|
432
|
-
forwardingRules.push({
|
|
433
|
-
type: config.tunnelType && config.tunnelType[0] || "http",
|
|
434
|
-
address: config.forwarding
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
if (Array.isArray(additionalForwarding) && additionalForwarding.length > 0) {
|
|
438
|
-
for (const rule of additionalForwarding) {
|
|
439
|
-
if (rule && rule.localDomain && rule.localPort && rule.remoteDomain && isValidPort(rule.localPort)) {
|
|
440
|
-
const forwardingRule = {
|
|
441
|
-
type: rule.protocol,
|
|
442
|
-
// In Future we can make this dynamic based on user input
|
|
443
|
-
address: `${rule.localDomain}:${rule.localPort}`,
|
|
444
|
-
listenAddress: rule.remotePort && isValidPort(rule.remotePort) ? `${rule.remoteDomain}:${rule.remotePort}` : rule.remoteDomain
|
|
445
|
-
};
|
|
446
|
-
forwardingRules.push(forwardingRule);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return {
|
|
451
|
-
...config,
|
|
452
|
-
forwarding: forwardingRules.length > 0 ? forwardingRules : config.forwarding
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
428
|
/**
|
|
456
429
|
* Start a tunnel that was created but not yet started
|
|
457
430
|
*/
|
|
@@ -463,7 +436,14 @@ var init_TunnelManager = __esm({
|
|
|
463
436
|
try {
|
|
464
437
|
urls = await managed.instance.start();
|
|
465
438
|
} catch (error) {
|
|
466
|
-
logger.
|
|
439
|
+
logger.warn("Failed to start tunnel", { tunnelId, error });
|
|
440
|
+
managed.isStopped = true;
|
|
441
|
+
managed.stoppedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
442
|
+
managed.lastError = {
|
|
443
|
+
message: "Failed to start tunnel",
|
|
444
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
445
|
+
isFatal: true
|
|
446
|
+
};
|
|
467
447
|
throw error;
|
|
468
448
|
}
|
|
469
449
|
logger.info("Tunnel started", { tunnelId, urls });
|
|
@@ -499,7 +479,7 @@ var init_TunnelManager = __esm({
|
|
|
499
479
|
stopTunnel(tunnelId) {
|
|
500
480
|
const managed = this.tunnelsByTunnelId.get(tunnelId);
|
|
501
481
|
if (!managed) throw new Error(`Tunnel "${tunnelId}" not found`);
|
|
502
|
-
logger.info("Stopping tunnel", { tunnelId, configId: managed.
|
|
482
|
+
logger.info("Stopping tunnel", { tunnelId, configId: managed.configId });
|
|
503
483
|
try {
|
|
504
484
|
managed.instance.stop();
|
|
505
485
|
if (managed.serveWorker) {
|
|
@@ -511,6 +491,7 @@ var init_TunnelManager = __esm({
|
|
|
511
491
|
this.tunnelStats.delete(tunnelId);
|
|
512
492
|
this.tunnelStatsListeners.delete(tunnelId);
|
|
513
493
|
this.tunnelErrorListeners.delete(tunnelId);
|
|
494
|
+
this.tunnelPollingErrorListeners.delete(tunnelId);
|
|
514
495
|
this.tunnelDisconnectListeners.delete(tunnelId);
|
|
515
496
|
this.tunnelWorkerErrorListeners.delete(tunnelId);
|
|
516
497
|
this.tunnelStartListeners.delete(tunnelId);
|
|
@@ -522,8 +503,8 @@ var init_TunnelManager = __esm({
|
|
|
522
503
|
managed.warnings = managed.warnings ?? [];
|
|
523
504
|
managed.isStopped = true;
|
|
524
505
|
managed.stoppedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
525
|
-
logger.info("Tunnel stopped", { tunnelId, configId: managed.
|
|
526
|
-
return {
|
|
506
|
+
logger.info("Tunnel stopped", { tunnelId, configId: managed.configId });
|
|
507
|
+
return { configId: managed.configId, tunnelid: managed.tunnelid };
|
|
527
508
|
} catch (error) {
|
|
528
509
|
logger.error("Failed to stop tunnel", { tunnelId, error });
|
|
529
510
|
throw error;
|
|
@@ -540,7 +521,6 @@ var init_TunnelManager = __esm({
|
|
|
540
521
|
return [];
|
|
541
522
|
}
|
|
542
523
|
const urls = await managed.instance.urls();
|
|
543
|
-
logger.debug("Queried tunnel URLs", { tunnelId, urls });
|
|
544
524
|
return urls;
|
|
545
525
|
} catch (error) {
|
|
546
526
|
logger.error("Error fetching tunnel URLs", { tunnelId, error });
|
|
@@ -556,11 +536,10 @@ var init_TunnelManager = __esm({
|
|
|
556
536
|
const tunnelList = await Promise.all(Array.from(this.tunnelsByTunnelId.values()).map(async (tunnel) => {
|
|
557
537
|
return {
|
|
558
538
|
tunnelid: tunnel.tunnelid,
|
|
559
|
-
|
|
539
|
+
configId: tunnel.configId,
|
|
560
540
|
tunnelName: tunnel.tunnelName,
|
|
561
541
|
tunnelConfig: tunnel.tunnelConfig,
|
|
562
|
-
remoteurls:
|
|
563
|
-
additionalForwarding: tunnel.additionalForwarding,
|
|
542
|
+
remoteurls: tunnel.isStopped || tunnel.lastError?.isFatal ? [] : await this.getTunnelUrls(tunnel.tunnelid),
|
|
564
543
|
serve: tunnel.serve
|
|
565
544
|
};
|
|
566
545
|
}));
|
|
@@ -583,7 +562,6 @@ var init_TunnelManager = __esm({
|
|
|
583
562
|
return "exited";
|
|
584
563
|
}
|
|
585
564
|
const status = await managed.instance.getStatus();
|
|
586
|
-
logger.debug("Queried tunnel status", { tunnelId, status });
|
|
587
565
|
return status;
|
|
588
566
|
}
|
|
589
567
|
/**
|
|
@@ -601,6 +579,15 @@ var init_TunnelManager = __esm({
|
|
|
601
579
|
this.tunnelsByConfigId.clear();
|
|
602
580
|
this.tunnelStats.clear();
|
|
603
581
|
this.tunnelStatsListeners.clear();
|
|
582
|
+
this.tunnelErrorListeners.clear();
|
|
583
|
+
this.tunnelPollingErrorListeners.clear();
|
|
584
|
+
this.tunnelDisconnectListeners.clear();
|
|
585
|
+
this.tunnelWorkerErrorListeners.clear();
|
|
586
|
+
this.tunnelStartListeners.clear();
|
|
587
|
+
this.tunnelWillReconnectListeners.clear();
|
|
588
|
+
this.tunnelReconnectingListeners.clear();
|
|
589
|
+
this.tunnelReconnectionCompletedListeners.clear();
|
|
590
|
+
this.tunnelReconnectionFailedListeners.clear();
|
|
604
591
|
logger.info("All tunnels stopped and cleared");
|
|
605
592
|
}
|
|
606
593
|
/**
|
|
@@ -621,7 +608,7 @@ var init_TunnelManager = __esm({
|
|
|
621
608
|
return false;
|
|
622
609
|
}
|
|
623
610
|
this._cleanupTunnelRecords(managed);
|
|
624
|
-
logger.info("Removed stopped tunnel records", { tunnelId, configId: managed.
|
|
611
|
+
logger.info("Removed stopped tunnel records", { tunnelId, configId: managed.configId });
|
|
625
612
|
return true;
|
|
626
613
|
}
|
|
627
614
|
/**
|
|
@@ -648,6 +635,7 @@ var init_TunnelManager = __esm({
|
|
|
648
635
|
this.tunnelStats.delete(managed.tunnelid);
|
|
649
636
|
this.tunnelStatsListeners.delete(managed.tunnelid);
|
|
650
637
|
this.tunnelErrorListeners.delete(managed.tunnelid);
|
|
638
|
+
this.tunnelPollingErrorListeners.delete(managed.tunnelid);
|
|
651
639
|
this.tunnelDisconnectListeners.delete(managed.tunnelid);
|
|
652
640
|
this.tunnelWorkerErrorListeners.delete(managed.tunnelid);
|
|
653
641
|
this.tunnelStartListeners.delete(managed.tunnelid);
|
|
@@ -656,7 +644,7 @@ var init_TunnelManager = __esm({
|
|
|
656
644
|
this.tunnelReconnectionCompletedListeners.delete(managed.tunnelid);
|
|
657
645
|
this.tunnelReconnectionFailedListeners.delete(managed.tunnelid);
|
|
658
646
|
this.tunnelsByTunnelId.delete(managed.tunnelid);
|
|
659
|
-
this.tunnelsByConfigId.delete(managed.
|
|
647
|
+
this.tunnelsByConfigId.delete(managed.configId);
|
|
660
648
|
} catch (e) {
|
|
661
649
|
logger.warn("Failed cleaning up tunnel records", { tunnelId: managed.tunnelid, error: e });
|
|
662
650
|
}
|
|
@@ -717,21 +705,20 @@ var init_TunnelManager = __esm({
|
|
|
717
705
|
}
|
|
718
706
|
logger.info("Initiating tunnel restart", {
|
|
719
707
|
tunnelId: tunnelid,
|
|
720
|
-
configId: existingTunnel.
|
|
708
|
+
configId: existingTunnel.configId
|
|
721
709
|
});
|
|
722
710
|
try {
|
|
723
711
|
const tunnelName = existingTunnel.tunnelName;
|
|
724
|
-
const currentConfigId = existingTunnel.
|
|
712
|
+
const currentConfigId = existingTunnel.configId;
|
|
725
713
|
const currentConfig = existingTunnel.tunnelConfig;
|
|
726
|
-
const configWithForwarding = existingTunnel.configWithForwarding;
|
|
727
|
-
const additionalForwarding = existingTunnel.additionalForwarding;
|
|
728
714
|
const currentServe = existingTunnel.serve;
|
|
729
715
|
const autoReconnect = existingTunnel.autoReconnect || false;
|
|
730
716
|
this.tunnelsByTunnelId.delete(tunnelid);
|
|
731
|
-
this.tunnelsByConfigId.delete(existingTunnel.
|
|
717
|
+
this.tunnelsByConfigId.delete(existingTunnel.configId);
|
|
732
718
|
this.tunnelStats.delete(tunnelid);
|
|
733
719
|
this.tunnelStatsListeners.delete(tunnelid);
|
|
734
720
|
this.tunnelErrorListeners.delete(tunnelid);
|
|
721
|
+
this.tunnelPollingErrorListeners.delete(tunnelid);
|
|
735
722
|
this.tunnelDisconnectListeners.delete(tunnelid);
|
|
736
723
|
this.tunnelWorkerErrorListeners.delete(tunnelid);
|
|
737
724
|
this.tunnelStartListeners.delete(tunnelid);
|
|
@@ -740,12 +727,10 @@ var init_TunnelManager = __esm({
|
|
|
740
727
|
this.tunnelReconnectionCompletedListeners.delete(tunnelid);
|
|
741
728
|
this.tunnelReconnectionFailedListeners.delete(tunnelid);
|
|
742
729
|
const newTunnel = await this._createTunnelWithProcessedConfig({
|
|
743
|
-
|
|
730
|
+
configId: currentConfigId,
|
|
744
731
|
tunnelid,
|
|
745
732
|
tunnelName,
|
|
746
733
|
originalConfig: currentConfig,
|
|
747
|
-
configWithForwarding,
|
|
748
|
-
additionalForwarding,
|
|
749
734
|
serve: currentServe,
|
|
750
735
|
autoReconnect
|
|
751
736
|
});
|
|
@@ -774,20 +759,18 @@ var init_TunnelManager = __esm({
|
|
|
774
759
|
* @throws Error if the tunnel is not found or if the update process fails
|
|
775
760
|
*/
|
|
776
761
|
async updateConfig(newConfig) {
|
|
777
|
-
const {
|
|
778
|
-
if (!
|
|
779
|
-
throw new Error(`Invalid
|
|
762
|
+
const { configId, tunnelName: newTunnelName } = newConfig;
|
|
763
|
+
if (!configId || configId.trim().length === 0) {
|
|
764
|
+
throw new Error(`Invalid configId: "${configId}"`);
|
|
780
765
|
}
|
|
781
|
-
const existingTunnel = this.tunnelsByConfigId.get(
|
|
766
|
+
const existingTunnel = this.tunnelsByConfigId.get(configId);
|
|
782
767
|
if (!existingTunnel) {
|
|
783
|
-
throw new Error(`Tunnel with config id "${
|
|
768
|
+
throw new Error(`Tunnel with config id "${configId}" not found`);
|
|
784
769
|
}
|
|
785
770
|
const isStopped = existingTunnel.isStopped;
|
|
786
771
|
const currentTunnelConfig = existingTunnel.tunnelConfig;
|
|
787
|
-
const currentConfigWithForwarding = existingTunnel.configWithForwarding;
|
|
788
772
|
const currentTunnelId = existingTunnel.tunnelid;
|
|
789
|
-
const currentTunnelConfigId = existingTunnel.
|
|
790
|
-
const currentAdditionalForwarding = existingTunnel.additionalForwarding;
|
|
773
|
+
const currentTunnelConfigId = existingTunnel.configId;
|
|
791
774
|
const currentTunnelName = existingTunnel.tunnelName;
|
|
792
775
|
const currentServe = existingTunnel.serve;
|
|
793
776
|
const currentAutoReconnect = existingTunnel.autoReconnect || false;
|
|
@@ -799,22 +782,19 @@ var init_TunnelManager = __esm({
|
|
|
799
782
|
this.tunnelsByConfigId.delete(currentTunnelConfigId);
|
|
800
783
|
const mergedBaseConfig = {
|
|
801
784
|
...newConfig,
|
|
802
|
-
|
|
785
|
+
configId,
|
|
803
786
|
tunnelName: newTunnelName !== void 0 ? newTunnelName : currentTunnelName,
|
|
804
787
|
serve: newConfig.serve !== void 0 ? newConfig.serve : currentServe
|
|
805
788
|
};
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
);
|
|
789
|
+
const effectiveServe = newConfig.serve !== void 0 ? newConfig.serve : currentServe;
|
|
790
|
+
const effectiveTunnelName = newTunnelName !== void 0 ? newTunnelName : currentTunnelName;
|
|
791
|
+
let configWithForwarding;
|
|
810
792
|
const newTunnel = await this._createTunnelWithProcessedConfig({
|
|
811
|
-
|
|
793
|
+
configId,
|
|
812
794
|
tunnelid: currentTunnelId,
|
|
813
|
-
tunnelName:
|
|
795
|
+
tunnelName: effectiveTunnelName,
|
|
814
796
|
originalConfig: mergedBaseConfig,
|
|
815
|
-
|
|
816
|
-
additionalForwarding: additionalForwarding !== void 0 ? additionalForwarding : currentAdditionalForwarding,
|
|
817
|
-
serve: newConfig.serve !== void 0 ? newConfig.serve : currentServe,
|
|
797
|
+
serve: effectiveServe,
|
|
818
798
|
autoReconnect: currentAutoReconnect
|
|
819
799
|
});
|
|
820
800
|
if (!isStopped) {
|
|
@@ -822,23 +802,21 @@ var init_TunnelManager = __esm({
|
|
|
822
802
|
}
|
|
823
803
|
logger.info("Tunnel configuration updated", {
|
|
824
804
|
tunnelId: newTunnel.tunnelid,
|
|
825
|
-
configId: newTunnel.
|
|
805
|
+
configId: newTunnel.configId,
|
|
826
806
|
isStopped
|
|
827
807
|
});
|
|
828
808
|
return newTunnel;
|
|
829
809
|
} catch (error) {
|
|
830
810
|
logger.error("Error updating tunnel configuration", {
|
|
831
|
-
configId
|
|
811
|
+
configId,
|
|
832
812
|
error: error instanceof Error ? error.message : String(error)
|
|
833
813
|
});
|
|
834
814
|
try {
|
|
835
815
|
const originalTunnel = await this._createTunnelWithProcessedConfig({
|
|
836
|
-
|
|
816
|
+
configId: currentTunnelConfigId,
|
|
837
817
|
tunnelid: currentTunnelId,
|
|
838
818
|
tunnelName: currentTunnelName,
|
|
839
819
|
originalConfig: currentTunnelConfig,
|
|
840
|
-
configWithForwarding: currentConfigWithForwarding,
|
|
841
|
-
additionalForwarding: currentAdditionalForwarding,
|
|
842
820
|
serve: currentServe,
|
|
843
821
|
autoReconnect: currentAutoReconnect
|
|
844
822
|
});
|
|
@@ -954,6 +932,19 @@ var init_TunnelManager = __esm({
|
|
|
954
932
|
logger.info("Error listener registered for tunnel", { tunnelId, listenerId });
|
|
955
933
|
return listenerId;
|
|
956
934
|
}
|
|
935
|
+
async registerPollingErrorListener(tunnelId, listener) {
|
|
936
|
+
const managed = this.tunnelsByTunnelId.get(tunnelId);
|
|
937
|
+
if (!managed) {
|
|
938
|
+
throw new Error(`Tunnel "${tunnelId}" not found`);
|
|
939
|
+
}
|
|
940
|
+
if (!this.tunnelPollingErrorListeners.has(tunnelId)) {
|
|
941
|
+
this.tunnelPollingErrorListeners.set(tunnelId, /* @__PURE__ */ new Map());
|
|
942
|
+
}
|
|
943
|
+
const listenerId = getRandomId();
|
|
944
|
+
this.tunnelPollingErrorListeners.get(tunnelId).set(listenerId, listener);
|
|
945
|
+
logger.info("Polling error listener registered for tunnel", { tunnelId, listenerId });
|
|
946
|
+
return listenerId;
|
|
947
|
+
}
|
|
957
948
|
async registerDisconnectListener(tunnelId, listener) {
|
|
958
949
|
const managed = this.tunnelsByTunnelId.get(tunnelId);
|
|
959
950
|
if (!managed) {
|
|
@@ -1085,6 +1076,22 @@ var init_TunnelManager = __esm({
|
|
|
1085
1076
|
logger.warn("Attempted to deregister non-existent error listener", { tunnelId, listenerId });
|
|
1086
1077
|
}
|
|
1087
1078
|
}
|
|
1079
|
+
deregisterPollingErrorListener(tunnelId, listenerId) {
|
|
1080
|
+
const listeners = this.tunnelPollingErrorListeners.get(tunnelId);
|
|
1081
|
+
if (!listeners) {
|
|
1082
|
+
logger.warn("No polling error listeners found for tunnel", { tunnelId });
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
const removed = listeners.delete(listenerId);
|
|
1086
|
+
if (removed) {
|
|
1087
|
+
logger.info("Polling error listener deregistered", { tunnelId, listenerId });
|
|
1088
|
+
if (listeners.size === 0) {
|
|
1089
|
+
this.tunnelPollingErrorListeners.delete(tunnelId);
|
|
1090
|
+
}
|
|
1091
|
+
} else {
|
|
1092
|
+
logger.warn("Attempted to deregister non-existent polling error listener", { tunnelId, listenerId });
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1088
1095
|
deregisterDisconnectListener(tunnelId, listenerId) {
|
|
1089
1096
|
const listeners = this.tunnelDisconnectListeners.get(tunnelId);
|
|
1090
1097
|
if (!listeners) {
|
|
@@ -1202,6 +1209,46 @@ var init_TunnelManager = __esm({
|
|
|
1202
1209
|
logger.warn("Failed to set up stats callback", { tunnelId, error });
|
|
1203
1210
|
}
|
|
1204
1211
|
}
|
|
1212
|
+
setupTunnelPollingErrorCallback(tunnelId, managed) {
|
|
1213
|
+
try {
|
|
1214
|
+
const callback = ({ error }) => {
|
|
1215
|
+
try {
|
|
1216
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1217
|
+
logger.info("Tunnel reported polling error", { tunnelId, errorMessage });
|
|
1218
|
+
const managedTunnel = this.tunnelsByTunnelId.get(tunnelId);
|
|
1219
|
+
if (managedTunnel) {
|
|
1220
|
+
managedTunnel.lastError = {
|
|
1221
|
+
message: errorMessage,
|
|
1222
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1223
|
+
isFatal: true
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
this.notifyPollingErrorListeners(tunnelId, errorMessage);
|
|
1227
|
+
} catch (e) {
|
|
1228
|
+
logger.warn("Error handling tunnel polling error callback", { tunnelId, e });
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
managed.instance.setPollingErrorCallback(callback);
|
|
1232
|
+
logger.debug("Tunnel polling error callback set up for tunnel", { tunnelId });
|
|
1233
|
+
} catch (error) {
|
|
1234
|
+
logger.warn("Failed to set up tunnel polling error callback", { tunnelId, error });
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
notifyPollingErrorListeners(tunnelId, errorMsg) {
|
|
1238
|
+
try {
|
|
1239
|
+
const listeners = this.tunnelPollingErrorListeners.get(tunnelId);
|
|
1240
|
+
if (!listeners) return;
|
|
1241
|
+
for (const [id, listener] of listeners) {
|
|
1242
|
+
try {
|
|
1243
|
+
listener(tunnelId, errorMsg);
|
|
1244
|
+
} catch (err) {
|
|
1245
|
+
logger.debug("Error in polling-error-listener callback", { listenerId: id, tunnelId, err });
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
} catch (err) {
|
|
1249
|
+
logger.debug("Failed to notify polling error listeners", { tunnelId, err });
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1205
1252
|
notifyErrorListeners(tunnelId, errorMsg, isFatal) {
|
|
1206
1253
|
try {
|
|
1207
1254
|
const listeners = this.tunnelErrorListeners.get(tunnelId);
|
|
@@ -1224,6 +1271,14 @@ var init_TunnelManager = __esm({
|
|
|
1224
1271
|
const msg = typeof error === "string" ? error : String(error);
|
|
1225
1272
|
const isFatal = true;
|
|
1226
1273
|
logger.debug("Tunnel reported error", { tunnelId, errorNo, errorMsg: msg, recoverable });
|
|
1274
|
+
const managedTunnel = this.tunnelsByTunnelId.get(tunnelId);
|
|
1275
|
+
if (managedTunnel) {
|
|
1276
|
+
managedTunnel.lastError = {
|
|
1277
|
+
message: msg,
|
|
1278
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1279
|
+
isFatal: false
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1227
1282
|
this.notifyErrorListeners(tunnelId, msg, isFatal);
|
|
1228
1283
|
} catch (e) {
|
|
1229
1284
|
logger.warn("Error handling tunnel error callback", { tunnelId, e });
|
|
@@ -1474,9 +1529,9 @@ var init_TunnelManager = __esm({
|
|
|
1474
1529
|
}
|
|
1475
1530
|
startStaticFileServer(managed) {
|
|
1476
1531
|
try {
|
|
1477
|
-
const
|
|
1478
|
-
const
|
|
1479
|
-
const fileServerWorkerPath = import_node_path.default.join(
|
|
1532
|
+
const __filename4 = (0, import_node_url.fileURLToPath)(importMetaUrl);
|
|
1533
|
+
const __dirname3 = import_node_path.default.dirname(__filename4);
|
|
1534
|
+
const fileServerWorkerPath = import_node_path.default.join(__dirname3, "workers", "file_serve_worker.cjs");
|
|
1480
1535
|
const staticServerWorker = new import_node_worker_threads.Worker(fileServerWorkerPath, {
|
|
1481
1536
|
workerData: {
|
|
1482
1537
|
dir: managed.serve,
|
|
@@ -1628,15 +1683,57 @@ var init_types = __esm({
|
|
|
1628
1683
|
});
|
|
1629
1684
|
|
|
1630
1685
|
// src/remote_management/remote_schema.ts
|
|
1686
|
+
function pinggyOptionsToTunnelConfigV1(opts, configStoredInCli) {
|
|
1687
|
+
const parsedTokens = opts.bearerTokenAuth ? Array.isArray(opts.bearerTokenAuth) ? opts.bearerTokenAuth : JSON.parse(opts.bearerTokenAuth) : [];
|
|
1688
|
+
return {
|
|
1689
|
+
version: configStoredInCli.version || "1.0",
|
|
1690
|
+
name: configStoredInCli.name || "",
|
|
1691
|
+
configId: configStoredInCli.configId || "",
|
|
1692
|
+
serverAddress: opts.serverAddress || "a.pinggy.io:443",
|
|
1693
|
+
token: opts.token || "",
|
|
1694
|
+
autoReconnect: opts.autoReconnect ?? true,
|
|
1695
|
+
force: opts.force ?? false,
|
|
1696
|
+
webDebugger: opts.webDebugger || "",
|
|
1697
|
+
forwarding: opts.forwarding ? opts.forwarding : "",
|
|
1698
|
+
ipWhitelist: opts.ipWhitelist ? Array.isArray(opts.ipWhitelist) ? opts.ipWhitelist : JSON.parse(opts.ipWhitelist) : [],
|
|
1699
|
+
basicAuth: opts.basicAuth && Object.keys(opts.basicAuth).length ? opts.basicAuth : void 0,
|
|
1700
|
+
bearerTokenAuth: parsedTokens.length ? parsedTokens : void 0,
|
|
1701
|
+
headerModification: opts.headerModification || [],
|
|
1702
|
+
reverseProxy: opts.reverseProxy ?? false,
|
|
1703
|
+
xForwardedFor: !!opts.xForwardedFor,
|
|
1704
|
+
httpsOnly: opts.httpsOnly ?? false,
|
|
1705
|
+
originalRequestUrl: opts.originalRequestUrl ?? false,
|
|
1706
|
+
allowPreflight: opts.allowPreflight ?? false,
|
|
1707
|
+
optional: opts.optional || {}
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1631
1710
|
function tunnelConfigToPinggyOptions(config) {
|
|
1711
|
+
const forwardingData = [];
|
|
1712
|
+
forwardingData.push({
|
|
1713
|
+
address: `${config.forwardedhost}:${config.localport}`,
|
|
1714
|
+
type: config.type || import_pinggy3.TunnelType.Http
|
|
1715
|
+
// Default to HTTP for the primary forwarding entry
|
|
1716
|
+
});
|
|
1717
|
+
if (config.additionalForwarding && Array.isArray(config.additionalForwarding)) {
|
|
1718
|
+
config.additionalForwarding.forEach((entry) => {
|
|
1719
|
+
if (entry.localDomain && entry.localPort && entry.remoteDomain) {
|
|
1720
|
+
const listenAddress = entry.remotePort && isValidPort(entry.remotePort) ? `${entry.remoteDomain}:${entry.remotePort}` : entry.remoteDomain;
|
|
1721
|
+
forwardingData.push({
|
|
1722
|
+
address: `${entry.localDomain}:${entry.localPort}`,
|
|
1723
|
+
listenAddress,
|
|
1724
|
+
type: import_pinggy3.TunnelType.Http
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1632
1729
|
return {
|
|
1633
1730
|
token: config.token || "",
|
|
1634
1731
|
serverAddress: config.serveraddress || "free.pinggy.io",
|
|
1635
|
-
forwarding:
|
|
1732
|
+
forwarding: forwardingData,
|
|
1636
1733
|
webDebugger: config.webdebuggerport ? `localhost:${config.webdebuggerport}` : "",
|
|
1637
1734
|
ipWhitelist: config.ipwhitelist || [],
|
|
1638
1735
|
basicAuth: config.basicauth ? config.basicauth : [],
|
|
1639
|
-
bearerTokenAuth: config.bearerauth
|
|
1736
|
+
bearerTokenAuth: config.bearerauth || [],
|
|
1640
1737
|
headerModification: config.headermodification,
|
|
1641
1738
|
xForwardedFor: !!config.xff,
|
|
1642
1739
|
httpsOnly: config.httpsOnly,
|
|
@@ -1650,18 +1747,38 @@ function tunnelConfigToPinggyOptions(config) {
|
|
|
1650
1747
|
}
|
|
1651
1748
|
};
|
|
1652
1749
|
}
|
|
1653
|
-
function pinggyOptionsToTunnelConfig(opts, configid, configName, localserverTls, greetMsg,
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1750
|
+
function pinggyOptionsToTunnelConfig(opts, configid, configName, localserverTls, greetMsg, serve) {
|
|
1751
|
+
let primaryEntry;
|
|
1752
|
+
let additionalEntries = [];
|
|
1753
|
+
if (Array.isArray(opts.forwarding)) {
|
|
1754
|
+
primaryEntry = opts.forwarding.find((e) => !e.listenAddress) ?? opts.forwarding[0];
|
|
1755
|
+
additionalEntries = opts.forwarding.filter(
|
|
1756
|
+
(e) => e !== primaryEntry && Boolean(e.listenAddress)
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1759
|
+
const forwarding = primaryEntry ? String(primaryEntry.address) : String(opts.forwarding);
|
|
1760
|
+
const [parsedForwardedHost, portStr] = forwarding.split(":");
|
|
1761
|
+
const parsedLocalPort = parseInt(portStr, 10);
|
|
1762
|
+
const tunnelType = primaryEntry?.type ?? import_pinggy3.TunnelType.Http;
|
|
1763
|
+
const additionalForwarding = additionalEntries.map((e) => {
|
|
1764
|
+
const [localDomain, localPortStr] = String(e.address).split(":");
|
|
1765
|
+
const [remoteDomain, remotePortStr] = String(e.listenAddress).split(":");
|
|
1766
|
+
const localPort = parseInt(localPortStr, 10);
|
|
1767
|
+
const remotePort = parseInt(remotePortStr, 10);
|
|
1768
|
+
return {
|
|
1769
|
+
localDomain,
|
|
1770
|
+
localPort: isNaN(localPort) ? 0 : localPort,
|
|
1771
|
+
remoteDomain,
|
|
1772
|
+
remotePort: isNaN(remotePort) ? 0 : remotePort
|
|
1773
|
+
};
|
|
1774
|
+
});
|
|
1658
1775
|
const parsedTokens = opts.bearerTokenAuth ? Array.isArray(opts.bearerTokenAuth) ? opts.bearerTokenAuth : JSON.parse(opts.bearerTokenAuth) : [];
|
|
1659
1776
|
return {
|
|
1660
1777
|
allowPreflight: opts.allowPreflight ?? false,
|
|
1661
1778
|
allowpreflight: opts.allowPreflight ?? false,
|
|
1662
1779
|
autoreconnect: opts.autoReconnect ?? false,
|
|
1663
1780
|
basicauth: opts.basicAuth && Object.keys(opts.basicAuth).length ? opts.basicAuth : null,
|
|
1664
|
-
bearerauth: parsedTokens.length ? parsedTokens.join(",") : null,
|
|
1781
|
+
bearerauth: parsedTokens.length ? [parsedTokens.join(",")] : null,
|
|
1665
1782
|
configid,
|
|
1666
1783
|
configname: configName,
|
|
1667
1784
|
greetmsg: greetMsg || "",
|
|
@@ -1690,16 +1807,17 @@ function pinggyOptionsToTunnelConfig(opts, configid, configName, localserverTls,
|
|
|
1690
1807
|
serve: serve || ""
|
|
1691
1808
|
};
|
|
1692
1809
|
}
|
|
1693
|
-
var import_pinggy3, import_zod, HeaderModificationSchema, AdditionalForwardingSchema, TunnelConfigSchema, StartSchema, StopSchema, GetSchema, RestartSchema, UpdateConfigSchema;
|
|
1810
|
+
var import_pinggy3, import_zod, HeaderModificationSchema, AdditionalForwardingSchema, TunnelConfigSchema, StartSchema, StopSchema, GetSchema, RestartSchema, UpdateConfigSchema, ForwardingEntryV2Schema, TunnelConfigV1Schema, StartV2Schema, UpdateConfigV2Schema;
|
|
1694
1811
|
var init_remote_schema = __esm({
|
|
1695
1812
|
"src/remote_management/remote_schema.ts"() {
|
|
1696
1813
|
"use strict";
|
|
1697
1814
|
init_cjs_shims();
|
|
1698
1815
|
import_pinggy3 = require("@pinggy/pinggy");
|
|
1699
1816
|
import_zod = require("zod");
|
|
1817
|
+
init_util();
|
|
1700
1818
|
HeaderModificationSchema = import_zod.z.object({
|
|
1701
1819
|
key: import_zod.z.string(),
|
|
1702
|
-
value: import_zod.z.array(import_zod.z.string()).optional(),
|
|
1820
|
+
value: import_zod.z.array(import_zod.z.string()).nullable().optional(),
|
|
1703
1821
|
type: import_zod.z.enum(["add", "remove", "update"])
|
|
1704
1822
|
});
|
|
1705
1823
|
AdditionalForwardingSchema = import_zod.z.object({
|
|
@@ -1715,7 +1833,7 @@ var init_remote_schema = __esm({
|
|
|
1715
1833
|
// legacy key
|
|
1716
1834
|
autoreconnect: import_zod.z.boolean(),
|
|
1717
1835
|
basicauth: import_zod.z.array(import_zod.z.object({ username: import_zod.z.string(), password: import_zod.z.string() })).nullable(),
|
|
1718
|
-
bearerauth: import_zod.z.string().nullable(),
|
|
1836
|
+
bearerauth: import_zod.z.array(import_zod.z.string()).nullable(),
|
|
1719
1837
|
configid: import_zod.z.string(),
|
|
1720
1838
|
configname: import_zod.z.string(),
|
|
1721
1839
|
greetmsg: import_zod.z.string().optional(),
|
|
@@ -1772,11 +1890,56 @@ var init_remote_schema = __esm({
|
|
|
1772
1890
|
UpdateConfigSchema = import_zod.z.object({
|
|
1773
1891
|
tunnelConfig: TunnelConfigSchema
|
|
1774
1892
|
});
|
|
1893
|
+
ForwardingEntryV2Schema = import_zod.z.object({
|
|
1894
|
+
listenAddress: import_zod.z.string().optional(),
|
|
1895
|
+
address: import_zod.z.string(),
|
|
1896
|
+
type: import_zod.z.enum([import_pinggy3.TunnelType.Http, import_pinggy3.TunnelType.Tcp, import_pinggy3.TunnelType.Udp, import_pinggy3.TunnelType.Tls, import_pinggy3.TunnelType.TlsTcp]).optional()
|
|
1897
|
+
});
|
|
1898
|
+
TunnelConfigV1Schema = import_zod.z.object({
|
|
1899
|
+
// Meta Info
|
|
1900
|
+
version: import_zod.z.string(),
|
|
1901
|
+
name: import_zod.z.string(),
|
|
1902
|
+
configId: import_zod.z.string(),
|
|
1903
|
+
// General tunnel configurations
|
|
1904
|
+
serverAddress: import_zod.z.string().optional(),
|
|
1905
|
+
token: import_zod.z.string().optional(),
|
|
1906
|
+
autoReconnect: import_zod.z.boolean().optional(),
|
|
1907
|
+
reconnectInterval: import_zod.z.number().optional(),
|
|
1908
|
+
maxReconnectAttempts: import_zod.z.number().optional(),
|
|
1909
|
+
force: import_zod.z.boolean(),
|
|
1910
|
+
keepAliveInterval: import_zod.z.number().optional(),
|
|
1911
|
+
webDebugger: import_zod.z.string(),
|
|
1912
|
+
//Forwarding
|
|
1913
|
+
// Either a URL string (e.g. "https://localhost:5555") or an array of forwarding entries.
|
|
1914
|
+
forwarding: import_zod.z.union([
|
|
1915
|
+
import_zod.z.string(),
|
|
1916
|
+
import_zod.z.array(ForwardingEntryV2Schema)
|
|
1917
|
+
]),
|
|
1918
|
+
// IP whitelist
|
|
1919
|
+
ipWhitelist: import_zod.z.array(import_zod.z.string()).optional(),
|
|
1920
|
+
basicAuth: import_zod.z.array(import_zod.z.object({ username: import_zod.z.string(), password: import_zod.z.string() })).optional(),
|
|
1921
|
+
bearerTokenAuth: import_zod.z.array(import_zod.z.string()).optional(),
|
|
1922
|
+
headerModification: import_zod.z.array(HeaderModificationSchema).optional(),
|
|
1923
|
+
reverseProxy: import_zod.z.boolean().optional(),
|
|
1924
|
+
xForwardedFor: import_zod.z.boolean().optional(),
|
|
1925
|
+
httpsOnly: import_zod.z.boolean().optional(),
|
|
1926
|
+
originalRequestUrl: import_zod.z.boolean().optional(),
|
|
1927
|
+
allowPreflight: import_zod.z.boolean().optional(),
|
|
1928
|
+
serve: import_zod.z.string().optional(),
|
|
1929
|
+
optional: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
1930
|
+
});
|
|
1931
|
+
StartV2Schema = import_zod.z.object({
|
|
1932
|
+
tunnelID: import_zod.z.string().nullable().optional(),
|
|
1933
|
+
tunnelConfig: TunnelConfigV1Schema
|
|
1934
|
+
});
|
|
1935
|
+
UpdateConfigV2Schema = import_zod.z.object({
|
|
1936
|
+
tunnelConfig: TunnelConfigV1Schema
|
|
1937
|
+
});
|
|
1775
1938
|
}
|
|
1776
1939
|
});
|
|
1777
1940
|
|
|
1778
1941
|
// src/remote_management/handler.ts
|
|
1779
|
-
var
|
|
1942
|
+
var TunnelOperations;
|
|
1780
1943
|
var init_handler = __esm({
|
|
1781
1944
|
"src/remote_management/handler.ts"() {
|
|
1782
1945
|
"use strict";
|
|
@@ -1784,7 +1947,6 @@ var init_handler = __esm({
|
|
|
1784
1947
|
init_types();
|
|
1785
1948
|
init_TunnelManager();
|
|
1786
1949
|
init_remote_schema();
|
|
1787
|
-
import_pinggy4 = require("@pinggy/pinggy");
|
|
1788
1950
|
TunnelOperations = class {
|
|
1789
1951
|
constructor() {
|
|
1790
1952
|
this.tunnelManager = TunnelManager.getInstance();
|
|
@@ -1798,12 +1960,15 @@ var init_handler = __esm({
|
|
|
1798
1960
|
status.starttimestamp = managed.startedAt || "";
|
|
1799
1961
|
status.endtimestamp = managed.stoppedAt || "";
|
|
1800
1962
|
}
|
|
1963
|
+
if (managed?.lastError) {
|
|
1964
|
+
status.lastError = managed.lastError;
|
|
1965
|
+
}
|
|
1801
1966
|
} catch (e) {
|
|
1802
1967
|
}
|
|
1803
1968
|
return status;
|
|
1804
1969
|
}
|
|
1805
1970
|
// --- Helper to construct TunnelResponse ---
|
|
1806
|
-
async buildTunnelResponse(tunnelid, tunnelConfig, configid, tunnelName,
|
|
1971
|
+
async buildTunnelResponse(tunnelid, tunnelConfig, configid, tunnelName, serve) {
|
|
1807
1972
|
const [status, stats, tlsInfo, greetMsg, remoteurls] = await Promise.all([
|
|
1808
1973
|
this.tunnelManager.getTunnelStatus(tunnelid),
|
|
1809
1974
|
this.tunnelManager.getLatestTunnelStats(tunnelid) || newStats(),
|
|
@@ -1814,11 +1979,27 @@ var init_handler = __esm({
|
|
|
1814
1979
|
return {
|
|
1815
1980
|
tunnelid,
|
|
1816
1981
|
remoteurls,
|
|
1817
|
-
tunnelconfig: pinggyOptionsToTunnelConfig(tunnelConfig, configid, tunnelName, tlsInfo, greetMsg
|
|
1982
|
+
tunnelconfig: pinggyOptionsToTunnelConfig(tunnelConfig, configid, tunnelName, tlsInfo, greetMsg),
|
|
1818
1983
|
status: this.buildStatus(tunnelid, status, "" /* NoError */),
|
|
1819
1984
|
stats
|
|
1820
1985
|
};
|
|
1821
1986
|
}
|
|
1987
|
+
async buildTunnelResponseV2(tunnelid, tunnelConfig, configFromCli, configid, tunnelName, serve) {
|
|
1988
|
+
const [status, stats, greetMsg, remoteurls] = await Promise.all([
|
|
1989
|
+
this.tunnelManager.getTunnelStatus(tunnelid),
|
|
1990
|
+
this.tunnelManager.getLatestTunnelStats(tunnelid) || newStats(),
|
|
1991
|
+
this.tunnelManager.getTunnelGreetMessage(tunnelid),
|
|
1992
|
+
this.tunnelManager.getTunnelUrls(tunnelid)
|
|
1993
|
+
]);
|
|
1994
|
+
return {
|
|
1995
|
+
tunnelid,
|
|
1996
|
+
remoteurls,
|
|
1997
|
+
tunnelconfig: pinggyOptionsToTunnelConfigV1(tunnelConfig, configFromCli),
|
|
1998
|
+
status: this.buildStatus(tunnelid, status, "" /* NoError */),
|
|
1999
|
+
stats,
|
|
2000
|
+
greetmsg: greetMsg
|
|
2001
|
+
};
|
|
2002
|
+
}
|
|
1822
2003
|
error(code, err, fallback) {
|
|
1823
2004
|
return newErrorResponse({
|
|
1824
2005
|
code,
|
|
@@ -1829,19 +2010,28 @@ var init_handler = __esm({
|
|
|
1829
2010
|
async handleStart(config) {
|
|
1830
2011
|
try {
|
|
1831
2012
|
const opts = tunnelConfigToPinggyOptions(config);
|
|
1832
|
-
const
|
|
1833
|
-
const { tunnelid, instance, tunnelName, additionalForwarding, serve } = await this.tunnelManager.createTunnel({
|
|
2013
|
+
const { tunnelid, instance, tunnelName, serve, tunnelConfig } = await this.tunnelManager.createTunnel({
|
|
1834
2014
|
...opts,
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
serve: config.serve
|
|
2015
|
+
configId: config.configid,
|
|
2016
|
+
name: config.configname,
|
|
2017
|
+
optional: {
|
|
2018
|
+
serve: config.serve
|
|
2019
|
+
}
|
|
1841
2020
|
});
|
|
1842
|
-
this.tunnelManager.startTunnel(tunnelid);
|
|
2021
|
+
await this.tunnelManager.startTunnel(tunnelid);
|
|
1843
2022
|
const tunnelPconfig = await this.tunnelManager.getTunnelConfig("", tunnelid);
|
|
1844
|
-
const resp = this.buildTunnelResponse(tunnelid, tunnelPconfig, config.configid, tunnelName,
|
|
2023
|
+
const resp = this.buildTunnelResponse(tunnelid, tunnelPconfig, config.configid, tunnelName, serve);
|
|
2024
|
+
return resp;
|
|
2025
|
+
} catch (err) {
|
|
2026
|
+
return this.error(ErrorCode.ErrorStartingTunnel, err, "Unknown error occurred while starting tunnel");
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
async handleStartV2(config) {
|
|
2030
|
+
try {
|
|
2031
|
+
const { tunnelid, instance, serve } = await this.tunnelManager.createTunnel(config);
|
|
2032
|
+
await this.tunnelManager.startTunnel(tunnelid);
|
|
2033
|
+
const tunnelPconfig = await this.tunnelManager.getTunnelConfig("", tunnelid);
|
|
2034
|
+
const resp = this.buildTunnelResponseV2(tunnelid, tunnelPconfig, config, config.configId, config.name, config.serve);
|
|
1845
2035
|
return resp;
|
|
1846
2036
|
} catch (err) {
|
|
1847
2037
|
return this.error(ErrorCode.ErrorStartingTunnel, err, "Unknown error occurred while starting tunnel");
|
|
@@ -1852,20 +2042,59 @@ var init_handler = __esm({
|
|
|
1852
2042
|
const opts = tunnelConfigToPinggyOptions(config);
|
|
1853
2043
|
const tunnel = await this.tunnelManager.updateConfig({
|
|
1854
2044
|
...opts,
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
serve: config.serve
|
|
2045
|
+
configId: config.configid,
|
|
2046
|
+
name: config.configname,
|
|
2047
|
+
optional: {
|
|
2048
|
+
serve: config.serve
|
|
2049
|
+
}
|
|
1861
2050
|
});
|
|
1862
2051
|
if (!tunnel.instance || !tunnel.tunnelConfig)
|
|
1863
2052
|
throw new Error("Invalid tunnel state after configuration update");
|
|
1864
|
-
return this.buildTunnelResponse(tunnel.tunnelid, tunnel.tunnelConfig, config.configid, tunnel.tunnelName, tunnel.
|
|
2053
|
+
return this.buildTunnelResponse(tunnel.tunnelid, tunnel.tunnelConfig, config.configid, tunnel.tunnelName, tunnel.serve);
|
|
2054
|
+
} catch (err) {
|
|
2055
|
+
return this.error(ErrorCode.InternalServerError, err, "Failed to update tunnel configuration");
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
async handleUpdateConfigV2(config) {
|
|
2059
|
+
try {
|
|
2060
|
+
const tunnel = await this.tunnelManager.updateConfig(config);
|
|
2061
|
+
if (!tunnel.instance || !tunnel.tunnelConfig)
|
|
2062
|
+
throw new Error("Invalid tunnel state after configuration update");
|
|
2063
|
+
return this.buildTunnelResponseV2(tunnel.tunnelid, tunnel.tunnelConfig, config, config.configId, tunnel.tunnelName, tunnel.serve);
|
|
1865
2064
|
} catch (err) {
|
|
1866
2065
|
return this.error(ErrorCode.InternalServerError, err, "Failed to update tunnel configuration");
|
|
1867
2066
|
}
|
|
1868
2067
|
}
|
|
2068
|
+
async handleListV2() {
|
|
2069
|
+
try {
|
|
2070
|
+
const tunnels = await this.tunnelManager.getAllTunnels();
|
|
2071
|
+
if (tunnels.length === 0) {
|
|
2072
|
+
return [];
|
|
2073
|
+
}
|
|
2074
|
+
return Promise.all(
|
|
2075
|
+
tunnels.map(async (t) => {
|
|
2076
|
+
const rawStats = this.tunnelManager.getLatestTunnelStats(t.tunnelid) || newStats();
|
|
2077
|
+
const [status, tlsInfo, greetMsg] = await Promise.all([
|
|
2078
|
+
this.tunnelManager.getTunnelStatus(t.tunnelid),
|
|
2079
|
+
this.tunnelManager.getLocalserverTlsInfo(t.tunnelid),
|
|
2080
|
+
this.tunnelManager.getTunnelGreetMessage(t.tunnelid)
|
|
2081
|
+
]);
|
|
2082
|
+
const tunnelConfguration = status !== "closed" /* Closed */ && status !== "exited" /* Exited */ ? await this.tunnelManager.getTunnelConfig("", t.tunnelid) : t.tunnelConfig;
|
|
2083
|
+
const tunnelConfig = pinggyOptionsToTunnelConfigV1(tunnelConfguration, t.tunnelConfig);
|
|
2084
|
+
return {
|
|
2085
|
+
tunnelid: t.tunnelid,
|
|
2086
|
+
remoteurls: t.remoteurls,
|
|
2087
|
+
status: this.buildStatus(t.tunnelid, status, "" /* NoError */),
|
|
2088
|
+
stats: rawStats,
|
|
2089
|
+
tunnelconfig: tunnelConfig,
|
|
2090
|
+
greetmsg: greetMsg
|
|
2091
|
+
};
|
|
2092
|
+
})
|
|
2093
|
+
);
|
|
2094
|
+
} catch (err) {
|
|
2095
|
+
return this.error(ErrorCode.InternalServerError, err, "Failed to list tunnels");
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
1869
2098
|
async handleList() {
|
|
1870
2099
|
try {
|
|
1871
2100
|
const tunnels = await this.tunnelManager.getAllTunnels();
|
|
@@ -1881,7 +2110,7 @@ var init_handler = __esm({
|
|
|
1881
2110
|
this.tunnelManager.getTunnelGreetMessage(t.tunnelid)
|
|
1882
2111
|
]);
|
|
1883
2112
|
const pinggyOptions = status !== "closed" /* Closed */ && status !== "exited" /* Exited */ ? await this.tunnelManager.getTunnelConfig("", t.tunnelid) : t.tunnelConfig;
|
|
1884
|
-
const tunnelConfig = pinggyOptionsToTunnelConfig(pinggyOptions, t.
|
|
2113
|
+
const tunnelConfig = pinggyOptionsToTunnelConfig(pinggyOptions, t.configId, t.tunnelName, tlsInfo, greetMsg, t.serve);
|
|
1885
2114
|
return {
|
|
1886
2115
|
tunnelid: t.tunnelid,
|
|
1887
2116
|
remoteurls: t.remoteurls,
|
|
@@ -1897,10 +2126,10 @@ var init_handler = __esm({
|
|
|
1897
2126
|
}
|
|
1898
2127
|
async handleStop(tunnelid) {
|
|
1899
2128
|
try {
|
|
1900
|
-
const {
|
|
2129
|
+
const { configId } = this.tunnelManager.stopTunnel(tunnelid);
|
|
1901
2130
|
const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
|
|
1902
2131
|
if (!managed?.tunnelConfig) throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
|
|
1903
|
-
return this.buildTunnelResponse(tunnelid, managed.tunnelConfig,
|
|
2132
|
+
return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, configId, managed.tunnelName, managed.serve);
|
|
1904
2133
|
} catch (err) {
|
|
1905
2134
|
return this.error(ErrorCode.TunnelNotFound, err, "Failed to stop tunnel");
|
|
1906
2135
|
}
|
|
@@ -1909,7 +2138,7 @@ var init_handler = __esm({
|
|
|
1909
2138
|
try {
|
|
1910
2139
|
const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
|
|
1911
2140
|
if (!managed?.tunnelConfig) throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
|
|
1912
|
-
return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, managed.
|
|
2141
|
+
return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, managed.configId, managed.tunnelName, managed.serve);
|
|
1913
2142
|
} catch (err) {
|
|
1914
2143
|
return this.error(ErrorCode.TunnelNotFound, err, "Failed to get tunnel information");
|
|
1915
2144
|
}
|
|
@@ -1919,7 +2148,7 @@ var init_handler = __esm({
|
|
|
1919
2148
|
await this.tunnelManager.restartTunnel(tunnelid);
|
|
1920
2149
|
const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
|
|
1921
2150
|
if (!managed?.tunnelConfig) throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
|
|
1922
|
-
return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, managed.
|
|
2151
|
+
return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, managed.configId, managed.tunnelName, managed.serve);
|
|
1923
2152
|
} catch (err) {
|
|
1924
2153
|
return this.error(ErrorCode.TunnelNotFound, err, "Failed to restart tunnel");
|
|
1925
2154
|
}
|
|
@@ -1962,7 +2191,216 @@ var init_handler = __esm({
|
|
|
1962
2191
|
}
|
|
1963
2192
|
});
|
|
1964
2193
|
|
|
2194
|
+
// src/remote_management/websocket_printer.ts
|
|
2195
|
+
var import_picocolors3, PENDING_START_TIMEOUT_MS, RemoteManagementWebSocketPrinter, remoteManagementWebSocketPrinter;
|
|
2196
|
+
var init_websocket_printer = __esm({
|
|
2197
|
+
"src/remote_management/websocket_printer.ts"() {
|
|
2198
|
+
"use strict";
|
|
2199
|
+
init_cjs_shims();
|
|
2200
|
+
init_logger();
|
|
2201
|
+
init_TunnelManager();
|
|
2202
|
+
init_types();
|
|
2203
|
+
init_printer();
|
|
2204
|
+
import_picocolors3 = __toESM(require("picocolors"), 1);
|
|
2205
|
+
PENDING_START_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2206
|
+
RemoteManagementWebSocketPrinter = class {
|
|
2207
|
+
constructor() {
|
|
2208
|
+
this.tunnelManager = TunnelManager.getInstance();
|
|
2209
|
+
this.pendingStarts = /* @__PURE__ */ new Map();
|
|
2210
|
+
}
|
|
2211
|
+
setTunnelHandler(tunnelHandler) {
|
|
2212
|
+
this.tunnelHandler = tunnelHandler;
|
|
2213
|
+
}
|
|
2214
|
+
queueStart(config) {
|
|
2215
|
+
this.cleanupExpiredPendingStarts();
|
|
2216
|
+
const entry = {
|
|
2217
|
+
configId: this.getConfigIdFromRequest(config),
|
|
2218
|
+
configName: this.getConfigNameFromRequest(config),
|
|
2219
|
+
queuedAt: Date.now()
|
|
2220
|
+
};
|
|
2221
|
+
this.latestPendingConfigId = entry.configId;
|
|
2222
|
+
this.pendingStarts.set(entry.configId, entry);
|
|
2223
|
+
printer_default.startSpinner("Starting tunnel with config name: " + entry.configName);
|
|
2224
|
+
}
|
|
2225
|
+
failQueuedStart(config, reason) {
|
|
2226
|
+
const configId = this.getConfigIdFromRequest(config);
|
|
2227
|
+
const pending = this.pendingStarts.get(configId);
|
|
2228
|
+
const configName = pending?.configName || this.getConfigNameFromRequest(config);
|
|
2229
|
+
this.pendingStarts.delete(configId);
|
|
2230
|
+
if (this.latestPendingConfigId === configId) {
|
|
2231
|
+
this.latestPendingConfigId = void 0;
|
|
2232
|
+
printer_default.stopSpinnerFail(`Failed to start tunnel with config name: ${configName}. ${reason}`);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
handleStartResult(config, result) {
|
|
2236
|
+
this.cleanupExpiredPendingStarts();
|
|
2237
|
+
const requestedConfigId = this.getConfigIdFromRequest(config);
|
|
2238
|
+
if (this.latestPendingConfigId && requestedConfigId !== this.latestPendingConfigId) {
|
|
2239
|
+
this.pendingStarts.delete(requestedConfigId);
|
|
2240
|
+
return;
|
|
2241
|
+
}
|
|
2242
|
+
if (isErrorResponse(result)) {
|
|
2243
|
+
this.failQueuedStart(config, result.message);
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
2246
|
+
const configId = this.getConfigIdFromTunnel(result);
|
|
2247
|
+
const pending = this.pendingStarts.get(requestedConfigId) || {
|
|
2248
|
+
configId: requestedConfigId,
|
|
2249
|
+
configName: this.getConfigNameFromRequest(config),
|
|
2250
|
+
queuedAt: Date.now()
|
|
2251
|
+
};
|
|
2252
|
+
pending.tunnelId = result.tunnelid;
|
|
2253
|
+
this.pendingStarts.set(requestedConfigId, pending);
|
|
2254
|
+
if (result.remoteurls.length > 0) {
|
|
2255
|
+
this.completePendingStart(pending, result.remoteurls);
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
printStopRequested(tunnelId) {
|
|
2259
|
+
const details = this.resolveTunnelDetails(tunnelId);
|
|
2260
|
+
printer_default.startSpinner("Stopping tunnel with config name: " + details.configName);
|
|
2261
|
+
}
|
|
2262
|
+
handleStopResult(tunnelId, result) {
|
|
2263
|
+
const details = this.resolveTunnelDetails(tunnelId, result);
|
|
2264
|
+
if (isErrorResponse(result)) {
|
|
2265
|
+
printer_default.stopSpinnerFail("Failed to stop tunnel with config name: " + details.configName);
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
this.pendingStarts.delete(details.configId);
|
|
2269
|
+
printer_default.stopSpinnerSuccess("Stopped tunnel with config name: " + details.configName);
|
|
2270
|
+
}
|
|
2271
|
+
printRestartRequested(tunnelId) {
|
|
2272
|
+
const details = this.resolveTunnelDetails(tunnelId);
|
|
2273
|
+
printer_default.startSpinner("Restarting tunnel with config name: " + details.configName);
|
|
2274
|
+
}
|
|
2275
|
+
handleRestartResult(tunnelId, result) {
|
|
2276
|
+
const details = this.resolveTunnelDetails(tunnelId, result);
|
|
2277
|
+
if (isErrorResponse(result)) {
|
|
2278
|
+
printer_default.warn(`Failed to restart tunnel with config name: ${details.configName}. ${result.message}`);
|
|
2279
|
+
printer_default.stopSpinnerFail("Failed to restart tunnel with config name: " + details.configName);
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
2282
|
+
printer_default.stopSpinnerSuccess("Restarted tunnel with config name: " + details.configName);
|
|
2283
|
+
if (result.remoteurls?.length > 0) {
|
|
2284
|
+
printer_default.info(import_picocolors3.default.cyanBright("Remote URLs:"));
|
|
2285
|
+
(result.remoteurls ?? []).forEach(
|
|
2286
|
+
(url) => printer_default.print(" " + import_picocolors3.default.magentaBright(url))
|
|
2287
|
+
);
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
monitorList(result) {
|
|
2291
|
+
this.cleanupExpiredPendingStarts();
|
|
2292
|
+
if (!Array.isArray(result) || this.pendingStarts.size === 0 || !this.latestPendingConfigId) {
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
for (const tunnel of result) {
|
|
2296
|
+
const pending = this.findPendingStart(tunnel);
|
|
2297
|
+
if (!pending) {
|
|
2298
|
+
continue;
|
|
2299
|
+
}
|
|
2300
|
+
if (pending.configId !== this.latestPendingConfigId) {
|
|
2301
|
+
continue;
|
|
2302
|
+
}
|
|
2303
|
+
pending.tunnelId = tunnel.tunnelid;
|
|
2304
|
+
this.pendingStarts.set(pending.configId, pending);
|
|
2305
|
+
if (tunnel.remoteurls.length > 0) {
|
|
2306
|
+
this.completePendingStart(pending, tunnel.remoteurls);
|
|
2307
|
+
continue;
|
|
2308
|
+
}
|
|
2309
|
+
if (tunnel.status.state === "exited" /* Exited */) {
|
|
2310
|
+
const reason = tunnel.status.errormsg || "Tunnel exited before a public URL was assigned";
|
|
2311
|
+
this.pendingStarts.delete(pending.configId);
|
|
2312
|
+
this.latestPendingConfigId = void 0;
|
|
2313
|
+
printer_default.stopSpinnerFail(`Tunnel start did not complete for config name: ${pending.configName}. ${reason}`);
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
completePendingStart(entry, urls) {
|
|
2318
|
+
if (this.latestPendingConfigId && entry.configId !== this.latestPendingConfigId) {
|
|
2319
|
+
this.pendingStarts.delete(entry.configId);
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
this.pendingStarts.delete(entry.configId);
|
|
2323
|
+
this.latestPendingConfigId = void 0;
|
|
2324
|
+
printer_default.stopSpinnerSuccess(`Tunnel started with config name: ${entry.configName}.`);
|
|
2325
|
+
printer_default.info(import_picocolors3.default.cyanBright("Remote URLs:"));
|
|
2326
|
+
(urls ?? []).forEach(
|
|
2327
|
+
(url) => printer_default.print(" " + import_picocolors3.default.magentaBright(url))
|
|
2328
|
+
);
|
|
2329
|
+
}
|
|
2330
|
+
cleanupExpiredPendingStarts() {
|
|
2331
|
+
const now = Date.now();
|
|
2332
|
+
for (const [configId, entry] of this.pendingStarts.entries()) {
|
|
2333
|
+
if (now - entry.queuedAt <= PENDING_START_TIMEOUT_MS) {
|
|
2334
|
+
continue;
|
|
2335
|
+
}
|
|
2336
|
+
this.pendingStarts.delete(configId);
|
|
2337
|
+
printer_default.warn(`Timed out while waiting for tunnel URL for config name: ${entry.configName}`);
|
|
2338
|
+
logger.warn("Pending websocket start entry expired", { configId, tunnelId: entry.tunnelId });
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
findPendingStart(tunnel) {
|
|
2342
|
+
const configId = this.getConfigIdFromTunnel(tunnel);
|
|
2343
|
+
const byConfigId = this.pendingStarts.get(configId);
|
|
2344
|
+
if (byConfigId) {
|
|
2345
|
+
return byConfigId;
|
|
2346
|
+
}
|
|
2347
|
+
for (const entry of this.pendingStarts.values()) {
|
|
2348
|
+
if (entry.tunnelId === tunnel.tunnelid) {
|
|
2349
|
+
return entry;
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
return void 0;
|
|
2353
|
+
}
|
|
2354
|
+
resolveTunnelDetails(tunnelId, result) {
|
|
2355
|
+
try {
|
|
2356
|
+
const managed = this.tunnelManager.getManagedTunnel(void 0, tunnelId);
|
|
2357
|
+
return {
|
|
2358
|
+
configId: managed.configId,
|
|
2359
|
+
configName: managed.tunnelName || managed.configId || tunnelId
|
|
2360
|
+
};
|
|
2361
|
+
} catch {
|
|
2362
|
+
if (result && !isErrorResponse(result)) {
|
|
2363
|
+
return {
|
|
2364
|
+
configId: this.getConfigIdFromTunnel(result),
|
|
2365
|
+
configName: this.getConfigNameFromTunnel(result)
|
|
2366
|
+
};
|
|
2367
|
+
}
|
|
2368
|
+
return {
|
|
2369
|
+
configId: tunnelId,
|
|
2370
|
+
configName: tunnelId
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
getConfigIdFromRequest(config) {
|
|
2375
|
+
return "configid" in config ? config.configid : config.configId;
|
|
2376
|
+
}
|
|
2377
|
+
getConfigNameFromRequest(config) {
|
|
2378
|
+
return "configname" in config ? config.configname : config.name;
|
|
2379
|
+
}
|
|
2380
|
+
getConfigIdFromTunnel(tunnel) {
|
|
2381
|
+
return "configid" in tunnel.tunnelconfig ? tunnel.tunnelconfig.configid : tunnel.tunnelconfig.configId;
|
|
2382
|
+
}
|
|
2383
|
+
getConfigNameFromTunnel(tunnel) {
|
|
2384
|
+
return "configname" in tunnel.tunnelconfig ? tunnel.tunnelconfig.configname : tunnel.tunnelconfig.name;
|
|
2385
|
+
}
|
|
2386
|
+
};
|
|
2387
|
+
remoteManagementWebSocketPrinter = new RemoteManagementWebSocketPrinter();
|
|
2388
|
+
}
|
|
2389
|
+
});
|
|
2390
|
+
|
|
1965
2391
|
// src/remote_management/websocket_handlers.ts
|
|
2392
|
+
function sendVersionResponse(ws) {
|
|
2393
|
+
const versionResponse = {
|
|
2394
|
+
cli_version: getVersion()
|
|
2395
|
+
};
|
|
2396
|
+
const payload = {
|
|
2397
|
+
command: "get-version",
|
|
2398
|
+
requestid: "0",
|
|
2399
|
+
response: JSON.stringify(versionResponse),
|
|
2400
|
+
error: false
|
|
2401
|
+
};
|
|
2402
|
+
ws.send(JSON.stringify(payload));
|
|
2403
|
+
}
|
|
1966
2404
|
function handleConnectionStatusMessage(firstMessage) {
|
|
1967
2405
|
try {
|
|
1968
2406
|
const text = typeof firstMessage === "string" ? firstMessage : firstMessage.toString();
|
|
@@ -1988,11 +2426,14 @@ var init_websocket_handlers = __esm({
|
|
|
1988
2426
|
init_types();
|
|
1989
2427
|
init_handler();
|
|
1990
2428
|
init_remote_schema();
|
|
2429
|
+
init_websocket_printer();
|
|
1991
2430
|
import_zod2 = __toESM(require("zod"), 1);
|
|
1992
2431
|
init_printer();
|
|
2432
|
+
init_util();
|
|
1993
2433
|
WebSocketCommandHandler = class {
|
|
1994
2434
|
constructor() {
|
|
1995
2435
|
this.tunnelHandler = new TunnelOperations();
|
|
2436
|
+
remoteManagementWebSocketPrinter.setTunnelHandler(this.tunnelHandler);
|
|
1996
2437
|
}
|
|
1997
2438
|
safeParse(text) {
|
|
1998
2439
|
if (!text) return void 0;
|
|
@@ -2017,35 +2458,157 @@ var init_websocket_handlers = __esm({
|
|
|
2017
2458
|
this.sendResponse(ws, resp);
|
|
2018
2459
|
}
|
|
2019
2460
|
async handleStartReq(req, raw) {
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2461
|
+
let queuedConfig;
|
|
2462
|
+
try {
|
|
2463
|
+
const dc = StartSchema.parse(raw);
|
|
2464
|
+
queuedConfig = dc.tunnelConfig;
|
|
2465
|
+
remoteManagementWebSocketPrinter.queueStart(dc.tunnelConfig);
|
|
2466
|
+
const result = await this.tunnelHandler.handleStart(dc.tunnelConfig);
|
|
2467
|
+
remoteManagementWebSocketPrinter.handleStartResult(dc.tunnelConfig, result);
|
|
2468
|
+
return this.wrapResponse(result, req);
|
|
2469
|
+
} catch (e) {
|
|
2470
|
+
if (queuedConfig) {
|
|
2471
|
+
remoteManagementWebSocketPrinter.failQueuedStart(queuedConfig, String(e));
|
|
2472
|
+
}
|
|
2473
|
+
if (e instanceof import_zod2.default.ZodError) {
|
|
2474
|
+
printer_default.warn("Validation failed for start request");
|
|
2475
|
+
return NewErrorResponseObject({ code: ErrorCode.InvalidBodyFormatError, message: "Validation failed" });
|
|
2476
|
+
}
|
|
2477
|
+
printer_default.warn(`Error in handleStartReq error: ${String(e)}`);
|
|
2478
|
+
return NewErrorResponseObject({ code: ErrorCode.InternalServerError, message: String(e) });
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
async handleStartV2Req(req, raw) {
|
|
2482
|
+
let queuedConfig;
|
|
2483
|
+
try {
|
|
2484
|
+
const dc = StartV2Schema.parse(raw);
|
|
2485
|
+
queuedConfig = dc.tunnelConfig;
|
|
2486
|
+
remoteManagementWebSocketPrinter.queueStart(dc.tunnelConfig);
|
|
2487
|
+
const result = await this.tunnelHandler.handleStartV2(dc.tunnelConfig);
|
|
2488
|
+
remoteManagementWebSocketPrinter.handleStartResult(dc.tunnelConfig, result);
|
|
2489
|
+
return this.wrapResponse(result, req);
|
|
2490
|
+
} catch (e) {
|
|
2491
|
+
if (queuedConfig) {
|
|
2492
|
+
remoteManagementWebSocketPrinter.failQueuedStart(queuedConfig, String(e));
|
|
2493
|
+
}
|
|
2494
|
+
if (e instanceof import_zod2.default.ZodError) {
|
|
2495
|
+
printer_default.warn("Validation failed for start-v2 request");
|
|
2496
|
+
return NewErrorResponseObject({ code: ErrorCode.InvalidBodyFormatError, message: "Validation failed" });
|
|
2497
|
+
}
|
|
2498
|
+
printer_default.warn(`Error in handleStartV2Req error: ${String(e)}`);
|
|
2499
|
+
return NewErrorResponseObject({ code: ErrorCode.InternalServerError, message: String(e) });
|
|
2500
|
+
}
|
|
2024
2501
|
}
|
|
2025
2502
|
async handleStopReq(req, raw) {
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2503
|
+
try {
|
|
2504
|
+
const dc = StopSchema.parse(raw);
|
|
2505
|
+
remoteManagementWebSocketPrinter.printStopRequested(dc.tunnelID);
|
|
2506
|
+
const result = await this.tunnelHandler.handleStop(dc.tunnelID);
|
|
2507
|
+
remoteManagementWebSocketPrinter.handleStopResult(dc.tunnelID, result);
|
|
2508
|
+
return this.wrapResponse(result, req);
|
|
2509
|
+
} catch (e) {
|
|
2510
|
+
if (e instanceof import_zod2.default.ZodError) {
|
|
2511
|
+
printer_default.warn("Validation failed for stop request");
|
|
2512
|
+
return NewErrorResponseObject({ code: ErrorCode.InvalidBodyFormatError, message: "Validation failed" });
|
|
2513
|
+
}
|
|
2514
|
+
printer_default.warn(`Error in handleStopReq error: ${String(e)}`);
|
|
2515
|
+
return NewErrorResponseObject({ code: ErrorCode.InternalServerError, message: String(e) });
|
|
2516
|
+
}
|
|
2030
2517
|
}
|
|
2031
2518
|
async handleGetReq(req, raw) {
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2519
|
+
try {
|
|
2520
|
+
const dc = GetSchema.parse(raw);
|
|
2521
|
+
const result = await this.tunnelHandler.handleGet(dc.tunnelID);
|
|
2522
|
+
return this.wrapResponse(result, req);
|
|
2523
|
+
} catch (e) {
|
|
2524
|
+
if (e instanceof import_zod2.default.ZodError) {
|
|
2525
|
+
printer_default.warn("Validation failed for get request");
|
|
2526
|
+
return NewErrorResponseObject({ code: ErrorCode.InvalidBodyFormatError, message: "Validation failed" });
|
|
2527
|
+
}
|
|
2528
|
+
printer_default.warn(`Error in handleGetReq error: ${String(e)}`);
|
|
2529
|
+
return NewErrorResponseObject({ code: ErrorCode.InternalServerError, message: String(e) });
|
|
2530
|
+
}
|
|
2035
2531
|
}
|
|
2036
2532
|
async handleRestartReq(req, raw) {
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2533
|
+
try {
|
|
2534
|
+
const dc = RestartSchema.parse(raw);
|
|
2535
|
+
remoteManagementWebSocketPrinter.printRestartRequested(dc.tunnelID);
|
|
2536
|
+
const result = await this.tunnelHandler.handleRestart(dc.tunnelID);
|
|
2537
|
+
remoteManagementWebSocketPrinter.handleRestartResult(dc.tunnelID, result);
|
|
2538
|
+
return this.wrapResponse(result, req);
|
|
2539
|
+
} catch (e) {
|
|
2540
|
+
if (e instanceof import_zod2.default.ZodError) {
|
|
2541
|
+
printer_default.warn("Validation failed for restart request");
|
|
2542
|
+
return NewErrorResponseObject({ code: ErrorCode.InvalidBodyFormatError, message: "Validation failed" });
|
|
2543
|
+
}
|
|
2544
|
+
printer_default.warn(`Error in handleRestartReq error: ${String(e)}`);
|
|
2545
|
+
return NewErrorResponseObject({ code: ErrorCode.InternalServerError, message: String(e) });
|
|
2546
|
+
}
|
|
2040
2547
|
}
|
|
2041
2548
|
async handleUpdateConfigReq(req, raw) {
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2549
|
+
try {
|
|
2550
|
+
const dc = UpdateConfigSchema.parse(raw);
|
|
2551
|
+
const result = await this.tunnelHandler.handleUpdateConfig(dc.tunnelConfig);
|
|
2552
|
+
return this.wrapResponse(result, req);
|
|
2553
|
+
} catch (e) {
|
|
2554
|
+
if (e instanceof import_zod2.default.ZodError) {
|
|
2555
|
+
printer_default.warn("Validation failed for updateconfig request");
|
|
2556
|
+
return NewErrorResponseObject({ code: ErrorCode.InvalidBodyFormatError, message: "Validation failed" });
|
|
2557
|
+
}
|
|
2558
|
+
printer_default.warn(`Error in handleUpdateConfigReq error: ${String(e)}`);
|
|
2559
|
+
return NewErrorResponseObject({ code: ErrorCode.InternalServerError, message: String(e) });
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
async handleUpdateConfigV2Req(req, raw) {
|
|
2563
|
+
try {
|
|
2564
|
+
const dc = UpdateConfigV2Schema.parse(raw);
|
|
2565
|
+
const result = await this.tunnelHandler.handleUpdateConfigV2(dc.tunnelConfig);
|
|
2566
|
+
return this.wrapResponse(result, req);
|
|
2567
|
+
} catch (e) {
|
|
2568
|
+
if (e instanceof import_zod2.default.ZodError) {
|
|
2569
|
+
printer_default.warn("Validation failed for update-config-v2 request");
|
|
2570
|
+
return NewErrorResponseObject({ code: ErrorCode.InvalidBodyFormatError, message: "Validation failed" });
|
|
2571
|
+
}
|
|
2572
|
+
printer_default.warn(`Error in handleUpdateConfigV2Req error: ${String(e)}`);
|
|
2573
|
+
return NewErrorResponseObject({ code: ErrorCode.InternalServerError, message: String(e) });
|
|
2574
|
+
}
|
|
2045
2575
|
}
|
|
2046
2576
|
async handleListReq(req) {
|
|
2047
|
-
|
|
2048
|
-
|
|
2577
|
+
try {
|
|
2578
|
+
const result = await this.tunnelHandler.handleList();
|
|
2579
|
+
remoteManagementWebSocketPrinter.monitorList(result);
|
|
2580
|
+
return this.wrapResponse(result, req);
|
|
2581
|
+
} catch (e) {
|
|
2582
|
+
printer_default.warn(`Error in handleListReq error: ${String(e)}`);
|
|
2583
|
+
return NewErrorResponseObject({ code: ErrorCode.InternalServerError, message: String(e) });
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
async handleListV2Req(req) {
|
|
2587
|
+
try {
|
|
2588
|
+
const result = await this.tunnelHandler.handleListV2();
|
|
2589
|
+
remoteManagementWebSocketPrinter.monitorList(result);
|
|
2590
|
+
return this.wrapResponse(result, req);
|
|
2591
|
+
} catch (e) {
|
|
2592
|
+
printer_default.warn(`Error in handleListV2Req error: ${String(e)}`);
|
|
2593
|
+
return NewErrorResponseObject({ code: ErrorCode.InternalServerError, message: String(e) });
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
async handleGetVersionReq(ws, req) {
|
|
2597
|
+
try {
|
|
2598
|
+
const versionResponse = {
|
|
2599
|
+
cli_version: getVersion()
|
|
2600
|
+
};
|
|
2601
|
+
const payload = {
|
|
2602
|
+
command: req.command,
|
|
2603
|
+
requestid: req.requestid,
|
|
2604
|
+
response: JSON.stringify(versionResponse),
|
|
2605
|
+
error: false
|
|
2606
|
+
};
|
|
2607
|
+
ws.send(JSON.stringify(payload));
|
|
2608
|
+
} catch (e) {
|
|
2609
|
+
printer_default.warn(`Error in handleGetVersionReq error: ${String(e)}`);
|
|
2610
|
+
this.sendError(ws, req, String(e));
|
|
2611
|
+
}
|
|
2049
2612
|
}
|
|
2050
2613
|
wrapResponse(result, req) {
|
|
2051
2614
|
if (isErrorResponse(result)) {
|
|
@@ -2079,6 +2642,10 @@ var init_websocket_handlers = __esm({
|
|
|
2079
2642
|
response = await this.handleStartReq(req, raw);
|
|
2080
2643
|
break;
|
|
2081
2644
|
}
|
|
2645
|
+
case "start-v2": {
|
|
2646
|
+
response = await this.handleStartV2Req(req, raw);
|
|
2647
|
+
break;
|
|
2648
|
+
}
|
|
2082
2649
|
case "stop": {
|
|
2083
2650
|
response = await this.handleStopReq(req, raw);
|
|
2084
2651
|
break;
|
|
@@ -2095,10 +2662,22 @@ var init_websocket_handlers = __esm({
|
|
|
2095
2662
|
response = await this.handleUpdateConfigReq(req, raw);
|
|
2096
2663
|
break;
|
|
2097
2664
|
}
|
|
2665
|
+
case "update-config-v2": {
|
|
2666
|
+
response = await this.handleUpdateConfigV2Req(req, raw);
|
|
2667
|
+
break;
|
|
2668
|
+
}
|
|
2098
2669
|
case "list": {
|
|
2099
2670
|
response = await this.handleListReq(req);
|
|
2100
2671
|
break;
|
|
2101
2672
|
}
|
|
2673
|
+
case "list-v2": {
|
|
2674
|
+
response = await this.handleListV2Req(req);
|
|
2675
|
+
break;
|
|
2676
|
+
}
|
|
2677
|
+
case "get-version": {
|
|
2678
|
+
await this.handleGetVersionReq(ws, req);
|
|
2679
|
+
return;
|
|
2680
|
+
}
|
|
2102
2681
|
default:
|
|
2103
2682
|
if (typeof req.command === "string") {
|
|
2104
2683
|
logger.warn("Unknown command", { command: req.command });
|
|
@@ -2145,7 +2724,11 @@ async function parseRemoteManagement(values) {
|
|
|
2145
2724
|
if (typeof rmToken === "string" && rmToken.trim().length > 0) {
|
|
2146
2725
|
const manageHost = values["manage"];
|
|
2147
2726
|
try {
|
|
2148
|
-
|
|
2727
|
+
const remoteManagementConfig = {
|
|
2728
|
+
apiKey: rmToken,
|
|
2729
|
+
serverUrl: buildRemoteManagementWsUrl(manageHost)
|
|
2730
|
+
};
|
|
2731
|
+
await initiateRemoteManagement(remoteManagementConfig);
|
|
2149
2732
|
return { ok: true };
|
|
2150
2733
|
} catch (e) {
|
|
2151
2734
|
logger.error("Failed to initiate remote management:", e);
|
|
@@ -2153,11 +2736,11 @@ async function parseRemoteManagement(values) {
|
|
|
2153
2736
|
}
|
|
2154
2737
|
}
|
|
2155
2738
|
}
|
|
2156
|
-
async function initiateRemoteManagement(
|
|
2157
|
-
if (!
|
|
2739
|
+
async function initiateRemoteManagement(remoteManagementConfig) {
|
|
2740
|
+
if (!remoteManagementConfig.apiKey || remoteManagementConfig.apiKey.trim().length === 0) {
|
|
2158
2741
|
throw new Error("Remote management token is required (use --remote-management <TOKEN>)");
|
|
2159
2742
|
}
|
|
2160
|
-
const wsUrl =
|
|
2743
|
+
const wsUrl = remoteManagementConfig.serverUrl;
|
|
2161
2744
|
const wsHost = extractHostname(wsUrl);
|
|
2162
2745
|
logger.info("Remote management mode enabled.");
|
|
2163
2746
|
_stopRequested = false;
|
|
@@ -2173,7 +2756,7 @@ async function initiateRemoteManagement(token, manage) {
|
|
|
2173
2756
|
logConnecting();
|
|
2174
2757
|
setRemoteManagementState({ status: RemoteManagementStatus.Connecting, errorMessage: "" });
|
|
2175
2758
|
try {
|
|
2176
|
-
await handleWebSocketConnection(wsUrl, wsHost,
|
|
2759
|
+
await handleWebSocketConnection(wsUrl, wsHost, remoteManagementConfig.apiKey);
|
|
2177
2760
|
} catch (error) {
|
|
2178
2761
|
logger.warn("Remote management connection error", { error: String(error) });
|
|
2179
2762
|
}
|
|
@@ -2201,6 +2784,7 @@ async function handleWebSocketConnection(wsUrl, wsHost, token) {
|
|
|
2201
2784
|
};
|
|
2202
2785
|
ws.once("open", () => {
|
|
2203
2786
|
printer_default.success(`Connected to ${wsHost}`);
|
|
2787
|
+
setRemoteManagementState({ status: RemoteManagementStatus.Running, errorMessage: "" });
|
|
2204
2788
|
heartbeat = setInterval(() => {
|
|
2205
2789
|
if (ws.readyState === import_ws.default.OPEN) ws.ping();
|
|
2206
2790
|
}, PING_INTERVAL_MS);
|
|
@@ -2211,7 +2795,11 @@ async function handleWebSocketConnection(wsUrl, wsHost, token) {
|
|
|
2211
2795
|
if (firstMessage) {
|
|
2212
2796
|
firstMessage = false;
|
|
2213
2797
|
const ok = handleConnectionStatusMessage(data);
|
|
2214
|
-
if (!ok)
|
|
2798
|
+
if (!ok) {
|
|
2799
|
+
ws.close();
|
|
2800
|
+
return;
|
|
2801
|
+
}
|
|
2802
|
+
sendVersionResponse(ws);
|
|
2215
2803
|
return;
|
|
2216
2804
|
}
|
|
2217
2805
|
setRemoteManagementState({ status: RemoteManagementStatus.Running, errorMessage: "" });
|
|
@@ -2222,20 +2810,21 @@ async function handleWebSocketConnection(wsUrl, wsHost, token) {
|
|
|
2222
2810
|
}
|
|
2223
2811
|
});
|
|
2224
2812
|
ws.on("unexpected-response", (_, res) => {
|
|
2225
|
-
setRemoteManagementState({ status: RemoteManagementStatus.NotRunning, errorMessage: `HTTP ${res.statusCode}` });
|
|
2226
2813
|
if (res.statusCode === 401) {
|
|
2814
|
+
setRemoteManagementState({ status: RemoteManagementStatus.NotRunning, errorMessage: `HTTP ${res.statusCode}` });
|
|
2227
2815
|
printer_default.error("Unauthorized. Please enter a valid token.");
|
|
2228
2816
|
logger.error("Unauthorized (401) on remote management connect");
|
|
2817
|
+
ws.close();
|
|
2229
2818
|
} else {
|
|
2819
|
+
logger.warn("Unexpected HTTP response ", { statusCode: res.statusCode });
|
|
2230
2820
|
printer_default.warn(`Unexpected HTTP ${res.statusCode}. Retrying...`);
|
|
2231
|
-
|
|
2821
|
+
cleanup();
|
|
2232
2822
|
}
|
|
2233
|
-
ws.close();
|
|
2234
2823
|
});
|
|
2235
2824
|
ws.on("close", (code, reason) => {
|
|
2236
2825
|
setRemoteManagementState({ status: RemoteManagementStatus.NotRunning, errorMessage: "" });
|
|
2237
2826
|
logger.info("WebSocket closed", { code, reason: reason.toString() });
|
|
2238
|
-
printer_default.warn(`Disconnected (code: ${code}). Retrying...`);
|
|
2827
|
+
printer_default.warn(`Disconnected (code: ${code}). Retrying in ${RECONNECT_SLEEP_MS / 1e3}s...`);
|
|
2239
2828
|
cleanup();
|
|
2240
2829
|
});
|
|
2241
2830
|
ws.on("error", (err) => {
|
|
@@ -2325,6 +2914,7 @@ var init_options = __esm({
|
|
|
2325
2914
|
localport: { type: "string", short: "l", description: "Takes input as [protocol:][host:]port. Eg. --localport https://localhost:8000 OR -l 3000" },
|
|
2326
2915
|
debugger: { type: "string", short: "d", description: "Port for web debugger. Eg. --debugger 4300 OR -d 4300" },
|
|
2327
2916
|
token: { type: "string", description: "Token for authentication. Eg. --token TOKEN_VALUE" },
|
|
2917
|
+
force: { type: "boolean", short: "f", description: "Forcefully close existing tunnels and establish a new tunnel" },
|
|
2328
2918
|
// Logging options (CLI overrides env)
|
|
2329
2919
|
loglevel: { type: "string", description: "Logging level: ERROR, INFO, DEBUG. Overrides PINGGY_LOG_LEVEL environment variable" },
|
|
2330
2920
|
logfile: { type: "string", description: "Path to log file. Overrides PINGGY_LOG_FILE environment variable" },
|
|
@@ -2340,7 +2930,8 @@ var init_options = __esm({
|
|
|
2340
2930
|
// Remote Control
|
|
2341
2931
|
"remote-management": { type: "string", description: "Enable remote management of tunnels with token. Eg. --remote-management API_KEY" },
|
|
2342
2932
|
manage: { type: "string", description: "Provide a server address to manage tunnels. Eg --manage dashboard.pinggy.io" },
|
|
2343
|
-
|
|
2933
|
+
noTui: { type: "boolean", description: "Disable TUI in remote management mode" },
|
|
2934
|
+
notui: { type: "boolean", description: "hidden", hidden: true },
|
|
2344
2935
|
// Misc
|
|
2345
2936
|
version: { type: "boolean", description: "Print version" },
|
|
2346
2937
|
// Help
|
|
@@ -2421,8 +3012,8 @@ var init_defaults = __esm({
|
|
|
2421
3012
|
});
|
|
2422
3013
|
|
|
2423
3014
|
// src/cli/extendedOptions.ts
|
|
2424
|
-
function parseExtendedOptions(options, config) {
|
|
2425
|
-
if (!options) return;
|
|
3015
|
+
function parseExtendedOptions(options, config, localServerTls) {
|
|
3016
|
+
if (!options) return localServerTls;
|
|
2426
3017
|
for (const opt of options) {
|
|
2427
3018
|
const [key, value] = opt.replace(/^"|"$/g, "").split(/:(.+)/).filter(Boolean);
|
|
2428
3019
|
switch (key) {
|
|
@@ -2446,10 +3037,16 @@ function parseExtendedOptions(options, config) {
|
|
|
2446
3037
|
case "fullrequesturl":
|
|
2447
3038
|
config.originalRequestUrl = true;
|
|
2448
3039
|
break;
|
|
2449
|
-
default:
|
|
2450
|
-
|
|
2451
|
-
|
|
3040
|
+
default: {
|
|
3041
|
+
if (value && (value.startsWith("localServerTls") || value.startsWith("localservertls"))) {
|
|
3042
|
+
const parts = value.split(/:(.+)/);
|
|
3043
|
+
localServerTls = parts[1] ? parts[1] : "";
|
|
3044
|
+
} else {
|
|
3045
|
+
printer_default.warn(`Unknown extended option "${value}"`);
|
|
3046
|
+
logger.warn(`Warning: Unknown extended option "${value}"`);
|
|
3047
|
+
}
|
|
2452
3048
|
break;
|
|
3049
|
+
}
|
|
2453
3050
|
}
|
|
2454
3051
|
break;
|
|
2455
3052
|
case "w":
|
|
@@ -2520,6 +3117,7 @@ function parseExtendedOptions(options, config) {
|
|
|
2520
3117
|
break;
|
|
2521
3118
|
}
|
|
2522
3119
|
}
|
|
3120
|
+
return localServerTls;
|
|
2523
3121
|
}
|
|
2524
3122
|
function isValidIpV4Cidr(input) {
|
|
2525
3123
|
if (input.includes("/")) {
|
|
@@ -2570,7 +3168,7 @@ function parseUserAndDomain(str) {
|
|
|
2570
3168
|
const [user, domain] = str.split("@", 2);
|
|
2571
3169
|
if (domainRegex.test(domain)) {
|
|
2572
3170
|
let processKeyword2 = function(keyword) {
|
|
2573
|
-
if ([
|
|
3171
|
+
if ([import_pinggy4.TunnelType.Http, import_pinggy4.TunnelType.Tcp, import_pinggy4.TunnelType.Tls, import_pinggy4.TunnelType.Udp, import_pinggy4.TunnelType.TlsTcp].includes(keyword)) {
|
|
2574
3172
|
type = keyword;
|
|
2575
3173
|
} else if (keyword === "force") {
|
|
2576
3174
|
forceFlag = true;
|
|
@@ -2639,9 +3237,9 @@ function parseUsers(positionalArgs, explicitToken) {
|
|
|
2639
3237
|
return { token, server, type, forceFlag, qrCode, remaining };
|
|
2640
3238
|
}
|
|
2641
3239
|
function parseType(finalConfig, values, inferredType) {
|
|
2642
|
-
const t = inferredType || values.type
|
|
2643
|
-
if (t ===
|
|
2644
|
-
|
|
3240
|
+
const t = inferredType || values.type;
|
|
3241
|
+
if (t === import_pinggy4.TunnelType.Http || t === import_pinggy4.TunnelType.Tcp || t === import_pinggy4.TunnelType.Tls || t === import_pinggy4.TunnelType.Udp || t === import_pinggy4.TunnelType.TlsTcp) {
|
|
3242
|
+
return t;
|
|
2645
3243
|
}
|
|
2646
3244
|
}
|
|
2647
3245
|
function parseLocalPort(finalConfig, values) {
|
|
@@ -2775,15 +3373,14 @@ function parseAdditionalForwarding(forwarding) {
|
|
|
2775
3373
|
return new Error("forwarding address incorrect: invalid local port");
|
|
2776
3374
|
}
|
|
2777
3375
|
return {
|
|
2778
|
-
protocol,
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
localDomain,
|
|
2782
|
-
localPort
|
|
3376
|
+
type: protocol,
|
|
3377
|
+
listenAddress: `${remoteDomainRaw}:${remotePort}`,
|
|
3378
|
+
address: `${localDomain}:${localPort}`
|
|
2783
3379
|
};
|
|
2784
3380
|
}
|
|
2785
|
-
function parseReverseTunnelAddr(finalConfig, values) {
|
|
3381
|
+
function parseReverseTunnelAddr(finalConfig, values, primaryType) {
|
|
2786
3382
|
const reverseTunnel = values.R;
|
|
3383
|
+
let forwardingData = [];
|
|
2787
3384
|
if ((!Array.isArray(reverseTunnel) || reverseTunnel.length === 0) && !values.localport && !finalConfig.forwarding) {
|
|
2788
3385
|
return new Error("local port not specified. Please use '-h' option for help.");
|
|
2789
3386
|
}
|
|
@@ -2795,18 +3392,21 @@ function parseReverseTunnelAddr(finalConfig, values) {
|
|
|
2795
3392
|
if (slicedForwarding.length === 3) {
|
|
2796
3393
|
const parsed = parseDefaultForwarding(forwarding);
|
|
2797
3394
|
if (parsed instanceof Error) return parsed;
|
|
2798
|
-
|
|
3395
|
+
forwardingData.push({
|
|
3396
|
+
address: `${parsed.localDomain}:${parsed.localPort}`,
|
|
3397
|
+
type: primaryType || import_pinggy4.TunnelType.Http
|
|
3398
|
+
});
|
|
2799
3399
|
} else if (slicedForwarding.length === 4) {
|
|
2800
|
-
finalConfig.additionalForwarding ?? (finalConfig.additionalForwarding = []);
|
|
2801
3400
|
const parsed = parseAdditionalForwarding(forwarding);
|
|
2802
3401
|
if (parsed instanceof Error) return parsed;
|
|
2803
|
-
|
|
3402
|
+
forwardingData.push(parsed);
|
|
2804
3403
|
} else {
|
|
2805
3404
|
return new Error(
|
|
2806
3405
|
"Incorrect command line arguments: reverse tunnel address incorrect. Please use '-h' option for help."
|
|
2807
3406
|
);
|
|
2808
3407
|
}
|
|
2809
3408
|
}
|
|
3409
|
+
finalConfig.forwarding = forwardingData;
|
|
2810
3410
|
return null;
|
|
2811
3411
|
}
|
|
2812
3412
|
function parseLocalTunnelAddr(finalConfig, values) {
|
|
@@ -2842,13 +3442,19 @@ function parseToken(finalConfig, explicitToken) {
|
|
|
2842
3442
|
}
|
|
2843
3443
|
}
|
|
2844
3444
|
function parseArgs(finalConfig, remainingPositionals) {
|
|
2845
|
-
|
|
3445
|
+
let localserverTls = "";
|
|
3446
|
+
localserverTls = parseExtendedOptions(remainingPositionals, finalConfig, localserverTls);
|
|
3447
|
+
if (localserverTls.length > 0 && finalConfig.forwarding) {
|
|
3448
|
+
if (typeof finalConfig.forwarding[0] === "object" && "address" in finalConfig.forwarding[0]) {
|
|
3449
|
+
finalConfig.forwarding[0].address = `https://${finalConfig.forwarding[0].address}`;
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
2846
3452
|
}
|
|
2847
3453
|
function storeJson(config, saveconf) {
|
|
2848
3454
|
if (saveconf) {
|
|
2849
3455
|
const path5 = saveconf;
|
|
2850
3456
|
try {
|
|
2851
|
-
|
|
3457
|
+
import_fs4.default.writeFileSync(path5, JSON.stringify(config, null, 2), { encoding: "utf-8", flag: "w" });
|
|
2852
3458
|
logger.info(`Configuration saved to ${path5}`);
|
|
2853
3459
|
} catch (err) {
|
|
2854
3460
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -2859,9 +3465,9 @@ function storeJson(config, saveconf) {
|
|
|
2859
3465
|
function loadJsonConfig(config) {
|
|
2860
3466
|
const configpath = config["conf"];
|
|
2861
3467
|
if (typeof configpath === "string" && configpath.trim().length > 0) {
|
|
2862
|
-
const filepath =
|
|
3468
|
+
const filepath = import_path4.default.resolve(configpath);
|
|
2863
3469
|
try {
|
|
2864
|
-
const data =
|
|
3470
|
+
const data = import_fs4.default.readFileSync(filepath, { encoding: "utf-8" });
|
|
2865
3471
|
const json = JSON.parse(data);
|
|
2866
3472
|
return json;
|
|
2867
3473
|
} catch (err) {
|
|
@@ -2880,7 +3486,7 @@ function isSaveConfOption(values) {
|
|
|
2880
3486
|
function parseServe(finalConfig, values) {
|
|
2881
3487
|
const sv = values.serve;
|
|
2882
3488
|
if (typeof sv !== "string" || sv.trim().length === 0) return null;
|
|
2883
|
-
finalConfig.serve = sv;
|
|
3489
|
+
finalConfig.optional.serve = sv;
|
|
2884
3490
|
return null;
|
|
2885
3491
|
}
|
|
2886
3492
|
function parseAutoReconnect(finalConfig, values) {
|
|
@@ -2918,21 +3524,23 @@ async function buildFinalConfig(values, positionals) {
|
|
|
2918
3524
|
...defaultOptions,
|
|
2919
3525
|
...configFromFile || {},
|
|
2920
3526
|
// Apply loaded config on top of defaults
|
|
2921
|
-
|
|
3527
|
+
configId: getRandomId(),
|
|
2922
3528
|
token: token || (configFromFile?.token || (typeof values.token === "string" ? values.token : "")),
|
|
2923
3529
|
serverAddress: server || (configFromFile?.serverAddress || defaultOptions.serverAddress),
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
3530
|
+
isQRCode: qrCode || (configFromFile?.isQRCode || false),
|
|
3531
|
+
autoReconnect: configFromFile?.autoReconnect ? configFromFile.autoReconnect : defaultOptions.autoReconnect,
|
|
3532
|
+
optional: {
|
|
3533
|
+
serve: configFromFile?.optional?.serve || void 0,
|
|
3534
|
+
noTui: values.noTui || values.notui || (configFromFile?.optional?.noTui || false)
|
|
3535
|
+
}
|
|
2928
3536
|
};
|
|
2929
|
-
parseType(finalConfig, values, type);
|
|
3537
|
+
type = parseType(finalConfig, values, type);
|
|
2930
3538
|
parseToken(finalConfig, token || values.token);
|
|
2931
3539
|
const dbgErr = parseDebugger(finalConfig, values);
|
|
2932
3540
|
if (dbgErr instanceof Error) throw dbgErr;
|
|
2933
3541
|
const lpErr = parseLocalPort(finalConfig, values);
|
|
2934
3542
|
if (lpErr instanceof Error) throw lpErr;
|
|
2935
|
-
const rErr = parseReverseTunnelAddr(finalConfig, values);
|
|
3543
|
+
const rErr = parseReverseTunnelAddr(finalConfig, values, type);
|
|
2936
3544
|
if (rErr instanceof Error) throw rErr;
|
|
2937
3545
|
const lErr = parseLocalTunnelAddr(finalConfig, values);
|
|
2938
3546
|
if (lErr instanceof Error) throw lErr;
|
|
@@ -2940,12 +3548,12 @@ async function buildFinalConfig(values, positionals) {
|
|
|
2940
3548
|
if (serveErr instanceof Error) throw serveErr;
|
|
2941
3549
|
const autoReconnectErr = parseAutoReconnect(finalConfig, values);
|
|
2942
3550
|
if (autoReconnectErr instanceof Error) throw autoReconnectErr;
|
|
2943
|
-
if (forceFlag) finalConfig.force = true;
|
|
3551
|
+
if (forceFlag || values.force) finalConfig.force = true;
|
|
2944
3552
|
parseArgs(finalConfig, remainingPositionals);
|
|
2945
3553
|
storeJson(finalConfig, saveconf);
|
|
2946
3554
|
return finalConfig;
|
|
2947
3555
|
}
|
|
2948
|
-
var
|
|
3556
|
+
var import_pinggy4, import_fs4, import_path4, domainRegex, KEYWORDS, VALID_PROTOCOLS;
|
|
2949
3557
|
var init_buildConfig = __esm({
|
|
2950
3558
|
"src/cli/buildConfig.ts"() {
|
|
2951
3559
|
"use strict";
|
|
@@ -2954,16 +3562,16 @@ var init_buildConfig = __esm({
|
|
|
2954
3562
|
init_extendedOptions();
|
|
2955
3563
|
init_logger();
|
|
2956
3564
|
init_util();
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
3565
|
+
import_pinggy4 = require("@pinggy/pinggy");
|
|
3566
|
+
import_fs4 = __toESM(require("fs"), 1);
|
|
3567
|
+
import_path4 = __toESM(require("path"), 1);
|
|
2960
3568
|
domainRegex = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
2961
3569
|
KEYWORDS = /* @__PURE__ */ new Set([
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
3570
|
+
import_pinggy4.TunnelType.Http,
|
|
3571
|
+
import_pinggy4.TunnelType.Tcp,
|
|
3572
|
+
import_pinggy4.TunnelType.Tls,
|
|
3573
|
+
import_pinggy4.TunnelType.Udp,
|
|
3574
|
+
import_pinggy4.TunnelType.TlsTcp,
|
|
2967
3575
|
"force",
|
|
2968
3576
|
"qr"
|
|
2969
3577
|
]);
|
|
@@ -3000,7 +3608,7 @@ function preprocessWindowsArgs(args) {
|
|
|
3000
3608
|
function parseCliArgs(options) {
|
|
3001
3609
|
const rawArgs = process.argv.slice(2);
|
|
3002
3610
|
const processedArgs = preprocessWindowsArgs(rawArgs);
|
|
3003
|
-
const parsed = (0,
|
|
3611
|
+
const parsed = (0, import_util6.parseArgs)({
|
|
3004
3612
|
args: processedArgs,
|
|
3005
3613
|
options,
|
|
3006
3614
|
allowPositionals: true
|
|
@@ -3011,12 +3619,12 @@ function parseCliArgs(options) {
|
|
|
3011
3619
|
hasAnyArgs
|
|
3012
3620
|
};
|
|
3013
3621
|
}
|
|
3014
|
-
var
|
|
3622
|
+
var import_util6, os2;
|
|
3015
3623
|
var init_parseArgs = __esm({
|
|
3016
3624
|
"src/utils/parseArgs.ts"() {
|
|
3017
3625
|
"use strict";
|
|
3018
3626
|
init_cjs_shims();
|
|
3019
|
-
|
|
3627
|
+
import_util6 = require("util");
|
|
3020
3628
|
os2 = __toESM(require("os"), 1);
|
|
3021
3629
|
}
|
|
3022
3630
|
});
|
|
@@ -4448,7 +5056,7 @@ async function launchTui(finalConfig, urls, greet, tunnel) {
|
|
|
4448
5056
|
}
|
|
4449
5057
|
}
|
|
4450
5058
|
async function startCli(finalConfig, manager) {
|
|
4451
|
-
if (!finalConfig.
|
|
5059
|
+
if (!finalConfig.optional?.noTui && finalConfig.webDebugger === "") {
|
|
4452
5060
|
const freePort = await getFreePort(finalConfig.webDebugger || "");
|
|
4453
5061
|
finalConfig.webDebugger = `localhost:${freePort}`;
|
|
4454
5062
|
}
|
|
@@ -4456,7 +5064,7 @@ async function startCli(finalConfig, manager) {
|
|
|
4456
5064
|
const manager2 = TunnelManager.getInstance();
|
|
4457
5065
|
const tunnel = await manager2.createTunnel(finalConfig);
|
|
4458
5066
|
printer_default.startSpinner("Connecting to Pinggy...");
|
|
4459
|
-
if (!finalConfig.
|
|
5067
|
+
if (!finalConfig.optional?.noTui) {
|
|
4460
5068
|
manager2.registerStatsListener(tunnel.tunnelid, (tunnelId, stats) => {
|
|
4461
5069
|
globalThis.__PINGGY_TUNNEL_STATS__?.(stats);
|
|
4462
5070
|
});
|
|
@@ -4466,26 +5074,26 @@ async function startCli(finalConfig, manager) {
|
|
|
4466
5074
|
});
|
|
4467
5075
|
await manager2.startTunnel(tunnel.tunnelid);
|
|
4468
5076
|
printer_default.stopSpinnerSuccess(" Connected to Pinggy");
|
|
4469
|
-
printer_default.success(
|
|
4470
|
-
printer_default.print(
|
|
5077
|
+
printer_default.success(import_picocolors4.default.bold("Tunnel established!"));
|
|
5078
|
+
printer_default.print(import_picocolors4.default.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4471
5079
|
TunnelData.urls = await manager2.getTunnelUrls(tunnel.tunnelid);
|
|
4472
5080
|
TunnelData.greet = await manager2.getTunnelGreetMessage(tunnel.tunnelid);
|
|
4473
|
-
printer_default.info(
|
|
5081
|
+
printer_default.info(import_picocolors4.default.cyanBright("Remote URLs:"));
|
|
4474
5082
|
(TunnelData.urls ?? []).forEach(
|
|
4475
|
-
(url) => printer_default.print(" " +
|
|
5083
|
+
(url) => printer_default.print(" " + import_picocolors4.default.magentaBright(url))
|
|
4476
5084
|
);
|
|
4477
|
-
printer_default.print(
|
|
5085
|
+
printer_default.print(import_picocolors4.default.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4478
5086
|
if (TunnelData.greet?.includes("not authenticated")) {
|
|
4479
|
-
printer_default.warn(
|
|
5087
|
+
printer_default.warn(import_picocolors4.default.yellowBright(TunnelData.greet));
|
|
4480
5088
|
} else if (TunnelData.greet?.includes("authenticated as")) {
|
|
4481
5089
|
const emailMatch = /authenticated as (.+)/.exec(TunnelData.greet);
|
|
4482
5090
|
if (emailMatch) {
|
|
4483
5091
|
const email = emailMatch[1];
|
|
4484
|
-
printer_default.info(
|
|
5092
|
+
printer_default.info(import_picocolors4.default.cyanBright("Authenticated as: " + email));
|
|
4485
5093
|
}
|
|
4486
5094
|
}
|
|
4487
|
-
printer_default.print(
|
|
4488
|
-
printer_default.print(
|
|
5095
|
+
printer_default.print(import_picocolors4.default.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
5096
|
+
printer_default.print(import_picocolors4.default.gray("\nPress Ctrl+C to stop the tunnel.\n"));
|
|
4489
5097
|
manager2.registerWillReconnectListener(tunnel.tunnelid, (tunnelId, error, messages) => {
|
|
4490
5098
|
if (activeTui) {
|
|
4491
5099
|
const msg = messages?.join("\n") || error || "Tunnel disconnected, reconnecting...";
|
|
@@ -4555,34 +5163,34 @@ async function startCli(finalConfig, manager) {
|
|
|
4555
5163
|
printer_default.stopSpinnerSuccess("Reconnected to Pinggy");
|
|
4556
5164
|
} catch (e) {
|
|
4557
5165
|
}
|
|
4558
|
-
printer_default.success(
|
|
4559
|
-
printer_default.print(
|
|
5166
|
+
printer_default.success(import_picocolors4.default.bold("Tunnel re-established!"));
|
|
5167
|
+
printer_default.print(import_picocolors4.default.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4560
5168
|
TunnelData.urls = urls;
|
|
4561
5169
|
TunnelData.greet = await manager2.getTunnelGreetMessage(tunnel.tunnelid);
|
|
4562
|
-
printer_default.info(
|
|
5170
|
+
printer_default.info(import_picocolors4.default.cyanBright("Remote URLs:"));
|
|
4563
5171
|
(TunnelData.urls ?? []).forEach(
|
|
4564
|
-
(url) => printer_default.print(" " +
|
|
5172
|
+
(url) => printer_default.print(" " + import_picocolors4.default.magentaBright(url))
|
|
4565
5173
|
);
|
|
4566
|
-
printer_default.print(
|
|
5174
|
+
printer_default.print(import_picocolors4.default.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4567
5175
|
if (TunnelData.greet?.includes("not authenticated")) {
|
|
4568
|
-
printer_default.warn(
|
|
5176
|
+
printer_default.warn(import_picocolors4.default.yellowBright(TunnelData.greet));
|
|
4569
5177
|
} else if (TunnelData.greet?.includes("authenticated as")) {
|
|
4570
5178
|
const emailMatch = /authenticated as (.+)/.exec(TunnelData.greet);
|
|
4571
5179
|
if (emailMatch) {
|
|
4572
5180
|
const email = emailMatch[1];
|
|
4573
|
-
printer_default.info(
|
|
5181
|
+
printer_default.info(import_picocolors4.default.cyanBright("Authenticated as: " + email));
|
|
4574
5182
|
}
|
|
4575
5183
|
}
|
|
4576
|
-
printer_default.print(
|
|
4577
|
-
printer_default.print(
|
|
4578
|
-
if (!finalConfig.
|
|
5184
|
+
printer_default.print(import_picocolors4.default.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
5185
|
+
printer_default.print(import_picocolors4.default.gray("\nPress Ctrl+C to stop the tunnel.\n"));
|
|
5186
|
+
if (!finalConfig.optional?.noTui) {
|
|
4579
5187
|
await launchTui(finalConfig, TunnelData.urls, TunnelData.greet, tunnel);
|
|
4580
5188
|
}
|
|
4581
5189
|
});
|
|
4582
5190
|
} catch (e) {
|
|
4583
5191
|
logger.debug("Failed to register start listener", e);
|
|
4584
5192
|
}
|
|
4585
|
-
if (!finalConfig.
|
|
5193
|
+
if (!finalConfig.optional?.noTui) {
|
|
4586
5194
|
await launchTui(finalConfig, TunnelData.urls, TunnelData.greet, tunnel);
|
|
4587
5195
|
}
|
|
4588
5196
|
} catch (err) {
|
|
@@ -4591,7 +5199,7 @@ async function startCli(finalConfig, manager) {
|
|
|
4591
5199
|
throw err;
|
|
4592
5200
|
}
|
|
4593
5201
|
}
|
|
4594
|
-
var
|
|
5202
|
+
var import_picocolors4, TunnelData, activeTui, disconnectState;
|
|
4595
5203
|
var init_starCli = __esm({
|
|
4596
5204
|
"src/cli/starCli.ts"() {
|
|
4597
5205
|
"use strict";
|
|
@@ -4600,7 +5208,7 @@ var init_starCli = __esm({
|
|
|
4600
5208
|
init_TunnelManager();
|
|
4601
5209
|
init_getFreePort();
|
|
4602
5210
|
init_logger();
|
|
4603
|
-
|
|
5211
|
+
import_picocolors4 = __toESM(require("picocolors"), 1);
|
|
4604
5212
|
init_blessed();
|
|
4605
5213
|
TunnelData = {
|
|
4606
5214
|
urls: null,
|
|
@@ -4657,7 +5265,7 @@ async function main() {
|
|
|
4657
5265
|
printer_default.error(error);
|
|
4658
5266
|
}
|
|
4659
5267
|
}
|
|
4660
|
-
var
|
|
5268
|
+
var import_url2, import_process, import_fs5, currentFile, entryFile;
|
|
4661
5269
|
var init_main = __esm({
|
|
4662
5270
|
"src/main.ts"() {
|
|
4663
5271
|
"use strict";
|
|
@@ -4673,15 +5281,15 @@ var init_main = __esm({
|
|
|
4673
5281
|
init_starCli();
|
|
4674
5282
|
init_util();
|
|
4675
5283
|
init_handler();
|
|
4676
|
-
|
|
5284
|
+
import_url2 = require("url");
|
|
4677
5285
|
import_process = require("process");
|
|
4678
|
-
|
|
5286
|
+
import_fs5 = require("fs");
|
|
4679
5287
|
init_logger();
|
|
4680
5288
|
init_remoteManagement();
|
|
4681
|
-
currentFile = (0,
|
|
5289
|
+
currentFile = (0, import_url2.fileURLToPath)(importMetaUrl);
|
|
4682
5290
|
entryFile = null;
|
|
4683
5291
|
try {
|
|
4684
|
-
entryFile = import_process.argv[1] ? (0,
|
|
5292
|
+
entryFile = import_process.argv[1] ? (0, import_fs5.realpathSync)(import_process.argv[1]) : null;
|
|
4685
5293
|
} catch (e) {
|
|
4686
5294
|
entryFile = null;
|
|
4687
5295
|
}
|