pinggy 0.5.3 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +596 -0
- package/README.md +4 -0
- package/dist/{TunnelManager-OPUMAZFX.js → TunnelManager-ZSVX7U3Z.js} +2 -2
- package/dist/{TunnelTui-QZEWWH2H.js → TunnelTui-S35BNVPO.js} +85 -16
- package/dist/{chunk-GK2PQ7KX.js → chunk-HN4YLM7U.js} +227 -74
- package/dist/{chunk-BBPR2LJB.js → chunk-OH6FSLYF.js} +39 -9
- package/dist/{chunk-7G6SJEEA.js → chunk-P7WNBN7F.js} +1 -1
- package/dist/{chunk-DLNUDW6G.js → chunk-PQSLSIDA.js} +67 -13
- package/dist/{chunk-5YHD6M35.js → chunk-YTJEV27N.js} +2 -2
- package/dist/{chunk-WM7I57AA.js → chunk-YWXADADB.js} +1 -1
- package/dist/{configStore-HP3NXPH4.js → configStore-2AZRILVC.js} +2 -2
- package/dist/{daemonChild-WIRWKBKB.js → daemonChild-3ONQO2XI.js} +6 -6
- package/dist/index.cjs +420 -114
- package/dist/index.d.cts +24 -17
- package/dist/index.d.ts +24 -17
- package/dist/index.js +6 -6
- package/dist/{ipcClient-Z2RXDQUQ.js → ipcClient-XRL2WUUM.js} +1 -1
- package/dist/{main-B2EBHFN2.js → main-WXFARRMN.js} +6 -6
- package/dist/workers/file_serve_worker.js +1 -1
- package/jest.config.cjs +1 -0
- package/package.json +2 -2
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
startDaemon,
|
|
11
11
|
startRemoteManagement,
|
|
12
12
|
stopDaemon
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-HN4YLM7U.js";
|
|
14
14
|
import {
|
|
15
15
|
readDaemonConfig
|
|
16
16
|
} from "./chunk-MT44NAXX.js";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
Route,
|
|
20
20
|
SessionMode,
|
|
21
21
|
ShutdownStatus
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-YTJEV27N.js";
|
|
23
23
|
import {
|
|
24
24
|
ConfigVerb,
|
|
25
25
|
SUBCOMMANDS,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
updateConfigAutoStart,
|
|
37
37
|
updateTunnelConfig,
|
|
38
38
|
validateName
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-YWXADADB.js";
|
|
40
40
|
import {
|
|
41
41
|
TunnelManager,
|
|
42
42
|
detachAllTunnelLoggers,
|
|
@@ -48,14 +48,14 @@ import {
|
|
|
48
48
|
isValidPort,
|
|
49
49
|
printer_default,
|
|
50
50
|
setTunnelLoggingEnabled
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-PQSLSIDA.js";
|
|
52
52
|
import {
|
|
53
53
|
configureLogger,
|
|
54
54
|
enablePackageLogging,
|
|
55
55
|
getLogLevel,
|
|
56
56
|
logger,
|
|
57
57
|
setLogLevel
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-P7WNBN7F.js";
|
|
59
59
|
import {
|
|
60
60
|
ensurePinggyConfigDir,
|
|
61
61
|
ensurePinggyLogDir,
|
|
@@ -137,6 +137,7 @@ function printHelpMessage() {
|
|
|
137
137
|
console.log(" x:noreverseproxy Disable built-in reverse-proxy header injection");
|
|
138
138
|
console.log(" x:localservertls:host Connect to local HTTPS server with SNI");
|
|
139
139
|
console.log(" x:passpreflight Pass CORS preflight requests unchanged");
|
|
140
|
+
console.log(" x:haproxy[:v1|:v2] Enable HAProxy PROXY protocol, TCP tunnels only (default v1)");
|
|
140
141
|
console.log(" a:Key:Val Add header");
|
|
141
142
|
console.log(" u:Key:Val Update header");
|
|
142
143
|
console.log(" r:Key Remove header");
|
|
@@ -274,6 +275,7 @@ var defaultOptions = {
|
|
|
274
275
|
};
|
|
275
276
|
|
|
276
277
|
// src/cli/extendedOptions.ts
|
|
278
|
+
import { HaProxyVersion } from "@pinggy/pinggy";
|
|
277
279
|
import { isIP } from "net";
|
|
278
280
|
function parseExtendedOptions(options, config, localServerTls) {
|
|
279
281
|
if (!options) return localServerTls;
|
|
@@ -300,10 +302,20 @@ function parseExtendedOptions(options, config, localServerTls) {
|
|
|
300
302
|
case "fullrequesturl":
|
|
301
303
|
config.originalRequestUrl = true;
|
|
302
304
|
break;
|
|
305
|
+
case "haproxy":
|
|
306
|
+
case "haproxy:v1":
|
|
307
|
+
config.haProxy = HaProxyVersion.V1;
|
|
308
|
+
break;
|
|
309
|
+
case "haproxy:v2":
|
|
310
|
+
config.haProxy = HaProxyVersion.V2;
|
|
311
|
+
break;
|
|
303
312
|
default: {
|
|
304
313
|
if (value && (value.startsWith("localServerTls") || value.startsWith("localservertls"))) {
|
|
305
314
|
const parts = value.split(/:(.+)/);
|
|
306
315
|
localServerTls = parts[1] ? parts[1] : "";
|
|
316
|
+
} else if (value && value.startsWith("haproxy:")) {
|
|
317
|
+
printer_default.warn(`Invalid HAProxy version in "${opt}". Use x:haproxy, x:haproxy:v1 or x:haproxy:v2`);
|
|
318
|
+
logger.warn(`Warning: Invalid HAProxy version in "${opt}". Use x:haproxy, x:haproxy:v1 or x:haproxy:v2`);
|
|
307
319
|
} else {
|
|
308
320
|
printer_default.warn(`Unknown extended option "${value}"`);
|
|
309
321
|
logger.warn(`Warning: Unknown extended option "${value}"`);
|
|
@@ -828,6 +840,20 @@ function hasRemoteManagement(values) {
|
|
|
828
840
|
const token = values["remote-management"];
|
|
829
841
|
return typeof token === "string" && token.trim().length > 0;
|
|
830
842
|
}
|
|
843
|
+
function validateHaProxy(finalConfig) {
|
|
844
|
+
if (!finalConfig.haProxy) {
|
|
845
|
+
return null;
|
|
846
|
+
}
|
|
847
|
+
const forwarding = finalConfig.forwarding;
|
|
848
|
+
const entries = Array.isArray(forwarding) ? forwarding : [];
|
|
849
|
+
const primaryType = entries.length > 0 ? entries[0].type : void 0;
|
|
850
|
+
if (primaryType === TunnelType.Tcp) {
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
return new Error(
|
|
854
|
+
`HAProxy PROXY protocol (x:haproxy) can only be used with TCP tunnels, but this tunnel is "${primaryType ?? TunnelType.Http}". Make it a TCP tunnel (--type tcp, or the tcp@ server prefix) or drop x:haproxy.`
|
|
855
|
+
);
|
|
856
|
+
}
|
|
831
857
|
function buildFinalConfig(values, positionals, baseConfig) {
|
|
832
858
|
let token;
|
|
833
859
|
let server;
|
|
@@ -890,6 +916,10 @@ function buildFinalConfig(values, positionals, baseConfig) {
|
|
|
890
916
|
}
|
|
891
917
|
normalizeForwardingToArray(finalConfig, type);
|
|
892
918
|
parseArgs2(finalConfig, remainingPositionals);
|
|
919
|
+
const haProxyErr = validateHaProxy(finalConfig);
|
|
920
|
+
if (haProxyErr instanceof Error) {
|
|
921
|
+
throw haProxyErr;
|
|
922
|
+
}
|
|
893
923
|
storeJson(finalConfig, saveconf);
|
|
894
924
|
return finalConfig;
|
|
895
925
|
}
|
|
@@ -1087,7 +1117,7 @@ async function connectTui(opts) {
|
|
|
1087
1117
|
const exitMessage = opts.exitMessage || "Stopping tunnel...";
|
|
1088
1118
|
if (!noTui && process.stdin.isTTY) {
|
|
1089
1119
|
try {
|
|
1090
|
-
const { TunnelTui } = await import("./TunnelTui-
|
|
1120
|
+
const { TunnelTui } = await import("./TunnelTui-S35BNVPO.js");
|
|
1091
1121
|
const tui = new TunnelTui({
|
|
1092
1122
|
urls,
|
|
1093
1123
|
greet,
|
|
@@ -1310,7 +1340,7 @@ async function startBackgroundTunnels(configs, values, positionals) {
|
|
|
1310
1340
|
client.close();
|
|
1311
1341
|
}
|
|
1312
1342
|
async function startAutoStartTunnels() {
|
|
1313
|
-
const { getAutoStartConfigs: getAutoStartConfigs2 } = await import("./configStore-
|
|
1343
|
+
const { getAutoStartConfigs: getAutoStartConfigs2 } = await import("./configStore-2AZRILVC.js");
|
|
1314
1344
|
const configs = getAutoStartConfigs2();
|
|
1315
1345
|
if (configs.length === 0) {
|
|
1316
1346
|
printer_default.warn("No configs marked for auto-start. Use: pinggy config auto <name>");
|
|
@@ -2635,7 +2665,7 @@ var IPCServer = class {
|
|
|
2635
2665
|
},
|
|
2636
2666
|
[Route.RestartTunnel]: async (req) => {
|
|
2637
2667
|
if (!req.tunnelid) throw new Error("Missing 'tunnelid' field");
|
|
2638
|
-
return await this.ops.handleRestart(req.tunnelid);
|
|
2668
|
+
return await this.ops.handleRestart(req.tunnelid, req.noWait);
|
|
2639
2669
|
},
|
|
2640
2670
|
[Route.UpdateConfig]: async (req) => {
|
|
2641
2671
|
if (!req.config) throw new Error("Missing 'config' field");
|
|
@@ -3414,7 +3444,7 @@ async function main() {
|
|
|
3414
3444
|
const { values, positionals, hasAnyArgs } = parseCliArgs(cliOptions);
|
|
3415
3445
|
configureLogger(values);
|
|
3416
3446
|
if (values["_daemon-child"]) {
|
|
3417
|
-
const { runDaemonChild: runDaemonChild2 } = await import("./daemonChild-
|
|
3447
|
+
const { runDaemonChild: runDaemonChild2 } = await import("./daemonChild-3ONQO2XI.js");
|
|
3418
3448
|
await runDaemonChild2();
|
|
3419
3449
|
return;
|
|
3420
3450
|
}
|
|
@@ -16,7 +16,7 @@ function setLogLevel(level) {
|
|
|
16
16
|
}
|
|
17
17
|
import("./daemonConfig-G6S46GPJ.js").then(({ writeDaemonConfig }) => writeDaemonConfig({ logLevel: level })).catch(() => {
|
|
18
18
|
});
|
|
19
|
-
import("./TunnelManager-
|
|
19
|
+
import("./TunnelManager-ZSVX7U3Z.js").then(({ TunnelManager }) => TunnelManager.getInstance().applyLogLevelToActiveTunnels(level)).catch(() => {
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
var _logger = null;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
getLogLevel,
|
|
6
6
|
logger
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-P7WNBN7F.js";
|
|
8
8
|
import {
|
|
9
9
|
getTunnelLogPath
|
|
10
10
|
} from "./chunk-GBYF2H4H.js";
|
|
@@ -121,7 +121,7 @@ function startSpinner(name = "dots", text = "Loading") {
|
|
|
121
121
|
}
|
|
122
122
|
currentTimer = setInterval(() => {
|
|
123
123
|
const frame = spinner.frames[i = ++i % spinner.frames.length];
|
|
124
|
-
process.stdout.write(`\r${pico.cyan(frame)} ${text}`);
|
|
124
|
+
process.stdout.write(`\r${pico.cyan(frame)} ${text}\x1B[K`);
|
|
125
125
|
}, spinner.interval);
|
|
126
126
|
return () => stopSpinner();
|
|
127
127
|
}
|
|
@@ -137,7 +137,7 @@ function stopSpinnerSuccess(message) {
|
|
|
137
137
|
clearInterval(currentTimer);
|
|
138
138
|
currentTimer = null;
|
|
139
139
|
const finalMessage = message || currentText;
|
|
140
|
-
process.stdout.write(`\r${pico.green("\u2714")} ${finalMessage}
|
|
140
|
+
process.stdout.write(`\r${pico.green("\u2714")} ${finalMessage}\x1B[K
|
|
141
141
|
`);
|
|
142
142
|
}
|
|
143
143
|
}
|
|
@@ -146,7 +146,7 @@ function stopSpinnerFail(message) {
|
|
|
146
146
|
clearInterval(currentTimer);
|
|
147
147
|
currentTimer = null;
|
|
148
148
|
const finalMessage = message || currentText;
|
|
149
|
-
process.stdout.write(`\r${pico.red("\u2716")} ${finalMessage}
|
|
149
|
+
process.stdout.write(`\r${pico.red("\u2716")} ${finalMessage}\x1B[K
|
|
150
150
|
`);
|
|
151
151
|
}
|
|
152
152
|
}
|
|
@@ -724,6 +724,29 @@ var TunnelManager = class _TunnelManager {
|
|
|
724
724
|
}
|
|
725
725
|
return Promise.reject(new Error(`Either configId or tunnelId must be provided`));
|
|
726
726
|
}
|
|
727
|
+
/**
|
|
728
|
+
* Stop a tunnel instance and wait for the stop to settle, capped by a
|
|
729
|
+
* timeout. Failure is logged, not thrown: the caller replaces the
|
|
730
|
+
* instance either way and a hung stop must not block that forever.
|
|
731
|
+
*/
|
|
732
|
+
async stopInstanceGuarded(managed, timeoutMs = 5e3) {
|
|
733
|
+
let timer;
|
|
734
|
+
try {
|
|
735
|
+
await Promise.race([
|
|
736
|
+
managed.instance.stop(),
|
|
737
|
+
new Promise((_, reject) => {
|
|
738
|
+
timer = setTimeout(() => reject(new Error(`Stop timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
739
|
+
})
|
|
740
|
+
]);
|
|
741
|
+
} catch (e) {
|
|
742
|
+
logger.warn("Failed to stop tunnel instance before replacement", {
|
|
743
|
+
tunnelId: managed.tunnelid,
|
|
744
|
+
error: errorMessage(e)
|
|
745
|
+
});
|
|
746
|
+
} finally {
|
|
747
|
+
if (timer) clearTimeout(timer);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
727
750
|
/**
|
|
728
751
|
* Restarts a tunnel with its current configuration.
|
|
729
752
|
* This function will stop the tunnel if it's running and start it again.
|
|
@@ -745,6 +768,9 @@ var TunnelManager = class _TunnelManager {
|
|
|
745
768
|
const currentServe = existingTunnel.serve;
|
|
746
769
|
const autoReconnect = existingTunnel.autoReconnect || false;
|
|
747
770
|
const currentOrigin = existingTunnel.origin;
|
|
771
|
+
if (!existingTunnel.isStopped) {
|
|
772
|
+
await this.stopInstanceGuarded(existingTunnel);
|
|
773
|
+
}
|
|
748
774
|
this.tunnelsByTunnelId.delete(tunnelid);
|
|
749
775
|
this.tunnelsByConfigId.delete(existingTunnel.configId);
|
|
750
776
|
this.tunnelStats.delete(tunnelid);
|
|
@@ -779,9 +805,26 @@ var TunnelManager = class _TunnelManager {
|
|
|
779
805
|
throw new Error(`Failed to restart tunnel: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
780
806
|
}
|
|
781
807
|
}
|
|
808
|
+
/**
|
|
809
|
+
* Carry lifecycle state from a replaced tunnel over to its replacement:
|
|
810
|
+
* keep createdAt, start the replacement if the old tunnel was running,
|
|
811
|
+
* otherwise keep it stopped with the original timestamps.
|
|
812
|
+
*/
|
|
813
|
+
async applyPreservedLifecycle(tunnel, prior) {
|
|
814
|
+
if (prior.createdAt) {
|
|
815
|
+
tunnel.createdAt = prior.createdAt;
|
|
816
|
+
}
|
|
817
|
+
if (!prior.isStopped) {
|
|
818
|
+
await this.startTunnel(tunnel.tunnelid);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
tunnel.isStopped = true;
|
|
822
|
+
tunnel.startedAt = prior.startedAt;
|
|
823
|
+
tunnel.stoppedAt = prior.stoppedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
824
|
+
}
|
|
782
825
|
/**
|
|
783
826
|
* Updates the configuration of an existing tunnel.
|
|
784
|
-
*
|
|
827
|
+
*
|
|
785
828
|
* This method handles the process of updating a tunnel's configuration while preserving
|
|
786
829
|
* its state. If the tunnel is running, it will be stopped, updated, and restarted.
|
|
787
830
|
* In case of failure, it attempts to restore the original configuration.
|
|
@@ -808,10 +851,13 @@ var TunnelManager = class _TunnelManager {
|
|
|
808
851
|
const currentServe = existingTunnel.serve;
|
|
809
852
|
const currentAutoReconnect = existingTunnel.autoReconnect || false;
|
|
810
853
|
const currentOrigin = existingTunnel.origin;
|
|
854
|
+
const currentCreatedAt = existingTunnel.createdAt;
|
|
855
|
+
const currentStartedAt = existingTunnel.startedAt;
|
|
856
|
+
const currentStoppedAt = existingTunnel.stoppedAt;
|
|
811
857
|
const requestedServe = this.resolveServePath(newConfig);
|
|
812
858
|
try {
|
|
813
859
|
if (!isStopped) {
|
|
814
|
-
|
|
860
|
+
await this.stopInstanceGuarded(existingTunnel);
|
|
815
861
|
}
|
|
816
862
|
this.tunnelsByTunnelId.delete(currentTunnelId);
|
|
817
863
|
this.tunnelsByConfigId.delete(currentTunnelConfigId);
|
|
@@ -823,7 +869,6 @@ var TunnelManager = class _TunnelManager {
|
|
|
823
869
|
};
|
|
824
870
|
const effectiveServe = requestedServe !== void 0 ? requestedServe : currentServe;
|
|
825
871
|
const effectiveTunnelName = newTunnelName !== void 0 ? newTunnelName : currentTunnelName;
|
|
826
|
-
let configWithForwarding;
|
|
827
872
|
const newTunnel = await this._createTunnelWithProcessedConfig({
|
|
828
873
|
configId,
|
|
829
874
|
tunnelid: currentTunnelId,
|
|
@@ -833,9 +878,12 @@ var TunnelManager = class _TunnelManager {
|
|
|
833
878
|
serve: effectiveServe,
|
|
834
879
|
autoReconnect: currentAutoReconnect
|
|
835
880
|
});
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
881
|
+
await this.applyPreservedLifecycle(newTunnel, {
|
|
882
|
+
isStopped,
|
|
883
|
+
createdAt: currentCreatedAt,
|
|
884
|
+
startedAt: currentStartedAt,
|
|
885
|
+
stoppedAt: currentStoppedAt
|
|
886
|
+
});
|
|
839
887
|
logger.info("Tunnel configuration updated", {
|
|
840
888
|
tunnelId: newTunnel.tunnelid,
|
|
841
889
|
configId: newTunnel.configId,
|
|
@@ -857,9 +905,12 @@ var TunnelManager = class _TunnelManager {
|
|
|
857
905
|
serve: currentServe,
|
|
858
906
|
autoReconnect: currentAutoReconnect
|
|
859
907
|
});
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
908
|
+
await this.applyPreservedLifecycle(originalTunnel, {
|
|
909
|
+
isStopped,
|
|
910
|
+
createdAt: currentCreatedAt,
|
|
911
|
+
startedAt: currentStartedAt,
|
|
912
|
+
stoppedAt: currentStoppedAt
|
|
913
|
+
});
|
|
863
914
|
logger.warn("Restored original tunnel configuration after update failure", {
|
|
864
915
|
currentTunnelId,
|
|
865
916
|
error: errorMessage(error)
|
|
@@ -1476,6 +1527,9 @@ var TunnelManager = class _TunnelManager {
|
|
|
1476
1527
|
try {
|
|
1477
1528
|
logger.info("Tunnel reconnection completed", { tunnelId, urls });
|
|
1478
1529
|
const managedTunnel = this.tunnelsByTunnelId.get(tunnelId);
|
|
1530
|
+
if (managedTunnel?.isStopping || managedTunnel?.isStopped) {
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1479
1533
|
if (managedTunnel) {
|
|
1480
1534
|
managedTunnel.isStopped = false;
|
|
1481
1535
|
managedTunnel.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -62,8 +62,8 @@ var IPCClient = class {
|
|
|
62
62
|
async stopTunnel(tunnelid) {
|
|
63
63
|
return this.call(Route.StopTunnel, { tunnelid });
|
|
64
64
|
}
|
|
65
|
-
async restartTunnel(tunnelid) {
|
|
66
|
-
return this.call(Route.RestartTunnel, { tunnelid });
|
|
65
|
+
async restartTunnel(tunnelid, noWait) {
|
|
66
|
+
return this.call(Route.RestartTunnel, { tunnelid, noWait });
|
|
67
67
|
}
|
|
68
68
|
// v1 operations (used by remote management via daemon)
|
|
69
69
|
async startTunnelV1(config, mode, noWait) {
|
|
@@ -22,8 +22,8 @@ import {
|
|
|
22
22
|
validateName,
|
|
23
23
|
validateNameForStorage,
|
|
24
24
|
validateNameStrict
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import "./chunk-
|
|
25
|
+
} from "./chunk-YWXADADB.js";
|
|
26
|
+
import "./chunk-P7WNBN7F.js";
|
|
27
27
|
import "./chunk-GBYF2H4H.js";
|
|
28
28
|
export {
|
|
29
29
|
CONFIG_VERBS,
|
|
@@ -6,16 +6,16 @@ import {
|
|
|
6
6
|
trackIPCTunnelStart,
|
|
7
7
|
trackTunnelStart,
|
|
8
8
|
trackTunnelStop
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-OH6FSLYF.js";
|
|
10
|
+
import "./chunk-HN4YLM7U.js";
|
|
11
11
|
import "./chunk-MT44NAXX.js";
|
|
12
12
|
import {
|
|
13
13
|
DaemonHost
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-YTJEV27N.js";
|
|
15
|
+
import "./chunk-YWXADADB.js";
|
|
16
|
+
import "./chunk-PQSLSIDA.js";
|
|
17
17
|
import "./chunk-UB26QJ4T.js";
|
|
18
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-P7WNBN7F.js";
|
|
19
19
|
import "./chunk-GBYF2H4H.js";
|
|
20
20
|
export {
|
|
21
21
|
DaemonHost,
|