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
@@ -1,244 +0,0 @@
1
- import {
2
- ErrorCode,
3
- Status,
4
- newErrorResponse,
5
- ErrorResponse,
6
- newStatus,
7
- TunnelStateType,
8
- TunnelErrorCodeType,
9
- newStats,
10
- ErrorCodeType,
11
- AdditionalForwarding
12
- } from "../types.js";
13
- import { DisconnectListener, TunnelManager } from "../tunnel_manager/TunnelManager.js";
14
- import { pinggyOptionsToTunnelConfig, tunnelConfigToPinggyOptions, TunnelConfig } from "./remote_schema.js";
15
- import { PinggyOptions, TunnelType, TunnelUsageType } from "@pinggy/pinggy";
16
-
17
- export interface TunnelResponse {
18
- tunnelid: string;
19
- remoteurls: string[];
20
- tunnelconfig: TunnelConfig;
21
- status: Status;
22
- stats: TunnelUsageType;
23
- }
24
-
25
- interface TunnelHandler {
26
- handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
27
- handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
28
- handleList(): Promise<TunnelResponse[] | ErrorResponse>;
29
- handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
30
- handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
31
- handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
32
- handleRegisterStatsListener(tunnelid: string, listener: (tunnelId: string, stats: TunnelUsageType) => void): void;
33
- handleUnregisterStatsListener(tunnelid: string, listnerId: string): void;
34
- handleGetTunnelStats(tunnelid: string): TunnelUsageType[] | ErrorResponse;
35
- handleRegisterDisconnectListener(tunnelid: string, listener: DisconnectListener): void;
36
- handleRemoveStoppedTunnelByTunnelId(tunnelId: string): boolean | ErrorResponse;
37
- handleRemoveStoppedTunnelByConfigId(configId: string): boolean | ErrorResponse;
38
- }
39
-
40
- export class TunnelOperations implements TunnelHandler {
41
- private tunnelManager: TunnelManager;
42
-
43
- constructor() {
44
- this.tunnelManager = TunnelManager.getInstance(); // Use singleton instance
45
- }
46
-
47
-
48
- private buildStatus(tunnelId: string, state: TunnelStateType, errorCode: TunnelErrorCodeType): Status {
49
- const status = newStatus(state, errorCode, "");
50
- try {
51
- const managed = this.tunnelManager.getManagedTunnel("", tunnelId);
52
- if (managed) {
53
- status.createdtimestamp = managed.createdAt || "";
54
- status.starttimestamp = managed.startedAt || "";
55
- status.endtimestamp = managed.stoppedAt || "";
56
- }
57
- } catch (e) {
58
- //ignore
59
- }
60
- return status;
61
- }
62
-
63
- // --- Helper to construct TunnelResponse ---
64
- private async buildTunnelResponse(tunnelid: string, tunnelConfig: PinggyOptions, configid: string, tunnelName: string, additionalForwarding?: AdditionalForwarding[], serve?: string): Promise<TunnelResponse> {
65
- const [status, stats, tlsInfo, greetMsg, remoteurls] = await Promise.all([
66
- this.tunnelManager.getTunnelStatus(tunnelid),
67
- this.tunnelManager.getLatestTunnelStats(tunnelid) || newStats(),
68
- this.tunnelManager.getLocalserverTlsInfo(tunnelid),
69
- this.tunnelManager.getTunnelGreetMessage(tunnelid),
70
- this.tunnelManager.getTunnelUrls(tunnelid)
71
- ]);
72
-
73
- return {
74
- tunnelid,
75
- remoteurls,
76
- tunnelconfig: pinggyOptionsToTunnelConfig(tunnelConfig, configid, tunnelName, tlsInfo, greetMsg as string, additionalForwarding),
77
- status: this.buildStatus(tunnelid, status as TunnelStateType, TunnelErrorCodeType.NoError),
78
- stats
79
- };
80
- }
81
-
82
- private error(code: ErrorCodeType, err: unknown, fallback: string): ErrorResponse {
83
- return newErrorResponse({
84
- code,
85
- message: err instanceof Error ? err.message : fallback
86
- });
87
- }
88
-
89
- // --- Operations ---
90
- async handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse> {
91
-
92
- try {
93
- // Convert TunnelConfig -> PinggyOptions
94
- const opts = tunnelConfigToPinggyOptions(config);
95
- const additionalForwardingParsed = config.additionalForwarding || [];
96
- const { tunnelid, instance, tunnelName, additionalForwarding, serve } = await this.tunnelManager.createTunnel({
97
- ...opts,
98
- tunnelType: Array.isArray(config.type) ? config.type : (config.type ? [config.type] : [TunnelType.Http]), // Temporary fix in future we will not use this field.
99
- configid: config.configid,
100
- tunnelName: config.configname,
101
- additionalForwarding: additionalForwardingParsed,
102
- serve: config.serve
103
- });
104
-
105
- this.tunnelManager.startTunnel(tunnelid);
106
- const tunnelPconfig = await this.tunnelManager.getTunnelConfig("", tunnelid);
107
- const resp = this.buildTunnelResponse(tunnelid, tunnelPconfig, config.configid, tunnelName as string, additionalForwarding, serve);
108
- return resp;
109
- } catch (err) {
110
- return this.error(ErrorCode.ErrorStartingTunnel, err, "Unknown error occurred while starting tunnel");
111
- }
112
- }
113
-
114
- async handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse> {
115
- try {
116
- const opts = tunnelConfigToPinggyOptions(config);
117
- const tunnel = await this.tunnelManager.updateConfig({
118
- ...opts,
119
- tunnelType: Array.isArray(config.type) ? config.type : (config.type ? [config.type] : [TunnelType.Http]), // // Temporary fix in future we will not use this field.
120
- configid: config.configid,
121
- tunnelName: config.configname,
122
- additionalForwarding: config.additionalForwarding || [],
123
- serve: config.serve
124
-
125
- });
126
-
127
- if (!tunnel.instance || !tunnel.tunnelConfig)
128
- throw new Error("Invalid tunnel state after configuration update");
129
-
130
- return this.buildTunnelResponse(tunnel.tunnelid, tunnel.tunnelConfig, config.configid, tunnel.tunnelName as string, tunnel.additionalForwarding, tunnel.serve);
131
- } catch (err) {
132
- return this.error(ErrorCode.InternalServerError, err, "Failed to update tunnel configuration");
133
- }
134
- }
135
-
136
- async handleList(): Promise<TunnelResponse[] | ErrorResponse> {
137
-
138
- try {
139
- const tunnels = await this.tunnelManager.getAllTunnels();
140
- if (tunnels.length === 0) {
141
- return [];
142
- }
143
- return Promise.all(
144
- tunnels.map(async (t) => {
145
- const rawStats = this.tunnelManager.getLatestTunnelStats(t.tunnelid) || newStats();
146
- const [status, tlsInfo, greetMsg] = await Promise.all([
147
- this.tunnelManager.getTunnelStatus(t.tunnelid),
148
- this.tunnelManager.getLocalserverTlsInfo(t.tunnelid),
149
- this.tunnelManager.getTunnelGreetMessage(t.tunnelid)
150
- ]);
151
- const pinggyOptions = status !== TunnelStateType.Closed && status !== TunnelStateType.Exited
152
- ? await this.tunnelManager.getTunnelConfig("", t.tunnelid)
153
- : t.tunnelConfig!;
154
-
155
- const tunnelConfig = pinggyOptionsToTunnelConfig(pinggyOptions, t.configid, t.tunnelName as string, tlsInfo, greetMsg, t.additionalForwarding, t.serve);
156
-
157
- return {
158
- tunnelid: t.tunnelid,
159
- remoteurls: t.remoteurls,
160
- status: this.buildStatus(t.tunnelid, status as TunnelStateType, TunnelErrorCodeType.NoError),
161
- stats: rawStats,
162
- tunnelconfig: tunnelConfig
163
- };
164
- })
165
- );
166
- } catch (err) {
167
- return this.error(ErrorCode.InternalServerError, err, "Failed to list tunnels");
168
- }
169
- }
170
-
171
- async handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse> {
172
- try {
173
- const { configid } = this.tunnelManager.stopTunnel(tunnelid);
174
- const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
175
- if (!managed?.tunnelConfig) throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
176
- return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, configid, managed.tunnelName as string, managed.additionalForwarding, managed.serve);
177
- } catch (err) {
178
- return this.error(ErrorCode.TunnelNotFound, err, "Failed to stop tunnel");
179
- }
180
- }
181
-
182
- async handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse> {
183
- try {
184
- const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
185
- if (!managed?.tunnelConfig) throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
186
- return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, managed.configid, managed.tunnelName as string, managed.additionalForwarding, managed.serve);
187
- } catch (err) {
188
- return this.error(ErrorCode.TunnelNotFound, err, "Failed to get tunnel information");
189
- }
190
- }
191
-
192
- async handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse> {
193
- try {
194
- await this.tunnelManager.restartTunnel(tunnelid);
195
- const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
196
- if (!managed?.tunnelConfig) throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
197
- return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, managed.configid, managed.tunnelName as string, managed.additionalForwarding, managed.serve);
198
- } catch (err) {
199
- return this.error(ErrorCode.TunnelNotFound, err, "Failed to restart tunnel");
200
- }
201
- }
202
- handleRegisterStatsListener(tunnelid: string, listener: (tunnelId: string, stats: TunnelUsageType) => void): void {
203
- this.tunnelManager.registerStatsListener(tunnelid, listener);
204
- }
205
-
206
- handleUnregisterStatsListener(tunnelid: string, listnerId: string): void {
207
- this.tunnelManager.deregisterStatsListener(tunnelid, listnerId);
208
- }
209
-
210
- handleGetTunnelStats(tunnelid: string): TunnelUsageType[] | ErrorResponse {
211
- try {
212
- const stats = this.tunnelManager.getTunnelStats(tunnelid);
213
- if (!stats) {
214
- // if no stats found, return new stats object
215
- return [newStats()];
216
- }
217
- return stats;
218
- } catch (err) {
219
- return this.error(ErrorCode.TunnelNotFound, err, "Failed to get tunnel stats");
220
- }
221
- }
222
-
223
- handleRegisterDisconnectListener(tunnelid: string, listener: DisconnectListener): void {
224
- this.tunnelManager.registerDisconnectListener(tunnelid, listener);
225
- }
226
-
227
- handleRemoveStoppedTunnelByConfigId(configId: string): boolean | ErrorResponse {
228
- try {
229
- return this.tunnelManager.removeStoppedTunnelByConfigId(configId);
230
- } catch (err) {
231
-
232
- return this.error(ErrorCode.InternalServerError, err, "Failed to remove stopped tunnel by configId");
233
- }
234
- }
235
-
236
- handleRemoveStoppedTunnelByTunnelId(tunnelId: string): boolean | ErrorResponse {
237
- try {
238
- return this.tunnelManager.removeStoppedTunnelByTunnelId(tunnelId);
239
- } catch (err) {
240
-
241
- return this.error(ErrorCode.InternalServerError, err, "Failed to remove stopped tunnel by tunnelId");
242
- }
243
- }
244
- }
@@ -1,226 +0,0 @@
1
- import WebSocket from "ws";
2
- import { logger } from "../logger.js";
3
- import { handleConnectionStatusMessage, WebSocketCommandHandler, WebSocketRequest } from "./websocket_handlers.js";
4
- import CLIPrinter from "../utils/printer.js";
5
- import { RemoteManagementState, RemoteManagementStatus } from "../types.js";
6
-
7
- const RECONNECT_SLEEP_MS = 5000; // 5 seconds
8
- const PING_INTERVAL_MS = 30000; // 30 seconds
9
-
10
- type RemoteManagementResult =
11
- | { ok: true }
12
- | { ok: false; error: unknown };
13
-
14
- interface RemoteManagementValues {
15
- "remote-management"?: string;
16
- "manage"?: string;
17
- }
18
-
19
- let _remoteManagementState: RemoteManagementState = {
20
- status: "NOT_RUNNING",
21
- errorMessage: "",
22
- };
23
-
24
- let _stopRequested = false;
25
- let currentWs: WebSocket | null = null;
26
-
27
- export function buildRemoteManagementWsUrl(manage?: string): string {
28
- let baseUrl = (manage || "dashboard.pinggy.io").trim();
29
- if (!(baseUrl.startsWith("ws://") || baseUrl.startsWith("wss://"))) {
30
- baseUrl = "wss://" + baseUrl;
31
- }
32
- // Avoid duplicate slashes when concatenating
33
- const trimmed = baseUrl.replace(/\/$/, "");
34
- return `${trimmed}/backend/api/v1/remote-management/connect`;
35
- }
36
-
37
- function extractHostname(u: string): string {
38
- try {
39
- const url = new URL(u);
40
- return url.host;
41
- } catch {
42
- return u;
43
- }
44
- }
45
-
46
- function sleep(ms: number) {
47
- return new Promise((res) => setTimeout(res, ms));
48
- }
49
-
50
- export async function parseRemoteManagement(values: RemoteManagementValues): Promise<RemoteManagementResult | void> {
51
- const rmToken = values["remote-management"];
52
- if (typeof rmToken === "string" && rmToken.trim().length > 0) {
53
- const manageHost = values["manage"];
54
- try {
55
- await initiateRemoteManagement(rmToken, manageHost);
56
- return { ok: true };
57
- } catch (e) {
58
- logger.error("Failed to initiate remote management:", e);
59
- return { ok: false, error: e };
60
- }
61
- }
62
- }
63
-
64
- /**
65
- * Initiate remote management mode with a WebSocket connection.
66
- * - Connect with Authorization: Bearer <token>
67
- * - On HTTP 401: print Unauthorized and exit
68
- * - On other failures: retry every 15 seconds
69
- * - Keep running until closed or SIGINT
70
- */
71
- export async function initiateRemoteManagement(token: string, manage?: string): Promise<RemoteManagementState> {
72
-
73
- if (!token || token.trim().length === 0) {
74
- throw new Error("Remote management token is required (use --remote-management <TOKEN>)");
75
- }
76
-
77
- const wsUrl = buildRemoteManagementWsUrl(manage);
78
- const wsHost = extractHostname(wsUrl);
79
-
80
- logger.info("Remote management mode enabled.");
81
-
82
- // Ensure process exits cleanly on Ctrl+C
83
- _stopRequested = false;
84
- const sigintHandler = () => { _stopRequested = true; };
85
- process.once('SIGINT', sigintHandler);
86
-
87
- const logConnecting = () => {
88
- CLIPrinter.print(`Connecting to ${wsHost}`);
89
- logger.info("Connecting to remote management", { wsUrl });
90
- }
91
-
92
-
93
- while (!_stopRequested) {
94
- logConnecting();
95
- setRemoteManagementState({ status: RemoteManagementStatus.Connecting, errorMessage: "" });
96
- try {
97
- await handleWebSocketConnection(wsUrl, wsHost, token);
98
- } catch (error) {
99
- logger.warn("Remote management connection error", { error: String(error) });
100
-
101
- }
102
- if (_stopRequested) break;
103
- CLIPrinter.warn(`Remote management disconnected. Reconnecting in ${RECONNECT_SLEEP_MS / 1000} seconds...`);
104
- logger.info("Reconnecting to remote management after disconnect");
105
- await sleep(RECONNECT_SLEEP_MS);
106
- }
107
-
108
-
109
- process.removeListener('SIGINT', sigintHandler);
110
- logger.info("Remote management stopped.");
111
- return getRemoteManagementState();
112
- }
113
-
114
- async function handleWebSocketConnection(wsUrl: string, wsHost: string, token: string): Promise<void> {
115
- return new Promise<void>((resolve) => {
116
-
117
- const ws = new WebSocket(wsUrl, {
118
- headers: { Authorization: `Bearer ${token}` },
119
- });
120
- // Tracking the ws for cleanup
121
- currentWs = ws;
122
-
123
- let heartbeat: NodeJS.Timeout | null = null;
124
- let firstMessage = true;
125
-
126
- /** Safely cleanup on any exit */
127
- const cleanup = () => {
128
- if (heartbeat) clearInterval(heartbeat);
129
- currentWs = null;
130
- resolve();
131
- };
132
-
133
- ws.once("open", () => {
134
- CLIPrinter.success(`Connected to ${wsHost}`);
135
-
136
- heartbeat = setInterval(() => {
137
- if (ws.readyState === WebSocket.OPEN) ws.ping();
138
- }, PING_INTERVAL_MS);
139
- });
140
-
141
- ws.on("ping", () => ws.pong());
142
-
143
- ws.on("message", async (data) => {
144
- try {
145
- if (firstMessage) {
146
- firstMessage = false;
147
- const ok = handleConnectionStatusMessage(data);
148
- if (!ok) ws.close();
149
- return;
150
- }
151
- setRemoteManagementState({ status: RemoteManagementStatus.Running, errorMessage: "" });
152
- const req = JSON.parse(data.toString("utf8")) as WebSocketRequest;
153
- await new WebSocketCommandHandler().handle(ws, req);
154
- } catch (e) {
155
- logger.warn("Failed handling websocket message", { error: String(e) });
156
- }
157
- });
158
-
159
- ws.on("unexpected-response", (_, res) => {
160
- setRemoteManagementState({ status: RemoteManagementStatus.NotRunning, errorMessage: `HTTP ${res.statusCode}` });
161
- if (res.statusCode === 401) {
162
- CLIPrinter.error("Unauthorized. Please enter a valid token.");
163
- logger.error("Unauthorized (401) on remote management connect");
164
- } else {
165
- CLIPrinter.warn(`Unexpected HTTP ${res.statusCode}. Retrying...`);
166
- logger.warn("Unexpected HTTP response", { statusCode: res.statusCode });
167
- }
168
- ws.close();
169
- });
170
-
171
- ws.on("close", (code, reason) => {
172
- setRemoteManagementState({ status: RemoteManagementStatus.NotRunning, errorMessage: "" });
173
- logger.info("WebSocket closed", { code, reason: reason.toString() });
174
- CLIPrinter.warn(`Disconnected (code: ${code}). Retrying...`);
175
- cleanup();
176
- });
177
-
178
- ws.on("error", (err) => {
179
- setRemoteManagementState({ status: RemoteManagementStatus.Error, errorMessage: err.message });
180
- logger.warn("WebSocket error", { error: err.message });
181
- CLIPrinter.error(err);
182
- cleanup();
183
- });
184
- });
185
-
186
- }
187
-
188
- export async function closeRemoteManagement(timeoutMs = 10000): Promise<RemoteManagementState> {
189
- _stopRequested = true;
190
- try {
191
- if (currentWs) {
192
- try {
193
- setRemoteManagementState({ status: RemoteManagementStatus.Disconnecting, errorMessage: "" });
194
- currentWs.close();
195
- } catch (e) {
196
- logger.warn("Error while closing current remote management websocket", { error: String(e) });
197
- }
198
- }
199
-
200
- const start = Date.now();
201
- while (_remoteManagementState.status === "RUNNING") {
202
- if (Date.now() - start > timeoutMs) {
203
- logger.warn("Timed out waiting for remote management to stop");
204
- break;
205
- }
206
- await sleep(200);
207
- }
208
- } finally {
209
- // Ensure ws ref cleared
210
- currentWs = null;
211
- setRemoteManagementState({ status: RemoteManagementStatus.NotRunning, errorMessage: "" });
212
- return getRemoteManagementState();
213
- }
214
- }
215
-
216
-
217
- export function getRemoteManagementState(): RemoteManagementState {
218
- return _remoteManagementState;
219
- }
220
-
221
- function setRemoteManagementState(state: RemoteManagementState, errorMessage?: string) {
222
- _remoteManagementState = {
223
- status: state.status,
224
- errorMessage: errorMessage || "",
225
- };
226
- }
@@ -1,176 +0,0 @@
1
- import { PinggyOptions, TunnelType } from "@pinggy/pinggy";
2
- import { z } from "zod";
3
- import { AdditionalForwarding } from "../types.js";
4
-
5
-
6
- export const HeaderModificationSchema = z.object({
7
- key: z.string(),
8
- value: z.array(z.string()).optional(),
9
- type: z.enum(["add", "remove", "update"]),
10
- });
11
-
12
- export const AdditionalForwardingSchema = z.object({
13
- remoteDomain: z.string().optional(),
14
- remotePort: z.number().optional(),
15
- localDomain: z.string(),
16
- localPort: z.number(),
17
- });
18
-
19
-
20
- // TunnelConfig schema
21
- export const TunnelConfigSchema = z
22
- .object({
23
- allowPreflight: z.boolean().optional(), // primary key
24
- allowpreflight: z.boolean().optional(), // legacy key
25
- autoreconnect: z.boolean(),
26
- basicauth: z.array(z.object({ username: z.string(), password: z.string() })).nullable(),
27
- bearerauth: z.string().nullable(),
28
- configid: z.string(),
29
- configname: z.string(),
30
- greetmsg: z.string().optional(),
31
- force: z.boolean(),
32
- forwardedhost: z.string(),
33
- fullRequestUrl: z.boolean(),
34
- headermodification: z.array(HeaderModificationSchema),
35
- httpsOnly: z.boolean(),
36
- internalwebdebuggerport: z.number(),
37
- ipwhitelist: z.array(z.string()).nullable(),
38
- localport: z.number(),
39
- localsservertls: z.union([z.boolean(), z.string()]),
40
- localservertlssni: z.string().nullable(),
41
- regioncode: z.string(),
42
- noReverseProxy: z.boolean(),
43
- serveraddress: z.string(),
44
- serverport: z.number(),
45
- statusCheckInterval: z.number(),
46
- token: z.string(),
47
- tunnelTimeout: z.number(),
48
- type: z.enum([
49
- TunnelType.Http,
50
- TunnelType.Tcp,
51
- TunnelType.Udp,
52
- TunnelType.Tls,
53
- TunnelType.TlsTcp
54
- ]),
55
- webdebuggerport: z.number(),
56
- xff: z.string(),
57
- additionalForwarding: z.array(AdditionalForwardingSchema).optional(),
58
- serve: z.string().optional(),
59
- })
60
- .superRefine((data, ctx) => {
61
- if (data.allowPreflight === undefined && data.allowpreflight === undefined) {
62
- ctx.addIssue({
63
- code: "custom",
64
- message: "Either allowPreflight or allowpreflight is required",
65
- path: ["allowPreflight"],
66
- });
67
- }
68
- })
69
- .transform((data) => ({
70
- ...data,
71
- allowPreflight: data.allowPreflight ?? data.allowpreflight,
72
- allowpreflight: data.allowPreflight ?? data.allowpreflight,
73
- }));
74
-
75
-
76
- /**
77
- * Schema for the payload used to manage tunnels using websocket.
78
- *
79
- * @remarks
80
- * This schema is intended for input validation (e.g. API request bodies or remote management socket data)
81
- * and enforces structural and primitive constraints but does not
82
- * perform side effects.
83
- */
84
-
85
- export const StartSchema = z.object({
86
- tunnelID: z.string().nullable().optional(),
87
- tunnelConfig: TunnelConfigSchema,
88
- });
89
-
90
- export const StopSchema = z.object({
91
- tunnelID: z.string().min(1),
92
- });
93
-
94
- export const GetSchema = StopSchema;
95
- export const RestartSchema = StopSchema;
96
-
97
- export const UpdateConfigSchema = z.object({
98
- tunnelConfig: TunnelConfigSchema,
99
- });
100
-
101
- export type TunnelConfig = z.infer<typeof TunnelConfigSchema>;
102
-
103
- export function tunnelConfigToPinggyOptions(config: TunnelConfig): PinggyOptions {
104
- return {
105
- token: config.token || "",
106
- serverAddress: config.serveraddress || "free.pinggy.io",
107
- forwarding: `${config.forwardedhost || "localhost"}:${config.localport}`,
108
- webDebugger: config.webdebuggerport ? `localhost:${config.webdebuggerport}` : "",
109
- ipWhitelist: config.ipwhitelist || [],
110
- basicAuth: config.basicauth ? config.basicauth : [],
111
- bearerTokenAuth: config.bearerauth ? [config.bearerauth] : [],
112
- headerModification: config.headermodification,
113
- xForwardedFor: !!config.xff,
114
- httpsOnly: config.httpsOnly,
115
- originalRequestUrl: config.fullRequestUrl,
116
- allowPreflight: config.allowPreflight,
117
- reverseProxy: config.noReverseProxy,
118
- force: config.force,
119
- autoReconnect: config.autoreconnect,
120
- optional: {
121
- sniServerName: config.localservertlssni || "",
122
- },
123
- };
124
- }
125
-
126
- export function pinggyOptionsToTunnelConfig(opts: PinggyOptions, configid: string, configName: string, localserverTls?: string | boolean, greetMsg?: string | null, additionalForwarding?: AdditionalForwarding[], serve?: string): TunnelConfig {
127
-
128
- const forwarding: string = Array.isArray(opts.forwarding) ? String(opts.forwarding[0].address).replace("//", "").replace(/\/$/, "") : String(opts.forwarding).replace("//", "").replace(/\/$/, "");
129
- const parsedForwardedHost = forwarding.split(":").length == 3 ? forwarding.split(":")[1] : forwarding.split(":")[0];
130
- const parsedLocalPort = forwarding.split(":").length == 3 ? parseInt(forwarding.split(":")[2], 10) : parseInt(forwarding.split(":")[1], 10);
131
-
132
- const tunnelType =
133
- (Array.isArray(opts.forwarding) ? opts.forwarding[0]?.type : undefined) ?? TunnelType.Http;
134
-
135
-
136
- const parsedTokens: string[] = opts.bearerTokenAuth ? (Array.isArray(opts.bearerTokenAuth)
137
- ? opts.bearerTokenAuth : (JSON.parse(opts.bearerTokenAuth) as string[])) : [];
138
- return {
139
- allowPreflight: opts.allowPreflight ?? false,
140
- allowpreflight: opts.allowPreflight ?? false,
141
- autoreconnect: opts.autoReconnect ?? false,
142
- basicauth: opts.basicAuth && Object.keys(opts.basicAuth).length
143
- ? opts.basicAuth
144
- : null,
145
- bearerauth: parsedTokens.length ? parsedTokens.join(',') : null,
146
- configid: configid,
147
- configname: configName,
148
- greetmsg: greetMsg || "",
149
- force: opts.force ?? false,
150
- forwardedhost: parsedForwardedHost || "localhost",
151
- fullRequestUrl: opts.originalRequestUrl ?? false,
152
- headermodification: opts.headerModification || [], //structured list
153
- httpsOnly: opts.httpsOnly ?? false,
154
- internalwebdebuggerport: 0,
155
- ipwhitelist: opts.ipWhitelist
156
- ? (Array.isArray(opts.ipWhitelist)
157
- ? opts.ipWhitelist
158
- : JSON.parse(opts.ipWhitelist) as string[])
159
- : null,
160
- localport: parsedLocalPort || 0,
161
- localservertlssni: null,
162
- regioncode: "",
163
- noReverseProxy: opts.reverseProxy ?? false,
164
- serveraddress: opts.serverAddress || "free.pinggy.io",
165
- serverport: 0,
166
- statusCheckInterval: 0,
167
- token: opts.token || "",
168
- tunnelTimeout: 0,
169
- type: tunnelType,
170
- webdebuggerport: Number(opts.webDebugger?.split(":")[0]) || 0,
171
- xff: opts.xForwardedFor ? "1" : "",
172
- localsservertls: localserverTls || false,
173
- additionalForwarding: additionalForwarding || [],
174
- serve: serve || "",
175
- };
176
- }