htpx-cli 0.1.2 → 0.2.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.
Files changed (252) hide show
  1. package/LICENSE +665 -21
  2. package/README.md +422 -116
  3. package/dist/cli/commands/clear.d.ts.map +1 -1
  4. package/dist/cli/commands/clear.js +11 -11
  5. package/dist/cli/commands/clear.js.map +1 -1
  6. package/dist/cli/commands/daemon.d.ts +3 -0
  7. package/dist/cli/commands/daemon.d.ts.map +1 -0
  8. package/dist/cli/commands/daemon.js +59 -0
  9. package/dist/cli/commands/daemon.js.map +1 -0
  10. package/dist/cli/commands/debug-dump.d.ts.map +1 -1
  11. package/dist/cli/commands/debug-dump.js +8 -10
  12. package/dist/cli/commands/debug-dump.js.map +1 -1
  13. package/dist/cli/commands/helpers.d.ts +18 -0
  14. package/dist/cli/commands/helpers.d.ts.map +1 -0
  15. package/dist/cli/commands/helpers.js +34 -0
  16. package/dist/cli/commands/helpers.js.map +1 -0
  17. package/dist/cli/commands/init.d.ts +1 -1
  18. package/dist/cli/commands/init.d.ts.map +1 -1
  19. package/dist/cli/commands/init.js +3 -4
  20. package/dist/cli/commands/init.js.map +1 -1
  21. package/dist/cli/commands/intercept.d.ts +2 -1
  22. package/dist/cli/commands/intercept.d.ts.map +1 -1
  23. package/dist/cli/commands/intercept.js +74 -30
  24. package/dist/cli/commands/intercept.js.map +1 -1
  25. package/dist/cli/commands/interceptors.d.ts +3 -0
  26. package/dist/cli/commands/interceptors.d.ts.map +1 -0
  27. package/dist/cli/commands/interceptors.js +163 -0
  28. package/dist/cli/commands/interceptors.js.map +1 -0
  29. package/dist/cli/commands/mcp.d.ts +3 -0
  30. package/dist/cli/commands/mcp.d.ts.map +1 -0
  31. package/dist/cli/commands/mcp.js +24 -0
  32. package/dist/cli/commands/mcp.js.map +1 -0
  33. package/dist/cli/commands/off.d.ts +8 -0
  34. package/dist/cli/commands/off.d.ts.map +1 -0
  35. package/dist/cli/commands/off.js +34 -0
  36. package/dist/cli/commands/off.js.map +1 -0
  37. package/dist/cli/commands/on.d.ts +9 -0
  38. package/dist/cli/commands/on.d.ts.map +1 -0
  39. package/dist/cli/commands/on.js +121 -0
  40. package/dist/cli/commands/on.js.map +1 -0
  41. package/dist/cli/commands/project.d.ts.map +1 -1
  42. package/dist/cli/commands/project.js +5 -3
  43. package/dist/cli/commands/project.js.map +1 -1
  44. package/dist/cli/commands/restart.d.ts.map +1 -1
  45. package/dist/cli/commands/restart.js +5 -10
  46. package/dist/cli/commands/restart.js.map +1 -1
  47. package/dist/cli/commands/status.d.ts.map +1 -1
  48. package/dist/cli/commands/status.js +50 -20
  49. package/dist/cli/commands/status.js.map +1 -1
  50. package/dist/cli/commands/stop.d.ts.map +1 -1
  51. package/dist/cli/commands/stop.js +7 -10
  52. package/dist/cli/commands/stop.js.map +1 -1
  53. package/dist/cli/commands/tui.d.ts.map +1 -1
  54. package/dist/cli/commands/tui.js +6 -13
  55. package/dist/cli/commands/tui.js.map +1 -1
  56. package/dist/cli/index.js +12 -7
  57. package/dist/cli/index.js.map +1 -1
  58. package/dist/cli/tui/App.d.ts +7 -2
  59. package/dist/cli/tui/App.d.ts.map +1 -1
  60. package/dist/cli/tui/App.js +490 -33
  61. package/dist/cli/tui/App.js.map +1 -1
  62. package/dist/cli/tui/components/AccordionContent.d.ts +28 -0
  63. package/dist/cli/tui/components/AccordionContent.d.ts.map +1 -0
  64. package/dist/cli/tui/components/AccordionContent.js +87 -0
  65. package/dist/cli/tui/components/AccordionContent.js.map +1 -0
  66. package/dist/cli/tui/components/AccordionPanel.d.ts +38 -0
  67. package/dist/cli/tui/components/AccordionPanel.d.ts.map +1 -0
  68. package/dist/cli/tui/components/AccordionPanel.js +110 -0
  69. package/dist/cli/tui/components/AccordionPanel.js.map +1 -0
  70. package/dist/cli/tui/components/AccordionSection.d.ts +32 -0
  71. package/dist/cli/tui/components/AccordionSection.d.ts.map +1 -0
  72. package/dist/cli/tui/components/AccordionSection.js +41 -0
  73. package/dist/cli/tui/components/AccordionSection.js.map +1 -0
  74. package/dist/cli/tui/components/ExportModal.d.ts +34 -0
  75. package/dist/cli/tui/components/ExportModal.d.ts.map +1 -0
  76. package/dist/cli/tui/components/ExportModal.js +109 -0
  77. package/dist/cli/tui/components/ExportModal.js.map +1 -0
  78. package/dist/cli/tui/components/FilterBar.d.ts +21 -0
  79. package/dist/cli/tui/components/FilterBar.d.ts.map +1 -0
  80. package/dist/cli/tui/components/FilterBar.js +155 -0
  81. package/dist/cli/tui/components/FilterBar.js.map +1 -0
  82. package/dist/cli/tui/components/HelpModal.d.ts +13 -0
  83. package/dist/cli/tui/components/HelpModal.d.ts.map +1 -0
  84. package/dist/cli/tui/components/HelpModal.js +78 -0
  85. package/dist/cli/tui/components/HelpModal.js.map +1 -0
  86. package/dist/cli/tui/components/HintContent.d.ts +25 -0
  87. package/dist/cli/tui/components/HintContent.d.ts.map +1 -0
  88. package/dist/cli/tui/components/HintContent.js +44 -0
  89. package/dist/cli/tui/components/HintContent.js.map +1 -0
  90. package/dist/cli/tui/components/InfoModal.d.ts +15 -0
  91. package/dist/cli/tui/components/InfoModal.d.ts.map +1 -0
  92. package/dist/cli/tui/components/InfoModal.js +17 -0
  93. package/dist/cli/tui/components/InfoModal.js.map +1 -0
  94. package/dist/cli/tui/components/JsonExplorerModal.d.ts +24 -0
  95. package/dist/cli/tui/components/JsonExplorerModal.d.ts.map +1 -0
  96. package/dist/cli/tui/components/JsonExplorerModal.js +311 -0
  97. package/dist/cli/tui/components/JsonExplorerModal.js.map +1 -0
  98. package/dist/cli/tui/components/Modal.d.ts +26 -0
  99. package/dist/cli/tui/components/Modal.d.ts.map +1 -0
  100. package/dist/cli/tui/components/Modal.js +15 -0
  101. package/dist/cli/tui/components/Modal.js.map +1 -0
  102. package/dist/cli/tui/components/Panel.d.ts +19 -0
  103. package/dist/cli/tui/components/Panel.d.ts.map +1 -0
  104. package/dist/cli/tui/components/Panel.js +37 -0
  105. package/dist/cli/tui/components/Panel.js.map +1 -0
  106. package/dist/cli/tui/components/RequestDetails.d.ts +4 -1
  107. package/dist/cli/tui/components/RequestDetails.d.ts.map +1 -1
  108. package/dist/cli/tui/components/RequestDetails.js +9 -5
  109. package/dist/cli/tui/components/RequestDetails.js.map +1 -1
  110. package/dist/cli/tui/components/RequestList.d.ts +9 -3
  111. package/dist/cli/tui/components/RequestList.d.ts.map +1 -1
  112. package/dist/cli/tui/components/RequestList.js +24 -11
  113. package/dist/cli/tui/components/RequestList.js.map +1 -1
  114. package/dist/cli/tui/components/RequestListItem.d.ts +26 -3
  115. package/dist/cli/tui/components/RequestListItem.d.ts.map +1 -1
  116. package/dist/cli/tui/components/RequestListItem.js +86 -9
  117. package/dist/cli/tui/components/RequestListItem.js.map +1 -1
  118. package/dist/cli/tui/components/SaveModal.d.ts +30 -0
  119. package/dist/cli/tui/components/SaveModal.d.ts.map +1 -0
  120. package/dist/cli/tui/components/SaveModal.js +95 -0
  121. package/dist/cli/tui/components/SaveModal.js.map +1 -0
  122. package/dist/cli/tui/components/StatusBar.d.ts +31 -2
  123. package/dist/cli/tui/components/StatusBar.d.ts.map +1 -1
  124. package/dist/cli/tui/components/StatusBar.js +44 -9
  125. package/dist/cli/tui/components/StatusBar.js.map +1 -1
  126. package/dist/cli/tui/components/TextViewerModal.d.ts +19 -0
  127. package/dist/cli/tui/components/TextViewerModal.d.ts.map +1 -0
  128. package/dist/cli/tui/components/TextViewerModal.js +227 -0
  129. package/dist/cli/tui/components/TextViewerModal.js.map +1 -0
  130. package/dist/cli/tui/hooks/useBodyExport.d.ts +26 -0
  131. package/dist/cli/tui/hooks/useBodyExport.d.ts.map +1 -0
  132. package/dist/cli/tui/hooks/useBodyExport.js +173 -0
  133. package/dist/cli/tui/hooks/useBodyExport.js.map +1 -0
  134. package/dist/cli/tui/hooks/useExport.d.ts +13 -2
  135. package/dist/cli/tui/hooks/useExport.d.ts.map +1 -1
  136. package/dist/cli/tui/hooks/useExport.js +46 -40
  137. package/dist/cli/tui/hooks/useExport.js.map +1 -1
  138. package/dist/cli/tui/hooks/useRequests.d.ts +9 -3
  139. package/dist/cli/tui/hooks/useRequests.d.ts.map +1 -1
  140. package/dist/cli/tui/hooks/useRequests.js +61 -15
  141. package/dist/cli/tui/hooks/useRequests.js.map +1 -1
  142. package/dist/cli/tui/hooks/useSaveBinary.d.ts +26 -0
  143. package/dist/cli/tui/hooks/useSaveBinary.d.ts.map +1 -0
  144. package/dist/cli/tui/hooks/useSaveBinary.js +165 -0
  145. package/dist/cli/tui/hooks/useSaveBinary.js.map +1 -0
  146. package/dist/cli/tui/hooks/useSpinner.d.ts +5 -0
  147. package/dist/cli/tui/hooks/useSpinner.d.ts.map +1 -0
  148. package/dist/cli/tui/hooks/useSpinner.js +25 -0
  149. package/dist/cli/tui/hooks/useSpinner.js.map +1 -0
  150. package/dist/cli/tui/utils/binary.d.ts +24 -0
  151. package/dist/cli/tui/utils/binary.d.ts.map +1 -0
  152. package/dist/cli/tui/utils/binary.js +152 -0
  153. package/dist/cli/tui/utils/binary.js.map +1 -0
  154. package/dist/cli/tui/utils/clipboard.d.ts +9 -0
  155. package/dist/cli/tui/utils/clipboard.d.ts.map +1 -0
  156. package/dist/cli/tui/utils/clipboard.js +58 -0
  157. package/dist/cli/tui/utils/clipboard.js.map +1 -0
  158. package/dist/cli/tui/utils/content-type.d.ts +8 -0
  159. package/dist/cli/tui/utils/content-type.d.ts.map +1 -0
  160. package/dist/cli/tui/utils/content-type.js +10 -0
  161. package/dist/cli/tui/utils/content-type.js.map +1 -0
  162. package/dist/cli/tui/utils/curl.d.ts.map +1 -1
  163. package/dist/cli/tui/utils/curl.js +9 -2
  164. package/dist/cli/tui/utils/curl.js.map +1 -1
  165. package/dist/cli/tui/utils/filters.d.ts +6 -0
  166. package/dist/cli/tui/utils/filters.d.ts.map +1 -0
  167. package/dist/cli/tui/utils/filters.js +13 -0
  168. package/dist/cli/tui/utils/filters.js.map +1 -0
  169. package/dist/cli/tui/utils/formatters.d.ts +8 -0
  170. package/dist/cli/tui/utils/formatters.d.ts.map +1 -1
  171. package/dist/cli/tui/utils/formatters.js +85 -0
  172. package/dist/cli/tui/utils/formatters.js.map +1 -1
  173. package/dist/cli/tui/utils/har.d.ts.map +1 -1
  174. package/dist/cli/tui/utils/har.js +3 -25
  175. package/dist/cli/tui/utils/har.js.map +1 -1
  176. package/dist/cli/tui/utils/json-tree.d.ts +69 -0
  177. package/dist/cli/tui/utils/json-tree.d.ts.map +1 -0
  178. package/dist/cli/tui/utils/json-tree.js +339 -0
  179. package/dist/cli/tui/utils/json-tree.js.map +1 -0
  180. package/dist/cli/tui/utils/open-external.d.ts +17 -0
  181. package/dist/cli/tui/utils/open-external.d.ts.map +1 -0
  182. package/dist/cli/tui/utils/open-external.js +57 -0
  183. package/dist/cli/tui/utils/open-external.js.map +1 -0
  184. package/dist/cli/tui/utils/syntax-highlight.d.ts +16 -0
  185. package/dist/cli/tui/utils/syntax-highlight.d.ts.map +1 -0
  186. package/dist/cli/tui/utils/syntax-highlight.js +64 -0
  187. package/dist/cli/tui/utils/syntax-highlight.js.map +1 -0
  188. package/dist/daemon/control.d.ts +3 -49
  189. package/dist/daemon/control.d.ts.map +1 -1
  190. package/dist/daemon/control.js +183 -141
  191. package/dist/daemon/control.js.map +1 -1
  192. package/dist/daemon/htpx-client.d.ts +8 -0
  193. package/dist/daemon/htpx-client.d.ts.map +1 -0
  194. package/dist/daemon/htpx-client.js +25 -0
  195. package/dist/daemon/htpx-client.js.map +1 -0
  196. package/dist/daemon/index.js +50 -2
  197. package/dist/daemon/index.js.map +1 -1
  198. package/dist/daemon/interceptor-loader.d.ts +30 -0
  199. package/dist/daemon/interceptor-loader.d.ts.map +1 -0
  200. package/dist/daemon/interceptor-loader.js +249 -0
  201. package/dist/daemon/interceptor-loader.js.map +1 -0
  202. package/dist/daemon/interceptor-runner.d.ts +39 -0
  203. package/dist/daemon/interceptor-runner.d.ts.map +1 -0
  204. package/dist/daemon/interceptor-runner.js +312 -0
  205. package/dist/daemon/interceptor-runner.js.map +1 -0
  206. package/dist/daemon/proxy.d.ts +12 -0
  207. package/dist/daemon/proxy.d.ts.map +1 -1
  208. package/dist/daemon/proxy.js +121 -10
  209. package/dist/daemon/proxy.js.map +1 -1
  210. package/dist/daemon/storage.d.ts +64 -2
  211. package/dist/daemon/storage.d.ts.map +1 -1
  212. package/dist/daemon/storage.js +527 -12
  213. package/dist/daemon/storage.js.map +1 -1
  214. package/dist/interceptors.d.ts +2 -0
  215. package/dist/interceptors.d.ts.map +1 -0
  216. package/dist/interceptors.js +2 -0
  217. package/dist/interceptors.js.map +1 -0
  218. package/dist/mcp/server.d.ts +110 -0
  219. package/dist/mcp/server.d.ts.map +1 -0
  220. package/dist/mcp/server.js +806 -0
  221. package/dist/mcp/server.js.map +1 -0
  222. package/dist/shared/config.d.ts +21 -0
  223. package/dist/shared/config.d.ts.map +1 -0
  224. package/dist/shared/config.js +83 -0
  225. package/dist/shared/config.js.map +1 -0
  226. package/dist/shared/content-type.d.ts +64 -0
  227. package/dist/shared/content-type.d.ts.map +1 -0
  228. package/dist/shared/content-type.js +145 -0
  229. package/dist/shared/content-type.js.map +1 -0
  230. package/dist/shared/control-client.d.ts +144 -0
  231. package/dist/shared/control-client.d.ts.map +1 -0
  232. package/dist/shared/control-client.js +272 -0
  233. package/dist/shared/control-client.js.map +1 -0
  234. package/dist/shared/daemon.d.ts.map +1 -1
  235. package/dist/shared/daemon.js +17 -4
  236. package/dist/shared/daemon.js.map +1 -1
  237. package/dist/shared/logger.d.ts +21 -5
  238. package/dist/shared/logger.d.ts.map +1 -1
  239. package/dist/shared/logger.js +100 -21
  240. package/dist/shared/logger.js.map +1 -1
  241. package/dist/shared/project.d.ts +16 -3
  242. package/dist/shared/project.d.ts.map +1 -1
  243. package/dist/shared/project.js +45 -5
  244. package/dist/shared/project.js.map +1 -1
  245. package/dist/shared/proxy-info.d.ts +10 -0
  246. package/dist/shared/proxy-info.d.ts.map +1 -0
  247. package/dist/shared/proxy-info.js +15 -0
  248. package/dist/shared/proxy-info.js.map +1 -0
  249. package/dist/shared/types.d.ts +95 -0
  250. package/dist/shared/types.d.ts.map +1 -1
  251. package/package.json +24 -5
  252. package/skills/htpx/SKILL.md +228 -0
@@ -2,43 +2,55 @@
2
2
  * Hook for fetching and polling captured requests from the daemon.
3
3
  */
4
4
  import { useState, useEffect, useCallback, useRef } from "react";
5
- import { ControlClient } from "../../../daemon/control.js";
5
+ import { ControlClient } from "../../../shared/control-client.js";
6
6
  import { findProjectRoot, getHtpxPaths } from "../../../shared/project.js";
7
+ const DEFAULT_QUERY_LIMIT = 1000;
8
+ const DEFAULT_POLL_INTERVAL_MS = 2000;
7
9
  /**
8
10
  * Hook to fetch and poll for captured requests.
9
11
  */
10
12
  export function useRequests(options = {}) {
11
- const { label, pollInterval = 2000 } = options;
13
+ const { pollInterval = DEFAULT_POLL_INTERVAL_MS, filter, projectRoot } = options;
12
14
  const [requests, setRequests] = useState([]);
13
15
  const [isLoading, setIsLoading] = useState(true);
14
16
  const [error, setError] = useState(null);
15
17
  const clientRef = useRef(null);
16
18
  const lastCountRef = useRef(0);
19
+ const requestsLengthRef = useRef(0);
20
+ const filterRef = useRef(filter);
17
21
  // Initialise control client
18
22
  useEffect(() => {
19
- const projectRoot = findProjectRoot();
20
- if (!projectRoot) {
23
+ const resolvedRoot = projectRoot ?? findProjectRoot();
24
+ if (!resolvedRoot) {
21
25
  setError("Not in an htpx project. Run 'htpx init' first.");
22
26
  setIsLoading(false);
23
27
  return;
24
28
  }
25
- const paths = getHtpxPaths(projectRoot);
29
+ const paths = getHtpxPaths(resolvedRoot);
26
30
  clientRef.current = new ControlClient(paths.controlSocketFile);
27
- }, []);
28
- // Fetch requests from daemon
31
+ return () => {
32
+ clientRef.current?.close();
33
+ };
34
+ }, [projectRoot]);
35
+ // Keep ref in sync with requests length
36
+ useEffect(() => {
37
+ requestsLengthRef.current = requests.length;
38
+ }, [requests.length]);
39
+ // Fetch request summaries from daemon
29
40
  const fetchRequests = useCallback(async () => {
30
41
  const client = clientRef.current;
31
42
  if (!client) {
32
43
  return;
33
44
  }
45
+ const currentFilter = filterRef.current;
34
46
  try {
35
47
  // First check the count to avoid unnecessary data transfer
36
- const count = await client.countRequests({ label });
37
- // Only fetch full list if count changed
38
- if (count !== lastCountRef.current || requests.length === 0) {
39
- const newRequests = await client.listRequests({
40
- label,
41
- limit: 1000,
48
+ const count = await client.countRequests({ filter: currentFilter });
49
+ // Only fetch list if count changed or we have no requests yet
50
+ if (count !== lastCountRef.current || requestsLengthRef.current === 0) {
51
+ const newRequests = await client.listRequestsSummary({
52
+ limit: DEFAULT_QUERY_LIMIT,
53
+ filter: currentFilter,
42
54
  });
43
55
  setRequests(newRequests);
44
56
  lastCountRef.current = count;
@@ -48,7 +60,7 @@ export function useRequests(options = {}) {
48
60
  catch (err) {
49
61
  const message = err instanceof Error ? err.message : "Failed to connect to daemon";
50
62
  if (message.includes("ENOENT") || message.includes("ECONNREFUSED")) {
51
- setError("Daemon not running. Start with 'htpx intercept'.");
63
+ setError("Daemon not running. Start with 'eval $(htpx on)'.");
52
64
  }
53
65
  else {
54
66
  setError(message);
@@ -57,13 +69,45 @@ export function useRequests(options = {}) {
57
69
  finally {
58
70
  setIsLoading(false);
59
71
  }
60
- }, [label, requests.length]);
72
+ }, []);
73
+ // Keep filter ref in sync and fetch immediately when filter changes
74
+ useEffect(() => {
75
+ filterRef.current = filter;
76
+ lastCountRef.current = 0;
77
+ void fetchRequests();
78
+ }, [filter, fetchRequests]);
61
79
  // Manual refresh function
62
80
  const refresh = useCallback(async () => {
63
81
  setIsLoading(true);
64
82
  lastCountRef.current = 0; // Force full refresh
65
83
  await fetchRequests();
66
84
  }, [fetchRequests]);
85
+ // Fetch full request data by ID
86
+ const getFullRequest = useCallback(async (id) => {
87
+ const client = clientRef.current;
88
+ if (!client) {
89
+ return null;
90
+ }
91
+ try {
92
+ return await client.getRequest(id);
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }, []);
98
+ // Fetch all requests with full data (for exports like HAR)
99
+ const getAllFullRequests = useCallback(async () => {
100
+ const client = clientRef.current;
101
+ if (!client) {
102
+ return [];
103
+ }
104
+ try {
105
+ return await client.listRequests({ limit: DEFAULT_QUERY_LIMIT });
106
+ }
107
+ catch {
108
+ return [];
109
+ }
110
+ }, []);
67
111
  // Initial fetch
68
112
  useEffect(() => {
69
113
  void fetchRequests();
@@ -80,6 +124,8 @@ export function useRequests(options = {}) {
80
124
  isLoading,
81
125
  error,
82
126
  refresh,
127
+ getFullRequest,
128
+ getAllFullRequests,
83
129
  };
84
130
  }
85
131
  //# sourceMappingURL=useRequests.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useRequests.js","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useRequests.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useRequests.js","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useRequests.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Hook for saving binary content to disk.
3
+ */
4
+ import type { SaveLocation } from "../components/SaveModal.js";
5
+ export interface SaveResult {
6
+ success: boolean;
7
+ message: string;
8
+ filePath?: string;
9
+ }
10
+ /**
11
+ * Generate a filename for binary content based on request metadata.
12
+ */
13
+ export declare function generateFilename(requestId: string, contentType: string | undefined, url: string): string;
14
+ /**
15
+ * Save binary content to disk.
16
+ */
17
+ export declare function saveBinaryContent(body: Buffer, filename: string, location: SaveLocation, customPath?: string): Promise<SaveResult>;
18
+ interface UseSaveBinaryResult {
19
+ saveBinary: (body: Buffer, requestId: string, contentType: string | undefined, url: string, location: SaveLocation, customPath?: string) => Promise<SaveResult>;
20
+ }
21
+ /**
22
+ * Hook providing binary save functionality.
23
+ */
24
+ export declare function useSaveBinary(): UseSaveBinaryResult;
25
+ export {};
26
+ //# sourceMappingURL=useSaveBinary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSaveBinary.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useSaveBinary.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,GAAG,EAAE,MAAM,GACV,MAAM,CAwBR;AAkGD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,YAAY,EACtB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,CAAC,CA6BrB;AAED,UAAU,mBAAmB;IAC3B,UAAU,EAAE,CACV,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,YAAY,EACtB,UAAU,CAAC,EAAE,MAAM,KAChB,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,mBAAmB,CAiBnD"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Hook for saving binary content to disk.
3
+ */
4
+ import { useCallback } from "react";
5
+ import * as fs from "node:fs";
6
+ import * as path from "node:path";
7
+ import * as os from "node:os";
8
+ import { copyToClipboard } from "../utils/clipboard.js";
9
+ import { findOrCreateProjectRoot, ensureHtpxDir } from "../../../shared/project.js";
10
+ /**
11
+ * Generate a filename for binary content based on request metadata.
12
+ */
13
+ export function generateFilename(requestId, contentType, url) {
14
+ // Try to extract extension from URL first
15
+ let extension = "";
16
+ try {
17
+ const urlPath = new URL(url).pathname;
18
+ const urlExtMatch = urlPath.match(/\.([a-zA-Z0-9]+)$/);
19
+ if (urlExtMatch?.[1]) {
20
+ extension = urlExtMatch[1].toLowerCase();
21
+ }
22
+ }
23
+ catch {
24
+ // Invalid URL, fall through to content-type detection
25
+ }
26
+ if (!extension && contentType) {
27
+ // Derive extension from content type
28
+ extension = getExtensionFromContentType(contentType);
29
+ }
30
+ // Generate timestamp for uniqueness
31
+ const timestamp = Date.now();
32
+ const shortId = requestId.slice(0, 8);
33
+ return extension ? `${shortId}-${timestamp}.${extension}` : `${shortId}-${timestamp}.bin`;
34
+ }
35
+ /**
36
+ * Map common content types to file extensions.
37
+ */
38
+ function getExtensionFromContentType(contentType) {
39
+ const type = contentType.split(";")[0]?.trim().toLowerCase() ?? "";
40
+ const mappings = {
41
+ // Images
42
+ "image/jpeg": "jpg",
43
+ "image/png": "png",
44
+ "image/gif": "gif",
45
+ "image/webp": "webp",
46
+ "image/svg+xml": "svg",
47
+ "image/x-icon": "ico",
48
+ "image/bmp": "bmp",
49
+ "image/tiff": "tiff",
50
+ // Audio
51
+ "audio/mpeg": "mp3",
52
+ "audio/wav": "wav",
53
+ "audio/ogg": "ogg",
54
+ "audio/webm": "weba",
55
+ "audio/aac": "aac",
56
+ "audio/flac": "flac",
57
+ // Video
58
+ "video/mp4": "mp4",
59
+ "video/webm": "webm",
60
+ "video/ogg": "ogv",
61
+ "video/quicktime": "mov",
62
+ "video/x-msvideo": "avi",
63
+ "video/x-matroska": "mkv",
64
+ // Documents
65
+ "application/pdf": "pdf",
66
+ "application/msword": "doc",
67
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
68
+ "application/vnd.ms-excel": "xls",
69
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
70
+ "application/vnd.ms-powerpoint": "ppt",
71
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
72
+ // Archives
73
+ "application/zip": "zip",
74
+ "application/gzip": "gz",
75
+ "application/x-tar": "tar",
76
+ "application/x-rar-compressed": "rar",
77
+ "application/x-7z-compressed": "7z",
78
+ // Other
79
+ "application/octet-stream": "bin",
80
+ "application/wasm": "wasm",
81
+ };
82
+ return mappings[type] ?? "bin";
83
+ }
84
+ /**
85
+ * Resolve the target directory based on save location.
86
+ */
87
+ function resolveTargetDir(location, customPath) {
88
+ switch (location) {
89
+ case "exports": {
90
+ const projectRoot = findOrCreateProjectRoot();
91
+ const htpxDir = ensureHtpxDir(projectRoot);
92
+ const exportsDir = path.join(htpxDir, "exports");
93
+ if (!fs.existsSync(exportsDir)) {
94
+ fs.mkdirSync(exportsDir, { recursive: true });
95
+ }
96
+ return exportsDir;
97
+ }
98
+ case "downloads": {
99
+ const downloadsDir = path.join(os.homedir(), "Downloads");
100
+ if (!fs.existsSync(downloadsDir)) {
101
+ fs.mkdirSync(downloadsDir, { recursive: true });
102
+ }
103
+ return downloadsDir;
104
+ }
105
+ case "custom": {
106
+ if (!customPath) {
107
+ throw new Error("Custom path required");
108
+ }
109
+ // Expand ~ to home directory
110
+ const expandedPath = customPath.startsWith("~")
111
+ ? path.join(os.homedir(), customPath.slice(1))
112
+ : customPath;
113
+ const resolvedPath = path.resolve(expandedPath);
114
+ // Ensure directory exists
115
+ if (!fs.existsSync(resolvedPath)) {
116
+ fs.mkdirSync(resolvedPath, { recursive: true });
117
+ }
118
+ return resolvedPath;
119
+ }
120
+ }
121
+ }
122
+ /**
123
+ * Save binary content to disk.
124
+ */
125
+ export async function saveBinaryContent(body, filename, location, customPath) {
126
+ try {
127
+ const targetDir = resolveTargetDir(location, customPath);
128
+ const filePath = path.join(targetDir, filename);
129
+ fs.writeFileSync(filePath, body);
130
+ // Copy path to clipboard
131
+ try {
132
+ await copyToClipboard(filePath);
133
+ return {
134
+ success: true,
135
+ message: `Saved to ${filePath} (path copied)`,
136
+ filePath,
137
+ };
138
+ }
139
+ catch {
140
+ // Clipboard failed but file was saved
141
+ return {
142
+ success: true,
143
+ message: `Saved to ${filePath}`,
144
+ filePath,
145
+ };
146
+ }
147
+ }
148
+ catch (err) {
149
+ return {
150
+ success: false,
151
+ message: err instanceof Error ? err.message : "Failed to save file",
152
+ };
153
+ }
154
+ }
155
+ /**
156
+ * Hook providing binary save functionality.
157
+ */
158
+ export function useSaveBinary() {
159
+ const saveBinary = useCallback(async (body, requestId, contentType, url, location, customPath) => {
160
+ const filename = generateFilename(requestId, contentType, url);
161
+ return saveBinaryContent(body, filename, location, customPath);
162
+ }, []);
163
+ return { saveBinary };
164
+ }
165
+ //# sourceMappingURL=useSaveBinary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSaveBinary.js","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useSaveBinary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Hook that cycles through braille spinner frames for loading indicators.
3
+ */
4
+ export declare function useSpinner(active?: boolean): string;
5
+ //# sourceMappingURL=useSpinner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSpinner.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useSpinner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,wBAAgB,UAAU,CAAC,MAAM,UAAO,GAAG,MAAM,CAqBhD"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Hook that cycles through braille spinner frames for loading indicators.
3
+ */
4
+ import { useState, useEffect, useRef } from "react";
5
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
6
+ const SPINNER_INTERVAL_MS = 80;
7
+ export function useSpinner(active = true) {
8
+ const [frameIndex, setFrameIndex] = useState(0);
9
+ const intervalRef = useRef(null);
10
+ useEffect(() => {
11
+ if (!active) {
12
+ return;
13
+ }
14
+ intervalRef.current = setInterval(() => {
15
+ setFrameIndex((prev) => (prev + 1) % SPINNER_FRAMES.length);
16
+ }, SPINNER_INTERVAL_MS);
17
+ return () => {
18
+ if (intervalRef.current) {
19
+ clearInterval(intervalRef.current);
20
+ }
21
+ };
22
+ }, [active]);
23
+ return SPINNER_FRAMES[frameIndex] ?? SPINNER_FRAMES[0];
24
+ }
25
+ //# sourceMappingURL=useSpinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSpinner.js","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useSpinner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEpD,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AACnF,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B,MAAM,UAAU,UAAU,CAAC,MAAM,GAAG,IAAI;IACtC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,MAAM,CAAwB,IAAI,CAAC,CAAC;IAExD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QAED,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;YACrC,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QAC9D,CAAC,EAAE,mBAAmB,CAAC,CAAC;QAExB,OAAO,GAAG,EAAE;YACV,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;gBACxB,aAAa,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACrC,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO,cAAc,CAAC,UAAU,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Binary content detection utilities.
3
+ *
4
+ * Determines whether a buffer contains binary or text content based on
5
+ * Content-Type headers and byte scanning.
6
+ */
7
+ export interface BinaryCheckResult {
8
+ isBinary: boolean;
9
+ reason: "content-type" | "content-scan" | "text-content-type";
10
+ }
11
+ /**
12
+ * Check if content is binary based on Content-Type and/or byte scanning.
13
+ *
14
+ * Detection logic:
15
+ * 1. Check Content-Type against text whitelist - if match, return not binary
16
+ * 2. Check Content-Type against binary patterns - if match, return binary
17
+ * 3. Fall back to scanning first 8KB for >10% non-printable characters
18
+ */
19
+ export declare function isBinaryContent(body: Buffer | undefined, contentType: string | undefined): BinaryCheckResult;
20
+ /**
21
+ * Get a human-readable description for a binary content type.
22
+ */
23
+ export declare function getBinaryTypeDescription(contentType: string | undefined): string;
24
+ //# sourceMappingURL=binary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binary.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/utils/binary.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4CH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,cAAc,GAAG,cAAc,GAAG,mBAAmB,CAAC;CAC/D;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,iBAAiB,CAiDnB;AAoCD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CA2BhF"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Binary content detection utilities.
3
+ *
4
+ * Determines whether a buffer contains binary or text content based on
5
+ * Content-Type headers and byte scanning.
6
+ */
7
+ import { TEXT_CONTENT_TYPES, TEXT_SUFFIXES } from "../../../shared/content-type.js";
8
+ /**
9
+ * Content types that are definitively binary.
10
+ */
11
+ const BINARY_CONTENT_TYPES = [
12
+ "image/",
13
+ "audio/",
14
+ "video/",
15
+ "application/octet-stream",
16
+ "application/pdf",
17
+ "application/zip",
18
+ "application/gzip",
19
+ "application/x-tar",
20
+ "application/x-rar-compressed",
21
+ "application/x-7z-compressed",
22
+ "application/vnd.ms-excel",
23
+ "application/vnd.ms-powerpoint",
24
+ "application/vnd.ms-word",
25
+ "application/vnd.openxmlformats-officedocument",
26
+ "application/x-shockwave-flash",
27
+ "application/wasm",
28
+ "font/",
29
+ ];
30
+ /**
31
+ * Human-readable descriptions for binary content types.
32
+ */
33
+ const BINARY_DESCRIPTIONS = {
34
+ "image/": "Image",
35
+ "audio/": "Audio",
36
+ "video/": "Video",
37
+ "font/": "Font",
38
+ "application/pdf": "PDF",
39
+ "application/zip": "Archive",
40
+ "application/gzip": "Archive",
41
+ "application/x-tar": "Archive",
42
+ "application/x-rar-compressed": "Archive",
43
+ "application/x-7z-compressed": "Archive",
44
+ "application/wasm": "WebAssembly",
45
+ };
46
+ /**
47
+ * Check if content is binary based on Content-Type and/or byte scanning.
48
+ *
49
+ * Detection logic:
50
+ * 1. Check Content-Type against text whitelist - if match, return not binary
51
+ * 2. Check Content-Type against binary patterns - if match, return binary
52
+ * 3. Fall back to scanning first 8KB for >10% non-printable characters
53
+ */
54
+ export function isBinaryContent(body, contentType) {
55
+ // No body means not binary (nothing to display)
56
+ if (!body || body.length === 0) {
57
+ return { isBinary: false, reason: "text-content-type" };
58
+ }
59
+ // Normalise content type (remove charset and other parameters)
60
+ const normalisedType = contentType?.split(";")[0]?.trim().toLowerCase();
61
+ // Check text content types first
62
+ if (normalisedType) {
63
+ // Check prefixes
64
+ let isTextContentType = false;
65
+ for (const prefix of TEXT_CONTENT_TYPES) {
66
+ if (normalisedType.startsWith(prefix)) {
67
+ isTextContentType = true;
68
+ break;
69
+ }
70
+ }
71
+ // Check suffixes (e.g., application/hal+json)
72
+ if (!isTextContentType) {
73
+ for (const suffix of TEXT_SUFFIXES) {
74
+ if (normalisedType.endsWith(suffix)) {
75
+ isTextContentType = true;
76
+ break;
77
+ }
78
+ }
79
+ }
80
+ if (isTextContentType) {
81
+ // Content-type says text, but verify with byte scan as safety net.
82
+ // Handles compressed bodies still in the DB, mislabelled content types, etc.
83
+ const scanResult = scanForBinaryContent(body);
84
+ return scanResult.isBinary
85
+ ? { isBinary: true, reason: "content-scan" }
86
+ : { isBinary: false, reason: "text-content-type" };
87
+ }
88
+ // Check binary content types
89
+ for (const prefix of BINARY_CONTENT_TYPES) {
90
+ if (normalisedType.startsWith(prefix)) {
91
+ return { isBinary: true, reason: "content-type" };
92
+ }
93
+ }
94
+ }
95
+ // Fall back to byte scanning
96
+ return scanForBinaryContent(body);
97
+ }
98
+ /**
99
+ * Scan buffer for binary content by checking for non-printable characters.
100
+ * Scans first 8KB and considers binary if >10% are non-printable.
101
+ */
102
+ function scanForBinaryContent(body) {
103
+ const SCAN_SIZE = 8 * 1024; // 8KB
104
+ const BINARY_THRESHOLD = 0.1; // 10%
105
+ const bytesToScan = Math.min(body.length, SCAN_SIZE);
106
+ let nonPrintableCount = 0;
107
+ for (let i = 0; i < bytesToScan; i++) {
108
+ const byte = body[i];
109
+ if (byte === undefined)
110
+ continue;
111
+ // Allow common text characters:
112
+ // - Tab (9), LF (10), CR (13)
113
+ // - Printable ASCII (32-126)
114
+ // - Extended ASCII (128-255) for UTF-8
115
+ const isPrintable = byte === 9 || byte === 10 || byte === 13 || (byte >= 32 && byte <= 126) || byte >= 128;
116
+ if (!isPrintable) {
117
+ nonPrintableCount++;
118
+ }
119
+ }
120
+ const ratio = nonPrintableCount / bytesToScan;
121
+ return {
122
+ isBinary: ratio > BINARY_THRESHOLD,
123
+ reason: "content-scan",
124
+ };
125
+ }
126
+ /**
127
+ * Get a human-readable description for a binary content type.
128
+ */
129
+ export function getBinaryTypeDescription(contentType) {
130
+ if (!contentType) {
131
+ return "Binary";
132
+ }
133
+ const normalisedType = contentType.split(";")[0]?.trim().toLowerCase() ?? "";
134
+ // Check exact matches first
135
+ if (BINARY_DESCRIPTIONS[normalisedType]) {
136
+ return BINARY_DESCRIPTIONS[normalisedType];
137
+ }
138
+ // Check prefix matches
139
+ for (const [prefix, description] of Object.entries(BINARY_DESCRIPTIONS)) {
140
+ if (prefix.endsWith("/") && normalisedType.startsWith(prefix)) {
141
+ return description;
142
+ }
143
+ }
144
+ // Extract subtype for better description
145
+ if (normalisedType.startsWith("application/")) {
146
+ const subtype = normalisedType.replace("application/", "");
147
+ // Capitalise first letter
148
+ return subtype.charAt(0).toUpperCase() + subtype.slice(1);
149
+ }
150
+ return "Binary";
151
+ }
152
+ //# sourceMappingURL=binary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binary.js","sourceRoot":"","sources":["../../../../src/cli/tui/utils/binary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Cross-platform clipboard utilities using native commands.
3
+ */
4
+ /**
5
+ * Copy text to the system clipboard.
6
+ * Uses pbcopy on macOS, xclip on Linux, clip on Windows.
7
+ */
8
+ export declare function copyToClipboard(text: string): Promise<void>;
9
+ //# sourceMappingURL=clipboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/utils/clipboard.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDjE"}