@limrun/api 0.13.1 → 0.14.0

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/src/tunnel.ts CHANGED
@@ -1,93 +1,237 @@
1
1
  import * as net from 'net';
2
2
  import { WebSocket } from 'ws';
3
3
 
4
+ /**
5
+ * Controls the verbosity of logging in the tunnel
6
+ */
7
+ export type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug';
8
+
9
+ /**
10
+ * Connection state of the tunnel
11
+ */
12
+ export type TunnelConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';
13
+
14
+ /**
15
+ * Callback function for tunnel connection state changes
16
+ */
17
+ export type TunnelConnectionStateCallback = (state: TunnelConnectionState) => void;
18
+
4
19
  export interface Tunnel {
5
20
  address: {
6
21
  address: string;
7
22
  port: number;
8
23
  };
9
24
  close: () => void;
25
+ /**
26
+ * Get current WebSocket connection state
27
+ */
28
+ getConnectionState: () => TunnelConnectionState;
29
+ /**
30
+ * Register callback for WebSocket connection state changes
31
+ * @returns A function to unregister the callback
32
+ */
33
+ onConnectionStateChange: (callback: TunnelConnectionStateCallback) => () => void;
34
+ }
35
+
36
+ export interface TcpTunnelOptions {
37
+ /**
38
+ * Maximum number of reconnection attempts
39
+ * @default 6
40
+ */
41
+ maxReconnectAttempts?: number;
42
+ /**
43
+ * Initial reconnection delay in milliseconds
44
+ * @default 1000
45
+ */
46
+ reconnectDelay?: number;
47
+ /**
48
+ * Maximum reconnection delay in milliseconds
49
+ * @default 30000
50
+ */
51
+ maxReconnectDelay?: number;
52
+ /**
53
+ * Controls logging verbosity
54
+ * @default 'info'
55
+ */
56
+ logLevel?: LogLevel;
10
57
  }
11
58
 
12
59
  /**
13
- * Starts a one-shot TCP → WebSocket proxy.
60
+ * Starts a persistent TCP → WebSocket proxy.
14
61
  *
15
62
  * The function creates a local TCP server that listens on an ephemeral port on
16
- * 127.0.0.1. As soon as the **first** TCP client connects the server stops
17
- * accepting further connections and forwards all traffic between that client
18
- * and `remoteURL` through an authenticated WebSocket. If you need to proxy
19
- * more than one TCP connection, call `startTcpTunnel` again to create a new
20
- * proxy instance.
63
+ * 127.0.0.1. When a TCP client connects, it forwards all traffic between that
64
+ * client and `remoteURL` through an authenticated WebSocket. The server remains
65
+ * active even after the client disconnects, allowing reconnection without
66
+ * recreating the tunnel.
21
67
  *
22
68
  * @param remoteURL Remote WebSocket endpoint (e.g. wss://example.com/instance)
23
69
  * @param token Bearer token sent as `Authorization` header
24
70
  * @param hostname Optional IP address to listen on. Default is 127.0.0.1
25
71
  * @param port Optional port number to listen on. Default is to ask Node.js
26
72
  * to find an available non-privileged port.
73
+ * @param options Optional reconnection configuration
27
74
  */
28
75
  export async function startTcpTunnel(
29
76
  remoteURL: string,
30
77
  token: string,
31
78
  hostname: string,
32
79
  port: number,
80
+ options?: TcpTunnelOptions,
33
81
  ): Promise<Tunnel> {
82
+ const maxReconnectAttempts = options?.maxReconnectAttempts ?? 6;
83
+ const reconnectDelay = options?.reconnectDelay ?? 1000;
84
+ const maxReconnectDelay = options?.maxReconnectDelay ?? 30000;
85
+ const logLevel = options?.logLevel ?? 'info';
86
+
87
+ // Logger functions
88
+ const logger = {
89
+ debug: (...args: any[]) => {
90
+ if (logLevel === 'debug') console.log('[Tunnel]', ...args);
91
+ },
92
+ info: (...args: any[]) => {
93
+ if (logLevel === 'info' || logLevel === 'debug') console.log('[Tunnel]', ...args);
94
+ },
95
+ warn: (...args: any[]) => {
96
+ if (logLevel === 'warn' || logLevel === 'info' || logLevel === 'debug')
97
+ console.warn('[Tunnel]', ...args);
98
+ },
99
+ error: (...args: any[]) => {
100
+ if (logLevel !== 'none') console.error('[Tunnel]', ...args);
101
+ },
102
+ };
103
+
34
104
  return new Promise((resolve, reject) => {
35
105
  const server = net.createServer();
36
106
 
37
107
  let ws: WebSocket | undefined;
38
108
  let pingInterval: NodeJS.Timeout | undefined;
109
+ let reconnectTimeout: NodeJS.Timeout | undefined;
110
+ let reconnectAttempts = 0;
111
+ let intentionalDisconnect = false;
112
+ let tcpSocket: net.Socket | undefined;
113
+ let connectionState: TunnelConnectionState = 'connecting';
39
114
 
40
- // close helper
41
- const close = () => {
115
+ const stateChangeCallbacks: Set<TunnelConnectionStateCallback> = new Set();
116
+
117
+ const updateConnectionState = (newState: TunnelConnectionState): void => {
118
+ if (connectionState !== newState) {
119
+ connectionState = newState;
120
+ logger.debug(`Connection state changed to: ${newState}`);
121
+ stateChangeCallbacks.forEach((callback) => {
122
+ try {
123
+ callback(newState);
124
+ } catch (err) {
125
+ logger.error('Error in connection state callback:', err);
126
+ }
127
+ });
128
+ }
129
+ };
130
+
131
+ const cleanup = () => {
132
+ if (reconnectTimeout) {
133
+ clearTimeout(reconnectTimeout);
134
+ reconnectTimeout = undefined;
135
+ }
42
136
  if (pingInterval) {
43
137
  clearInterval(pingInterval);
44
138
  pingInterval = undefined;
45
139
  }
46
- if (ws && ws.readyState === WebSocket.OPEN) {
47
- ws.close(1000, 'close');
140
+ if (ws) {
141
+ ws.removeAllListeners();
142
+ if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
143
+ ws.close(1000, 'close');
144
+ }
145
+ ws = undefined;
146
+ }
147
+ };
148
+
149
+ const close = () => {
150
+ intentionalDisconnect = true;
151
+ cleanup();
152
+ updateConnectionState('disconnected');
153
+ if (tcpSocket && !tcpSocket.destroyed) {
154
+ tcpSocket.destroy();
48
155
  }
49
156
  if (server.listening) {
50
157
  server.close();
51
158
  }
52
159
  };
53
160
 
54
- // No AbortController support proxy can be closed via the returned handle
161
+ const scheduleReconnect = (): void => {
162
+ if (intentionalDisconnect) {
163
+ logger.debug('Skipping reconnection (intentional disconnect)');
164
+ return;
165
+ }
55
166
 
56
- // TCP server error
57
- server.once('error', (err) => {
58
- close();
59
- reject(new Error(`TCP server error: ${err.message}`));
60
- });
167
+ if (!tcpSocket || tcpSocket.destroyed) {
168
+ logger.debug('Skipping reconnection (TCP socket closed)');
169
+ return;
170
+ }
61
171
 
62
- // Listening
63
- server.once('listening', () => {
64
- const address = server.address();
65
- if (!address || typeof address === 'string') {
172
+ if (reconnectAttempts >= maxReconnectAttempts) {
173
+ logger.error(`Max reconnection attempts (${maxReconnectAttempts}) reached. Closing tunnel.`);
66
174
  close();
67
- return reject(new Error('Failed to obtain listening address'));
175
+ return;
68
176
  }
69
- resolve({ address, close });
70
- });
71
177
 
72
- // On first TCP connection
73
- server.on('connection', (tcpSocket) => {
74
- // Single-connection proxy
75
- server.close();
178
+ const currentDelay = Math.min(reconnectDelay * Math.pow(2, reconnectAttempts), maxReconnectDelay);
179
+
180
+ reconnectAttempts++;
181
+ logger.debug(`Scheduling reconnection attempt ${reconnectAttempts} in ${currentDelay}ms...`);
182
+ updateConnectionState('reconnecting');
183
+
184
+ reconnectTimeout = setTimeout(() => {
185
+ logger.debug(`Attempting to reconnect (attempt ${reconnectAttempts})...`);
186
+ setupWebSocket();
187
+ }, currentDelay);
188
+ };
189
+
190
+ const setupWebSocket = (): void => {
191
+ if (!tcpSocket || tcpSocket.destroyed) {
192
+ logger.error('Cannot setup WebSocket: TCP socket is closed');
193
+ return;
194
+ }
195
+
196
+ cleanup();
197
+ updateConnectionState('connecting');
76
198
 
77
199
  ws = new WebSocket(remoteURL, {
78
200
  headers: { Authorization: `Bearer ${token}` },
79
201
  perMessageDeflate: false,
80
202
  });
81
203
 
82
- // WebSocket error
83
- ws.once('error', (err: any) => {
84
- console.error('WebSocket error:', err);
85
- tcpSocket.destroy();
86
- close();
204
+ ws.on('error', (err: any) => {
205
+ logger.error('WebSocket error:', err.message || err);
87
206
  });
88
207
 
89
- ws.once('open', () => {
90
- const socket = ws as WebSocket; // non-undefined after open
208
+ ws.on('close', () => {
209
+ if (pingInterval) {
210
+ clearInterval(pingInterval);
211
+ pingInterval = undefined;
212
+ }
213
+
214
+ const shouldReconnect = !intentionalDisconnect && connectionState !== 'disconnected';
215
+ updateConnectionState('disconnected');
216
+
217
+ logger.debug('WebSocket disconnected');
218
+
219
+ // Pause TCP socket to apply backpressure - TCP will handle buffering
220
+ if (tcpSocket && !tcpSocket.destroyed && !tcpSocket.isPaused()) {
221
+ logger.debug('Pausing TCP socket (applying backpressure)');
222
+ tcpSocket.pause();
223
+ }
224
+
225
+ if (shouldReconnect && tcpSocket && !tcpSocket.destroyed) {
226
+ scheduleReconnect();
227
+ }
228
+ });
229
+
230
+ ws.on('open', () => {
231
+ const socket = ws as WebSocket;
232
+ logger.debug('WebSocket connected');
233
+ reconnectAttempts = 0;
234
+ updateConnectionState('connected');
91
235
 
92
236
  pingInterval = setInterval(() => {
93
237
  if (socket.readyState === WebSocket.OPEN) {
@@ -95,29 +239,104 @@ export async function startTcpTunnel(
95
239
  }
96
240
  }, 30_000);
97
241
 
98
- // TCP WS
99
- tcpSocket.on('data', (chunk) => {
242
+ // Resume TCP socket - queued data will flow through
243
+ if (tcpSocket && tcpSocket.isPaused()) {
244
+ logger.debug('Resuming TCP socket (releasing backpressure)');
245
+ tcpSocket.resume();
246
+ }
247
+
248
+ // TCP → WS: Forward data directly
249
+ const onTcpData = (chunk: Buffer) => {
100
250
  if (socket.readyState === WebSocket.OPEN) {
101
251
  socket.send(chunk);
102
252
  }
103
- });
253
+ // If WebSocket is not ready, data will queue in TCP buffers (backpressure)
254
+ };
255
+
256
+ // Remove old listener if exists and add new one
257
+ tcpSocket!.removeListener('data', onTcpData);
258
+ tcpSocket!.on('data', onTcpData);
104
259
 
105
260
  // WS → TCP
106
261
  socket.on('message', (data: any) => {
107
- if (!tcpSocket.destroyed) {
262
+ if (tcpSocket && !tcpSocket.destroyed) {
108
263
  tcpSocket.write(data as Buffer);
109
264
  }
110
265
  });
111
266
  });
267
+ };
112
268
 
113
- // Mutual close
114
- tcpSocket.on('close', close);
115
- tcpSocket.on('error', (err: any) => {
116
- console.error('TCP socket error:', err);
269
+ // TCP server error
270
+ server.once('error', (err) => {
271
+ close();
272
+ reject(new Error(`TCP server error: ${err.message}`));
273
+ });
274
+
275
+ const getConnectionState = (): TunnelConnectionState => {
276
+ return connectionState;
277
+ };
278
+
279
+ const onConnectionStateChange = (callback: TunnelConnectionStateCallback): (() => void) => {
280
+ stateChangeCallbacks.add(callback);
281
+ return () => {
282
+ stateChangeCallbacks.delete(callback);
283
+ };
284
+ };
285
+
286
+ // Listening
287
+ server.once('listening', () => {
288
+ const address = server.address();
289
+ if (!address || typeof address === 'string') {
117
290
  close();
291
+ return reject(new Error('Failed to obtain listening address'));
292
+ }
293
+ resolve({
294
+ address,
295
+ close,
296
+ getConnectionState,
297
+ onConnectionStateChange,
298
+ });
299
+ });
300
+
301
+ // Helper to clean up current connection but keep server alive
302
+ const cleanupConnection = () => {
303
+ cleanup();
304
+ updateConnectionState('disconnected');
305
+ if (tcpSocket && !tcpSocket.destroyed) {
306
+ tcpSocket.destroy();
307
+ tcpSocket = undefined;
308
+ }
309
+ // Reset reconnection state for next connection
310
+ reconnectAttempts = 0;
311
+ intentionalDisconnect = false;
312
+ logger.debug('Connection cleaned up, ready for new TCP connection');
313
+ };
314
+
315
+ // On TCP connection (can happen multiple times)
316
+ server.on('connection', (socket) => {
317
+ // If there's already an active connection, reject the new one
318
+ if (tcpSocket && !tcpSocket.destroyed) {
319
+ logger.debug('Rejecting new TCP connection - already have an active connection');
320
+ socket.destroy();
321
+ return;
322
+ }
323
+
324
+ logger.debug('TCP client connected');
325
+ tcpSocket = socket;
326
+
327
+ // TCP socket handlers
328
+ tcpSocket.on('close', () => {
329
+ logger.debug('TCP socket closed by client');
330
+ cleanupConnection();
331
+ });
332
+
333
+ tcpSocket.on('error', (err: any) => {
334
+ logger.error('TCP socket error:', err);
335
+ cleanupConnection();
118
336
  });
119
337
 
120
- ws.on('close', () => tcpSocket.destroy());
338
+ // Start WebSocket connection
339
+ setupWebSocket();
121
340
  });
122
341
 
123
342
  // Start listening
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.13.1'; // x-release-please-version
1
+ export const VERSION = '0.14.0'; // x-release-please-version
package/tunnel.d.mts CHANGED
@@ -1,25 +1,68 @@
1
+ /**
2
+ * Controls the verbosity of logging in the tunnel
3
+ */
4
+ export type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug';
5
+ /**
6
+ * Connection state of the tunnel
7
+ */
8
+ export type TunnelConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';
9
+ /**
10
+ * Callback function for tunnel connection state changes
11
+ */
12
+ export type TunnelConnectionStateCallback = (state: TunnelConnectionState) => void;
1
13
  export interface Tunnel {
2
14
  address: {
3
15
  address: string;
4
16
  port: number;
5
17
  };
6
18
  close: () => void;
19
+ /**
20
+ * Get current WebSocket connection state
21
+ */
22
+ getConnectionState: () => TunnelConnectionState;
23
+ /**
24
+ * Register callback for WebSocket connection state changes
25
+ * @returns A function to unregister the callback
26
+ */
27
+ onConnectionStateChange: (callback: TunnelConnectionStateCallback) => () => void;
28
+ }
29
+ export interface TcpTunnelOptions {
30
+ /**
31
+ * Maximum number of reconnection attempts
32
+ * @default 6
33
+ */
34
+ maxReconnectAttempts?: number;
35
+ /**
36
+ * Initial reconnection delay in milliseconds
37
+ * @default 1000
38
+ */
39
+ reconnectDelay?: number;
40
+ /**
41
+ * Maximum reconnection delay in milliseconds
42
+ * @default 30000
43
+ */
44
+ maxReconnectDelay?: number;
45
+ /**
46
+ * Controls logging verbosity
47
+ * @default 'info'
48
+ */
49
+ logLevel?: LogLevel;
7
50
  }
8
51
  /**
9
- * Starts a one-shot TCP → WebSocket proxy.
52
+ * Starts a persistent TCP → WebSocket proxy.
10
53
  *
11
54
  * The function creates a local TCP server that listens on an ephemeral port on
12
- * 127.0.0.1. As soon as the **first** TCP client connects the server stops
13
- * accepting further connections and forwards all traffic between that client
14
- * and `remoteURL` through an authenticated WebSocket. If you need to proxy
15
- * more than one TCP connection, call `startTcpTunnel` again to create a new
16
- * proxy instance.
55
+ * 127.0.0.1. When a TCP client connects, it forwards all traffic between that
56
+ * client and `remoteURL` through an authenticated WebSocket. The server remains
57
+ * active even after the client disconnects, allowing reconnection without
58
+ * recreating the tunnel.
17
59
  *
18
60
  * @param remoteURL Remote WebSocket endpoint (e.g. wss://example.com/instance)
19
61
  * @param token Bearer token sent as `Authorization` header
20
62
  * @param hostname Optional IP address to listen on. Default is 127.0.0.1
21
63
  * @param port Optional port number to listen on. Default is to ask Node.js
22
64
  * to find an available non-privileged port.
65
+ * @param options Optional reconnection configuration
23
66
  */
24
- export declare function startTcpTunnel(remoteURL: string, token: string, hostname: string, port: number): Promise<Tunnel>;
67
+ export declare function startTcpTunnel(remoteURL: string, token: string, hostname: string, port: number, options?: TcpTunnelOptions): Promise<Tunnel>;
25
68
  //# sourceMappingURL=tunnel.d.mts.map
package/tunnel.d.mts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel.d.mts","sourceRoot":"","sources":["src/tunnel.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CA6FjB"}
1
+ {"version":3,"file":"tunnel.d.mts","sourceRoot":"","sources":["src/tunnel.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,cAAc,CAAC;AAEjG;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;AAEnF,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB;;OAEG;IACH,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;IAChD;;;OAGG;IACH,uBAAuB,EAAE,CAAC,QAAQ,EAAE,6BAA6B,KAAK,MAAM,IAAI,CAAC;CAClF;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,MAAM,CAAC,CAwQjB"}
package/tunnel.d.ts CHANGED
@@ -1,25 +1,68 @@
1
+ /**
2
+ * Controls the verbosity of logging in the tunnel
3
+ */
4
+ export type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug';
5
+ /**
6
+ * Connection state of the tunnel
7
+ */
8
+ export type TunnelConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';
9
+ /**
10
+ * Callback function for tunnel connection state changes
11
+ */
12
+ export type TunnelConnectionStateCallback = (state: TunnelConnectionState) => void;
1
13
  export interface Tunnel {
2
14
  address: {
3
15
  address: string;
4
16
  port: number;
5
17
  };
6
18
  close: () => void;
19
+ /**
20
+ * Get current WebSocket connection state
21
+ */
22
+ getConnectionState: () => TunnelConnectionState;
23
+ /**
24
+ * Register callback for WebSocket connection state changes
25
+ * @returns A function to unregister the callback
26
+ */
27
+ onConnectionStateChange: (callback: TunnelConnectionStateCallback) => () => void;
28
+ }
29
+ export interface TcpTunnelOptions {
30
+ /**
31
+ * Maximum number of reconnection attempts
32
+ * @default 6
33
+ */
34
+ maxReconnectAttempts?: number;
35
+ /**
36
+ * Initial reconnection delay in milliseconds
37
+ * @default 1000
38
+ */
39
+ reconnectDelay?: number;
40
+ /**
41
+ * Maximum reconnection delay in milliseconds
42
+ * @default 30000
43
+ */
44
+ maxReconnectDelay?: number;
45
+ /**
46
+ * Controls logging verbosity
47
+ * @default 'info'
48
+ */
49
+ logLevel?: LogLevel;
7
50
  }
8
51
  /**
9
- * Starts a one-shot TCP → WebSocket proxy.
52
+ * Starts a persistent TCP → WebSocket proxy.
10
53
  *
11
54
  * The function creates a local TCP server that listens on an ephemeral port on
12
- * 127.0.0.1. As soon as the **first** TCP client connects the server stops
13
- * accepting further connections and forwards all traffic between that client
14
- * and `remoteURL` through an authenticated WebSocket. If you need to proxy
15
- * more than one TCP connection, call `startTcpTunnel` again to create a new
16
- * proxy instance.
55
+ * 127.0.0.1. When a TCP client connects, it forwards all traffic between that
56
+ * client and `remoteURL` through an authenticated WebSocket. The server remains
57
+ * active even after the client disconnects, allowing reconnection without
58
+ * recreating the tunnel.
17
59
  *
18
60
  * @param remoteURL Remote WebSocket endpoint (e.g. wss://example.com/instance)
19
61
  * @param token Bearer token sent as `Authorization` header
20
62
  * @param hostname Optional IP address to listen on. Default is 127.0.0.1
21
63
  * @param port Optional port number to listen on. Default is to ask Node.js
22
64
  * to find an available non-privileged port.
65
+ * @param options Optional reconnection configuration
23
66
  */
24
- export declare function startTcpTunnel(remoteURL: string, token: string, hostname: string, port: number): Promise<Tunnel>;
67
+ export declare function startTcpTunnel(remoteURL: string, token: string, hostname: string, port: number, options?: TcpTunnelOptions): Promise<Tunnel>;
25
68
  //# sourceMappingURL=tunnel.d.ts.map
package/tunnel.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["src/tunnel.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CA6FjB"}
1
+ {"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["src/tunnel.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,cAAc,CAAC;AAEjG;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;AAEnF,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB;;OAEG;IACH,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;IAChD;;;OAGG;IACH,uBAAuB,EAAE,CAAC,QAAQ,EAAE,6BAA6B,KAAK,MAAM,IAAI,CAAC;CAClF;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,MAAM,CAAC,CAwQjB"}