pinggy 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +1 -1
  2. package/dist/chunk-65R2GMKQ.js +2101 -0
  3. package/dist/index.cjs +1814 -1362
  4. package/dist/index.d.cts +616 -0
  5. package/dist/index.d.ts +616 -0
  6. package/dist/index.js +38 -55
  7. package/dist/{main-CZY6GID4.js → main-2QDG7PWL.js} +229 -1726
  8. package/package.json +3 -4
  9. package/.github/workflows/npm-publish-github-packages.yml +0 -34
  10. package/.github/workflows/publish-binaries.yml +0 -223
  11. package/Makefile +0 -4
  12. package/caxa_build.js +0 -24
  13. package/dist/chunk-T5ESYDJY.js +0 -121
  14. package/ent.plist +0 -14
  15. package/jest.config.js +0 -19
  16. package/src/_tests_/build_config.test.ts +0 -91
  17. package/src/cli/buildConfig.ts +0 -475
  18. package/src/cli/defaults.ts +0 -20
  19. package/src/cli/extendedOptions.ts +0 -153
  20. package/src/cli/help.ts +0 -43
  21. package/src/cli/options.ts +0 -50
  22. package/src/cli/starCli.ts +0 -229
  23. package/src/index.ts +0 -30
  24. package/src/logger.ts +0 -138
  25. package/src/main.ts +0 -87
  26. package/src/remote_management/handler.ts +0 -244
  27. package/src/remote_management/remoteManagement.ts +0 -226
  28. package/src/remote_management/remote_schema.ts +0 -176
  29. package/src/remote_management/websocket_handlers.ts +0 -180
  30. package/src/tui/blessed/TunnelTui.ts +0 -340
  31. package/src/tui/blessed/components/DisplayUpdaters.ts +0 -189
  32. package/src/tui/blessed/components/KeyBindings.ts +0 -236
  33. package/src/tui/blessed/components/Modals.ts +0 -302
  34. package/src/tui/blessed/components/UIComponents.ts +0 -306
  35. package/src/tui/blessed/components/index.ts +0 -4
  36. package/src/tui/blessed/config.ts +0 -53
  37. package/src/tui/blessed/headerFetcher.ts +0 -42
  38. package/src/tui/blessed/index.ts +0 -2
  39. package/src/tui/blessed/qrCodeGenerator.ts +0 -20
  40. package/src/tui/blessed/webDebuggerConnection.ts +0 -128
  41. package/src/tui/ink/asciArt.ts +0 -7
  42. package/src/tui/ink/hooks/useQrCodes.ts +0 -27
  43. package/src/tui/ink/hooks/useReqResHeaders.ts +0 -27
  44. package/src/tui/ink/hooks/useTerminalSize.ts +0 -26
  45. package/src/tui/ink/hooks/useTerminalStats.ts +0 -24
  46. package/src/tui/ink/hooks/useWebDebugger.ts +0 -98
  47. package/src/tui/ink/index.tsx +0 -243
  48. package/src/tui/ink/layout/Borders.tsx +0 -15
  49. package/src/tui/ink/layout/Container.tsx +0 -15
  50. package/src/tui/ink/sections/DebuggerDetailModal.tsx +0 -53
  51. package/src/tui/ink/sections/KeyBindings.tsx +0 -58
  52. package/src/tui/ink/sections/QrCodeSection.tsx +0 -28
  53. package/src/tui/ink/sections/StatsSection.tsx +0 -20
  54. package/src/tui/ink/sections/URLsSection.tsx +0 -53
  55. package/src/tui/ink/utils/utils.ts +0 -35
  56. package/src/tui/spinner/spinner.ts +0 -64
  57. package/src/tunnel_manager/TunnelManager.ts +0 -1212
  58. package/src/types.ts +0 -255
  59. package/src/utils/FileServer.ts +0 -112
  60. package/src/utils/detect_vc_redist_on_windows.ts +0 -167
  61. package/src/utils/getFreePort.ts +0 -41
  62. package/src/utils/htmlTemplates.ts +0 -146
  63. package/src/utils/parseArgs.ts +0 -79
  64. package/src/utils/printer.ts +0 -81
  65. package/src/utils/util.ts +0 -18
  66. package/src/workers/file_serve_worker.ts +0 -33
  67. package/tsconfig.json +0 -17
  68. package/tsup.config.ts +0 -12
@@ -1,306 +0,0 @@
1
- import blessed from "blessed";
2
- import { FinalConfig } from "../../../types.js";
3
- import { asciiArtPinggyLogo } from "../../ink/asciArt.js";
4
-
5
- export const MIN_WIDTH_WARNING = 60;
6
- export const SIMPLE_LAYOUT_THRESHOLD = 80;
7
-
8
- export interface UIElements {
9
- mainContainer: blessed.Widgets.BoxElement;
10
- logoBox?: blessed.Widgets.BoxElement;
11
- contentBox?: blessed.Widgets.BoxElement;
12
- urlsBox: blessed.Widgets.BoxElement;
13
- statsBox: blessed.Widgets.BoxElement;
14
- requestsBox?: blessed.Widgets.BoxElement;
15
- qrCodeBox?: blessed.Widgets.BoxElement;
16
- footerBox: blessed.Widgets.BoxElement;
17
- warningBox?: blessed.Widgets.BoxElement;
18
- }
19
-
20
- /**
21
- * Colorizes text with a gradient of colors
22
- */
23
- export function colorizeGradient(text: string): string {
24
- const colors = ["red", "yellow", "green", "cyan", "blue", "magenta"];
25
- const lines = text.split("\n");
26
- return lines
27
- .map((line, i) => {
28
- const color = colors[i % colors.length];
29
- return `{${color}-fg}${line}{/${color}-fg}`;
30
- })
31
- .join("\n");
32
- }
33
-
34
- /**
35
- * Creates the warning UI when terminal is too narrow
36
- */
37
- export function createWarningUI(screen: blessed.Widgets.Screen): blessed.Widgets.BoxElement {
38
- return blessed.box({
39
- parent: screen,
40
- top: "center",
41
- left: "center",
42
- width: "80%",
43
- height: 5,
44
- content: `{red-fg}{bold}Terminal is too narrow to show TUI (${screen.width} cols).{/bold}{/red-fg}\n{yellow-fg}Please resize your terminal to at least ${MIN_WIDTH_WARNING} columns for proper display.{/yellow-fg}`,
45
- tags: true,
46
- align: "center",
47
- valign: "middle",
48
- style: {
49
- fg: 'red'
50
- }
51
- });
52
- }
53
-
54
- /**
55
- * Creates the full UI layout for wider terminals
56
- */
57
- export function createFullUI(
58
- screen: blessed.Widgets.Screen,
59
- urls: string[],
60
- greet: string,
61
- tunnelConfig?: FinalConfig
62
- ): UIElements {
63
- // Main container
64
- const mainContainer = blessed.box({
65
- parent: screen,
66
- top: 0,
67
- left: 0,
68
- width: "100%",
69
- height: "100%",
70
- padding: 1,
71
- });
72
-
73
- // Logo
74
- const logoBox = blessed.box({
75
- parent: mainContainer,
76
- top: 0,
77
- left: 0,
78
- width: "100%",
79
- height: 7,
80
- content: colorizeGradient(asciiArtPinggyLogo),
81
- tags: true,
82
- });
83
-
84
- // Content box with border
85
- const contentBox = blessed.box({
86
- parent: mainContainer,
87
- top: 8,
88
- left: 0,
89
- width: "100%-2",
90
- height: "100%-10",
91
- padding: 0,
92
- border: {
93
- type: "line",
94
- },
95
- style: {
96
- border: {
97
- fg: "green",
98
- },
99
- },
100
-
101
- });
102
-
103
- // Greet message
104
- let greetHeight = 0;
105
- if (greet) {
106
- const greetBox = blessed.box({
107
- parent: contentBox,
108
- top: 0,
109
- left: "center",
110
- width: "60%",
111
- height: 4,
112
- content: `{bold}${greet}{/bold}`,
113
- tags: true,
114
- align: "center",
115
- style: {
116
- fg: 'green',
117
- },
118
- });
119
- greetHeight = 4;
120
- }
121
-
122
- // Upper section: URLs + Stats
123
- const upperSectionTop = greetHeight > 0 ? greetHeight : 0;
124
-
125
- const upperSection = blessed.box({
126
- parent: contentBox,
127
- top: upperSectionTop,
128
- left: 0,
129
- width: "100%-2",
130
- height: 10,
131
- });
132
-
133
- // URLs section
134
- const urlsBox = blessed.box({
135
- parent: upperSection,
136
- top: 0,
137
- left: 0,
138
- width: "48%",
139
- height: "100%",
140
- padding: { left: 1, right: 1 },
141
- tags: true,
142
-
143
- });
144
-
145
-
146
- // Stats section
147
- const statsBox = blessed.box({
148
- parent: upperSection,
149
- top: 0,
150
- right: 0,
151
- left: "65%",
152
- width: "35%",
153
- height: "100%",
154
- padding: { left: 1, right: 1 },
155
- tags: true,
156
- align: "left",
157
- });
158
-
159
- // Lower section: Requests + QR Code
160
- const lowerSectionTop = greetHeight + 11;
161
- const lowerSection = blessed.box({
162
- parent: contentBox,
163
- top: lowerSectionTop,
164
- left: 0,
165
- right: 0,
166
- bottom: 2,
167
- width: "100%-2",
168
- height: `100%-${lowerSectionTop + 6}`,
169
- });
170
-
171
- const isQrCodeRequested = tunnelConfig?.qrCode || false;
172
-
173
- // Requests section
174
- const requestsBox = blessed.box({
175
- parent: lowerSection,
176
- top: 0,
177
- left: 0,
178
- width: isQrCodeRequested ? "60%" : "80%",
179
- height: "80%",
180
- padding: { left: 1, right: 1 },
181
- tags: true,
182
- scrollable: true,
183
-
184
- });
185
-
186
- // QR Code section
187
- let qrCodeBox: blessed.Widgets.BoxElement | undefined;
188
- if (isQrCodeRequested) {
189
- qrCodeBox = blessed.box({
190
- parent: lowerSection,
191
- top: 0,
192
- right: 0,
193
- width: "40%",
194
- height: "100%",
195
- tags: true,
196
- padding: { left: 1, right: 1 },
197
-
198
- });
199
- }
200
-
201
- // Footer
202
- const footerBox = blessed.box({
203
- parent: contentBox,
204
- bottom: 0,
205
- left: "center",
206
- width: "shrink",
207
- height: 1,
208
- content: "Press Ctrl+C to stop the tunnel. Or press h for key bindings.",
209
- tags: true,
210
- });
211
-
212
- return {
213
- mainContainer,
214
- logoBox,
215
- contentBox,
216
- urlsBox,
217
- statsBox,
218
- requestsBox,
219
- qrCodeBox,
220
- footerBox,
221
- };
222
- }
223
-
224
- /**
225
- * Creates a simple UI layout for narrower terminals
226
- */
227
- export function createSimpleUI(
228
- screen: blessed.Widgets.Screen,
229
- urls: string[],
230
- greet: string
231
- ): UIElements {
232
- const mainContainer = blessed.box({
233
- parent: screen,
234
- top: 0,
235
- left: 0,
236
- width: "100%",
237
- height: "100%",
238
- padding: { left: 1, right: 1 },
239
- });
240
-
241
- let currentTop = 0;
242
-
243
- // Greet message
244
- if (greet) {
245
- blessed.box({
246
- parent: mainContainer,
247
- top: currentTop,
248
- left: "center",
249
- width: "90%",
250
- height: "shrink",
251
- content: `{bold}${greet}{/bold}`,
252
- tags: true,
253
- align: "center",
254
- style: {
255
- fg: 'green'
256
- }
257
- });
258
-
259
- const lines = Math.ceil(greet.length / ((screen.width as number) * 0.9));
260
- currentTop += Math.max(lines, 1) + 1;
261
- }
262
-
263
- // URLs section
264
- const urlsBox = blessed.box({
265
- parent: mainContainer,
266
- top: currentTop,
267
- left: 0,
268
- width: "100%",
269
- height: urls.length + 2,
270
- tags: true,
271
- });
272
- currentTop += urls.length + 3;
273
-
274
- // Stats section
275
- const statsBox = blessed.box({
276
- parent: mainContainer,
277
- top: currentTop,
278
- left: 0,
279
- width: "100%",
280
- height: 8,
281
- tags: true,
282
- });
283
- currentTop += 9;
284
-
285
-
286
- // Footer
287
- const footerBox = blessed.box({
288
- parent: mainContainer,
289
- bottom: 0,
290
- left: "center",
291
- width: "shrink",
292
- height: 1,
293
- content: "Press Ctrl+C to stop the tunnel.",
294
- tags: true,
295
- style: {
296
- fg: 'white',
297
- }
298
- });
299
-
300
- return {
301
- mainContainer,
302
- urlsBox,
303
- statsBox,
304
- footerBox,
305
- };
306
- }
@@ -1,4 +0,0 @@
1
- export { createFullUI, createSimpleUI, createWarningUI, UIElements, MIN_WIDTH_WARNING, SIMPLE_LAYOUT_THRESHOLD, colorizeGradient } from './UIComponents.js';
2
- export { updateUrlsDisplay, updateStatsDisplay, updateRequestsDisplay, updateQrCodeDisplay } from './DisplayUpdaters.js';
3
- export { showDetailModal, closeDetailModal, showKeyBindingsModal, closeKeyBindingsModal, ModalManager } from './Modals.js';
4
- export { setupKeyBindings, KeyBindingsState, KeyBindingsCallbacks } from './KeyBindings.js';
@@ -1,53 +0,0 @@
1
- /**
2
- * TUI Configuration Settings
3
- */
4
-
5
- export interface TuiConfig {
6
- /**
7
- * Maximum number of request/response pairs to keep in memory.
8
- * Older requests will be removed when this limit is exceeded.
9
- * Default: 100
10
- */
11
- maxRequestPairs: number;
12
-
13
- /**
14
- * Number of visible request items to display in the requests box.
15
- * Default: 10
16
- */
17
- visibleRequestCount: number;
18
-
19
- /**
20
- * Margin from the viewport edge when auto-scrolling to keep selector visible.
21
- * Default: 2
22
- */
23
- viewportScrollMargin: number;
24
-
25
- /**
26
- * Inactivity timeout in milliseconds to auto-unselect the selected row and adjust viewport to latest request.
27
- * Default: 10000 (10 seconds)
28
- */
29
-
30
- inactivityHttpSelectorTimeoutMs?: number;
31
- }
32
-
33
- /**
34
- * Default TUI configuration values
35
- */
36
- export const defaultTuiConfig: TuiConfig = {
37
- maxRequestPairs: 100,
38
- visibleRequestCount: 10,
39
- viewportScrollMargin: 2,
40
- inactivityHttpSelectorTimeoutMs: 10000,
41
- };
42
-
43
- /**
44
- * Get the current TUI configuration.
45
- */
46
- export function getTuiConfig(): TuiConfig {
47
- return {
48
- maxRequestPairs: defaultTuiConfig.maxRequestPairs,
49
- visibleRequestCount:defaultTuiConfig.visibleRequestCount,
50
- viewportScrollMargin: defaultTuiConfig.viewportScrollMargin,
51
- inactivityHttpSelectorTimeoutMs: defaultTuiConfig.inactivityHttpSelectorTimeoutMs,
52
- };
53
- }
@@ -1,42 +0,0 @@
1
- import { logger } from "../../logger.js";
2
-
3
- export interface HeadersResult {
4
- req: string;
5
- res: string;
6
- }
7
-
8
- /**
9
- * Fetch request/response headers from the web debugger
10
- */
11
- export async function fetchReqResHeaders(
12
- baseUrl: string,
13
- key: number,
14
- signal?: AbortSignal
15
- ): Promise<HeadersResult> {
16
- if (!baseUrl) {
17
- return { req: "", res: "" };
18
- }
19
-
20
- try {
21
- const [reqRes, resRes] = await Promise.all([
22
- fetch(`http://${baseUrl}/introspec/getrawrequestheader`, {
23
- headers: { "X-Introspec-Key": key.toString() },
24
- signal,
25
- }),
26
- fetch(`http://${baseUrl}/introspec/getrawresponseheader`, {
27
- headers: { "X-Introspec-Key": key.toString() },
28
- signal,
29
- }),
30
- ]);
31
-
32
- const [req, res] = await Promise.all([reqRes.text(), resRes.text()]);
33
- return { req, res };
34
- } catch (err: any) {
35
- // Re-throw abort errors so caller can handle cancellation
36
- if (err?.name === 'AbortError') {
37
- throw err;
38
- }
39
- logger.error("Error fetching headers:", err.message || err);
40
- throw err;
41
- }
42
- }
@@ -1,2 +0,0 @@
1
- export { TunnelTui, default } from "./TunnelTui.js";
2
-
@@ -1,20 +0,0 @@
1
- import QRCode from "qrcode";
2
-
3
- /**
4
- * Generate QR codes for a list of URLs
5
- */
6
- export async function createQrCodes(urls: string[]): Promise<string[]> {
7
- const codes: string[] = [];
8
-
9
- for (const url of urls) {
10
- const qr = await QRCode.toString(url, {
11
- type: "terminal",
12
- small: true,
13
- margin: 0,
14
- errorCorrectionLevel: "L",
15
-
16
- });
17
- codes.push(qr);
18
- }
19
- return codes;
20
- }
@@ -1,128 +0,0 @@
1
- import WebSocket from "ws";
2
- import { ReqResPair, WebDebuggerSocketRequest } from "../../types.js";
3
- import { logger } from "../../logger.js";
4
- import { getTuiConfig } from "./config.js";
5
-
6
- export interface WebDebuggerConnection {
7
- close: () => void;
8
- }
9
-
10
- /**
11
- * We are using a WebSocket connection to the web debugger endpoint
12
- * to receive real-time HTTP request and response data.
13
- * @param webDebuggerUrl
14
- * @param onUpdate
15
- * @returns
16
- */
17
- export function createWebDebuggerConnection(
18
- webDebuggerUrl: string,
19
- onUpdate: (pairs: ReqResPair[]) => void
20
- ): WebDebuggerConnection {
21
- const pairs = new Map<number, ReqResPair>();
22
- const pairKeys: number[] = [];
23
- let socket: WebSocket | null = null;
24
- let reconnectTimeout: NodeJS.Timeout | null = null;
25
- let isStopped = false;
26
-
27
- const config = getTuiConfig();
28
- const maxPairs = config.maxRequestPairs;
29
-
30
-
31
- // Trim pairs to keep only the latest maxPairs entries
32
- const trimPairs = () => {
33
- while (pairKeys.length > maxPairs) {
34
- const oldestKey = pairKeys.shift();
35
- if (oldestKey !== undefined) {
36
- pairs.delete(oldestKey);
37
- }
38
- }
39
- };
40
-
41
-
42
- // Add or update a pair and track its key for ordering
43
- const upsertPair = (key: number, pair: ReqResPair) => {
44
- if (!pairs.has(key)) {
45
- pairKeys.push(key);
46
- }
47
- pairs.set(key, pair);
48
- trimPairs();
49
- };
50
-
51
- const connect = () => {
52
- const ws = new WebSocket(`ws://${webDebuggerUrl}/introspec/websocket`);
53
- socket = ws;
54
-
55
- ws.on("open", () => {
56
- logger.info("Web debugger connected.");
57
- });
58
-
59
- ws.on("message", (data) => {
60
- try {
61
- const raw = data.toString();
62
- const parsed = JSON.parse(raw);
63
- const msg = {
64
- Req: parsed.req,
65
- Res: parsed.res,
66
- } as Partial<WebDebuggerSocketRequest>;
67
-
68
- if (msg.Req) {
69
- const { key } = msg.Req;
70
- const existing = pairs.get(key) as ReqResPair | undefined;
71
- const merged: ReqResPair = {
72
- request: msg.Req,
73
- response: existing?.response,
74
- } as ReqResPair;
75
- upsertPair(key, merged);
76
- }
77
-
78
- if (msg.Res) {
79
- const { key } = msg.Res;
80
- const existing = pairs.get(key) as ReqResPair | undefined;
81
- const merged: ReqResPair = {
82
- request: existing?.request ?? ({} as any),
83
- response: msg.Res,
84
- } as ReqResPair;
85
- upsertPair(key, merged);
86
- }
87
-
88
- // Notify listener with reversed array (latest first)
89
- const reversedPairs: ReqResPair[] = [];
90
- for (let i = pairKeys.length - 1; i >= 0; i--) {
91
- const key = pairKeys[i];
92
- const pair = pairs.get(key);
93
- if (pair) {
94
- reversedPairs.push(pair);
95
- }
96
- }
97
- onUpdate(reversedPairs);
98
- } catch (err: any) {
99
- logger.error("Error parsing WebSocket message:", err.message || err);
100
- }
101
- });
102
-
103
- ws.on("close", () => {
104
- logger.warn("Web debugger disconnected. Reconnecting in 5s...");
105
- if (!isStopped) {
106
- reconnectTimeout = setTimeout(connect, 5000);
107
- }
108
- });
109
-
110
- ws.on("error", (err) => {
111
- logger.error(`WebSocket error: ${err.message}`);
112
- });
113
- };
114
-
115
- connect();
116
-
117
- return {
118
- close: () => {
119
- isStopped = true;
120
- if (socket) {
121
- socket.close();
122
- }
123
- if (reconnectTimeout) {
124
- clearTimeout(reconnectTimeout);
125
- }
126
- },
127
- };
128
- }
@@ -1,7 +0,0 @@
1
- export const asciiArtPinggyLogo = `
2
- ██████╗ ██╗███╗ ██╗ ██████╗ ██████╗██╗ ██╗
3
- ██╔══██╗██║████╗ ██║██╔════╝ ██╔════╝╚██╗ ██╔╝
4
- ██████╔╝██║██╔██╗ ██║██║ ███╗██║ ███╗╚████╔╝
5
- ██╔═══╝ ██║██║╚██╗██║██║ ██║██║ ██║ ╚██╔╝
6
- ██║ ██║██║ ╚████║╚██████╔╝╚██████╔╝ ██║
7
- ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═╝ `;
@@ -1,27 +0,0 @@
1
- import { useEffect, useState } from "react";
2
- import qrcode from "qrcode-terminal";
3
-
4
- export function useQrCodes(urls: string[], isQrCodeRequested: boolean) {
5
- const [qrCodes, setQrCodes] = useState<string[]>([]);
6
-
7
- useEffect(() => {
8
- if (!isQrCodeRequested || urls.length === 0) return;
9
-
10
- const generateAll = async () => {
11
- const codes: string[] = [];
12
- for (const url of urls) {
13
- await new Promise<void>((resolve) => {
14
- qrcode.generate(url, { small: true }, (qr) => {
15
- codes.push(qr);
16
- resolve();
17
- });
18
- });
19
- }
20
- setQrCodes(codes);
21
- };
22
-
23
- generateAll();
24
- }, [urls, isQrCodeRequested]);
25
-
26
- return qrCodes;
27
- }
@@ -1,27 +0,0 @@
1
- import { useState } from "react";
2
- import { logger } from "../../../logger.js";
3
-
4
- export function useReqResHeaders(baseUrl?: string) {
5
- const [headers, setHeaders] = useState<{ req: string; res: string } | null>(null);
6
-
7
- async function fetchHeaders(key: number) {
8
- if (!baseUrl) return;
9
- try {
10
- const [reqRes, resRes] = await Promise.all([
11
- fetch(`http://${baseUrl}/introspec/getrawrequestheader`, {
12
- headers: { "X-Introspec-Key": key.toString() },
13
- }),
14
- fetch(`http://${baseUrl}/introspec/getrawresponseheader`, {
15
- headers: { "X-Introspec-Key": key.toString() },
16
- }),
17
- ]);
18
-
19
- const [req, res] = await Promise.all([reqRes.text(), resRes.text()]);
20
- setHeaders({ req, res });
21
- } catch (err: any) {
22
- logger.error("Error fetching headers:", err.message || err);
23
- }
24
- }
25
-
26
- return { headers, fetchHeaders, clear: () => setHeaders(null) };
27
- }
@@ -1,26 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
-
3
- const TERMINAL_PADDING_X = 1;
4
-
5
- export function useTerminalSize(): { columns: number; rows: number } {
6
- const [size, setSize] = useState({
7
- columns: (process.stdout.columns || 60) - TERMINAL_PADDING_X,
8
- rows: process.stdout.rows || 20,
9
- });
10
-
11
- useEffect(() => {
12
- function updateSize() {
13
- setSize({
14
- columns: (process.stdout.columns || 60) - TERMINAL_PADDING_X,
15
- rows: process.stdout.rows || 20,
16
- });
17
- }
18
-
19
- process.stdout.on('resize', updateSize);
20
- return () => {
21
- process.stdout.off('resize', updateSize);
22
- };
23
- }, []);
24
-
25
- return size;
26
- }
@@ -1,24 +0,0 @@
1
- import { useEffect, useState } from "react";
2
- import { TunnelUsageType } from "@pinggy/pinggy";
3
-
4
- export function useTunnelStats() {
5
- const [stats, setStats] = useState<TunnelUsageType>({
6
- elapsedTime: 0,
7
- numLiveConnections: 0,
8
- numTotalConnections: 0,
9
- numTotalReqBytes: 0,
10
- numTotalResBytes: 0,
11
- numTotalTxBytes: 0,
12
- });
13
-
14
- useEffect(() => {
15
- globalThis.__PINGGY_TUNNEL_STATS__ = (newStats: TunnelUsageType) => {
16
- setStats({ ...newStats });
17
- };
18
- return () => {
19
- delete globalThis.__PINGGY_TUNNEL_STATS__;
20
- };
21
- }, []);
22
-
23
- return stats;
24
- }