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.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { TunnelConfigurationV1, TunnelUsageType, TunnelInstance, TunnelType, RemoteManagementConfig } from '@pinggy/pinggy';
|
|
3
3
|
import { Worker } from 'node:worker_threads';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import winston from 'winston';
|
|
@@ -14,7 +14,7 @@ interface AdditionalForwarding {
|
|
|
14
14
|
interface TunnelStatus {
|
|
15
15
|
tunnelid: string;
|
|
16
16
|
remoteurls: string[];
|
|
17
|
-
tunnelconfig:
|
|
17
|
+
tunnelconfig: TunnelConfigurationV1;
|
|
18
18
|
status: Status;
|
|
19
19
|
stats: TunnelUsageType;
|
|
20
20
|
}
|
|
@@ -49,20 +49,11 @@ interface Status {
|
|
|
49
49
|
starttimestamp: string;
|
|
50
50
|
endtimestamp: string;
|
|
51
51
|
warnings: Warning[];
|
|
52
|
+
lastError?: lastError;
|
|
52
53
|
}
|
|
53
|
-
type FinalConfig = (
|
|
54
|
-
configid: string;
|
|
55
|
-
}) & {
|
|
56
|
-
tunnelType: string[];
|
|
54
|
+
type FinalConfig = (TunnelConfigurationV1) & {
|
|
57
55
|
conf?: string;
|
|
58
56
|
saveconf?: string;
|
|
59
|
-
serve?: string;
|
|
60
|
-
remoteManagement?: string;
|
|
61
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
62
|
-
manage?: string;
|
|
63
|
-
version?: boolean;
|
|
64
|
-
NoTUI?: boolean;
|
|
65
|
-
qrCode?: boolean;
|
|
66
57
|
};
|
|
67
58
|
type ErrorCodeType = "INVALID_REQUEST_METHOD" | "COULD_NOT_READ_BODY" | "INTERNAL_SERVER_ERROR" | "INVALID_DATA_FORMAT" | "ERROR_STARTING_TUNNEL" | "TUNNEL_WITH_ID_OR_CONFIG_ID_NOT_FOUND" | "TUNNEL_WITH_ID_OR_CONFIG_ID_ALREADY_RUNNING" | "WEBSOCKET_UPGRADE_FAILED" | "REMOTE_MANAGEMENT_ALREADY_RUNNING" | "REMOTE_MANAGEMENT_NOT_RUNNING" | "REMOTE_MANAGEMENT_DESERIALIZATION_FAILED";
|
|
68
59
|
interface ErrorResponse {
|
|
@@ -93,12 +84,10 @@ interface RemoteManagementState {
|
|
|
93
84
|
|
|
94
85
|
interface ManagedTunnel {
|
|
95
86
|
tunnelid: string;
|
|
96
|
-
|
|
87
|
+
configId: string;
|
|
97
88
|
tunnelName?: string;
|
|
98
89
|
instance: TunnelInstance;
|
|
99
|
-
tunnelConfig?:
|
|
100
|
-
configWithForwarding?: PinggyOptions;
|
|
101
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
90
|
+
tunnelConfig?: TunnelConfigurationV1;
|
|
102
91
|
serveWorker?: Worker | null;
|
|
103
92
|
warnings?: Warning[];
|
|
104
93
|
serve?: string;
|
|
@@ -107,18 +96,33 @@ interface ManagedTunnel {
|
|
|
107
96
|
startedAt?: string | null;
|
|
108
97
|
stoppedAt?: string | null;
|
|
109
98
|
autoReconnect?: boolean;
|
|
99
|
+
lastError: lastError;
|
|
100
|
+
}
|
|
101
|
+
interface lastError {
|
|
102
|
+
message: string;
|
|
103
|
+
timestamp: string;
|
|
104
|
+
isFatal: boolean;
|
|
110
105
|
}
|
|
111
106
|
interface TunnelList {
|
|
112
107
|
tunnelid: string;
|
|
113
|
-
|
|
108
|
+
configId: string;
|
|
114
109
|
tunnelName?: string;
|
|
115
|
-
tunnelConfig:
|
|
110
|
+
tunnelConfig: TunnelConfigurationV1;
|
|
116
111
|
remoteurls: string[];
|
|
117
|
-
|
|
112
|
+
serve?: string;
|
|
113
|
+
}
|
|
114
|
+
interface TunnelCreationConfig extends TunnelConfigurationV1 {
|
|
115
|
+
tunnelid?: string;
|
|
116
|
+
tunnelName?: string;
|
|
117
|
+
serve?: string;
|
|
118
|
+
}
|
|
119
|
+
interface TunnelUpdateConfig extends TunnelConfigurationV1 {
|
|
120
|
+
tunnelName?: string;
|
|
118
121
|
serve?: string;
|
|
119
122
|
}
|
|
120
123
|
type StatsListener = (tunnelId: string, stats: TunnelUsageType) => void;
|
|
121
124
|
type ErrorListener = (tunnelId: string, errorMsg: string, isFatal: boolean) => void;
|
|
125
|
+
type PollingErrorListener = (tunnelId: string, errorMsg: string) => void;
|
|
122
126
|
type DisconnectListener = (tunnelId: string, error: string, messages: string[]) => void;
|
|
123
127
|
type TunnelWorkerErrorListner = (tunnelid: string, error: Error) => void;
|
|
124
128
|
type StartListener = (tunnelId: string, urls: string[]) => void;
|
|
@@ -127,16 +131,10 @@ type ReconnectingListener = (tunnelId: string, retryCnt: number) => void;
|
|
|
127
131
|
type ReconnectionCompletedListener = (tunnelId: string, urls: string[]) => void;
|
|
128
132
|
type ReconnectionFailedListener = (tunnelId: string, retryCnt: number) => void;
|
|
129
133
|
interface ITunnelManager {
|
|
130
|
-
createTunnel(config:
|
|
131
|
-
configid: string;
|
|
132
|
-
tunnelid?: string;
|
|
133
|
-
tunnelName?: string;
|
|
134
|
-
}) & {
|
|
135
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
136
|
-
}): Promise<ManagedTunnel>;
|
|
134
|
+
createTunnel(config: TunnelCreationConfig, buildConfig?: boolean): Promise<ManagedTunnel>;
|
|
137
135
|
startTunnel(tunnelId: string): Promise<string[]>;
|
|
138
136
|
stopTunnel(tunnelId: string): {
|
|
139
|
-
|
|
137
|
+
configId: string;
|
|
140
138
|
tunnelid: string;
|
|
141
139
|
};
|
|
142
140
|
stopAllTunnels(): void;
|
|
@@ -144,22 +142,20 @@ interface ITunnelManager {
|
|
|
144
142
|
getAllTunnels(): Promise<TunnelList[]>;
|
|
145
143
|
getTunnelStatus(tunnelId: string): Promise<string>;
|
|
146
144
|
getTunnelInstance(configId?: string, tunnelId?: string): TunnelInstance;
|
|
147
|
-
getTunnelConfig(configId?: string, tunnelId?: string): Promise<
|
|
145
|
+
getTunnelConfig(configId?: string, tunnelId?: string): Promise<TunnelConfigurationV1>;
|
|
148
146
|
restartTunnel(tunnelId: string): Promise<void>;
|
|
149
|
-
updateConfig(newConfig:
|
|
150
|
-
configid: string;
|
|
151
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
152
|
-
tunnelName?: string;
|
|
153
|
-
}): Promise<ManagedTunnel>;
|
|
147
|
+
updateConfig(newConfig: TunnelUpdateConfig, buildConfig: boolean): Promise<ManagedTunnel>;
|
|
154
148
|
getManagedTunnel(configId?: string, tunnelId?: string): ManagedTunnel;
|
|
155
149
|
getTunnelGreetMessage(tunnelId: string): Promise<string | null>;
|
|
156
150
|
getTunnelStats(tunnelId: string): TunnelUsageType[] | null;
|
|
157
151
|
getLatestTunnelStats(tunnelId: string): TunnelUsageType | null;
|
|
158
152
|
registerStatsListener(tunnelId: string, listener: StatsListener): Promise<[string, string]>;
|
|
159
153
|
registerErrorListener(tunnelId: string, listener: ErrorListener): Promise<string>;
|
|
154
|
+
registerPollingErrorListener(tunnelId: string, listener: PollingErrorListener): Promise<string>;
|
|
160
155
|
registerWorkerErrorListner(tunnelId: string, listener: TunnelWorkerErrorListner): void;
|
|
161
156
|
registerStartListener(tunnelId: string, listener: StartListener): Promise<string>;
|
|
162
157
|
deregisterErrorListener(tunnelId: string, listenerId: string): void;
|
|
158
|
+
deregisterPollingErrorListener(tunnelId: string, listenerId: string): void;
|
|
163
159
|
registerDisconnectListener(tunnelId: string, listener: DisconnectListener): Promise<string>;
|
|
164
160
|
deregisterDisconnectListener(tunnelId: string, listenerId: string): void;
|
|
165
161
|
deregisterStatsListener(tunnelId: string, listenerId: string): void;
|
|
@@ -182,6 +178,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
182
178
|
private tunnelStats;
|
|
183
179
|
private tunnelStatsListeners;
|
|
184
180
|
private tunnelErrorListeners;
|
|
181
|
+
private tunnelPollingErrorListeners;
|
|
185
182
|
private tunnelDisconnectListeners;
|
|
186
183
|
private tunnelWorkerErrorListeners;
|
|
187
184
|
private tunnelStartListeners;
|
|
@@ -193,12 +190,9 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
193
190
|
static getInstance(): TunnelManager;
|
|
194
191
|
/**
|
|
195
192
|
* Creates a new managed tunnel instance with the given configuration.
|
|
196
|
-
*
|
|
193
|
+
* Optionally builds the config with forwarding rules based on buildConfig flag.
|
|
197
194
|
*
|
|
198
195
|
* @param config - The tunnel configuration options
|
|
199
|
-
* @param config.configid - Unique identifier for the tunnel configuration
|
|
200
|
-
* @param config.tunnelid - Optional custom tunnel identifier. If not provided, a random UUID will be generated
|
|
201
|
-
* @param config.additionalForwarding - Optional array of additional forwarding configurations
|
|
202
196
|
*
|
|
203
197
|
* @throws {Error} When configId is invalid or empty
|
|
204
198
|
* @throws {Error} When a tunnel with the given configId already exists
|
|
@@ -206,17 +200,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
206
200
|
* @returns {ManagedTunnel} A new managed tunnel instance containing the tunnel details,
|
|
207
201
|
* status information, and statistics
|
|
208
202
|
*/
|
|
209
|
-
createTunnel(config:
|
|
210
|
-
tunnelType: string[] | undefined;
|
|
211
|
-
} & {
|
|
212
|
-
configid: string;
|
|
213
|
-
tunnelid?: string;
|
|
214
|
-
tunnelName?: string;
|
|
215
|
-
}) & {
|
|
216
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
217
|
-
} & {
|
|
218
|
-
serve?: string;
|
|
219
|
-
}): Promise<ManagedTunnel>;
|
|
203
|
+
createTunnel(config: TunnelCreationConfig): Promise<ManagedTunnel>;
|
|
220
204
|
/**
|
|
221
205
|
* Internal method to create a tunnel with an already-processed configuration.
|
|
222
206
|
* This is used by createTunnel, restartTunnel, and updateConfig to avoid config processing.
|
|
@@ -226,15 +210,6 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
226
210
|
* @private
|
|
227
211
|
*/
|
|
228
212
|
private _createTunnelWithProcessedConfig;
|
|
229
|
-
/**
|
|
230
|
-
* Builds the Pinggy configuration by merging the default forwarding rule
|
|
231
|
-
* with additional forwarding rules from additionalForwarding array.
|
|
232
|
-
*
|
|
233
|
-
* @param config - The base Pinggy configuration
|
|
234
|
-
* @param additionalForwarding - Optional array of additional forwarding rules
|
|
235
|
-
* @returns Modified PinggyOptions
|
|
236
|
-
*/
|
|
237
|
-
private buildPinggyConfig;
|
|
238
213
|
/**
|
|
239
214
|
* Start a tunnel that was created but not yet started
|
|
240
215
|
*/
|
|
@@ -250,7 +225,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
250
225
|
* - Logs the stop operation with tunnelId and configId
|
|
251
226
|
*/
|
|
252
227
|
stopTunnel(tunnelId: string): {
|
|
253
|
-
|
|
228
|
+
configId: string;
|
|
254
229
|
tunnelid: string;
|
|
255
230
|
};
|
|
256
231
|
/**
|
|
@@ -300,7 +275,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
300
275
|
* @returns The tunnel config
|
|
301
276
|
* @throws Error if neither configId nor tunnelId is provided, or if tunnel is not found
|
|
302
277
|
*/
|
|
303
|
-
getTunnelConfig(configId?: string, tunnelId?: string): Promise<
|
|
278
|
+
getTunnelConfig(configId?: string, tunnelId?: string): Promise<TunnelConfigurationV1>;
|
|
304
279
|
/**
|
|
305
280
|
* Restarts a tunnel with its current configuration.
|
|
306
281
|
* This function will stop the tunnel if it's running and start it again.
|
|
@@ -319,14 +294,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
319
294
|
* @returns Promise resolving to the updated ManagedTunnel
|
|
320
295
|
* @throws Error if the tunnel is not found or if the update process fails
|
|
321
296
|
*/
|
|
322
|
-
updateConfig(newConfig:
|
|
323
|
-
tunnelType: string[] | undefined;
|
|
324
|
-
} & {
|
|
325
|
-
configid: string;
|
|
326
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
327
|
-
tunnelName?: string;
|
|
328
|
-
serve?: string;
|
|
329
|
-
}): Promise<ManagedTunnel>;
|
|
297
|
+
updateConfig(newConfig: TunnelUpdateConfig): Promise<ManagedTunnel>;
|
|
330
298
|
/**
|
|
331
299
|
* Retrieve the ManagedTunnel object by either configId or tunnelId.
|
|
332
300
|
* Throws an error if neither id is provided or the tunnel is not found.
|
|
@@ -347,6 +315,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
347
315
|
*/
|
|
348
316
|
registerStatsListener(tunnelId: string, listener: StatsListener): Promise<[string, string]>;
|
|
349
317
|
registerErrorListener(tunnelId: string, listener: ErrorListener): Promise<string>;
|
|
318
|
+
registerPollingErrorListener(tunnelId: string, listener: PollingErrorListener): Promise<string>;
|
|
350
319
|
registerDisconnectListener(tunnelId: string, listener: DisconnectListener): Promise<string>;
|
|
351
320
|
registerWorkerErrorListner(tunnelId: string, listener: TunnelWorkerErrorListner): Promise<void>;
|
|
352
321
|
registerStartListener(tunnelId: string, listener: StartListener): Promise<string>;
|
|
@@ -362,6 +331,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
362
331
|
*/
|
|
363
332
|
deregisterStatsListener(tunnelId: string, listenerId: string): void;
|
|
364
333
|
deregisterErrorListener(tunnelId: string, listenerId: string): void;
|
|
334
|
+
deregisterPollingErrorListener(tunnelId: string, listenerId: string): void;
|
|
365
335
|
deregisterDisconnectListener(tunnelId: string, listenerId: string): void;
|
|
366
336
|
deregisterWillReconnectListener(tunnelId: string, listenerId: string): void;
|
|
367
337
|
deregisterReconnectingListener(tunnelId: string, listenerId: string): void;
|
|
@@ -373,6 +343,8 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
373
343
|
* This callback will update stored stats and notify all registered listeners.
|
|
374
344
|
*/
|
|
375
345
|
private setupStatsCallback;
|
|
346
|
+
private setupTunnelPollingErrorCallback;
|
|
347
|
+
private notifyPollingErrorListeners;
|
|
376
348
|
private notifyErrorListeners;
|
|
377
349
|
private setupErrorCallback;
|
|
378
350
|
private setupDisconnectCallback;
|
|
@@ -417,7 +389,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
417
389
|
username: z.ZodString;
|
|
418
390
|
password: z.ZodString;
|
|
419
391
|
}, z.core.$strip>>>;
|
|
420
|
-
bearerauth: z.ZodNullable<z.ZodString
|
|
392
|
+
bearerauth: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
421
393
|
configid: z.ZodString;
|
|
422
394
|
configname: z.ZodString;
|
|
423
395
|
greetmsg: z.ZodOptional<z.ZodString>;
|
|
@@ -426,7 +398,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
426
398
|
fullRequestUrl: z.ZodBoolean;
|
|
427
399
|
headermodification: z.ZodArray<z.ZodObject<{
|
|
428
400
|
key: z.ZodString;
|
|
429
|
-
value: z.ZodOptional<z.ZodArray<z.ZodString
|
|
401
|
+
value: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
430
402
|
type: z.ZodEnum<{
|
|
431
403
|
add: "add";
|
|
432
404
|
remove: "remove";
|
|
@@ -470,7 +442,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
470
442
|
username: string;
|
|
471
443
|
password: string;
|
|
472
444
|
}[] | null;
|
|
473
|
-
bearerauth: string | null;
|
|
445
|
+
bearerauth: string[] | null;
|
|
474
446
|
configid: string;
|
|
475
447
|
configname: string;
|
|
476
448
|
force: boolean;
|
|
@@ -479,7 +451,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
479
451
|
headermodification: {
|
|
480
452
|
key: string;
|
|
481
453
|
type: "add" | "remove" | "update";
|
|
482
|
-
value?: string[] | undefined;
|
|
454
|
+
value?: string[] | null | undefined;
|
|
483
455
|
}[];
|
|
484
456
|
httpsOnly: boolean;
|
|
485
457
|
internalwebdebuggerport: number;
|
|
@@ -511,7 +483,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
511
483
|
username: string;
|
|
512
484
|
password: string;
|
|
513
485
|
}[] | null;
|
|
514
|
-
bearerauth: string | null;
|
|
486
|
+
bearerauth: string[] | null;
|
|
515
487
|
configid: string;
|
|
516
488
|
configname: string;
|
|
517
489
|
force: boolean;
|
|
@@ -520,7 +492,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
520
492
|
headermodification: {
|
|
521
493
|
key: string;
|
|
522
494
|
type: "add" | "remove" | "update";
|
|
523
|
-
value?: string[] | undefined;
|
|
495
|
+
value?: string[] | null | undefined;
|
|
524
496
|
}[];
|
|
525
497
|
httpsOnly: boolean;
|
|
526
498
|
internalwebdebuggerport: number;
|
|
@@ -550,6 +522,56 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
550
522
|
serve?: string | undefined;
|
|
551
523
|
}>>;
|
|
552
524
|
type TunnelConfig = z.infer<typeof TunnelConfigSchema>;
|
|
525
|
+
/**
|
|
526
|
+
* V1 Tunnel Config Schema
|
|
527
|
+
*/
|
|
528
|
+
declare const TunnelConfigV1Schema: z.ZodObject<{
|
|
529
|
+
version: z.ZodString;
|
|
530
|
+
name: z.ZodString;
|
|
531
|
+
configId: z.ZodString;
|
|
532
|
+
serverAddress: z.ZodOptional<z.ZodString>;
|
|
533
|
+
token: z.ZodOptional<z.ZodString>;
|
|
534
|
+
autoReconnect: z.ZodOptional<z.ZodBoolean>;
|
|
535
|
+
reconnectInterval: z.ZodOptional<z.ZodNumber>;
|
|
536
|
+
maxReconnectAttempts: z.ZodOptional<z.ZodNumber>;
|
|
537
|
+
force: z.ZodBoolean;
|
|
538
|
+
keepAliveInterval: z.ZodOptional<z.ZodNumber>;
|
|
539
|
+
webDebugger: z.ZodString;
|
|
540
|
+
forwarding: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodObject<{
|
|
541
|
+
listenAddress: z.ZodOptional<z.ZodString>;
|
|
542
|
+
address: z.ZodString;
|
|
543
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
544
|
+
http: TunnelType.Http;
|
|
545
|
+
tcp: TunnelType.Tcp;
|
|
546
|
+
tls: TunnelType.Tls;
|
|
547
|
+
udp: TunnelType.Udp;
|
|
548
|
+
tlstcp: TunnelType.TlsTcp;
|
|
549
|
+
}>>;
|
|
550
|
+
}, z.core.$strip>>]>;
|
|
551
|
+
ipWhitelist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
552
|
+
basicAuth: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
553
|
+
username: z.ZodString;
|
|
554
|
+
password: z.ZodString;
|
|
555
|
+
}, z.core.$strip>>>;
|
|
556
|
+
bearerTokenAuth: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
557
|
+
headerModification: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
558
|
+
key: z.ZodString;
|
|
559
|
+
value: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
560
|
+
type: z.ZodEnum<{
|
|
561
|
+
add: "add";
|
|
562
|
+
remove: "remove";
|
|
563
|
+
update: "update";
|
|
564
|
+
}>;
|
|
565
|
+
}, z.core.$strip>>>;
|
|
566
|
+
reverseProxy: z.ZodOptional<z.ZodBoolean>;
|
|
567
|
+
xForwardedFor: z.ZodOptional<z.ZodBoolean>;
|
|
568
|
+
httpsOnly: z.ZodOptional<z.ZodBoolean>;
|
|
569
|
+
originalRequestUrl: z.ZodOptional<z.ZodBoolean>;
|
|
570
|
+
allowPreflight: z.ZodOptional<z.ZodBoolean>;
|
|
571
|
+
serve: z.ZodOptional<z.ZodString>;
|
|
572
|
+
optional: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
573
|
+
}, z.core.$strip>;
|
|
574
|
+
type TunnelConfigV1 = z.infer<typeof TunnelConfigV1Schema>;
|
|
553
575
|
|
|
554
576
|
interface TunnelResponse {
|
|
555
577
|
tunnelid: string;
|
|
@@ -558,10 +580,21 @@ interface TunnelResponse {
|
|
|
558
580
|
status: Status;
|
|
559
581
|
stats: TunnelUsageType;
|
|
560
582
|
}
|
|
583
|
+
interface TunnelResponseV2 {
|
|
584
|
+
tunnelid: string;
|
|
585
|
+
remoteurls: string[];
|
|
586
|
+
tunnelconfig: TunnelConfigV1;
|
|
587
|
+
status: Status;
|
|
588
|
+
stats: TunnelUsageType;
|
|
589
|
+
greetmsg?: string;
|
|
590
|
+
}
|
|
561
591
|
interface TunnelHandler {
|
|
562
592
|
handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
593
|
+
handleStartV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
563
594
|
handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
595
|
+
handleUpdateConfigV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
564
596
|
handleList(): Promise<TunnelResponse[] | ErrorResponse>;
|
|
597
|
+
handleListV2(): Promise<TunnelResponseV2[] | ErrorResponse>;
|
|
565
598
|
handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
566
599
|
handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
567
600
|
handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
@@ -577,9 +610,13 @@ declare class TunnelOperations implements TunnelHandler {
|
|
|
577
610
|
constructor();
|
|
578
611
|
private buildStatus;
|
|
579
612
|
private buildTunnelResponse;
|
|
613
|
+
private buildTunnelResponseV2;
|
|
580
614
|
private error;
|
|
581
615
|
handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
616
|
+
handleStartV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
582
617
|
handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
618
|
+
handleUpdateConfigV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
619
|
+
handleListV2(): Promise<TunnelResponseV2[] | ErrorResponse>;
|
|
583
620
|
handleList(): Promise<TunnelResponse[] | ErrorResponse>;
|
|
584
621
|
handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
585
622
|
handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
@@ -610,7 +647,7 @@ declare function enablePackageLogging(opts?: BaseLogConfigType): winston.Logger;
|
|
|
610
647
|
* - On other failures: retry every 15 seconds
|
|
611
648
|
* - Keep running until closed or SIGINT
|
|
612
649
|
*/
|
|
613
|
-
declare function initiateRemoteManagement(
|
|
650
|
+
declare function initiateRemoteManagement(remoteManagementConfig: RemoteManagementConfig): Promise<RemoteManagementState>;
|
|
614
651
|
declare function closeRemoteManagement(timeoutMs?: number): Promise<RemoteManagementState>;
|
|
615
652
|
declare function getRemoteManagementState(): RemoteManagementState;
|
|
616
653
|
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getRemoteManagementState,
|
|
10
10
|
initiateRemoteManagement,
|
|
11
11
|
printer_default
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-MBN3YBO4.js";
|
|
13
13
|
import {
|
|
14
14
|
enablePackageLogging
|
|
15
15
|
} from "./chunk-HUN2MRZO.js";
|
|
@@ -104,7 +104,7 @@ async function verifyAndLoad() {
|
|
|
104
104
|
process.exit(1);
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
await import("./main-
|
|
107
|
+
await import("./main-VCUAV22W.js");
|
|
108
108
|
}
|
|
109
109
|
verifyAndLoad().catch((err) => {
|
|
110
110
|
printer_default.error(`Failed to start CLI:, ${err}`);
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
isValidPort,
|
|
11
11
|
parseRemoteManagement,
|
|
12
12
|
printer_default
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-MBN3YBO4.js";
|
|
14
14
|
import {
|
|
15
15
|
configureLogger,
|
|
16
16
|
enablePackageLogging,
|
|
@@ -36,6 +36,7 @@ var cliOptions = {
|
|
|
36
36
|
localport: { type: "string", short: "l", description: "Takes input as [protocol:][host:]port. Eg. --localport https://localhost:8000 OR -l 3000" },
|
|
37
37
|
debugger: { type: "string", short: "d", description: "Port for web debugger. Eg. --debugger 4300 OR -d 4300" },
|
|
38
38
|
token: { type: "string", description: "Token for authentication. Eg. --token TOKEN_VALUE" },
|
|
39
|
+
force: { type: "boolean", short: "f", description: "Forcefully close existing tunnels and establish a new tunnel" },
|
|
39
40
|
// Logging options (CLI overrides env)
|
|
40
41
|
loglevel: { type: "string", description: "Logging level: ERROR, INFO, DEBUG. Overrides PINGGY_LOG_LEVEL environment variable" },
|
|
41
42
|
logfile: { type: "string", description: "Path to log file. Overrides PINGGY_LOG_FILE environment variable" },
|
|
@@ -51,7 +52,8 @@ var cliOptions = {
|
|
|
51
52
|
// Remote Control
|
|
52
53
|
"remote-management": { type: "string", description: "Enable remote management of tunnels with token. Eg. --remote-management API_KEY" },
|
|
53
54
|
manage: { type: "string", description: "Provide a server address to manage tunnels. Eg --manage dashboard.pinggy.io" },
|
|
54
|
-
|
|
55
|
+
noTui: { type: "boolean", description: "Disable TUI in remote management mode" },
|
|
56
|
+
notui: { type: "boolean", description: "hidden", hidden: true },
|
|
55
57
|
// Misc
|
|
56
58
|
version: { type: "boolean", description: "Print version" },
|
|
57
59
|
// Help
|
|
@@ -117,8 +119,8 @@ var defaultOptions = {
|
|
|
117
119
|
|
|
118
120
|
// src/cli/extendedOptions.ts
|
|
119
121
|
import { isIP } from "net";
|
|
120
|
-
function parseExtendedOptions(options, config) {
|
|
121
|
-
if (!options) return;
|
|
122
|
+
function parseExtendedOptions(options, config, localServerTls) {
|
|
123
|
+
if (!options) return localServerTls;
|
|
122
124
|
for (const opt of options) {
|
|
123
125
|
const [key, value] = opt.replace(/^"|"$/g, "").split(/:(.+)/).filter(Boolean);
|
|
124
126
|
switch (key) {
|
|
@@ -142,10 +144,16 @@ function parseExtendedOptions(options, config) {
|
|
|
142
144
|
case "fullrequesturl":
|
|
143
145
|
config.originalRequestUrl = true;
|
|
144
146
|
break;
|
|
145
|
-
default:
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
default: {
|
|
148
|
+
if (value && (value.startsWith("localServerTls") || value.startsWith("localservertls"))) {
|
|
149
|
+
const parts = value.split(/:(.+)/);
|
|
150
|
+
localServerTls = parts[1] ? parts[1] : "";
|
|
151
|
+
} else {
|
|
152
|
+
printer_default.warn(`Unknown extended option "${value}"`);
|
|
153
|
+
logger.warn(`Warning: Unknown extended option "${value}"`);
|
|
154
|
+
}
|
|
148
155
|
break;
|
|
156
|
+
}
|
|
149
157
|
}
|
|
150
158
|
break;
|
|
151
159
|
case "w":
|
|
@@ -216,6 +224,7 @@ function parseExtendedOptions(options, config) {
|
|
|
216
224
|
break;
|
|
217
225
|
}
|
|
218
226
|
}
|
|
227
|
+
return localServerTls;
|
|
219
228
|
}
|
|
220
229
|
function isValidIpV4Cidr(input) {
|
|
221
230
|
if (input.includes("/")) {
|
|
@@ -338,9 +347,9 @@ function parseUsers(positionalArgs, explicitToken) {
|
|
|
338
347
|
return { token, server, type, forceFlag, qrCode, remaining };
|
|
339
348
|
}
|
|
340
349
|
function parseType(finalConfig, values, inferredType) {
|
|
341
|
-
const t = inferredType || values.type
|
|
350
|
+
const t = inferredType || values.type;
|
|
342
351
|
if (t === TunnelType.Http || t === TunnelType.Tcp || t === TunnelType.Tls || t === TunnelType.Udp || t === TunnelType.TlsTcp) {
|
|
343
|
-
|
|
352
|
+
return t;
|
|
344
353
|
}
|
|
345
354
|
}
|
|
346
355
|
function parseLocalPort(finalConfig, values) {
|
|
@@ -475,15 +484,14 @@ function parseAdditionalForwarding(forwarding) {
|
|
|
475
484
|
return new Error("forwarding address incorrect: invalid local port");
|
|
476
485
|
}
|
|
477
486
|
return {
|
|
478
|
-
protocol,
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
localDomain,
|
|
482
|
-
localPort
|
|
487
|
+
type: protocol,
|
|
488
|
+
listenAddress: `${remoteDomainRaw}:${remotePort}`,
|
|
489
|
+
address: `${localDomain}:${localPort}`
|
|
483
490
|
};
|
|
484
491
|
}
|
|
485
|
-
function parseReverseTunnelAddr(finalConfig, values) {
|
|
492
|
+
function parseReverseTunnelAddr(finalConfig, values, primaryType) {
|
|
486
493
|
const reverseTunnel = values.R;
|
|
494
|
+
let forwardingData = [];
|
|
487
495
|
if ((!Array.isArray(reverseTunnel) || reverseTunnel.length === 0) && !values.localport && !finalConfig.forwarding) {
|
|
488
496
|
return new Error("local port not specified. Please use '-h' option for help.");
|
|
489
497
|
}
|
|
@@ -495,18 +503,21 @@ function parseReverseTunnelAddr(finalConfig, values) {
|
|
|
495
503
|
if (slicedForwarding.length === 3) {
|
|
496
504
|
const parsed = parseDefaultForwarding(forwarding);
|
|
497
505
|
if (parsed instanceof Error) return parsed;
|
|
498
|
-
|
|
506
|
+
forwardingData.push({
|
|
507
|
+
address: `${parsed.localDomain}:${parsed.localPort}`,
|
|
508
|
+
type: primaryType || TunnelType.Http
|
|
509
|
+
});
|
|
499
510
|
} else if (slicedForwarding.length === 4) {
|
|
500
|
-
finalConfig.additionalForwarding ?? (finalConfig.additionalForwarding = []);
|
|
501
511
|
const parsed = parseAdditionalForwarding(forwarding);
|
|
502
512
|
if (parsed instanceof Error) return parsed;
|
|
503
|
-
|
|
513
|
+
forwardingData.push(parsed);
|
|
504
514
|
} else {
|
|
505
515
|
return new Error(
|
|
506
516
|
"Incorrect command line arguments: reverse tunnel address incorrect. Please use '-h' option for help."
|
|
507
517
|
);
|
|
508
518
|
}
|
|
509
519
|
}
|
|
520
|
+
finalConfig.forwarding = forwardingData;
|
|
510
521
|
return null;
|
|
511
522
|
}
|
|
512
523
|
function parseLocalTunnelAddr(finalConfig, values) {
|
|
@@ -542,7 +553,13 @@ function parseToken(finalConfig, explicitToken) {
|
|
|
542
553
|
}
|
|
543
554
|
}
|
|
544
555
|
function parseArgs(finalConfig, remainingPositionals) {
|
|
545
|
-
|
|
556
|
+
let localserverTls = "";
|
|
557
|
+
localserverTls = parseExtendedOptions(remainingPositionals, finalConfig, localserverTls);
|
|
558
|
+
if (localserverTls.length > 0 && finalConfig.forwarding) {
|
|
559
|
+
if (typeof finalConfig.forwarding[0] === "object" && "address" in finalConfig.forwarding[0]) {
|
|
560
|
+
finalConfig.forwarding[0].address = `https://${finalConfig.forwarding[0].address}`;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
546
563
|
}
|
|
547
564
|
function storeJson(config, saveconf) {
|
|
548
565
|
if (saveconf) {
|
|
@@ -580,7 +597,7 @@ function isSaveConfOption(values) {
|
|
|
580
597
|
function parseServe(finalConfig, values) {
|
|
581
598
|
const sv = values.serve;
|
|
582
599
|
if (typeof sv !== "string" || sv.trim().length === 0) return null;
|
|
583
|
-
finalConfig.serve = sv;
|
|
600
|
+
finalConfig.optional.serve = sv;
|
|
584
601
|
return null;
|
|
585
602
|
}
|
|
586
603
|
function parseAutoReconnect(finalConfig, values) {
|
|
@@ -618,21 +635,23 @@ async function buildFinalConfig(values, positionals) {
|
|
|
618
635
|
...defaultOptions,
|
|
619
636
|
...configFromFile || {},
|
|
620
637
|
// Apply loaded config on top of defaults
|
|
621
|
-
|
|
638
|
+
configId: getRandomId(),
|
|
622
639
|
token: token || (configFromFile?.token || (typeof values.token === "string" ? values.token : "")),
|
|
623
640
|
serverAddress: server || (configFromFile?.serverAddress || defaultOptions.serverAddress),
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
641
|
+
isQRCode: qrCode || (configFromFile?.isQRCode || false),
|
|
642
|
+
autoReconnect: configFromFile?.autoReconnect ? configFromFile.autoReconnect : defaultOptions.autoReconnect,
|
|
643
|
+
optional: {
|
|
644
|
+
serve: configFromFile?.optional?.serve || void 0,
|
|
645
|
+
noTui: values.noTui || values.notui || (configFromFile?.optional?.noTui || false)
|
|
646
|
+
}
|
|
628
647
|
};
|
|
629
|
-
parseType(finalConfig, values, type);
|
|
648
|
+
type = parseType(finalConfig, values, type);
|
|
630
649
|
parseToken(finalConfig, token || values.token);
|
|
631
650
|
const dbgErr = parseDebugger(finalConfig, values);
|
|
632
651
|
if (dbgErr instanceof Error) throw dbgErr;
|
|
633
652
|
const lpErr = parseLocalPort(finalConfig, values);
|
|
634
653
|
if (lpErr instanceof Error) throw lpErr;
|
|
635
|
-
const rErr = parseReverseTunnelAddr(finalConfig, values);
|
|
654
|
+
const rErr = parseReverseTunnelAddr(finalConfig, values, type);
|
|
636
655
|
if (rErr instanceof Error) throw rErr;
|
|
637
656
|
const lErr = parseLocalTunnelAddr(finalConfig, values);
|
|
638
657
|
if (lErr instanceof Error) throw lErr;
|
|
@@ -640,7 +659,7 @@ async function buildFinalConfig(values, positionals) {
|
|
|
640
659
|
if (serveErr instanceof Error) throw serveErr;
|
|
641
660
|
const autoReconnectErr = parseAutoReconnect(finalConfig, values);
|
|
642
661
|
if (autoReconnectErr instanceof Error) throw autoReconnectErr;
|
|
643
|
-
if (forceFlag) finalConfig.force = true;
|
|
662
|
+
if (forceFlag || values.force) finalConfig.force = true;
|
|
644
663
|
parseArgs(finalConfig, remainingPositionals);
|
|
645
664
|
storeJson(finalConfig, saveconf);
|
|
646
665
|
return finalConfig;
|
|
@@ -2026,7 +2045,7 @@ async function launchTui(finalConfig, urls, greet, tunnel) {
|
|
|
2026
2045
|
}
|
|
2027
2046
|
}
|
|
2028
2047
|
async function startCli(finalConfig, manager) {
|
|
2029
|
-
if (!finalConfig.
|
|
2048
|
+
if (!finalConfig.optional?.noTui && finalConfig.webDebugger === "") {
|
|
2030
2049
|
const freePort = await getFreePort(finalConfig.webDebugger || "");
|
|
2031
2050
|
finalConfig.webDebugger = `localhost:${freePort}`;
|
|
2032
2051
|
}
|
|
@@ -2034,7 +2053,7 @@ async function startCli(finalConfig, manager) {
|
|
|
2034
2053
|
const manager2 = TunnelManager.getInstance();
|
|
2035
2054
|
const tunnel = await manager2.createTunnel(finalConfig);
|
|
2036
2055
|
printer_default.startSpinner("Connecting to Pinggy...");
|
|
2037
|
-
if (!finalConfig.
|
|
2056
|
+
if (!finalConfig.optional?.noTui) {
|
|
2038
2057
|
manager2.registerStatsListener(tunnel.tunnelid, (tunnelId, stats) => {
|
|
2039
2058
|
globalThis.__PINGGY_TUNNEL_STATS__?.(stats);
|
|
2040
2059
|
});
|
|
@@ -2153,14 +2172,14 @@ async function startCli(finalConfig, manager) {
|
|
|
2153
2172
|
}
|
|
2154
2173
|
printer_default.print(pico.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"));
|
|
2155
2174
|
printer_default.print(pico.gray("\nPress Ctrl+C to stop the tunnel.\n"));
|
|
2156
|
-
if (!finalConfig.
|
|
2175
|
+
if (!finalConfig.optional?.noTui) {
|
|
2157
2176
|
await launchTui(finalConfig, TunnelData.urls, TunnelData.greet, tunnel);
|
|
2158
2177
|
}
|
|
2159
2178
|
});
|
|
2160
2179
|
} catch (e) {
|
|
2161
2180
|
logger.debug("Failed to register start listener", e);
|
|
2162
2181
|
}
|
|
2163
|
-
if (!finalConfig.
|
|
2182
|
+
if (!finalConfig.optional?.noTui) {
|
|
2164
2183
|
await launchTui(finalConfig, TunnelData.urls, TunnelData.greet, tunnel);
|
|
2165
2184
|
}
|
|
2166
2185
|
} catch (err) {
|
package/jest.config.cjs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const { createDefaultEsmPreset } = require('ts-jest');
|
|
2
|
+
|
|
3
|
+
const presetConfig = createDefaultEsmPreset();
|
|
4
|
+
|
|
5
|
+
/** @type {import("jest").Config} **/
|
|
6
|
+
module.exports = {
|
|
7
|
+
...presetConfig,
|
|
8
|
+
testEnvironment: "node",
|
|
9
|
+
moduleNameMapper: {
|
|
10
|
+
// This handles the .js extension in your TS imports
|
|
11
|
+
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
12
|
+
},
|
|
13
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pinggy",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.10",
|
|
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. ",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"build:tsc": "tsc",
|
|
15
15
|
"build": "tsup",
|
|
16
16
|
"start": "node dist/index.js",
|
|
17
|
-
"test": "
|
|
17
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
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",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@pinggy/pinggy": "^0.3.
|
|
54
|
+
"@pinggy/pinggy": "^0.3.8",
|
|
55
55
|
"blessed": "^0.1.81",
|
|
56
56
|
"clipboardy": "^5.0.0",
|
|
57
57
|
"mime": "^4.1.0",
|