pinggy 0.3.8 → 0.3.9
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-JD3U36U5.js} +726 -177
- package/dist/index.cjs +830 -247
- package/dist/index.d.cts +105 -75
- package/dist/index.d.ts +105 -75
- package/dist/index.js +2 -2
- package/dist/{main-2QDG7PWL.js → main-VIBOPJ64.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
|
}
|
|
@@ -50,19 +50,9 @@ interface Status {
|
|
|
50
50
|
endtimestamp: string;
|
|
51
51
|
warnings: Warning[];
|
|
52
52
|
}
|
|
53
|
-
type FinalConfig = (
|
|
54
|
-
configid: string;
|
|
55
|
-
}) & {
|
|
56
|
-
tunnelType: string[];
|
|
53
|
+
type FinalConfig = (TunnelConfigurationV1) & {
|
|
57
54
|
conf?: string;
|
|
58
55
|
saveconf?: string;
|
|
59
|
-
serve?: string;
|
|
60
|
-
remoteManagement?: string;
|
|
61
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
62
|
-
manage?: string;
|
|
63
|
-
version?: boolean;
|
|
64
|
-
NoTUI?: boolean;
|
|
65
|
-
qrCode?: boolean;
|
|
66
56
|
};
|
|
67
57
|
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
58
|
interface ErrorResponse {
|
|
@@ -93,12 +83,10 @@ interface RemoteManagementState {
|
|
|
93
83
|
|
|
94
84
|
interface ManagedTunnel {
|
|
95
85
|
tunnelid: string;
|
|
96
|
-
|
|
86
|
+
configId: string;
|
|
97
87
|
tunnelName?: string;
|
|
98
88
|
instance: TunnelInstance;
|
|
99
|
-
tunnelConfig?:
|
|
100
|
-
configWithForwarding?: PinggyOptions;
|
|
101
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
89
|
+
tunnelConfig?: TunnelConfigurationV1;
|
|
102
90
|
serveWorker?: Worker | null;
|
|
103
91
|
warnings?: Warning[];
|
|
104
92
|
serve?: string;
|
|
@@ -110,15 +98,24 @@ interface ManagedTunnel {
|
|
|
110
98
|
}
|
|
111
99
|
interface TunnelList {
|
|
112
100
|
tunnelid: string;
|
|
113
|
-
|
|
101
|
+
configId: string;
|
|
114
102
|
tunnelName?: string;
|
|
115
|
-
tunnelConfig:
|
|
103
|
+
tunnelConfig: TunnelConfigurationV1;
|
|
116
104
|
remoteurls: string[];
|
|
117
|
-
|
|
105
|
+
serve?: string;
|
|
106
|
+
}
|
|
107
|
+
interface TunnelCreationConfig extends TunnelConfigurationV1 {
|
|
108
|
+
tunnelid?: string;
|
|
109
|
+
tunnelName?: string;
|
|
110
|
+
serve?: string;
|
|
111
|
+
}
|
|
112
|
+
interface TunnelUpdateConfig extends TunnelConfigurationV1 {
|
|
113
|
+
tunnelName?: string;
|
|
118
114
|
serve?: string;
|
|
119
115
|
}
|
|
120
116
|
type StatsListener = (tunnelId: string, stats: TunnelUsageType) => void;
|
|
121
117
|
type ErrorListener = (tunnelId: string, errorMsg: string, isFatal: boolean) => void;
|
|
118
|
+
type PollingErrorListener = (tunnelId: string, errorMsg: string) => void;
|
|
122
119
|
type DisconnectListener = (tunnelId: string, error: string, messages: string[]) => void;
|
|
123
120
|
type TunnelWorkerErrorListner = (tunnelid: string, error: Error) => void;
|
|
124
121
|
type StartListener = (tunnelId: string, urls: string[]) => void;
|
|
@@ -127,16 +124,10 @@ type ReconnectingListener = (tunnelId: string, retryCnt: number) => void;
|
|
|
127
124
|
type ReconnectionCompletedListener = (tunnelId: string, urls: string[]) => void;
|
|
128
125
|
type ReconnectionFailedListener = (tunnelId: string, retryCnt: number) => void;
|
|
129
126
|
interface ITunnelManager {
|
|
130
|
-
createTunnel(config:
|
|
131
|
-
configid: string;
|
|
132
|
-
tunnelid?: string;
|
|
133
|
-
tunnelName?: string;
|
|
134
|
-
}) & {
|
|
135
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
136
|
-
}): Promise<ManagedTunnel>;
|
|
127
|
+
createTunnel(config: TunnelCreationConfig, buildConfig?: boolean): Promise<ManagedTunnel>;
|
|
137
128
|
startTunnel(tunnelId: string): Promise<string[]>;
|
|
138
129
|
stopTunnel(tunnelId: string): {
|
|
139
|
-
|
|
130
|
+
configId: string;
|
|
140
131
|
tunnelid: string;
|
|
141
132
|
};
|
|
142
133
|
stopAllTunnels(): void;
|
|
@@ -144,22 +135,20 @@ interface ITunnelManager {
|
|
|
144
135
|
getAllTunnels(): Promise<TunnelList[]>;
|
|
145
136
|
getTunnelStatus(tunnelId: string): Promise<string>;
|
|
146
137
|
getTunnelInstance(configId?: string, tunnelId?: string): TunnelInstance;
|
|
147
|
-
getTunnelConfig(configId?: string, tunnelId?: string): Promise<
|
|
138
|
+
getTunnelConfig(configId?: string, tunnelId?: string): Promise<TunnelConfigurationV1>;
|
|
148
139
|
restartTunnel(tunnelId: string): Promise<void>;
|
|
149
|
-
updateConfig(newConfig:
|
|
150
|
-
configid: string;
|
|
151
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
152
|
-
tunnelName?: string;
|
|
153
|
-
}): Promise<ManagedTunnel>;
|
|
140
|
+
updateConfig(newConfig: TunnelUpdateConfig, buildConfig: boolean): Promise<ManagedTunnel>;
|
|
154
141
|
getManagedTunnel(configId?: string, tunnelId?: string): ManagedTunnel;
|
|
155
142
|
getTunnelGreetMessage(tunnelId: string): Promise<string | null>;
|
|
156
143
|
getTunnelStats(tunnelId: string): TunnelUsageType[] | null;
|
|
157
144
|
getLatestTunnelStats(tunnelId: string): TunnelUsageType | null;
|
|
158
145
|
registerStatsListener(tunnelId: string, listener: StatsListener): Promise<[string, string]>;
|
|
159
146
|
registerErrorListener(tunnelId: string, listener: ErrorListener): Promise<string>;
|
|
147
|
+
registerPollingErrorListener(tunnelId: string, listener: PollingErrorListener): Promise<string>;
|
|
160
148
|
registerWorkerErrorListner(tunnelId: string, listener: TunnelWorkerErrorListner): void;
|
|
161
149
|
registerStartListener(tunnelId: string, listener: StartListener): Promise<string>;
|
|
162
150
|
deregisterErrorListener(tunnelId: string, listenerId: string): void;
|
|
151
|
+
deregisterPollingErrorListener(tunnelId: string, listenerId: string): void;
|
|
163
152
|
registerDisconnectListener(tunnelId: string, listener: DisconnectListener): Promise<string>;
|
|
164
153
|
deregisterDisconnectListener(tunnelId: string, listenerId: string): void;
|
|
165
154
|
deregisterStatsListener(tunnelId: string, listenerId: string): void;
|
|
@@ -182,6 +171,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
182
171
|
private tunnelStats;
|
|
183
172
|
private tunnelStatsListeners;
|
|
184
173
|
private tunnelErrorListeners;
|
|
174
|
+
private tunnelPollingErrorListeners;
|
|
185
175
|
private tunnelDisconnectListeners;
|
|
186
176
|
private tunnelWorkerErrorListeners;
|
|
187
177
|
private tunnelStartListeners;
|
|
@@ -193,12 +183,9 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
193
183
|
static getInstance(): TunnelManager;
|
|
194
184
|
/**
|
|
195
185
|
* Creates a new managed tunnel instance with the given configuration.
|
|
196
|
-
*
|
|
186
|
+
* Optionally builds the config with forwarding rules based on buildConfig flag.
|
|
197
187
|
*
|
|
198
188
|
* @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
189
|
*
|
|
203
190
|
* @throws {Error} When configId is invalid or empty
|
|
204
191
|
* @throws {Error} When a tunnel with the given configId already exists
|
|
@@ -206,17 +193,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
206
193
|
* @returns {ManagedTunnel} A new managed tunnel instance containing the tunnel details,
|
|
207
194
|
* status information, and statistics
|
|
208
195
|
*/
|
|
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>;
|
|
196
|
+
createTunnel(config: TunnelCreationConfig): Promise<ManagedTunnel>;
|
|
220
197
|
/**
|
|
221
198
|
* Internal method to create a tunnel with an already-processed configuration.
|
|
222
199
|
* This is used by createTunnel, restartTunnel, and updateConfig to avoid config processing.
|
|
@@ -226,15 +203,6 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
226
203
|
* @private
|
|
227
204
|
*/
|
|
228
205
|
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
206
|
/**
|
|
239
207
|
* Start a tunnel that was created but not yet started
|
|
240
208
|
*/
|
|
@@ -250,7 +218,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
250
218
|
* - Logs the stop operation with tunnelId and configId
|
|
251
219
|
*/
|
|
252
220
|
stopTunnel(tunnelId: string): {
|
|
253
|
-
|
|
221
|
+
configId: string;
|
|
254
222
|
tunnelid: string;
|
|
255
223
|
};
|
|
256
224
|
/**
|
|
@@ -300,7 +268,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
300
268
|
* @returns The tunnel config
|
|
301
269
|
* @throws Error if neither configId nor tunnelId is provided, or if tunnel is not found
|
|
302
270
|
*/
|
|
303
|
-
getTunnelConfig(configId?: string, tunnelId?: string): Promise<
|
|
271
|
+
getTunnelConfig(configId?: string, tunnelId?: string): Promise<TunnelConfigurationV1>;
|
|
304
272
|
/**
|
|
305
273
|
* Restarts a tunnel with its current configuration.
|
|
306
274
|
* This function will stop the tunnel if it's running and start it again.
|
|
@@ -319,14 +287,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
319
287
|
* @returns Promise resolving to the updated ManagedTunnel
|
|
320
288
|
* @throws Error if the tunnel is not found or if the update process fails
|
|
321
289
|
*/
|
|
322
|
-
updateConfig(newConfig:
|
|
323
|
-
tunnelType: string[] | undefined;
|
|
324
|
-
} & {
|
|
325
|
-
configid: string;
|
|
326
|
-
additionalForwarding?: AdditionalForwarding[];
|
|
327
|
-
tunnelName?: string;
|
|
328
|
-
serve?: string;
|
|
329
|
-
}): Promise<ManagedTunnel>;
|
|
290
|
+
updateConfig(newConfig: TunnelUpdateConfig): Promise<ManagedTunnel>;
|
|
330
291
|
/**
|
|
331
292
|
* Retrieve the ManagedTunnel object by either configId or tunnelId.
|
|
332
293
|
* Throws an error if neither id is provided or the tunnel is not found.
|
|
@@ -347,6 +308,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
347
308
|
*/
|
|
348
309
|
registerStatsListener(tunnelId: string, listener: StatsListener): Promise<[string, string]>;
|
|
349
310
|
registerErrorListener(tunnelId: string, listener: ErrorListener): Promise<string>;
|
|
311
|
+
registerPollingErrorListener(tunnelId: string, listener: PollingErrorListener): Promise<string>;
|
|
350
312
|
registerDisconnectListener(tunnelId: string, listener: DisconnectListener): Promise<string>;
|
|
351
313
|
registerWorkerErrorListner(tunnelId: string, listener: TunnelWorkerErrorListner): Promise<void>;
|
|
352
314
|
registerStartListener(tunnelId: string, listener: StartListener): Promise<string>;
|
|
@@ -362,6 +324,7 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
362
324
|
*/
|
|
363
325
|
deregisterStatsListener(tunnelId: string, listenerId: string): void;
|
|
364
326
|
deregisterErrorListener(tunnelId: string, listenerId: string): void;
|
|
327
|
+
deregisterPollingErrorListener(tunnelId: string, listenerId: string): void;
|
|
365
328
|
deregisterDisconnectListener(tunnelId: string, listenerId: string): void;
|
|
366
329
|
deregisterWillReconnectListener(tunnelId: string, listenerId: string): void;
|
|
367
330
|
deregisterReconnectingListener(tunnelId: string, listenerId: string): void;
|
|
@@ -373,6 +336,8 @@ declare class TunnelManager implements ITunnelManager {
|
|
|
373
336
|
* This callback will update stored stats and notify all registered listeners.
|
|
374
337
|
*/
|
|
375
338
|
private setupStatsCallback;
|
|
339
|
+
private setupTunnelPollingErrorCallback;
|
|
340
|
+
private notifyPollingErrorListeners;
|
|
376
341
|
private notifyErrorListeners;
|
|
377
342
|
private setupErrorCallback;
|
|
378
343
|
private setupDisconnectCallback;
|
|
@@ -417,7 +382,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
417
382
|
username: z.ZodString;
|
|
418
383
|
password: z.ZodString;
|
|
419
384
|
}, z.core.$strip>>>;
|
|
420
|
-
bearerauth: z.ZodNullable<z.ZodString
|
|
385
|
+
bearerauth: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
421
386
|
configid: z.ZodString;
|
|
422
387
|
configname: z.ZodString;
|
|
423
388
|
greetmsg: z.ZodOptional<z.ZodString>;
|
|
@@ -426,7 +391,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
426
391
|
fullRequestUrl: z.ZodBoolean;
|
|
427
392
|
headermodification: z.ZodArray<z.ZodObject<{
|
|
428
393
|
key: z.ZodString;
|
|
429
|
-
value: z.ZodOptional<z.ZodArray<z.ZodString
|
|
394
|
+
value: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
430
395
|
type: z.ZodEnum<{
|
|
431
396
|
add: "add";
|
|
432
397
|
remove: "remove";
|
|
@@ -470,7 +435,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
470
435
|
username: string;
|
|
471
436
|
password: string;
|
|
472
437
|
}[] | null;
|
|
473
|
-
bearerauth: string | null;
|
|
438
|
+
bearerauth: string[] | null;
|
|
474
439
|
configid: string;
|
|
475
440
|
configname: string;
|
|
476
441
|
force: boolean;
|
|
@@ -479,7 +444,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
479
444
|
headermodification: {
|
|
480
445
|
key: string;
|
|
481
446
|
type: "add" | "remove" | "update";
|
|
482
|
-
value?: string[] | undefined;
|
|
447
|
+
value?: string[] | null | undefined;
|
|
483
448
|
}[];
|
|
484
449
|
httpsOnly: boolean;
|
|
485
450
|
internalwebdebuggerport: number;
|
|
@@ -511,7 +476,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
511
476
|
username: string;
|
|
512
477
|
password: string;
|
|
513
478
|
}[] | null;
|
|
514
|
-
bearerauth: string | null;
|
|
479
|
+
bearerauth: string[] | null;
|
|
515
480
|
configid: string;
|
|
516
481
|
configname: string;
|
|
517
482
|
force: boolean;
|
|
@@ -520,7 +485,7 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
520
485
|
headermodification: {
|
|
521
486
|
key: string;
|
|
522
487
|
type: "add" | "remove" | "update";
|
|
523
|
-
value?: string[] | undefined;
|
|
488
|
+
value?: string[] | null | undefined;
|
|
524
489
|
}[];
|
|
525
490
|
httpsOnly: boolean;
|
|
526
491
|
internalwebdebuggerport: number;
|
|
@@ -550,6 +515,56 @@ declare const TunnelConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
550
515
|
serve?: string | undefined;
|
|
551
516
|
}>>;
|
|
552
517
|
type TunnelConfig = z.infer<typeof TunnelConfigSchema>;
|
|
518
|
+
/**
|
|
519
|
+
* V1 Tunnel Config Schema
|
|
520
|
+
*/
|
|
521
|
+
declare const TunnelConfigV1Schema: z.ZodObject<{
|
|
522
|
+
version: z.ZodString;
|
|
523
|
+
name: z.ZodString;
|
|
524
|
+
configId: z.ZodString;
|
|
525
|
+
serverAddress: z.ZodOptional<z.ZodString>;
|
|
526
|
+
token: z.ZodOptional<z.ZodString>;
|
|
527
|
+
autoReconnect: z.ZodOptional<z.ZodBoolean>;
|
|
528
|
+
reconnectInterval: z.ZodOptional<z.ZodNumber>;
|
|
529
|
+
maxReconnectAttempts: z.ZodOptional<z.ZodNumber>;
|
|
530
|
+
force: z.ZodBoolean;
|
|
531
|
+
keepAliveInterval: z.ZodOptional<z.ZodNumber>;
|
|
532
|
+
webDebugger: z.ZodString;
|
|
533
|
+
forwarding: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodObject<{
|
|
534
|
+
listenAddress: z.ZodOptional<z.ZodString>;
|
|
535
|
+
address: z.ZodString;
|
|
536
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
537
|
+
http: TunnelType.Http;
|
|
538
|
+
tcp: TunnelType.Tcp;
|
|
539
|
+
tls: TunnelType.Tls;
|
|
540
|
+
udp: TunnelType.Udp;
|
|
541
|
+
tlstcp: TunnelType.TlsTcp;
|
|
542
|
+
}>>;
|
|
543
|
+
}, z.core.$strip>>]>;
|
|
544
|
+
ipWhitelist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
545
|
+
basicAuth: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
546
|
+
username: z.ZodString;
|
|
547
|
+
password: z.ZodString;
|
|
548
|
+
}, z.core.$strip>>>;
|
|
549
|
+
bearerTokenAuth: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
550
|
+
headerModification: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
551
|
+
key: z.ZodString;
|
|
552
|
+
value: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
553
|
+
type: z.ZodEnum<{
|
|
554
|
+
add: "add";
|
|
555
|
+
remove: "remove";
|
|
556
|
+
update: "update";
|
|
557
|
+
}>;
|
|
558
|
+
}, z.core.$strip>>>;
|
|
559
|
+
reverseProxy: z.ZodOptional<z.ZodBoolean>;
|
|
560
|
+
xForwardedFor: z.ZodOptional<z.ZodBoolean>;
|
|
561
|
+
httpsOnly: z.ZodOptional<z.ZodBoolean>;
|
|
562
|
+
originalRequestUrl: z.ZodOptional<z.ZodBoolean>;
|
|
563
|
+
allowPreflight: z.ZodOptional<z.ZodBoolean>;
|
|
564
|
+
serve: z.ZodOptional<z.ZodString>;
|
|
565
|
+
optional: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
566
|
+
}, z.core.$strip>;
|
|
567
|
+
type TunnelConfigV1 = z.infer<typeof TunnelConfigV1Schema>;
|
|
553
568
|
|
|
554
569
|
interface TunnelResponse {
|
|
555
570
|
tunnelid: string;
|
|
@@ -558,10 +573,21 @@ interface TunnelResponse {
|
|
|
558
573
|
status: Status;
|
|
559
574
|
stats: TunnelUsageType;
|
|
560
575
|
}
|
|
576
|
+
interface TunnelResponseV2 {
|
|
577
|
+
tunnelid: string;
|
|
578
|
+
remoteurls: string[];
|
|
579
|
+
tunnelconfig: TunnelConfigV1;
|
|
580
|
+
status: Status;
|
|
581
|
+
stats: TunnelUsageType;
|
|
582
|
+
greetmsg?: string;
|
|
583
|
+
}
|
|
561
584
|
interface TunnelHandler {
|
|
562
585
|
handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
586
|
+
handleStartV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
563
587
|
handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
588
|
+
handleUpdateConfigV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
564
589
|
handleList(): Promise<TunnelResponse[] | ErrorResponse>;
|
|
590
|
+
handleListV2(): Promise<TunnelResponseV2[] | ErrorResponse>;
|
|
565
591
|
handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
566
592
|
handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
567
593
|
handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
@@ -577,9 +603,13 @@ declare class TunnelOperations implements TunnelHandler {
|
|
|
577
603
|
constructor();
|
|
578
604
|
private buildStatus;
|
|
579
605
|
private buildTunnelResponse;
|
|
606
|
+
private buildTunnelResponseV2;
|
|
580
607
|
private error;
|
|
581
608
|
handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
609
|
+
handleStartV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
582
610
|
handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
611
|
+
handleUpdateConfigV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
612
|
+
handleListV2(): Promise<TunnelResponseV2[] | ErrorResponse>;
|
|
583
613
|
handleList(): Promise<TunnelResponse[] | ErrorResponse>;
|
|
584
614
|
handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
585
615
|
handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
@@ -610,7 +640,7 @@ declare function enablePackageLogging(opts?: BaseLogConfigType): winston.Logger;
|
|
|
610
640
|
* - On other failures: retry every 15 seconds
|
|
611
641
|
* - Keep running until closed or SIGINT
|
|
612
642
|
*/
|
|
613
|
-
declare function initiateRemoteManagement(
|
|
643
|
+
declare function initiateRemoteManagement(remoteManagementConfig: RemoteManagementConfig): Promise<RemoteManagementState>;
|
|
614
644
|
declare function closeRemoteManagement(timeoutMs?: number): Promise<RemoteManagementState>;
|
|
615
645
|
declare function getRemoteManagementState(): RemoteManagementState;
|
|
616
646
|
|
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-JD3U36U5.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-VIBOPJ64.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-JD3U36U5.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.9",
|
|
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",
|