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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { PinggyOptions, TunnelUsageType, TunnelInstance, TunnelType } from '@pinggy/pinggy';
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: PinggyOptions;
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 = (PinggyOptions & {
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
- configid: string;
86
+ configId: string;
97
87
  tunnelName?: string;
98
88
  instance: TunnelInstance;
99
- tunnelConfig?: PinggyOptions;
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
- configid: string;
101
+ configId: string;
114
102
  tunnelName?: string;
115
- tunnelConfig: PinggyOptions;
103
+ tunnelConfig: TunnelConfigurationV1;
116
104
  remoteurls: string[];
117
- additionalForwarding?: AdditionalForwarding[];
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: (PinggyOptions & {
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
- configid: string;
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<PinggyOptions>;
138
+ getTunnelConfig(configId?: string, tunnelId?: string): Promise<TunnelConfigurationV1>;
148
139
  restartTunnel(tunnelId: string): Promise<void>;
149
- updateConfig(newConfig: PinggyOptions & {
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
- * Builds the config with forwarding rules and creates the tunnel instance.
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: (PinggyOptions & {
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
- configid: string;
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<PinggyOptions>;
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: PinggyOptions & {
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(token: string, manage?: string): Promise<RemoteManagementState>;
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-65R2GMKQ.js";
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-2QDG7PWL.js");
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-65R2GMKQ.js";
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
- notui: { type: "boolean", description: "Disable TUI in remote management mode" },
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
- printer_default.warn(`Unknown extended option "${key}"`);
147
- logger.warn(`Warning: Unknown extended option "${key}"`);
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 || finalConfig.tunnelType;
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
- finalConfig.tunnelType = [t];
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
- remoteDomain: remoteDomainRaw,
480
- remotePort,
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
- finalConfig.forwarding = `${parsed.localDomain}:${parsed.localPort}`;
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
- finalConfig.additionalForwarding.push(parsed);
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
- parseExtendedOptions(remainingPositionals, finalConfig);
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
- configid: getRandomId(),
638
+ configId: getRandomId(),
622
639
  token: token || (configFromFile?.token || (typeof values.token === "string" ? values.token : "")),
623
640
  serverAddress: server || (configFromFile?.serverAddress || defaultOptions.serverAddress),
624
- tunnelType: initialTunnel ? [initialTunnel] : configFromFile?.tunnelType || [TunnelType.Http],
625
- NoTUI: values.notui || (configFromFile?.NoTUI || false),
626
- qrCode: qrCode || (configFromFile?.qrCode || false),
627
- autoReconnect: configFromFile?.autoReconnect ? configFromFile.autoReconnect : defaultOptions.autoReconnect
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.NoTUI && finalConfig.webDebugger === "") {
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.NoTUI) {
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.NoTUI) {
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.NoTUI) {
2182
+ if (!finalConfig.optional?.noTui) {
2164
2183
  await launchTui(finalConfig, TunnelData.urls, TunnelData.greet, tunnel);
2165
2184
  }
2166
2185
  } catch (err) {
@@ -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.8",
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": "jest --config jest.config.js",
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.5",
54
+ "@pinggy/pinggy": "^0.3.8",
55
55
  "blessed": "^0.1.81",
56
56
  "clipboardy": "^5.0.0",
57
57
  "mime": "^4.1.0",