pinggy 0.3.0 → 0.3.2

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.
Files changed (47) hide show
  1. package/.github/workflows/publish-binaries.yml +50 -54
  2. package/Makefile +2 -2
  3. package/dist/index.cjs +1060 -902
  4. package/dist/index.d.cts +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +1039 -129
  7. package/ent.plist +14 -0
  8. package/package.json +31 -14
  9. package/scripts/pre_pkg_processing.js +74 -0
  10. package/src/cli/buildConfig.ts +10 -13
  11. package/src/cli/{starCli.tsx → starCli.ts} +51 -80
  12. package/src/index.ts +0 -6
  13. package/src/remote_management/remoteManagement.ts +0 -3
  14. package/src/remote_management/remote_schema.ts +2 -2
  15. package/src/tui/blessed/TunnelTui.ts +298 -0
  16. package/src/tui/blessed/components/DisplayUpdaters.ts +118 -0
  17. package/src/tui/blessed/components/KeyBindings.ts +134 -0
  18. package/src/tui/blessed/components/Modals.ts +216 -0
  19. package/src/tui/blessed/components/UIComponents.ts +306 -0
  20. package/src/tui/blessed/components/index.ts +4 -0
  21. package/src/tui/blessed/headerFetcher.ts +35 -0
  22. package/src/tui/blessed/index.ts +2 -0
  23. package/src/tui/blessed/qrCodeGenerator.ts +20 -0
  24. package/src/tui/blessed/webDebuggerConnection.ts +100 -0
  25. package/src/tui/{hooks → ink/hooks}/useReqResHeaders.ts +1 -1
  26. package/src/tui/{hooks → ink/hooks}/useWebDebugger.ts +2 -2
  27. package/src/tui/{index.tsx → ink/index.tsx} +12 -2
  28. package/src/tui/spinner/spinner.ts +64 -0
  29. package/src/tunnel_manager/TunnelManager.ts +9 -10
  30. package/src/types.ts +1 -1
  31. package/src/utils/printer.ts +15 -21
  32. package/src/utils/util.ts +5 -0
  33. package/tsconfig.json +1 -1
  34. package/dist/tui-AZUFY7T2.js +0 -584
  35. package/src/utils/esmOnlyPackageLoader.ts +0 -29
  36. /package/src/tui/{asciArt.ts → ink/asciArt.ts} +0 -0
  37. /package/src/tui/{hooks → ink/hooks}/useQrCodes.ts +0 -0
  38. /package/src/tui/{hooks → ink/hooks}/useTerminalSize.ts +0 -0
  39. /package/src/tui/{hooks → ink/hooks}/useTerminalStats.ts +0 -0
  40. /package/src/tui/{layout → ink/layout}/Borders.tsx +0 -0
  41. /package/src/tui/{layout → ink/layout}/Container.tsx +0 -0
  42. /package/src/tui/{sections → ink/sections}/DebuggerDetailModal.tsx +0 -0
  43. /package/src/tui/{sections → ink/sections}/KeyBindings.tsx +0 -0
  44. /package/src/tui/{sections → ink/sections}/QrCodeSection.tsx +0 -0
  45. /package/src/tui/{sections → ink/sections}/StatsSection.tsx +0 -0
  46. /package/src/tui/{sections → ink/sections}/URLsSection.tsx +0 -0
  47. /package/src/tui/{utils → ink/utils}/utils.ts +0 -0
package/ent.plist ADDED
@@ -0,0 +1,14 @@
1
+ <!-- Entitlement for mac os signing since allow-unsigned-executable-memory is required -->
2
+ <?xml version="1.0" encoding="UTF-8"?>
3
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
4
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
5
+ <plist version="1.0">
6
+ <dict>
7
+ <key>com.apple.security.cs.allow-jit</key>
8
+ <true/>
9
+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
10
+ <true/>
11
+ <key>com.apple.security.cs.disable-library-validation</key>
12
+ <true/>
13
+ </dict>
14
+ </plist>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinggy",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "description": "Create secure, shareable tunnels to your localhost and manage them from the command line. ",
@@ -8,7 +8,7 @@
8
8
  "module": ".dist/index.js",
9
9
  "types": ".dist/index.d.ts",
10
10
  "bin": {
11
- "pinggy": "dist/index.js"
11
+ "pinggy": "dist/index.cjs"
12
12
  },
13
13
  "scripts": {
14
14
  "build:tsc": "tsc",
@@ -18,7 +18,19 @@
18
18
  "bump": "node scripts/bumpVersion.js --bump && npm install",
19
19
  "bump:minor": "node scripts/bumpVersion.js --bump --minor && npm install",
20
20
  "bump:major": "node scripts/bumpVersion.js --bump --major && npm install",
21
- "dev": "npm link @pinggy/pinggy && npm run build && npm link "
21
+ "dev": "npm link @pinggy/pinggy && npm run build && npm link ",
22
+ "pre-pkg": "node scripts/pre_pkg_processing.js remove",
23
+ "post-pkg": "node scripts/pre_pkg_processing.js restore",
24
+ "pack:linux-x64": "npm run pre-pkg && pkg . --targets node20-linux-x64 --output out/pinggy-linux-x64 && npm run post-pkg",
25
+ "pack:linux-arm64": "npm run pre-pkg && pkg . --targets node20-linux-arm64 --output out/pinggy-linux-arm64 && npm run post-pkg",
26
+ "pack:linux": "npm run pack:linux-x64 && npm run pack:linux-arm64",
27
+ "pack:win-x64": "npm run pre-pkg && pkg . --targets node20-win-x64 --output out/pinggy-win-x64.exe && npm run post-pkg",
28
+ "pack:win-arm64": "npm run pre-pkg && pkg . --targets node20-win-arm64 --output out/pinggy-win-arm64.exe && npm run post-pkg",
29
+ "pack:windows": "npm run pack:win-x64 && npm run pack:win-arm64",
30
+ "pack:macos-x64": "npm run pre-pkg && pkg . --targets node20-macos-x64 --output out/pinggy-macos-x64 && npm run post-pkg",
31
+ "pack:macos-arm64": "npm run pre-pkg && pkg . --targets node20-macos-arm64 --output out/pinggy-macos-arm64 && npm run post-pkg",
32
+ "pack:macos": "npm run pack:macos-x64 && npm run pack:macos-arm64",
33
+ "pack:all": "npm run pack:linux-x64 && npm run pack:linux-arm64 && npm run pack:win-x64 && npm run pack:macos-x64 && npm run pack:macos-arm64"
22
34
  },
23
35
  "exports": {
24
36
  ".": {
@@ -27,30 +39,35 @@
27
39
  "require": "./dist/index.cjs"
28
40
  }
29
41
  },
42
+ "pkg": {
43
+ "scripts": [
44
+ "dist/index.cjs"
45
+ ],
46
+ "assets": [
47
+ "node_modules/@pinggy/pinggy/**/*",
48
+ "node_modules/blessed/lib/**/*",
49
+ "node_modules/blessed/usr/**/*"
50
+ ]
51
+ },
30
52
  "dependencies": {
31
- "@pinggy/pinggy": "^0.3.1",
32
- "chalk": "^5.6.2",
53
+ "@pinggy/pinggy": "^0.3.2",
54
+ "blessed": "^0.1.81",
33
55
  "clipboardy": "^5.0.0",
34
- "fullscreen-ink": "^0.1.0",
35
- "ink": "^6.3.1",
36
- "ink-big-text": "^2.0.0",
37
- "ink-gradient": "^3.0.0",
38
56
  "mime": "^4.1.0",
39
- "ora": "^9.0.0",
40
- "qrcode-terminal": "^0.12.0",
41
- "react": "^19.1.1",
42
- "uuid": "^12.0.0",
57
+ "picocolors": "^1.1.1",
58
+ "qrcode": "^1.5.4",
43
59
  "winston": "^3.17.0",
44
60
  "ws": "^8.18.0",
45
61
  "zod": "^4.1.5"
46
62
  },
47
63
  "devDependencies": {
48
64
  "@appthreat/caxa": "^1.0.13",
65
+ "@types/blessed": "^0.1.25",
49
66
  "@types/jest": "^30.0.0",
50
67
  "@types/node": "^24.3.0",
51
68
  "@types/qrcode-terminal": "^0.12.2",
52
- "@types/react": "^19.2.0",
53
69
  "@types/ws": "^8.18.1",
70
+ "@yao-pkg/pkg": "^6.11.0",
54
71
  "jest": "^30.1.2",
55
72
  "ts-jest": "^29.4.1",
56
73
  "ts-node": "^10.9.2",
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Script to temporarily remove "type": "module" from package.json before running pkg
5
+ */
6
+
7
+ import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';
8
+ import { join, dirname } from 'path';
9
+ import { fileURLToPath } from 'url';
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+ const packageJsonPath = join(__dirname, '..', 'package.json');
14
+ const backupPath = join(__dirname, '..', 'package.json.backup');
15
+
16
+ function main() {
17
+ const action = process.argv[2] || 'remove';
18
+
19
+ if (action === 'remove') {
20
+ removeTypeModule();
21
+ } else if (action === 'restore') {
22
+ restoreTypeModule();
23
+ } else {
24
+ console.error('Usage: node pre-pkg.js [remove|restore]');
25
+ process.exit(1);
26
+ }
27
+ }
28
+
29
+ function removeTypeModule() {
30
+ try {
31
+ // Read package.json
32
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
33
+
34
+ // Create backup if type module exists
35
+ if (packageJson.type === 'module') {
36
+ writeFileSync(backupPath, JSON.stringify(packageJson, null, 2));
37
+ console.log('Backup created at package.json.backup');
38
+
39
+ // Remove type module
40
+ delete packageJson.type;
41
+
42
+ // Write back to package.json
43
+ writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
44
+ console.log('Removed "type": "module" from package.json');
45
+ } else {
46
+ console.log('No "type": "module" found in package.json');
47
+ }
48
+ } catch (error) {
49
+ console.error('Error removing type module:', error.message);
50
+ process.exit(1);
51
+ }
52
+ }
53
+
54
+ function restoreTypeModule() {
55
+ try {
56
+ if (existsSync(backupPath)) {
57
+ // Restore from backup
58
+ const backupContent = readFileSync(backupPath, 'utf8');
59
+ writeFileSync(packageJsonPath, backupContent);
60
+
61
+ // Remove backup file
62
+ unlinkSync(backupPath);
63
+
64
+ console.log('Restored package.json from backup');
65
+ } else {
66
+ console.log('No backup file found, nothing to restore');
67
+ }
68
+ } catch (error) {
69
+ console.error('Error restoring package.json:', error.message);
70
+ process.exit(1);
71
+ }
72
+ }
73
+
74
+ main();
@@ -4,11 +4,10 @@ import { logger } from "../logger.js";
4
4
  import { FinalConfig, Forwarding } from "../types.js";
5
5
  import { ParsedValues } from "../utils/parseArgs.js";
6
6
  import { cliOptions } from "./options.js";
7
- import { isValidPort } from "../utils/util.js";
7
+ import { getRandomId, isValidPort } from "../utils/util.js";
8
8
  import { TunnelType } from "@pinggy/pinggy";
9
9
  import fs from "fs";
10
10
  import path from "path";
11
- import { getUuid } from "../utils/esmOnlyPackageLoader.js";
12
11
 
13
12
  const domainRegex = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
14
13
 
@@ -188,7 +187,7 @@ function parseForwarding(forwarding: string): Forwarding | Error {
188
187
 
189
188
  function parseReverseTunnelAddr(finalConfig: FinalConfig, values: ParsedValues<typeof cliOptions>): Error | null {
190
189
  const reverseTunnel = values.R;
191
- if ((!Array.isArray(reverseTunnel) || reverseTunnel.length === 0) && !values.localport) {
190
+ if ((!Array.isArray(reverseTunnel) || reverseTunnel.length === 0) && !values.localport && !finalConfig.forwarding) {
192
191
  return new Error("local port not specified. Please use '-h' option for help.");
193
192
  }
194
193
 
@@ -314,9 +313,6 @@ export async function buildFinalConfig(values: ParsedValues<typeof cliOptions>,
314
313
  let saveconf = isSaveConfOption(values);
315
314
 
316
315
  const configFromFile = loadJsonConfig(values);
317
- if (configFromFile !== null) {
318
- finalConfig = { ...configFromFile };
319
- }
320
316
 
321
317
  const userParse = parseUsers(positionals, values.token);
322
318
  token = userParse.token;
@@ -329,13 +325,14 @@ export async function buildFinalConfig(values: ParsedValues<typeof cliOptions>,
329
325
  const initialTunnel = (type || values.type) as TunnelType;
330
326
  finalConfig = {
331
327
  ...defaultOptions,
332
- configid: await getUuid(),
333
- token: token || (typeof values.token === 'string' ? values.token : ''),
334
- serverAddress: server || defaultOptions.serverAddress,
335
- tunnelType: initialTunnel ? [initialTunnel] : [TunnelType.Http],
336
- NoTUI: values.notui || false,
337
- qrCode: qrCode || false,
338
- autoReconnect: values.autoreconnect || false,
328
+ ...(configFromFile || {}), // Apply loaded config on top of defaults
329
+ configid: getRandomId(),
330
+ token: token || (configFromFile?.token || (typeof values.token === 'string' ? values.token : '')),
331
+ serverAddress: server || (configFromFile?.serverAddress || defaultOptions.serverAddress),
332
+ tunnelType: initialTunnel ? [initialTunnel] : (configFromFile?.tunnelType || [TunnelType.Http]),
333
+ NoTUI: values.notui || (configFromFile?.NoTUI || false),
334
+ qrCode: qrCode || (configFromFile?.qrCode || false),
335
+ autoReconnect: values.autoreconnect || (configFromFile?.autoReconnect || false),
339
336
  };
340
337
 
341
338
 
@@ -1,9 +1,10 @@
1
1
  import CLIPrinter from "../utils/printer.js";
2
- import { TunnelManager } from "../tunnel_manager/TunnelManager.js";
3
- import { loadChalk } from "../utils/esmOnlyPackageLoader.js";
2
+ import { ManagedTunnel, TunnelManager } from "../tunnel_manager/TunnelManager.js";
4
3
  import { FinalConfig } from "../types.js";
5
4
  import { getFreePort } from "../utils/getFreePort.js";
6
5
  import { logger } from "../logger.js";
6
+ import pico from "picocolors";
7
+ import { TunnelTui } from "../tui/blessed/index.js"
7
8
 
8
9
  interface TunnelData {
9
10
  urls: string[] | null;
@@ -17,12 +18,7 @@ const TunnelData: TunnelData = {
17
18
  usage: null,
18
19
  };
19
20
 
20
- let activeTui: {
21
- instance?: { unmount?: () => void };
22
- start: () => Promise<void>;
23
- waitUntilExit: () => Promise<void>;
24
- } | null = null;
25
-
21
+ let activeTui: any = null; // TunnelTui type - loaded dynamically
26
22
 
27
23
  let disconnectState: {
28
24
  disconnected: boolean;
@@ -30,72 +26,47 @@ let disconnectState: {
30
26
  messages?: string[];
31
27
  } | null = null;
32
28
 
33
- let updateDisconnectState: ((state: typeof disconnectState) => void) | null = null;
34
-
35
29
  declare global {
36
30
  var __PINGGY_TUNNEL_STATS__: ((stats: any) => void) | undefined;
37
31
  }
38
32
 
39
- async function launchTui(finalConfig: FinalConfig, urls: string[] | null, greet: string | null) {
33
+ async function launchTui(finalConfig: FinalConfig, urls: string[] | null, greet: string | null, tunnel: ManagedTunnel) {
40
34
  try {
41
- const { withFullScreen } = await import("fullscreen-ink");
42
- const { default: TunnelTui } = await import("../tui/index.js");
43
- const React = await import("react");
44
35
  const isTTYEnabled = process.stdin.isTTY;
45
36
 
46
- const TunnelTuiWrapper = ({ finalConfig, urls, greet }: any) => {
47
- const [disconnectInfo, setDisconnectInfo] = React.useState<typeof disconnectState>(null);
37
+ if (!isTTYEnabled) {
38
+ CLIPrinter.warn("Unable to initiate the TUI: your terminal does not support the required input mode.");
39
+ return;
40
+ }
48
41
 
49
- React.useEffect(() => {
50
- updateDisconnectState = setDisconnectInfo;
51
- return () => {
52
- updateDisconnectState = null;
53
- };
54
- }, []);
55
-
56
- return (
57
- <TunnelTui
58
- urls={urls ?? []}
59
- greet={greet ?? ""}
60
- tunnelConfig={finalConfig}
61
- disconnectInfo={disconnectInfo}
62
- />
63
- );
64
- };
65
-
66
- const tui = withFullScreen(
67
- <TunnelTuiWrapper
68
- finalConfig={finalConfig}
69
- urls={urls}
70
- greet={greet}
71
- />
72
- );
42
+
43
+ const tui = new TunnelTui({
44
+ urls: urls ?? [],
45
+ greet: greet ?? "",
46
+ tunnelConfig: finalConfig,
47
+ disconnectInfo: null,
48
+ tunnelInstance: tunnel,
49
+ });
73
50
 
74
51
  activeTui = tui;
75
52
 
76
- if (isTTYEnabled) {
77
- try {
78
- await tui.start();
79
- await tui.waitUntilExit();
80
- } catch (e) {
81
- logger.warn("TUI error", e);
82
- } finally {
83
- activeTui = null;
84
- }
85
- } else {
86
- CLIPrinter.warn("Unable to initiate the TUI: your terminal does not support the required input mode.");
53
+ try {
54
+ tui.start();
55
+ await tui.waitUntilExit();
56
+ } catch (e) {
57
+ logger.warn("TUI error", e);
58
+ } finally {
59
+ activeTui = null;
87
60
  }
88
61
  } catch (e) {
89
62
  logger.warn("Failed to (re-)initiate TUI", e);
90
63
  }
91
- };
64
+ }
92
65
 
93
66
 
94
67
 
95
68
  export async function startCli(finalConfig: FinalConfig, manager: TunnelManager) {
96
69
 
97
- await CLIPrinter.ensureDeps();
98
- const chalk = await loadChalk();
99
70
 
100
71
  if (!finalConfig.NoTUI && finalConfig.webDebugger === "") {
101
72
  // Need a webdebugger port
@@ -128,46 +99,46 @@ export async function startCli(finalConfig: FinalConfig, manager: TunnelManager)
128
99
 
129
100
 
130
101
  await manager.startTunnel(tunnel.tunnelid);
131
- CLIPrinter.stopSpinnerSuccess("Connected to Pinggy");
132
- CLIPrinter.success(chalk.bold("Tunnel established!"));
133
- CLIPrinter.print(chalk.gray("───────────────────────────────"));
102
+ CLIPrinter.stopSpinnerSuccess(" Connected to Pinggy");
103
+ CLIPrinter.success(pico.bold("Tunnel established!"));
104
+ CLIPrinter.print(pico.gray("───────────────────────────────"));
134
105
 
135
106
  TunnelData.urls = await manager.getTunnelUrls(tunnel.tunnelid);
136
107
  TunnelData.greet = await manager.getTunnelGreetMessage(tunnel.tunnelid);
137
108
 
138
- CLIPrinter.info(chalk.cyanBright("Remote URLs:"));
109
+ CLIPrinter.info(pico.cyanBright("Remote URLs:"));
139
110
  (TunnelData.urls ?? []).forEach((url: string) =>
140
- CLIPrinter.print(" " + chalk.magentaBright(url))
111
+ CLIPrinter.print(" " + pico.magentaBright(url))
141
112
  );
142
- CLIPrinter.print(chalk.gray("───────────────────────────────"));
113
+ CLIPrinter.print(pico.gray("───────────────────────────────"));
143
114
 
144
115
 
145
116
  if (TunnelData.greet?.includes("not authenticated")) {
146
117
  // show unauthenticated warning
147
- CLIPrinter.warn(chalk.yellowBright(TunnelData.greet));
118
+ CLIPrinter.warn(pico.yellowBright(TunnelData.greet));
148
119
  } else if (TunnelData.greet?.includes("authenticated as")) {
149
120
  // extract email
150
121
  const emailMatch = /authenticated as (.+)/.exec(TunnelData.greet);
151
122
  if (emailMatch) {
152
123
  const email = emailMatch[1];
153
- CLIPrinter.info(chalk.cyanBright("Authenticated as: " + email));
124
+ CLIPrinter.info(pico.cyanBright("Authenticated as: " + email));
154
125
  }
155
126
  }
156
127
 
157
- CLIPrinter.print(chalk.gray("───────────────────────────────"));
158
- CLIPrinter.print(chalk.gray("\nPress Ctrl+C to stop the tunnel.\n"));
128
+ CLIPrinter.print(pico.gray("───────────────────────────────"));
129
+ CLIPrinter.print(pico.gray("\nPress Ctrl+C to stop the tunnel.\n"));
159
130
 
160
131
  manager.registerDisconnectListener(tunnel.tunnelid, async (tunnelId, error, messages) => {
161
- if (activeTui && updateDisconnectState) {
132
+ if (activeTui) {
162
133
  disconnectState = {
163
134
  disconnected: true,
164
135
  error: error,
165
136
  messages: messages
166
137
  };
167
- updateDisconnectState(disconnectState);
138
+ activeTui.updateDisconnectInfo(disconnectState);
168
139
 
169
140
  try {
170
- // Wait for Ink to fully exit
141
+ // Wait for Blessed TUI to fully exit
171
142
  await activeTui.waitUntilExit();
172
143
  } catch (e) {
173
144
  logger.warn("Failed to wait for TUI exit", e);
@@ -175,10 +146,10 @@ export async function startCli(finalConfig: FinalConfig, manager: TunnelManager)
175
146
  activeTui = null;
176
147
  CLIPrinter.warn(`Error in tunnel:`);
177
148
  messages?.forEach(function (m) {
178
- CLIPrinter.warn(m)
149
+ CLIPrinter.warnTxt(m)
179
150
  });
180
151
 
181
- // Exit ONLY after fullscreen ink has restored the terminal
152
+ // Exit ONLY after blessed has restored the terminal
182
153
  // On disconnect only exit if autoReconnect is false otherwise retry will not work
183
154
  if (!finalConfig.autoReconnect) {
184
155
  process.exit(0);
@@ -210,34 +181,34 @@ export async function startCli(finalConfig: FinalConfig, manager: TunnelManager)
210
181
  // ignore
211
182
  }
212
183
 
213
- CLIPrinter.success(chalk.bold("Tunnel re-established!"));
214
- CLIPrinter.print(chalk.gray("───────────────────────────────"));
184
+ CLIPrinter.success(pico.bold("Tunnel re-established!"));
185
+ CLIPrinter.print(pico.gray("───────────────────────────────"));
215
186
 
216
187
  TunnelData.urls = urls;
217
188
  TunnelData.greet = await manager.getTunnelGreetMessage(tunnel.tunnelid);
218
189
 
219
- CLIPrinter.info(chalk.cyanBright("Remote URLs:"));
190
+ CLIPrinter.info(pico.cyanBright("Remote URLs:"));
220
191
  (TunnelData.urls ?? []).forEach((url: string) =>
221
- CLIPrinter.print(" " + chalk.magentaBright(url))
192
+ CLIPrinter.print(" " + pico.magentaBright(url))
222
193
  );
223
- CLIPrinter.print(chalk.gray("───────────────────────────────"));
194
+ CLIPrinter.print(pico.gray("───────────────────────────────"));
224
195
 
225
196
  if (TunnelData.greet?.includes("not authenticated")) {
226
- CLIPrinter.warn(chalk.yellowBright(TunnelData.greet));
197
+ CLIPrinter.warn(pico.yellowBright(TunnelData.greet));
227
198
  } else if (TunnelData.greet?.includes("authenticated as")) {
228
199
  const emailMatch = /authenticated as (.+)/.exec(TunnelData.greet);
229
200
  if (emailMatch) {
230
201
  const email = emailMatch[1];
231
- CLIPrinter.info(chalk.cyanBright("Authenticated as: " + email));
202
+ CLIPrinter.info(pico.cyanBright("Authenticated as: " + email));
232
203
  }
233
204
  }
234
205
 
235
- CLIPrinter.print(chalk.gray("───────────────────────────────"));
236
- CLIPrinter.print(chalk.gray("\nPress Ctrl+C to stop the tunnel.\n"));
206
+ CLIPrinter.print(pico.gray("───────────────────────────────"));
207
+ CLIPrinter.print(pico.gray("\nPress Ctrl+C to stop the tunnel.\n"));
237
208
 
238
209
  // If the TUI was enabled previously, re-create and start it
239
210
  if (!finalConfig.NoTUI) {
240
- await launchTui(finalConfig, TunnelData.urls, TunnelData.greet);
211
+ await launchTui(finalConfig, TunnelData.urls, TunnelData.greet, tunnel);
241
212
  }
242
213
  });
243
214
  } catch (e) {
@@ -245,7 +216,7 @@ export async function startCli(finalConfig: FinalConfig, manager: TunnelManager)
245
216
  }
246
217
 
247
218
  if (!finalConfig.NoTUI) {
248
- await launchTui(finalConfig, TunnelData.urls, TunnelData.greet);
219
+ await launchTui(finalConfig, TunnelData.urls, TunnelData.greet,tunnel);
249
220
  }
250
221
 
251
222
 
package/src/index.ts CHANGED
@@ -15,16 +15,11 @@ import { argv } from 'process';
15
15
  import { realpathSync } from 'fs';
16
16
  import { enablePackageLogging } from "./logger.js"
17
17
  import { getRemoteManagementState, initiateRemoteManagement, closeRemoteManagement } from "./remote_management/remoteManagement.js";
18
- import { loadChalk } from "./utils/esmOnlyPackageLoader.js";
19
-
20
18
 
21
19
  export { TunnelManager, TunnelOperations, TunnelResponse, enablePackageLogging, getRemoteManagementState, initiateRemoteManagement, closeRemoteManagement };
22
20
 
23
-
24
21
  async function main() {
25
22
  try {
26
- await CLIPrinter.ensureDeps();
27
- await loadChalk();
28
23
  // Parse arguments from the command line
29
24
  const { values, positionals, hasAnyArgs } = parseCliArgs(cliOptions);
30
25
 
@@ -65,7 +60,6 @@ async function main() {
65
60
  logger.debug("Building final config from CLI values and positionals", { values, positionals });
66
61
  const finalConfig = await buildFinalConfig(values, positionals);
67
62
  logger.debug("Final configuration built", finalConfig);
68
-
69
63
  await startCli(finalConfig, manager);
70
64
 
71
65
  } catch (error) {
@@ -2,7 +2,6 @@ import WebSocket from "ws";
2
2
  import { logger } from "../logger.js";
3
3
  import { handleConnectionStatusMessage, WebSocketCommandHandler, WebSocketRequest } from "./websocket_handlers.js";
4
4
  import CLIPrinter from "../utils/printer.js";
5
- import { loadChalk } from "../utils/esmOnlyPackageLoader.js";
6
5
  import { RemoteManagementState, RemoteManagementStatus } from "../types.js";
7
6
 
8
7
  const RECONNECT_SLEEP_MS = 5000; // 5 seconds
@@ -70,8 +69,6 @@ export async function parseRemoteManagement(values: RemoteManagementValues): Pro
70
69
  * - Keep running until closed or SIGINT
71
70
  */
72
71
  export async function initiateRemoteManagement(token: string, manage?: string): Promise<RemoteManagementState> {
73
- await CLIPrinter.ensureDeps();
74
- await loadChalk();
75
72
 
76
73
  if (!token || token.trim().length === 0) {
77
74
  throw new Error("Remote management token is required (use --remote-management <TOKEN>)");
@@ -25,7 +25,7 @@ export const TunnelConfigSchema = z
25
25
  autoreconnect: z.boolean(),
26
26
  basicauth: z.array(z.object({ username: z.string(), password: z.string() })).nullable(),
27
27
  bearerauth: z.string().nullable(),
28
- configid: z.string().uuid(),
28
+ configid: z.string(),
29
29
  configname: z.string(),
30
30
  greetmsg: z.string().optional(),
31
31
  force: z.boolean(),
@@ -83,7 +83,7 @@ export const TunnelConfigSchema = z
83
83
  */
84
84
 
85
85
  export const StartSchema = z.object({
86
- tunnelID: z.string().uuid().nullable().optional(),
86
+ tunnelID: z.string().nullable().optional(),
87
87
  tunnelConfig: TunnelConfigSchema,
88
88
  });
89
89