pinggy 0.3.5 → 0.3.7

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 +1798 -1349
  4. package/dist/index.d.cts +616 -0
  5. package/dist/index.d.ts +616 -0
  6. package/dist/index.js +24 -2
  7. package/dist/{main-K44C44NW.js → main-2QDG7PWL.js} +166 -1705
  8. package/package.json +2 -3
  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 -535
  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 -31
  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 -111
  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,236 +0,0 @@
1
- import blessed from "blessed";
2
- import { ReqResPair, FinalConfig } from "../../../types.js";
3
- import { ManagedTunnel, TunnelManager } from "../../../tunnel_manager/TunnelManager.js";
4
- import { fetchReqResHeaders } from "../headerFetcher.js";
5
- import { logger } from "../../../logger.js";
6
- import { ModalManager, showDetailModal, closeDetailModal, showKeyBindingsModal, closeKeyBindingsModal, showLoadingModal, closeLoadingModal, showErrorModal } from "./Modals.js";
7
- import { getTuiConfig } from "../config.js";
8
-
9
- export interface KeyBindingsState {
10
- currentQrIndex: number;
11
- selectedIndex: number;
12
- pairs: ReqResPair[];
13
- urls: string[];
14
- }
15
-
16
- export interface KeyBindingsCallbacks {
17
- onQrIndexChange: (index: number) => void;
18
- onSelectedIndexChange: (index: number, requestKey: number | null) => void;
19
- onDestroy: () => void;
20
- updateUrlsDisplay: () => void;
21
- updateQrCodeDisplay: () => void;
22
- updateRequestsDisplay: () => void;
23
- }
24
-
25
- /**
26
- * Sets up all key bindings for the TUI
27
- */
28
- export function setupKeyBindings(
29
- screen: blessed.Widgets.Screen,
30
- modalManager: ModalManager,
31
- state: KeyBindingsState,
32
- callbacks: KeyBindingsCallbacks,
33
- tunnelConfig?: FinalConfig,
34
- ): void {
35
- let inactivityTimeout: NodeJS.Timeout | null = null;
36
- const { inactivityHttpSelectorTimeoutMs } = getTuiConfig();
37
- const INACTIVITY_TIMEOUT_MS = inactivityHttpSelectorTimeoutMs;
38
-
39
- // Function to reset inactivity timer
40
- const resetInactivityTimer = () => {
41
- if (inactivityTimeout) {
42
- clearTimeout(inactivityTimeout);
43
- }
44
- // Only start timer if there's a selection
45
- if (state.selectedIndex !== -1) {
46
- inactivityTimeout = setTimeout(() => {
47
- // Clear selection and reset viewport to top
48
- callbacks.onSelectedIndexChange(-1, null);
49
- callbacks.updateRequestsDisplay();
50
- }, INACTIVITY_TIMEOUT_MS);
51
- }
52
- };
53
-
54
- // Exit on Ctrl+C
55
- screen.key(["C-c"], () => {
56
- callbacks.onDestroy();
57
- process.exit(0);
58
- });
59
-
60
- // Escape key
61
- screen.key(["escape"], () => {
62
- // Close loading modal and cancel fetch request
63
- if (modalManager.loadingView) {
64
- if (modalManager.fetchAbortController) {
65
- modalManager.fetchAbortController.abort();
66
- modalManager.fetchAbortController = null;
67
- }
68
- closeLoadingModal(screen, modalManager);
69
- return;
70
- }
71
- if (modalManager.inDetailView) {
72
- closeDetailModal(screen, modalManager);
73
- return;
74
- }
75
- if (modalManager.keyBindingView) {
76
- closeKeyBindingsModal(screen, modalManager);
77
- return;
78
- }
79
- // Clear selection and reset viewport to top
80
- if (state.selectedIndex !== -1) {
81
- if (inactivityTimeout) {
82
- clearTimeout(inactivityTimeout);
83
- inactivityTimeout = null;
84
- }
85
- callbacks.onSelectedIndexChange(-1, null);
86
- callbacks.updateRequestsDisplay();
87
- }
88
- });
89
-
90
- // Navigation - Up
91
- screen.key(["up"], () => {
92
- if (modalManager.inDetailView || modalManager.keyBindingView || modalManager.loadingView) return;
93
- resetInactivityTimer();
94
- if (state.selectedIndex === -1) {
95
- // No selection: select first item (latest request)
96
- const requestKey = state.pairs[0]?.request?.key ?? null;
97
- callbacks.onSelectedIndexChange(0, requestKey);
98
- callbacks.updateRequestsDisplay();
99
- resetInactivityTimer(); // Start timer after selection
100
- } else if (state.selectedIndex > 0) {
101
- const newIndex = state.selectedIndex - 1;
102
- const requestKey = state.pairs[newIndex]?.request?.key ?? null;
103
- callbacks.onSelectedIndexChange(newIndex, requestKey);
104
- callbacks.updateRequestsDisplay();
105
- }
106
- });
107
-
108
- // Navigation - Down
109
- screen.key(["down"], () => {
110
- if (modalManager.inDetailView || modalManager.keyBindingView || modalManager.loadingView) return;
111
- resetInactivityTimer();
112
- const config = getTuiConfig();
113
- // Limit to maxRequestPairs for navigation bounds
114
- const limitedLength = Math.min(state.pairs.length, config.maxRequestPairs);
115
- if (state.selectedIndex === -1) {
116
- // No selection: select first item (latest request)
117
- if (limitedLength > 0) {
118
- const requestKey = state.pairs[0]?.request?.key ?? null;
119
- callbacks.onSelectedIndexChange(0, requestKey);
120
- callbacks.updateRequestsDisplay();
121
- resetInactivityTimer(); // Start timer after selection
122
- }
123
- } else if (state.selectedIndex < limitedLength - 1) {
124
- const newIndex = state.selectedIndex + 1;
125
- const requestKey = state.pairs[newIndex]?.request?.key ?? null;
126
- callbacks.onSelectedIndexChange(newIndex, requestKey);
127
- callbacks.updateRequestsDisplay();
128
- }
129
- });
130
-
131
- // End - Jump to last item
132
- screen.key(["end"], () => {
133
- if (modalManager.inDetailView || modalManager.keyBindingView || modalManager.loadingView) return;
134
- resetInactivityTimer();
135
- const config = getTuiConfig();
136
- const limitedLength = Math.min(state.pairs.length, config.maxRequestPairs);
137
- const lastIndex = Math.max(0, limitedLength - 1);
138
- if (state.selectedIndex !== lastIndex) {
139
- const requestKey = state.pairs[lastIndex]?.request?.key ?? null;
140
- callbacks.onSelectedIndexChange(lastIndex, requestKey);
141
- callbacks.updateRequestsDisplay();
142
- }
143
- });
144
-
145
- // Enter to view details
146
- screen.key(["enter"], async () => {
147
- if (modalManager.inDetailView || modalManager.keyBindingView || modalManager.loadingView) return;
148
- // Only work when there's a selection
149
- if (state.selectedIndex === -1) return;
150
-
151
- resetInactivityTimer();
152
- const pair = state.pairs[state.selectedIndex];
153
- if (pair?.request?.key !== undefined && pair?.request?.key !== null) {
154
- // Create AbortController for this fetch request
155
- const abortController = new AbortController();
156
- modalManager.fetchAbortController = abortController;
157
-
158
- showLoadingModal(screen, modalManager, "Fetching request details...");
159
-
160
- try {
161
- const headers = await fetchReqResHeaders(
162
- tunnelConfig?.webDebugger || "",
163
- pair.request.key,
164
- abortController.signal
165
- );
166
-
167
- // Check if request was aborted
168
- if (abortController.signal.aborted) {
169
- return;
170
- }
171
-
172
- // Close loading and show details
173
- closeLoadingModal(screen, modalManager);
174
- modalManager.fetchAbortController = null;
175
- showDetailModal(screen, modalManager, headers.req, headers.res);
176
- } catch (err: any) {
177
- // Don't show error if request was cancelled by user
178
- if (err?.name === 'AbortError' || abortController.signal.aborted) {
179
- logger.info("Fetch request cancelled by user");
180
- return;
181
- }
182
-
183
- // Close loading and show error modal
184
- closeLoadingModal(screen, modalManager);
185
- modalManager.fetchAbortController = null;
186
-
187
- const errorMessage = err?.message || String(err) || "Unknown error occurred";
188
- logger.error("Fetch error:", err);
189
- showErrorModal(screen, modalManager, "Failed to fetch request details", errorMessage);
190
- }
191
- }
192
- });
193
-
194
- // Help toggle
195
- screen.key(["h"], () => {
196
- if (modalManager.inDetailView || modalManager.loadingView) return;
197
- if (modalManager.keyBindingView) {
198
- closeKeyBindingsModal(screen, modalManager);
199
- } else {
200
- showKeyBindingsModal(screen, modalManager);
201
- }
202
- });
203
-
204
- // Copy URL
205
- screen.key(["c"], async () => {
206
- if (modalManager.inDetailView || modalManager.keyBindingView || modalManager.loadingView) return;
207
- if (state.urls.length > 0) {
208
- try {
209
- const clipboardy = await import("clipboardy");
210
- clipboardy.default.writeSync(state.urls[state.currentQrIndex]);
211
- } catch (err) {
212
- logger.error("Failed to copy to clipboard:", err);
213
- }
214
- }
215
- });
216
-
217
- // QR code navigation - Left
218
- screen.key(["left"], () => {
219
- if (modalManager.inDetailView || modalManager.keyBindingView || modalManager.loadingView) return;
220
- if (state.currentQrIndex > 0) {
221
- callbacks.onQrIndexChange(state.currentQrIndex - 1);
222
- callbacks.updateUrlsDisplay();
223
- callbacks.updateQrCodeDisplay();
224
- }
225
- });
226
-
227
- // QR code navigation - Right
228
- screen.key(["right"], () => {
229
- if (modalManager.inDetailView || modalManager.keyBindingView || modalManager.loadingView) return;
230
- if (state.currentQrIndex < state.urls.length - 1) {
231
- callbacks.onQrIndexChange(state.currentQrIndex + 1);
232
- callbacks.updateUrlsDisplay();
233
- callbacks.updateQrCodeDisplay();
234
- }
235
- });
236
- }
@@ -1,302 +0,0 @@
1
- import blessed from "blessed";
2
-
3
- export interface ModalManager {
4
- detailModal: blessed.Widgets.BoxElement | null;
5
- keyBindingsModal: blessed.Widgets.BoxElement | null;
6
- disconnectModal: blessed.Widgets.BoxElement | null;
7
- inDetailView: boolean;
8
- keyBindingView: boolean;
9
- inDisconnectView: boolean;
10
- loadingBox: blessed.Widgets.BoxElement | null;
11
- loadingView: boolean;
12
- fetchAbortController: AbortController | null;
13
- }
14
-
15
- /**
16
- * Shows the detail modal with request/response data
17
- */
18
- export function showDetailModal(
19
- screen: blessed.Widgets.Screen,
20
- manager: ModalManager,
21
- requestText?: string,
22
- responseText?: string
23
- ): void {
24
- manager.inDetailView = true;
25
-
26
- manager.detailModal = blessed.box({
27
- parent: screen,
28
- top: "center",
29
- left: "center",
30
- width: "90%",
31
- height: "90%",
32
- border: {
33
- type: "line",
34
- },
35
- style: {
36
- border: {
37
- fg: "green",
38
- },
39
- },
40
- padding: { left: 2, right: 2, top: 1, bottom: 1 },
41
- tags: true,
42
- scrollable: true,
43
- keys: true,
44
- vi: true,
45
- alwaysScroll: true,
46
- scrollbar: {
47
- ch: " ",
48
- track: {
49
- bg: "cyan",
50
- },
51
- style: {
52
- inverse: true,
53
- },
54
- },
55
- });
56
-
57
- const content = `{cyan-fg}{bold}Request{/bold}{/cyan-fg}
58
- ${requestText || "(no request data)"}
59
-
60
- {magenta-fg}{bold}Response{/bold}{/magenta-fg}
61
- ${responseText || "(no response data)"}
62
-
63
- {white-bg}{black-fg}Press ESC to close{/black-fg}{/white-bg}`;
64
-
65
- manager.detailModal.setContent(content);
66
- manager.detailModal.focus();
67
- screen.render();
68
- }
69
-
70
- /**
71
- * Closes the detail modal
72
- */
73
- export function closeDetailModal(
74
- screen: blessed.Widgets.Screen,
75
- manager: ModalManager
76
- ): void {
77
- if (manager.detailModal) {
78
- manager.detailModal.destroy();
79
- manager.detailModal = null;
80
- }
81
- manager.inDetailView = false;
82
- screen.render();
83
- }
84
-
85
- /**
86
- * Shows the key bindings modal
87
- */
88
- export function showKeyBindingsModal(
89
- screen: blessed.Widgets.Screen,
90
- manager: ModalManager
91
- ): void {
92
- manager.keyBindingView = true;
93
-
94
- manager.keyBindingsModal = blessed.box({
95
- parent: screen,
96
- top: "center",
97
- left: "center",
98
- width: "60%",
99
- height: "80%",
100
- border: {
101
- type: "line",
102
- },
103
- style: {
104
- border: {
105
- fg: "green",
106
- },
107
- },
108
- padding: { left: 2, right: 2, top: 1, bottom: 1 },
109
- tags: true,
110
- });
111
-
112
- const content = `{cyan-fg}{bold}Key Bindings{/bold}{/cyan-fg}
113
-
114
- {bold}h{/bold} This page
115
- {bold}c{/bold} Copy the selected URL to clipboard
116
- {bold}Ctrl+c{/bold} Exit
117
-
118
- Enter/Return Open selected request
119
- Esc Return to main page (or close modals)
120
- UP (↑) Scroll up the requests
121
- Down (↓) Scroll down the requests
122
- Left (←) Show qr code for previous url
123
- Right (→) Show qr code for next url
124
- Home Jump to top of requests
125
- End Jump to bottom of requests
126
- Ctrl+c Force Exit
127
-
128
- {white-bg}{black-fg}Press ESC to close{/black-fg}{/white-bg}`;
129
-
130
- manager.keyBindingsModal.setContent(content);
131
- manager.keyBindingsModal.focus();
132
- screen.render();
133
- }
134
-
135
- /**
136
- * Closes the key bindings modal
137
- */
138
- export function closeKeyBindingsModal(
139
- screen: blessed.Widgets.Screen,
140
- manager: ModalManager
141
- ): void {
142
- if (manager.keyBindingsModal) {
143
- manager.keyBindingsModal.destroy();
144
- manager.keyBindingsModal = null;
145
- }
146
- manager.keyBindingView = false;
147
- screen.render();
148
- }
149
-
150
- /**
151
- * Shows the disconnect modal
152
- */
153
- export function showDisconnectModal(
154
- screen: blessed.Widgets.Screen,
155
- manager: ModalManager,
156
- message?: string,
157
- onClose?: () => void
158
- ): void {
159
- manager.inDisconnectView = true;
160
-
161
- manager.disconnectModal = blessed.box({
162
- parent: screen,
163
- top: "center",
164
- left: "center",
165
- width: "50%",
166
- height: "20%",
167
- border: {
168
- type: "line",
169
- },
170
- style: {
171
- border: {
172
- fg: "red",
173
- },
174
- },
175
- padding: { left: 2, right: 2, top: 1, bottom: 1 },
176
- tags: true,
177
- align: "center",
178
- valign: "middle",
179
- });
180
-
181
- const content = `{red-fg}{bold}Tunnel Disconnected{/bold}{/red-fg}
182
-
183
- ${message || "Disconnect request received. Tunnel will be closed."}
184
-
185
- {white-bg}{black-fg}Closing in 3 seconds... {/black-fg}{/white-bg}`;
186
-
187
- manager.disconnectModal.setContent(content);
188
- manager.disconnectModal.focus();
189
- screen.render();
190
-
191
- // Auto-close after 5 seconds
192
- const timeout = setTimeout(() => {
193
- closeDisconnectModal(screen, manager);
194
- if (onClose) onClose();
195
- }, 5000);
196
-
197
- // Allow manual close with any key
198
- const keyHandler = () => {
199
- clearTimeout(timeout);
200
- closeDisconnectModal(screen, manager);
201
- if (onClose) onClose();
202
- };
203
-
204
- manager.disconnectModal.key(['escape', 'enter', 'space'], keyHandler);
205
- screen.key(['escape', 'enter', 'space'], keyHandler);
206
- }
207
-
208
- /**
209
- * Closes the disconnect modal
210
- */
211
- export function closeDisconnectModal(
212
- screen: blessed.Widgets.Screen,
213
- manager: ModalManager
214
- ): void {
215
- if (manager.disconnectModal) {
216
- manager.disconnectModal.destroy();
217
- manager.disconnectModal = null;
218
- }
219
- manager.inDisconnectView = false;
220
- screen.render();
221
- }
222
-
223
- export function showLoadingModal(
224
- screen: blessed.Widgets.Screen,
225
- modalManager: ModalManager,
226
- message: string = "Loading..."
227
- ): void {
228
- if (modalManager.loadingView) return;
229
-
230
- modalManager.loadingBox = blessed.box({
231
- parent: screen,
232
- top: "center",
233
- left: "center",
234
- width: "60%",
235
- height: 8,
236
- border: { type: "line" },
237
- style: {
238
- border: { fg: "yellow" },
239
- },
240
- tags: true,
241
- content: `{center}{yellow-fg}{bold}${message}{/bold}{/yellow-fg}
242
-
243
- {gray-fg}Press ESC to cancel{/gray-fg}{/center}`,
244
- valign: "middle",
245
- });
246
-
247
- modalManager.loadingView = true;
248
- screen.render();
249
- }
250
-
251
- /**
252
- * Closes the loading modal
253
- */
254
- export function closeLoadingModal(
255
- screen: blessed.Widgets.Screen,
256
- modalManager: ModalManager
257
- ): void {
258
- if (!modalManager.loadingView || !modalManager.loadingBox) return;
259
-
260
- modalManager.loadingBox.destroy();
261
- modalManager.loadingBox = null;
262
- modalManager.loadingView = false;
263
- screen.render();
264
- }
265
-
266
- /**
267
- * Shows an error modal with a message
268
- */
269
- export function showErrorModal(
270
- screen: blessed.Widgets.Screen,
271
- modalManager: ModalManager,
272
- title: string = "Error",
273
- message: string
274
- ): void {
275
- // Reuse the loading box for error display
276
- if (modalManager.loadingBox) {
277
- modalManager.loadingBox.destroy();
278
- modalManager.loadingBox = null;
279
- }
280
-
281
- modalManager.loadingBox = blessed.box({
282
- parent: screen,
283
- top: "center",
284
- left: "center",
285
- width: "60%",
286
- height: 9,
287
- border: { type: "line" },
288
- style: {
289
- border: { fg: "red" },
290
- },
291
- tags: true,
292
- content: `{center}{red-fg}{bold}${title}{/bold}{/red-fg}
293
-
294
- {white-fg}${message}{/white-fg}
295
-
296
- {gray-fg}Press ESC to close{/gray-fg}{/center}`,
297
- valign: "middle",
298
- });
299
-
300
- modalManager.loadingView = true;
301
- screen.render();
302
- }