pinggy 0.3.4 → 0.3.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.
Files changed (68) hide show
  1. package/README.md +1 -1
  2. package/dist/chunk-65R2GMKQ.js +2101 -0
  3. package/dist/index.cjs +1814 -1362
  4. package/dist/index.d.cts +616 -0
  5. package/dist/index.d.ts +616 -0
  6. package/dist/index.js +38 -55
  7. package/dist/{main-CZY6GID4.js → main-2QDG7PWL.js} +229 -1726
  8. package/package.json +3 -4
  9. package/.github/workflows/npm-publish-github-packages.yml +0 -34
  10. package/.github/workflows/publish-binaries.yml +0 -223
  11. package/Makefile +0 -4
  12. package/caxa_build.js +0 -24
  13. package/dist/chunk-T5ESYDJY.js +0 -121
  14. package/ent.plist +0 -14
  15. package/jest.config.js +0 -19
  16. package/src/_tests_/build_config.test.ts +0 -91
  17. package/src/cli/buildConfig.ts +0 -475
  18. package/src/cli/defaults.ts +0 -20
  19. package/src/cli/extendedOptions.ts +0 -153
  20. package/src/cli/help.ts +0 -43
  21. package/src/cli/options.ts +0 -50
  22. package/src/cli/starCli.ts +0 -229
  23. package/src/index.ts +0 -30
  24. package/src/logger.ts +0 -138
  25. package/src/main.ts +0 -87
  26. package/src/remote_management/handler.ts +0 -244
  27. package/src/remote_management/remoteManagement.ts +0 -226
  28. package/src/remote_management/remote_schema.ts +0 -176
  29. package/src/remote_management/websocket_handlers.ts +0 -180
  30. package/src/tui/blessed/TunnelTui.ts +0 -340
  31. package/src/tui/blessed/components/DisplayUpdaters.ts +0 -189
  32. package/src/tui/blessed/components/KeyBindings.ts +0 -236
  33. package/src/tui/blessed/components/Modals.ts +0 -302
  34. package/src/tui/blessed/components/UIComponents.ts +0 -306
  35. package/src/tui/blessed/components/index.ts +0 -4
  36. package/src/tui/blessed/config.ts +0 -53
  37. package/src/tui/blessed/headerFetcher.ts +0 -42
  38. package/src/tui/blessed/index.ts +0 -2
  39. package/src/tui/blessed/qrCodeGenerator.ts +0 -20
  40. package/src/tui/blessed/webDebuggerConnection.ts +0 -128
  41. package/src/tui/ink/asciArt.ts +0 -7
  42. package/src/tui/ink/hooks/useQrCodes.ts +0 -27
  43. package/src/tui/ink/hooks/useReqResHeaders.ts +0 -27
  44. package/src/tui/ink/hooks/useTerminalSize.ts +0 -26
  45. package/src/tui/ink/hooks/useTerminalStats.ts +0 -24
  46. package/src/tui/ink/hooks/useWebDebugger.ts +0 -98
  47. package/src/tui/ink/index.tsx +0 -243
  48. package/src/tui/ink/layout/Borders.tsx +0 -15
  49. package/src/tui/ink/layout/Container.tsx +0 -15
  50. package/src/tui/ink/sections/DebuggerDetailModal.tsx +0 -53
  51. package/src/tui/ink/sections/KeyBindings.tsx +0 -58
  52. package/src/tui/ink/sections/QrCodeSection.tsx +0 -28
  53. package/src/tui/ink/sections/StatsSection.tsx +0 -20
  54. package/src/tui/ink/sections/URLsSection.tsx +0 -53
  55. package/src/tui/ink/utils/utils.ts +0 -35
  56. package/src/tui/spinner/spinner.ts +0 -64
  57. package/src/tunnel_manager/TunnelManager.ts +0 -1212
  58. package/src/types.ts +0 -255
  59. package/src/utils/FileServer.ts +0 -112
  60. package/src/utils/detect_vc_redist_on_windows.ts +0 -167
  61. package/src/utils/getFreePort.ts +0 -41
  62. package/src/utils/htmlTemplates.ts +0 -146
  63. package/src/utils/parseArgs.ts +0 -79
  64. package/src/utils/printer.ts +0 -81
  65. package/src/utils/util.ts +0 -18
  66. package/src/workers/file_serve_worker.ts +0 -33
  67. package/tsconfig.json +0 -17
  68. package/tsup.config.ts +0 -12
package/src/types.ts DELETED
@@ -1,255 +0,0 @@
1
- import { PinggyOptions, TunnelUsageType } from "@pinggy/pinggy";
2
-
3
- // Local representation of additional forwarding
4
- export interface AdditionalForwarding {
5
- localDomain: string;
6
- localPort: number;
7
- remoteDomain?: string;
8
- remotePort?: number;
9
- protocol?: 'http' | 'tcp' | 'udp' | 'tls';
10
- }
11
-
12
-
13
- export interface TunnelStatus {
14
- tunnelid: string,
15
- remoteurls: string[],
16
- tunnelconfig: PinggyOptions,
17
- status: Status,
18
- stats: TunnelUsageType
19
- }
20
-
21
-
22
-
23
- // Enum for TunnelStateType
24
- export enum TunnelStateType {
25
- New = "idle",
26
- Starting = "starting",
27
- Running = "running",
28
- Live = "live",
29
- Closed = "closed",
30
- Exited = "exited"
31
- }
32
-
33
- // Enum for TunnelErrorCodeType
34
- export enum TunnelErrorCodeType {
35
- NonResponsive = "non_responsive",
36
- FailedToConnect = "failed_to_connect",
37
- ErrorInAdditionalForwarding = "additional_forwarding_error",
38
- WebdebuggerError = "webdebugger_error",
39
- NoError = ""
40
- }
41
-
42
- // Enum for TunnelWarningCode
43
- export enum TunnelWarningCode {
44
- InvalidTunnelServePath = "INVALID_TUNNEL_SERVE_PATH",
45
- UnknownWarning = "UNKNOWN_WARNING"
46
- }
47
-
48
- // Interface for Warning
49
- export interface Warning {
50
- code: TunnelWarningCode;
51
- message: string;
52
- }
53
-
54
-
55
-
56
- // Main Status interface
57
- export interface Status {
58
- state: TunnelStateType;
59
- errorcode: TunnelErrorCodeType;
60
- errormsg: string;
61
- createdtimestamp: string;
62
- starttimestamp: string;
63
- endtimestamp: string;
64
- warnings: Warning[];
65
- }
66
-
67
- export type FinalConfig = (PinggyOptions & { configid: string }) & {
68
- tunnelType: string[];
69
- conf?: string;
70
- saveconf?: string;
71
- serve?: string;
72
- remoteManagement?: string;
73
- additionalForwarding?: AdditionalForwarding[];
74
- manage?: string;
75
- version?: boolean;
76
- NoTUI?: boolean;
77
- qrCode?: boolean;
78
- };
79
-
80
- export type ErrorCodeType =
81
- | "INVALID_REQUEST_METHOD"
82
- | "COULD_NOT_READ_BODY"
83
- | "INTERNAL_SERVER_ERROR"
84
- | "INVALID_DATA_FORMAT"
85
- | "ERROR_STARTING_TUNNEL"
86
- | "TUNNEL_WITH_ID_OR_CONFIG_ID_NOT_FOUND"
87
- | "TUNNEL_WITH_ID_OR_CONFIG_ID_ALREADY_RUNNING"
88
- | "WEBSOCKET_UPGRADE_FAILED"
89
- | "REMOTE_MANAGEMENT_ALREADY_RUNNING"
90
- | "REMOTE_MANAGEMENT_NOT_RUNNING"
91
- | "REMOTE_MANAGEMENT_DESERIALIZATION_FAILED";
92
-
93
- export const ErrorCode: Record<string, ErrorCodeType> = {
94
- InvalidRequestMethodError: "INVALID_REQUEST_METHOD",
95
- InvalidRequestBodyError: "COULD_NOT_READ_BODY",
96
- InternalServerError: "INTERNAL_SERVER_ERROR",
97
- InvalidBodyFormatError: "INVALID_DATA_FORMAT",
98
- ErrorStartingTunnel: "ERROR_STARTING_TUNNEL",
99
- TunnelNotFound: "TUNNEL_WITH_ID_OR_CONFIG_ID_NOT_FOUND",
100
- TunnelAlreadyRunningError: "TUNNEL_WITH_ID_OR_CONFIG_ID_ALREADY_RUNNING",
101
- WebsocketUpgradeFailError: "WEBSOCKET_UPGRADE_FAILED",
102
- RemoteManagementAlreadyRunning: "REMOTE_MANAGEMENT_ALREADY_RUNNING",
103
- RemoteManagementNotRunning: "REMOTE_MANAGEMENT_NOT_RUNNING",
104
- RemoteManagementDeserializationFailed: "REMOTE_MANAGEMENT_DESERIALIZATION_FAILED",
105
- } as const;
106
-
107
- export interface ErrorResponse {
108
- code: ErrorCodeType;
109
- message: string;
110
- }
111
-
112
- export function isErrorResponse(obj: unknown): obj is ErrorResponse {
113
- return (
114
- typeof obj === 'object' &&
115
- obj !== null &&
116
- 'code' in obj &&
117
- 'message' in obj &&
118
- typeof (obj as ErrorResponse).message === 'string' &&
119
- Object.values(ErrorCode).includes((obj as ErrorResponse).code)
120
- );
121
- }
122
-
123
- export function newErrorResponse(errorResponse: ErrorResponse): ErrorResponse;
124
- export function newErrorResponse(code: ErrorCodeType, message: string): ErrorResponse;
125
- export function newErrorResponse(codeOrError: ErrorCodeType | ErrorResponse, message?: string): ErrorResponse {
126
- if (typeof codeOrError === 'object') {
127
- return codeOrError;
128
- }
129
- return {
130
- code: codeOrError,
131
- message: message!
132
- };
133
- }
134
-
135
-
136
- export interface ResponseObj {
137
- response: Uint8Array;
138
- requestid: string;
139
- command: string;
140
- error: boolean;
141
- errorresponse: ErrorResponse;
142
- }
143
-
144
- export function NewResponseObject(data: unknown): ResponseObj {
145
- const encoder = new TextEncoder();
146
- const bytes = encoder.encode(JSON.stringify(data));
147
- return {
148
- response: bytes,
149
- requestid: "",
150
- command: "",
151
- error: false,
152
- errorresponse: {} as ErrorResponse,
153
- };
154
- }
155
-
156
- export function NewErrorResponseObject(errorResponse: ErrorResponse): ResponseObj {
157
- return {
158
- response: new Uint8Array(),
159
- requestid: "",
160
- command: "",
161
- error: true,
162
- errorresponse: errorResponse,
163
- };
164
- }
165
-
166
- export function newStatus(
167
- tunnelState: TunnelStateType,
168
- errorCode: TunnelErrorCodeType,
169
- errorMsg: string,
170
- ): Status {
171
- let assignedState = tunnelState;
172
- if (tunnelState === TunnelStateType.Live) {
173
- assignedState = TunnelStateType.Running;
174
- } else if (tunnelState === TunnelStateType.New) {
175
- assignedState = TunnelStateType.New;
176
- } else if (tunnelState === TunnelStateType.Closed) {
177
- assignedState = TunnelStateType.Exited;
178
- }
179
- const now = new Date().toISOString();
180
- return {
181
- state: assignedState,
182
- errorcode: errorCode,
183
- errormsg: errorMsg,
184
- createdtimestamp: now,
185
- starttimestamp: now,
186
- endtimestamp: now,
187
- warnings: []
188
- };
189
- }
190
-
191
- export function newStats(): TunnelUsageType {
192
- return {
193
- numLiveConnections: 0,
194
- numTotalConnections: 0,
195
- numTotalReqBytes: 0,
196
- numTotalResBytes: 0,
197
- numTotalTxBytes: 0,
198
- elapsedTime: 0,
199
- };
200
- }
201
-
202
- export interface Request {
203
- key: number;
204
- method: string;
205
- uri: string;
206
- }
207
-
208
- export interface Response {
209
- key: number;
210
- status: string;
211
- }
212
-
213
- export interface ReqResPair {
214
- request: Request;
215
- response: Response;
216
- reqHeaders: string;
217
- resHeaders: string;
218
- headersLoaded: boolean;
219
- }
220
- export interface StatsAll {
221
- activeConn: number;
222
- numRequests: number;
223
- numResponses: number;
224
- reqBytes: number;
225
- resBytes: number;
226
- totalConn: number;
227
- }
228
- export interface WebDebuggerSocketRequest {
229
- Req: Request;
230
- Res: Response;
231
- }
232
-
233
- export type RemoteManagementStatusType =
234
- | "CONNECTING"
235
- | "DISCONNECTING"
236
- | "RECONNECTING"
237
- | "RUNNING"
238
- | "NOT_RUNNING"
239
- | "ERROR";
240
-
241
- export const RemoteManagementStatus: Record<string, RemoteManagementStatusType> = {
242
- Connecting: "CONNECTING",
243
- Disconnecting: "DISCONNECTING",
244
- Reconnecting: "RECONNECTING",
245
- Running: "RUNNING",
246
- NotRunning: "NOT_RUNNING",
247
- Error: "ERROR",
248
- } as const;
249
-
250
- export interface RemoteManagementState {
251
- status: RemoteManagementStatusType;
252
- errorMessage: string;
253
- }
254
-
255
-
@@ -1,112 +0,0 @@
1
- import { createServer } from "http";
2
- import { readFile, readdir, stat } from "fs/promises";
3
- import { existsSync } from "fs";
4
- import { extname, join, resolve, relative } from "path";
5
- import { URL } from "url";
6
- import mime from "mime";
7
- import { logger } from "../logger.js";
8
- import { directoryListingHtml, invalidPathErrorHtml } from "./htmlTemplates.js";
9
-
10
- export class FileServerError extends Error {
11
- code: string;
12
- constructor(message: string, code: string) {
13
- super(message);
14
- this.name = "FileServerError";
15
- this.code = code;
16
- }
17
- }
18
-
19
- export async function startFileServer(dirPath: string, port = 8080) {
20
- let invalidPathError: FileServerError | null = null;
21
- const root = resolve(dirPath);
22
- logger.debug("Starting file server with root:", root, "on port:", port);
23
-
24
- if (!existsSync(root)) {
25
- logger.debug("Invalid root path for file server:", root);
26
- invalidPathError = new FileServerError(`The path ${dirPath} does not exist. Please check the path and try again.`, "INVALID_TUNNEL_SERVE_PATH");
27
- }
28
-
29
-
30
- const server = createServer(async (req, res) => {
31
- try {
32
- // If invalid root, show an HTML error page
33
- if (invalidPathError) {
34
- const html = invalidPathErrorHtml(invalidPathError);
35
- res.writeHead(200, { "Content-Type": "text/html" });
36
- res.end(html);
37
- return;
38
- }
39
- const reqUrl = new URL(req.url || "/", `http://${req.headers.host}`);
40
- let filePath = join(root, decodeURIComponent(reqUrl.pathname));
41
-
42
- let stats;
43
- try {
44
- stats = await stat(filePath);
45
- } catch {
46
- res.statusCode = 404;
47
- res.end("404 Not Found");
48
- return;
49
- }
50
-
51
- if (stats.isDirectory() && !reqUrl.pathname.endsWith("/")) {
52
- res.writeHead(301, { Location: reqUrl.pathname + "/" });
53
- res.end();
54
- return;
55
- }
56
-
57
- // Directory handling
58
- if (stats.isDirectory()) {
59
- const indexPath = join(filePath, "index.html");
60
- if (existsSync(indexPath)) {
61
- filePath = indexPath;
62
- } else {
63
- // No index.html — show directory listing
64
- const items = await readdir(filePath, { withFileTypes: true });
65
-
66
- const list = items
67
- .map((item) => {
68
- // Get the display name
69
- const name = item.name + (item.isDirectory() ? "/" : "");
70
- // Construct the current base URL
71
- const base = new URL(reqUrl.pathname, `http://${req.headers.host}`);
72
- // Create the full URL
73
- const hrefUrl = new URL(encodeURIComponent(name), base);
74
- return `<li><a href="${hrefUrl.pathname}">${name}</a></li>`;
75
- })
76
- .join("");
77
-
78
- const relativePath = relative(root, filePath) || "/";
79
- const html = directoryListingHtml(relativePath, list);
80
- res.writeHead(200, { "Content-Type": "text/html" });
81
- res.end(html);
82
- return;
83
- }
84
- }
85
-
86
- // Normal file serving
87
- const content = await readFile(filePath);
88
- const type = mime.getType(extname(filePath)) || "application/octet-stream";
89
- res.writeHead(200, { "Content-Type": type });
90
- res.end(content);
91
- } catch (err: any) {
92
- logger.debug("Error in handling request", err)
93
- res.statusCode = 500;
94
- res.end(`Internal Server Error: ${err.message}`);
95
- }
96
- });
97
-
98
- await new Promise<void>((resolve, reject) => {
99
- server.listen(port, () => {
100
- resolve();
101
- });
102
- server.on("error", (err) => {
103
- logger.debug("Error starting file server", err);
104
- reject(err);
105
- });
106
- });
107
-
108
- return {
109
- hasInvalidPath: !!invalidPathError,
110
- error: invalidPathError ? { message: invalidPathError.message, code: invalidPathError.code } : null
111
- }
112
- }
@@ -1,167 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { exec, execSync } from "child_process";
4
- import os from "os";
5
- import CLIPrinter from "./printer.js";
6
- import { promisify } from "util";
7
-
8
- const execAsync = promisify(exec);
9
-
10
- const DLLS = ["vcruntime140.dll", "vcruntime140_1.dll", "msvcp140.dll"];
11
-
12
- const PATHS = ["C:\\Windows\\System32", "C:\\Windows\\SysWOW64"];
13
-
14
- // Registry keys for different VC++ Redistributable versions
15
- const REGISTRY_KEYS = [
16
- "HKLM\\SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\X64",
17
- "HKLM\\SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\X86",
18
- "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\X64",
19
- "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\X86",
20
- ];
21
-
22
- /**
23
- * Check if VC++ Redistributable DLLs exist
24
- */
25
- function checkDLLs() {
26
- return DLLS.every((dll) =>
27
- PATHS.some((p) => {
28
- try {
29
- return fs.existsSync(path.join(p, dll));
30
- } catch {
31
- return false;
32
- }
33
- }),
34
- );
35
- }
36
-
37
- /**
38
- * Check Windows Registry for VC++ Redistributable installation
39
- */
40
- function checkRegistry() {
41
- if (os.platform() !== "win32") return false;
42
-
43
- try {
44
- for (const key of REGISTRY_KEYS) {
45
- const cmd = `reg query "${key}" /v Installed 2>nul`;
46
- const result = execSync(cmd, { encoding: "utf8" });
47
-
48
- if (result.includes("0x1")) {
49
- return true;
50
- }
51
- }
52
- } catch {
53
- // Registry check failed, fall back to DLL check
54
- }
55
-
56
- return false;
57
- }
58
-
59
- function getVCRedistVersion() {
60
- if (os.platform() !== "win32") return null;
61
-
62
- try {
63
- for (const key of REGISTRY_KEYS) {
64
- const cmd = `reg query "${key}" /v Version 2>nul`;
65
- const result = execSync(cmd, { encoding: "utf8" });
66
-
67
- const match = result.match(/Version\s+REG_SZ\s+(\S+)/);
68
- if (match) {
69
- return match[1];
70
- }
71
- }
72
- } catch {
73
- // Ignore errors
74
- }
75
-
76
- return null;
77
- }
78
-
79
- /**
80
- * Main detection function
81
- */
82
- export function hasVCRedist() {
83
- if (os.platform() !== "win32") {
84
- return true; // Not Windows, assume OK
85
- }
86
-
87
- if (checkRegistry()) {
88
- return true;
89
- }
90
-
91
- if (checkDLLs()) {
92
- return true;
93
- }
94
-
95
- return false;
96
- }
97
-
98
- export function getVCRedistStatus() {
99
- if (os.platform() !== "win32") {
100
- return {
101
- required: false,
102
- installed: true,
103
- version: null,
104
- method: "non-windows",
105
- };
106
- }
107
-
108
- const registryInstalled = checkRegistry();
109
- const dllsPresent = checkDLLs();
110
- const version = getVCRedistVersion();
111
-
112
- return {
113
- required: true,
114
- installed: registryInstalled || dllsPresent,
115
- version,
116
- registryCheck: registryInstalled,
117
- dllCheck: dllsPresent,
118
- method: registryInstalled ? "registry" : dllsPresent ? "dll" : "none",
119
- };
120
- }
121
-
122
- /**
123
- * Open download page in browser
124
- */
125
- export async function openDownloadPage() {
126
- if (process.platform !== "win32") {
127
- return;
128
- }
129
- const url =
130
- "https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170";
131
-
132
- // Use cmd.exe explicitly for better compatibility
133
- const command = `cmd.exe /c start "" "${url}"`;
134
-
135
- try {
136
- await execAsync(command);
137
- CLIPrinter.info("\nOpening Microsoft download page in your browser...");
138
- CLIPrinter.info(
139
- "Please install the Visual C++ Runtime and restart this application.\n",
140
- );
141
- } catch (err) {
142
- CLIPrinter.info("\nUnable to open your browser automatically.");
143
- CLIPrinter.info(
144
- "Please visit the following page to download the runtime:\n",
145
- );
146
- CLIPrinter.info(url + "\n");
147
- }
148
- }
149
-
150
-
151
- /**
152
- * Get error message
153
- */
154
- export function getVCRedistMessage() {
155
- const status = getVCRedistStatus();
156
-
157
- if (!status.required || status.installed) {
158
- return null;
159
- }
160
-
161
- return {
162
- error: true,
163
- message:
164
- "Missing Microsoft Visual C++ Runtime. This application requires the Microsoft Visual C++ Runtime to run on Windows.\n" +
165
- "Please download and install it using the link below, then restart this application.\n",
166
- };
167
- }
@@ -1,41 +0,0 @@
1
- import net from "net";
2
-
3
- /**
4
- * Get a free TCP port.
5
- * If `providedPort` is available, returns that.
6
- * Otherwise, returns a randomly assigned free port from the OS.
7
- */
8
- export function getFreePort(webDebugger: string): Promise<number> {
9
- return new Promise((resolve, reject) => {
10
- // Try provided port first
11
- const tryPort = (portToTry: number) => {
12
- const server = net.createServer();
13
-
14
- server.unref();
15
-
16
- server.on("error", (err) => {
17
- // If provided port failed, try random port (0)
18
- if (portToTry !== 0) {
19
- tryPort(0);
20
- } else {
21
- reject(err);
22
- }
23
- });
24
-
25
- server.listen(portToTry, () => {
26
- const address: net.AddressInfo = server.address() as net.AddressInfo;
27
- const port = address ? address.port : 0;
28
- server.close(() => resolve(port));
29
- });
30
- };
31
- let providedPort = 0;
32
- if (webDebugger && webDebugger.includes(":")) {
33
- const portPart = webDebugger.split(":")[1];
34
- const parsed = parseInt(portPart, 10);
35
- if (!isNaN(parsed) && parsed > 0 && parsed < 65536) {
36
- providedPort = parsed;
37
- }
38
- }
39
- tryPort(providedPort);
40
- });
41
- }