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.
- package/LICENSE +665 -21
- package/README.md +422 -116
- package/dist/cli/commands/clear.d.ts.map +1 -1
- package/dist/cli/commands/clear.js +11 -11
- package/dist/cli/commands/clear.js.map +1 -1
- package/dist/cli/commands/daemon.d.ts +3 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -0
- package/dist/cli/commands/daemon.js +59 -0
- package/dist/cli/commands/daemon.js.map +1 -0
- package/dist/cli/commands/debug-dump.d.ts.map +1 -1
- package/dist/cli/commands/debug-dump.js +8 -10
- package/dist/cli/commands/debug-dump.js.map +1 -1
- package/dist/cli/commands/helpers.d.ts +18 -0
- package/dist/cli/commands/helpers.d.ts.map +1 -0
- package/dist/cli/commands/helpers.js +34 -0
- package/dist/cli/commands/helpers.js.map +1 -0
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +3 -4
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/intercept.d.ts +2 -1
- package/dist/cli/commands/intercept.d.ts.map +1 -1
- package/dist/cli/commands/intercept.js +74 -30
- package/dist/cli/commands/intercept.js.map +1 -1
- package/dist/cli/commands/interceptors.d.ts +3 -0
- package/dist/cli/commands/interceptors.d.ts.map +1 -0
- package/dist/cli/commands/interceptors.js +163 -0
- package/dist/cli/commands/interceptors.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +3 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +24 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/off.d.ts +8 -0
- package/dist/cli/commands/off.d.ts.map +1 -0
- package/dist/cli/commands/off.js +34 -0
- package/dist/cli/commands/off.js.map +1 -0
- package/dist/cli/commands/on.d.ts +9 -0
- package/dist/cli/commands/on.d.ts.map +1 -0
- package/dist/cli/commands/on.js +121 -0
- package/dist/cli/commands/on.js.map +1 -0
- package/dist/cli/commands/project.d.ts.map +1 -1
- package/dist/cli/commands/project.js +5 -3
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/restart.d.ts.map +1 -1
- package/dist/cli/commands/restart.js +5 -10
- package/dist/cli/commands/restart.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +50 -20
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/stop.d.ts.map +1 -1
- package/dist/cli/commands/stop.js +7 -10
- package/dist/cli/commands/stop.js.map +1 -1
- package/dist/cli/commands/tui.d.ts.map +1 -1
- package/dist/cli/commands/tui.js +6 -13
- package/dist/cli/commands/tui.js.map +1 -1
- package/dist/cli/index.js +12 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/tui/App.d.ts +7 -2
- package/dist/cli/tui/App.d.ts.map +1 -1
- package/dist/cli/tui/App.js +490 -33
- package/dist/cli/tui/App.js.map +1 -1
- package/dist/cli/tui/components/AccordionContent.d.ts +28 -0
- package/dist/cli/tui/components/AccordionContent.d.ts.map +1 -0
- package/dist/cli/tui/components/AccordionContent.js +87 -0
- package/dist/cli/tui/components/AccordionContent.js.map +1 -0
- package/dist/cli/tui/components/AccordionPanel.d.ts +38 -0
- package/dist/cli/tui/components/AccordionPanel.d.ts.map +1 -0
- package/dist/cli/tui/components/AccordionPanel.js +110 -0
- package/dist/cli/tui/components/AccordionPanel.js.map +1 -0
- package/dist/cli/tui/components/AccordionSection.d.ts +32 -0
- package/dist/cli/tui/components/AccordionSection.d.ts.map +1 -0
- package/dist/cli/tui/components/AccordionSection.js +41 -0
- package/dist/cli/tui/components/AccordionSection.js.map +1 -0
- package/dist/cli/tui/components/ExportModal.d.ts +34 -0
- package/dist/cli/tui/components/ExportModal.d.ts.map +1 -0
- package/dist/cli/tui/components/ExportModal.js +109 -0
- package/dist/cli/tui/components/ExportModal.js.map +1 -0
- package/dist/cli/tui/components/FilterBar.d.ts +21 -0
- package/dist/cli/tui/components/FilterBar.d.ts.map +1 -0
- package/dist/cli/tui/components/FilterBar.js +155 -0
- package/dist/cli/tui/components/FilterBar.js.map +1 -0
- package/dist/cli/tui/components/HelpModal.d.ts +13 -0
- package/dist/cli/tui/components/HelpModal.d.ts.map +1 -0
- package/dist/cli/tui/components/HelpModal.js +78 -0
- package/dist/cli/tui/components/HelpModal.js.map +1 -0
- package/dist/cli/tui/components/HintContent.d.ts +25 -0
- package/dist/cli/tui/components/HintContent.d.ts.map +1 -0
- package/dist/cli/tui/components/HintContent.js +44 -0
- package/dist/cli/tui/components/HintContent.js.map +1 -0
- package/dist/cli/tui/components/InfoModal.d.ts +15 -0
- package/dist/cli/tui/components/InfoModal.d.ts.map +1 -0
- package/dist/cli/tui/components/InfoModal.js +17 -0
- package/dist/cli/tui/components/InfoModal.js.map +1 -0
- package/dist/cli/tui/components/JsonExplorerModal.d.ts +24 -0
- package/dist/cli/tui/components/JsonExplorerModal.d.ts.map +1 -0
- package/dist/cli/tui/components/JsonExplorerModal.js +311 -0
- package/dist/cli/tui/components/JsonExplorerModal.js.map +1 -0
- package/dist/cli/tui/components/Modal.d.ts +26 -0
- package/dist/cli/tui/components/Modal.d.ts.map +1 -0
- package/dist/cli/tui/components/Modal.js +15 -0
- package/dist/cli/tui/components/Modal.js.map +1 -0
- package/dist/cli/tui/components/Panel.d.ts +19 -0
- package/dist/cli/tui/components/Panel.d.ts.map +1 -0
- package/dist/cli/tui/components/Panel.js +37 -0
- package/dist/cli/tui/components/Panel.js.map +1 -0
- package/dist/cli/tui/components/RequestDetails.d.ts +4 -1
- package/dist/cli/tui/components/RequestDetails.d.ts.map +1 -1
- package/dist/cli/tui/components/RequestDetails.js +9 -5
- package/dist/cli/tui/components/RequestDetails.js.map +1 -1
- package/dist/cli/tui/components/RequestList.d.ts +9 -3
- package/dist/cli/tui/components/RequestList.d.ts.map +1 -1
- package/dist/cli/tui/components/RequestList.js +24 -11
- package/dist/cli/tui/components/RequestList.js.map +1 -1
- package/dist/cli/tui/components/RequestListItem.d.ts +26 -3
- package/dist/cli/tui/components/RequestListItem.d.ts.map +1 -1
- package/dist/cli/tui/components/RequestListItem.js +86 -9
- package/dist/cli/tui/components/RequestListItem.js.map +1 -1
- package/dist/cli/tui/components/SaveModal.d.ts +30 -0
- package/dist/cli/tui/components/SaveModal.d.ts.map +1 -0
- package/dist/cli/tui/components/SaveModal.js +95 -0
- package/dist/cli/tui/components/SaveModal.js.map +1 -0
- package/dist/cli/tui/components/StatusBar.d.ts +31 -2
- package/dist/cli/tui/components/StatusBar.d.ts.map +1 -1
- package/dist/cli/tui/components/StatusBar.js +44 -9
- package/dist/cli/tui/components/StatusBar.js.map +1 -1
- package/dist/cli/tui/components/TextViewerModal.d.ts +19 -0
- package/dist/cli/tui/components/TextViewerModal.d.ts.map +1 -0
- package/dist/cli/tui/components/TextViewerModal.js +227 -0
- package/dist/cli/tui/components/TextViewerModal.js.map +1 -0
- package/dist/cli/tui/hooks/useBodyExport.d.ts +26 -0
- package/dist/cli/tui/hooks/useBodyExport.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useBodyExport.js +173 -0
- package/dist/cli/tui/hooks/useBodyExport.js.map +1 -0
- package/dist/cli/tui/hooks/useExport.d.ts +13 -2
- package/dist/cli/tui/hooks/useExport.d.ts.map +1 -1
- package/dist/cli/tui/hooks/useExport.js +46 -40
- package/dist/cli/tui/hooks/useExport.js.map +1 -1
- package/dist/cli/tui/hooks/useRequests.d.ts +9 -3
- package/dist/cli/tui/hooks/useRequests.d.ts.map +1 -1
- package/dist/cli/tui/hooks/useRequests.js +61 -15
- package/dist/cli/tui/hooks/useRequests.js.map +1 -1
- package/dist/cli/tui/hooks/useSaveBinary.d.ts +26 -0
- package/dist/cli/tui/hooks/useSaveBinary.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useSaveBinary.js +165 -0
- package/dist/cli/tui/hooks/useSaveBinary.js.map +1 -0
- package/dist/cli/tui/hooks/useSpinner.d.ts +5 -0
- package/dist/cli/tui/hooks/useSpinner.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useSpinner.js +25 -0
- package/dist/cli/tui/hooks/useSpinner.js.map +1 -0
- package/dist/cli/tui/utils/binary.d.ts +24 -0
- package/dist/cli/tui/utils/binary.d.ts.map +1 -0
- package/dist/cli/tui/utils/binary.js +152 -0
- package/dist/cli/tui/utils/binary.js.map +1 -0
- package/dist/cli/tui/utils/clipboard.d.ts +9 -0
- package/dist/cli/tui/utils/clipboard.d.ts.map +1 -0
- package/dist/cli/tui/utils/clipboard.js +58 -0
- package/dist/cli/tui/utils/clipboard.js.map +1 -0
- package/dist/cli/tui/utils/content-type.d.ts +8 -0
- package/dist/cli/tui/utils/content-type.d.ts.map +1 -0
- package/dist/cli/tui/utils/content-type.js +10 -0
- package/dist/cli/tui/utils/content-type.js.map +1 -0
- package/dist/cli/tui/utils/curl.d.ts.map +1 -1
- package/dist/cli/tui/utils/curl.js +9 -2
- package/dist/cli/tui/utils/curl.js.map +1 -1
- package/dist/cli/tui/utils/filters.d.ts +6 -0
- package/dist/cli/tui/utils/filters.d.ts.map +1 -0
- package/dist/cli/tui/utils/filters.js +13 -0
- package/dist/cli/tui/utils/filters.js.map +1 -0
- package/dist/cli/tui/utils/formatters.d.ts +8 -0
- package/dist/cli/tui/utils/formatters.d.ts.map +1 -1
- package/dist/cli/tui/utils/formatters.js +85 -0
- package/dist/cli/tui/utils/formatters.js.map +1 -1
- package/dist/cli/tui/utils/har.d.ts.map +1 -1
- package/dist/cli/tui/utils/har.js +3 -25
- package/dist/cli/tui/utils/har.js.map +1 -1
- package/dist/cli/tui/utils/json-tree.d.ts +69 -0
- package/dist/cli/tui/utils/json-tree.d.ts.map +1 -0
- package/dist/cli/tui/utils/json-tree.js +339 -0
- package/dist/cli/tui/utils/json-tree.js.map +1 -0
- package/dist/cli/tui/utils/open-external.d.ts +17 -0
- package/dist/cli/tui/utils/open-external.d.ts.map +1 -0
- package/dist/cli/tui/utils/open-external.js +57 -0
- package/dist/cli/tui/utils/open-external.js.map +1 -0
- package/dist/cli/tui/utils/syntax-highlight.d.ts +16 -0
- package/dist/cli/tui/utils/syntax-highlight.d.ts.map +1 -0
- package/dist/cli/tui/utils/syntax-highlight.js +64 -0
- package/dist/cli/tui/utils/syntax-highlight.js.map +1 -0
- package/dist/daemon/control.d.ts +3 -49
- package/dist/daemon/control.d.ts.map +1 -1
- package/dist/daemon/control.js +183 -141
- package/dist/daemon/control.js.map +1 -1
- package/dist/daemon/htpx-client.d.ts +8 -0
- package/dist/daemon/htpx-client.d.ts.map +1 -0
- package/dist/daemon/htpx-client.js +25 -0
- package/dist/daemon/htpx-client.js.map +1 -0
- package/dist/daemon/index.js +50 -2
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/interceptor-loader.d.ts +30 -0
- package/dist/daemon/interceptor-loader.d.ts.map +1 -0
- package/dist/daemon/interceptor-loader.js +249 -0
- package/dist/daemon/interceptor-loader.js.map +1 -0
- package/dist/daemon/interceptor-runner.d.ts +39 -0
- package/dist/daemon/interceptor-runner.d.ts.map +1 -0
- package/dist/daemon/interceptor-runner.js +312 -0
- package/dist/daemon/interceptor-runner.js.map +1 -0
- package/dist/daemon/proxy.d.ts +12 -0
- package/dist/daemon/proxy.d.ts.map +1 -1
- package/dist/daemon/proxy.js +121 -10
- package/dist/daemon/proxy.js.map +1 -1
- package/dist/daemon/storage.d.ts +64 -2
- package/dist/daemon/storage.d.ts.map +1 -1
- package/dist/daemon/storage.js +527 -12
- package/dist/daemon/storage.js.map +1 -1
- package/dist/interceptors.d.ts +2 -0
- package/dist/interceptors.d.ts.map +1 -0
- package/dist/interceptors.js +2 -0
- package/dist/interceptors.js.map +1 -0
- package/dist/mcp/server.d.ts +110 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +806 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/shared/config.d.ts +21 -0
- package/dist/shared/config.d.ts.map +1 -0
- package/dist/shared/config.js +83 -0
- package/dist/shared/config.js.map +1 -0
- package/dist/shared/content-type.d.ts +64 -0
- package/dist/shared/content-type.d.ts.map +1 -0
- package/dist/shared/content-type.js +145 -0
- package/dist/shared/content-type.js.map +1 -0
- package/dist/shared/control-client.d.ts +144 -0
- package/dist/shared/control-client.d.ts.map +1 -0
- package/dist/shared/control-client.js +272 -0
- package/dist/shared/control-client.js.map +1 -0
- package/dist/shared/daemon.d.ts.map +1 -1
- package/dist/shared/daemon.js +17 -4
- package/dist/shared/daemon.js.map +1 -1
- package/dist/shared/logger.d.ts +21 -5
- package/dist/shared/logger.d.ts.map +1 -1
- package/dist/shared/logger.js +100 -21
- package/dist/shared/logger.js.map +1 -1
- package/dist/shared/project.d.ts +16 -3
- package/dist/shared/project.d.ts.map +1 -1
- package/dist/shared/project.js +45 -5
- package/dist/shared/project.js.map +1 -1
- package/dist/shared/proxy-info.d.ts +10 -0
- package/dist/shared/proxy-info.d.ts.map +1 -0
- package/dist/shared/proxy-info.js +15 -0
- package/dist/shared/proxy-info.js.map +1 -0
- package/dist/shared/types.d.ts +95 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/package.json +24 -5
- package/skills/htpx/SKILL.md +228 -0
package/dist/shared/project.d.ts
CHANGED
|
@@ -2,15 +2,26 @@
|
|
|
2
2
|
* Find the project root by looking for .htpx directory or .git directory.
|
|
3
3
|
* Walks up the directory tree from the current working directory.
|
|
4
4
|
* Returns undefined if no project root is found.
|
|
5
|
+
*
|
|
6
|
+
* When override is provided, returns the resolved override path only if
|
|
7
|
+
* it contains an .htpx or .git directory; otherwise returns undefined.
|
|
8
|
+
*
|
|
9
|
+
* @param startDir - Directory to start searching from. Pass `undefined` to
|
|
10
|
+
* use `process.cwd()` (common when only providing an override).
|
|
11
|
+
* @param override - If provided, resolves this path (with `~` expansion)
|
|
12
|
+
* and checks it directly instead of walking the tree.
|
|
5
13
|
*/
|
|
6
|
-
export declare function findProjectRoot(startDir?: string): string | undefined;
|
|
14
|
+
export declare function findProjectRoot(startDir?: string, override?: string): string | undefined;
|
|
7
15
|
/**
|
|
8
16
|
* Determine the project root, creating .htpx if needed.
|
|
9
17
|
* - If .htpx exists anywhere in the tree, use that directory
|
|
10
18
|
* - If .git exists, use the git root
|
|
11
|
-
* - Otherwise,
|
|
19
|
+
* - Otherwise, fall back to the user's home directory (global instance)
|
|
20
|
+
*
|
|
21
|
+
* When override is provided, returns the resolved override path directly
|
|
22
|
+
* (the caller is responsible for creating .htpx as needed).
|
|
12
23
|
*/
|
|
13
|
-
export declare function findOrCreateProjectRoot(startDir?: string): string;
|
|
24
|
+
export declare function findOrCreateProjectRoot(startDir?: string, override?: string): string;
|
|
14
25
|
/**
|
|
15
26
|
* Get the .htpx directory path for a project root.
|
|
16
27
|
*/
|
|
@@ -32,6 +43,8 @@ export declare function getHtpxPaths(projectRoot: string): {
|
|
|
32
43
|
caCertFile: string;
|
|
33
44
|
pidFile: string;
|
|
34
45
|
logFile: string;
|
|
46
|
+
configFile: string;
|
|
47
|
+
interceptorsDir: string;
|
|
35
48
|
};
|
|
36
49
|
/**
|
|
37
50
|
* Read the proxy port from the .htpx directory.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/shared/project.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/shared/project.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CA8BpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAyBR;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM;;;;;;;;;;;EAe/C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWrE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAGtE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWrE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAGrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAMzD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQrD"}
|
package/dist/shared/project.js
CHANGED
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
const HTPX_DIR = ".htpx";
|
|
5
|
+
const HOME_DIR_PREFIX = "~";
|
|
6
|
+
/**
|
|
7
|
+
* Resolve an override path, expanding ~ to the user's home directory
|
|
8
|
+
* and converting relative paths to absolute.
|
|
9
|
+
*/
|
|
10
|
+
function resolveOverridePath(override) {
|
|
11
|
+
if (override.startsWith(HOME_DIR_PREFIX + path.sep) || override === HOME_DIR_PREFIX) {
|
|
12
|
+
return path.join(os.homedir(), override.slice(HOME_DIR_PREFIX.length));
|
|
13
|
+
}
|
|
14
|
+
// Also handle ~/foo on platforms where sep is /
|
|
15
|
+
if (override.startsWith(HOME_DIR_PREFIX + "/")) {
|
|
16
|
+
return path.join(os.homedir(), override.slice(2));
|
|
17
|
+
}
|
|
18
|
+
return path.resolve(override);
|
|
19
|
+
}
|
|
4
20
|
/**
|
|
5
21
|
* Find the project root by looking for .htpx directory or .git directory.
|
|
6
22
|
* Walks up the directory tree from the current working directory.
|
|
7
23
|
* Returns undefined if no project root is found.
|
|
24
|
+
*
|
|
25
|
+
* When override is provided, returns the resolved override path only if
|
|
26
|
+
* it contains an .htpx or .git directory; otherwise returns undefined.
|
|
27
|
+
*
|
|
28
|
+
* @param startDir - Directory to start searching from. Pass `undefined` to
|
|
29
|
+
* use `process.cwd()` (common when only providing an override).
|
|
30
|
+
* @param override - If provided, resolves this path (with `~` expansion)
|
|
31
|
+
* and checks it directly instead of walking the tree.
|
|
8
32
|
*/
|
|
9
|
-
export function findProjectRoot(startDir = process.cwd()) {
|
|
33
|
+
export function findProjectRoot(startDir = process.cwd(), override) {
|
|
34
|
+
if (override !== undefined) {
|
|
35
|
+
const resolved = resolveOverridePath(override);
|
|
36
|
+
if (fs.existsSync(path.join(resolved, HTPX_DIR)) ||
|
|
37
|
+
fs.existsSync(path.join(resolved, ".git"))) {
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
10
42
|
let currentDir = path.resolve(startDir);
|
|
11
43
|
const root = path.parse(currentDir).root;
|
|
12
44
|
while (currentDir !== root) {
|
|
@@ -26,9 +58,15 @@ export function findProjectRoot(startDir = process.cwd()) {
|
|
|
26
58
|
* Determine the project root, creating .htpx if needed.
|
|
27
59
|
* - If .htpx exists anywhere in the tree, use that directory
|
|
28
60
|
* - If .git exists, use the git root
|
|
29
|
-
* - Otherwise,
|
|
61
|
+
* - Otherwise, fall back to the user's home directory (global instance)
|
|
62
|
+
*
|
|
63
|
+
* When override is provided, returns the resolved override path directly
|
|
64
|
+
* (the caller is responsible for creating .htpx as needed).
|
|
30
65
|
*/
|
|
31
|
-
export function findOrCreateProjectRoot(startDir = process.cwd()) {
|
|
66
|
+
export function findOrCreateProjectRoot(startDir = process.cwd(), override) {
|
|
67
|
+
if (override !== undefined) {
|
|
68
|
+
return resolveOverridePath(override);
|
|
69
|
+
}
|
|
32
70
|
let currentDir = path.resolve(startDir);
|
|
33
71
|
const root = path.parse(currentDir).root;
|
|
34
72
|
let gitRoot;
|
|
@@ -43,8 +81,8 @@ export function findOrCreateProjectRoot(startDir = process.cwd()) {
|
|
|
43
81
|
}
|
|
44
82
|
currentDir = path.dirname(currentDir);
|
|
45
83
|
}
|
|
46
|
-
//
|
|
47
|
-
return gitRoot ??
|
|
84
|
+
// Fall back to home directory for a global htpx instance
|
|
85
|
+
return gitRoot ?? os.homedir();
|
|
48
86
|
}
|
|
49
87
|
/**
|
|
50
88
|
* Get the .htpx directory path for a project root.
|
|
@@ -77,6 +115,8 @@ export function getHtpxPaths(projectRoot) {
|
|
|
77
115
|
caCertFile: path.join(htpxDir, "ca.pem"),
|
|
78
116
|
pidFile: path.join(htpxDir, "daemon.pid"),
|
|
79
117
|
logFile: path.join(htpxDir, "htpx.log"),
|
|
118
|
+
configFile: path.join(htpxDir, "config.json"),
|
|
119
|
+
interceptorsDir: path.join(htpxDir, "interceptors"),
|
|
80
120
|
};
|
|
81
121
|
}
|
|
82
122
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/shared/project.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,QAAQ,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/shared/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface ProxyInfo {
|
|
2
|
+
proxyUrl: string;
|
|
3
|
+
caCertPath: string;
|
|
4
|
+
envBlock: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Build proxy connection details from port and CA cert path.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildProxyInfo(proxyPort: number, caCertPath: string): ProxyInfo;
|
|
10
|
+
//# sourceMappingURL=proxy-info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-info.d.ts","sourceRoot":"","sources":["../../src/shared/proxy-info.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,CAY/E"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build proxy connection details from port and CA cert path.
|
|
3
|
+
*/
|
|
4
|
+
export function buildProxyInfo(proxyPort, caCertPath) {
|
|
5
|
+
const proxyUrl = `http://127.0.0.1:${proxyPort}`;
|
|
6
|
+
const envBlock = [
|
|
7
|
+
`export HTTP_PROXY="${proxyUrl}"`,
|
|
8
|
+
`export HTTPS_PROXY="${proxyUrl}"`,
|
|
9
|
+
`export SSL_CERT_FILE="${caCertPath}"`,
|
|
10
|
+
`export REQUESTS_CA_BUNDLE="${caCertPath}"`,
|
|
11
|
+
`export NODE_EXTRA_CA_CERTS="${caCertPath}"`,
|
|
12
|
+
].join("\n");
|
|
13
|
+
return { proxyUrl, caCertPath, envBlock };
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=proxy-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-info.js","sourceRoot":"","sources":["../../src/shared/proxy-info.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,UAAkB;IAClE,MAAM,QAAQ,GAAG,oBAAoB,SAAS,EAAE,CAAC;IAEjD,MAAM,QAAQ,GAAG;QACf,sBAAsB,QAAQ,GAAG;QACjC,uBAAuB,QAAQ,GAAG;QAClC,yBAAyB,UAAU,GAAG;QACtC,8BAA8B,UAAU,GAAG;QAC3C,+BAA+B,UAAU,GAAG;KAC7C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAC5C,CAAC"}
|
package/dist/shared/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core types for htpx
|
|
3
3
|
*/
|
|
4
|
+
export type InterceptionType = "modified" | "mocked";
|
|
4
5
|
export interface CapturedRequest {
|
|
5
6
|
id: string;
|
|
6
7
|
sessionId: string;
|
|
@@ -12,10 +13,36 @@ export interface CapturedRequest {
|
|
|
12
13
|
path: string;
|
|
13
14
|
requestHeaders: Record<string, string>;
|
|
14
15
|
requestBody?: Buffer;
|
|
16
|
+
requestBodyTruncated?: boolean;
|
|
15
17
|
responseStatus?: number;
|
|
16
18
|
responseHeaders?: Record<string, string>;
|
|
17
19
|
responseBody?: Buffer;
|
|
20
|
+
responseBodyTruncated?: boolean;
|
|
18
21
|
durationMs?: number;
|
|
22
|
+
interceptedBy?: string;
|
|
23
|
+
interceptionType?: InterceptionType;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Summary version of CapturedRequest for list views.
|
|
27
|
+
* Excludes body and header data to reduce transfer size.
|
|
28
|
+
*/
|
|
29
|
+
export interface CapturedRequestSummary {
|
|
30
|
+
id: string;
|
|
31
|
+
sessionId: string;
|
|
32
|
+
label?: string;
|
|
33
|
+
timestamp: number;
|
|
34
|
+
method: string;
|
|
35
|
+
url: string;
|
|
36
|
+
host: string;
|
|
37
|
+
path: string;
|
|
38
|
+
responseStatus?: number;
|
|
39
|
+
durationMs?: number;
|
|
40
|
+
/** Size of request body in bytes (without transferring the body itself) */
|
|
41
|
+
requestBodySize: number;
|
|
42
|
+
/** Size of response body in bytes (without transferring the body itself) */
|
|
43
|
+
responseBodySize: number;
|
|
44
|
+
interceptedBy?: string;
|
|
45
|
+
interceptionType?: InterceptionType;
|
|
19
46
|
}
|
|
20
47
|
export interface Session {
|
|
21
48
|
id: string;
|
|
@@ -29,5 +56,73 @@ export interface DaemonStatus {
|
|
|
29
56
|
sessionCount: number;
|
|
30
57
|
requestCount: number;
|
|
31
58
|
version: string;
|
|
59
|
+
interceptorCount?: number;
|
|
60
|
+
}
|
|
61
|
+
export interface RequestFilter {
|
|
62
|
+
methods?: string[];
|
|
63
|
+
statusRange?: string;
|
|
64
|
+
search?: string;
|
|
65
|
+
host?: string;
|
|
66
|
+
pathPrefix?: string;
|
|
67
|
+
since?: number;
|
|
68
|
+
before?: number;
|
|
69
|
+
headerName?: string;
|
|
70
|
+
headerValue?: string;
|
|
71
|
+
headerTarget?: "request" | "response" | "both";
|
|
72
|
+
interceptedBy?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Result from a JSON body query — a summary with the extracted value appended.
|
|
76
|
+
*/
|
|
77
|
+
export interface JsonQueryResult extends CapturedRequestSummary {
|
|
78
|
+
extractedValue: unknown;
|
|
79
|
+
}
|
|
80
|
+
export interface InterceptorRequest {
|
|
81
|
+
method: string;
|
|
82
|
+
url: string;
|
|
83
|
+
host: string;
|
|
84
|
+
path: string;
|
|
85
|
+
headers: Record<string, string>;
|
|
86
|
+
body?: Buffer;
|
|
87
|
+
}
|
|
88
|
+
export interface InterceptorResponse {
|
|
89
|
+
status: number;
|
|
90
|
+
headers?: Record<string, string>;
|
|
91
|
+
body?: string | Buffer;
|
|
92
|
+
}
|
|
93
|
+
export interface InterceptorContext {
|
|
94
|
+
request: Readonly<InterceptorRequest>;
|
|
95
|
+
forward: () => Promise<InterceptorResponse>;
|
|
96
|
+
htpx: HtpxClient;
|
|
97
|
+
log: (message: string) => void;
|
|
98
|
+
}
|
|
99
|
+
export interface Interceptor {
|
|
100
|
+
name?: string;
|
|
101
|
+
match?: (request: InterceptorRequest) => boolean | Promise<boolean>;
|
|
102
|
+
handler: (ctx: InterceptorContext) => Promise<InterceptorResponse | undefined | void>;
|
|
103
|
+
}
|
|
104
|
+
export interface HtpxClient {
|
|
105
|
+
countRequests(filter?: RequestFilter): Promise<number>;
|
|
106
|
+
listRequests(options?: {
|
|
107
|
+
filter?: RequestFilter;
|
|
108
|
+
limit?: number;
|
|
109
|
+
offset?: number;
|
|
110
|
+
}): Promise<CapturedRequestSummary[]>;
|
|
111
|
+
getRequest(id: string): Promise<CapturedRequest | null>;
|
|
112
|
+
searchBodies(options: {
|
|
113
|
+
query: string;
|
|
114
|
+
filter?: RequestFilter;
|
|
115
|
+
limit?: number;
|
|
116
|
+
}): Promise<CapturedRequestSummary[]>;
|
|
117
|
+
queryJsonBodies(options: {
|
|
118
|
+
jsonPath: string;
|
|
119
|
+
filter?: RequestFilter;
|
|
120
|
+
}): Promise<JsonQueryResult[]>;
|
|
121
|
+
}
|
|
122
|
+
export interface InterceptorInfo {
|
|
123
|
+
name: string;
|
|
124
|
+
hasMatch: boolean;
|
|
125
|
+
sourceFile: string;
|
|
126
|
+
error?: string;
|
|
32
127
|
}
|
|
33
128
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "htpx-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Terminal HTTP interception toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"htpx": "dist/cli/index.js"
|
|
9
9
|
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./dist/cli/index.js",
|
|
12
|
+
"./interceptors": {
|
|
13
|
+
"types": "./dist/interceptors.d.ts",
|
|
14
|
+
"default": "./dist/interceptors.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
10
17
|
"files": [
|
|
11
|
-
"dist"
|
|
18
|
+
"dist",
|
|
19
|
+
"skills"
|
|
12
20
|
],
|
|
21
|
+
"agents": {
|
|
22
|
+
"skills": [
|
|
23
|
+
{ "name": "htpx", "path": "./skills/htpx" }
|
|
24
|
+
]
|
|
25
|
+
},
|
|
13
26
|
"scripts": {
|
|
14
27
|
"build": "tsc",
|
|
15
28
|
"dev": "tsc --watch",
|
|
16
29
|
"start": "node dist/cli/index.js",
|
|
17
30
|
"test": "vitest run",
|
|
18
31
|
"test:watch": "vitest",
|
|
19
|
-
"test:unit": "vitest run --dir
|
|
32
|
+
"test:unit": "vitest run --dir src",
|
|
20
33
|
"test:int": "vitest run --dir tests/integration",
|
|
21
34
|
"lint": "eslint src tests",
|
|
22
35
|
"lint:fix": "eslint src tests --fix",
|
|
@@ -43,7 +56,7 @@
|
|
|
43
56
|
"terminal"
|
|
44
57
|
],
|
|
45
58
|
"author": "",
|
|
46
|
-
"license": "
|
|
59
|
+
"license": "AGPL-3.0-or-later",
|
|
47
60
|
"repository": {
|
|
48
61
|
"type": "git",
|
|
49
62
|
"url": "git+https://github.com/mtford90/htpx.git"
|
|
@@ -52,17 +65,23 @@
|
|
|
52
65
|
"url": "https://github.com/mtford90/htpx/issues"
|
|
53
66
|
},
|
|
54
67
|
"homepage": "https://github.com/mtford90/htpx#readme",
|
|
68
|
+
"packageManager": "pnpm@10.13.1",
|
|
55
69
|
"engines": {
|
|
56
70
|
"node": ">=20"
|
|
57
71
|
},
|
|
58
72
|
"dependencies": {
|
|
73
|
+
"@ink-tools/ink-mouse": "^2.1.0",
|
|
74
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
59
75
|
"better-sqlite3": "^12.6.2",
|
|
76
|
+
"cli-highlight": "^2.1.11",
|
|
60
77
|
"commander": "^14.0.3",
|
|
61
78
|
"ink": "^6.6.0",
|
|
62
79
|
"ink-use-stdout-dimensions": "^1.0.5",
|
|
80
|
+
"jiti": "^2.6.1",
|
|
63
81
|
"mockttp": "^4.2.1",
|
|
64
82
|
"react": "^19.2.4",
|
|
65
|
-
"uuid": "^13.0.0"
|
|
83
|
+
"uuid": "^13.0.0",
|
|
84
|
+
"zod": "^4.3.6"
|
|
66
85
|
},
|
|
67
86
|
"devDependencies": {
|
|
68
87
|
"@eslint/js": "^9.39.2",
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# /htpx
|
|
2
|
+
|
|
3
|
+
Use htpx to inspect, filter, and intercept HTTP traffic. Activate when htpx MCP tools are available or when the user mentions HTTP traffic, API debugging, request interception, or mocking.
|
|
4
|
+
|
|
5
|
+
## Installation & Setup
|
|
6
|
+
|
|
7
|
+
If htpx is not installed or the daemon is not running, you can set it up:
|
|
8
|
+
|
|
9
|
+
1. **Install**: `npm install -g htpx-cli`
|
|
10
|
+
2. **Shell setup** (one-time): Add `eval "$(htpx init)"` to the user's shell config (`~/.zshrc` or `~/.bashrc`), then source it or ask them to restart their shell
|
|
11
|
+
3. **Start intercepting**: `htpx on` in the project directory
|
|
12
|
+
4. **MCP config**: Add htpx to the MCP configuration:
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"htpx": {
|
|
17
|
+
"command": "htpx",
|
|
18
|
+
"args": ["mcp"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
After setup, call `htpx_get_status` to verify the daemon is running.
|
|
25
|
+
|
|
26
|
+
## When to Use htpx
|
|
27
|
+
|
|
28
|
+
- **Debugging failing API calls** -- filter by status code, inspect headers and response bodies
|
|
29
|
+
- **Understanding traffic patterns** -- count requests, group by host/path/method
|
|
30
|
+
- **Writing mocks/interceptors** -- capture real traffic as a template, write TypeScript interceptors
|
|
31
|
+
- **Investigating auth issues** -- filter by `authorization` header, inspect tokens
|
|
32
|
+
- **Performance analysis** -- check response times (`durationMs`), body sizes
|
|
33
|
+
|
|
34
|
+
## Preflight
|
|
35
|
+
|
|
36
|
+
Always call `htpx_get_status` first to confirm the daemon is running. If it is not running, try to start it by running `htpx on` in the project directory. If htpx is not installed, follow the Installation & Setup steps above.
|
|
37
|
+
|
|
38
|
+
## MCP Tool Reference
|
|
39
|
+
|
|
40
|
+
| Tool | Purpose | Key Parameters |
|
|
41
|
+
|------|---------|----------------|
|
|
42
|
+
| `htpx_get_status` | Check daemon is running, get proxy port and request count | -- |
|
|
43
|
+
| `htpx_list_requests` | Browse/filter captured traffic (returns summaries) | `method`, `status_range`, `search`, `host`, `path`, `header_name`, `header_value`, `header_target`, `intercepted_by`, `since`, `before`, `limit`, `offset`, `format` |
|
|
44
|
+
| `htpx_get_request` | Full request details -- headers, bodies, timing | `id` (single or comma-separated IDs), `format` |
|
|
45
|
+
| `htpx_search_bodies` | Full-text search in request/response bodies | `query`, plus all filter params |
|
|
46
|
+
| `htpx_query_json` | Extract JSON values with JSONPath (SQLite `json_extract`) | `json_path`, `value`, `target` (`request`/`response`/`both`), plus filters |
|
|
47
|
+
| `htpx_count_requests` | Count matching requests | All filter params, `format` |
|
|
48
|
+
| `htpx_clear_requests` | Delete all captured traffic (irreversible) | -- |
|
|
49
|
+
| `htpx_list_sessions` | List active proxy sessions | -- |
|
|
50
|
+
| `htpx_list_interceptors` | List loaded interceptors with status/errors | `format` |
|
|
51
|
+
| `htpx_reload_interceptors` | Hot-reload interceptors from disk | `format` |
|
|
52
|
+
|
|
53
|
+
### Output Formats
|
|
54
|
+
|
|
55
|
+
All query tools accept `format`:
|
|
56
|
+
- `"text"` (default) -- human-readable markdown summaries
|
|
57
|
+
- `"json"` -- structured JSON for programmatic processing
|
|
58
|
+
|
|
59
|
+
Use `"json"` when you need to process results (e.g. extract IDs, compare values). Use `"text"` when presenting to the user.
|
|
60
|
+
|
|
61
|
+
## Common Filter Patterns
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
status_range: "5xx" # Server errors
|
|
65
|
+
status_range: "4xx" # Client errors
|
|
66
|
+
status_range: "401" # Exact status code
|
|
67
|
+
status_range: "500-503" # Numeric range
|
|
68
|
+
method: "POST,PUT" # Mutation requests only
|
|
69
|
+
host: ".api.example.com" # Suffix match (note leading dot)
|
|
70
|
+
host: "api.example.com" # Exact match
|
|
71
|
+
path: "/api/v2" # Path prefix match
|
|
72
|
+
search: "api/users" # URL substring match
|
|
73
|
+
header_name: "authorization" # Requests with this header
|
|
74
|
+
header_name: "content-type", header_value: "application/json" # Exact header match
|
|
75
|
+
header_target: "request" # Only search request headers
|
|
76
|
+
intercepted_by: "my-mock" # Requests handled by a specific interceptor
|
|
77
|
+
since: "2024-01-15T10:30:00Z" # Time-bounded queries
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Filters can be combined freely. All are optional.
|
|
81
|
+
|
|
82
|
+
## Workflow Patterns
|
|
83
|
+
|
|
84
|
+
### Pattern 1: Investigate a Bug
|
|
85
|
+
|
|
86
|
+
1. `htpx_list_requests` with relevant filters (status code, host, path) to find the request
|
|
87
|
+
2. `htpx_get_request` with the ID to inspect full headers, bodies, timing
|
|
88
|
+
3. If searching for specific content in bodies, use `htpx_search_bodies`
|
|
89
|
+
|
|
90
|
+
### Pattern 2: Write a Mock Interceptor
|
|
91
|
+
|
|
92
|
+
1. `htpx_list_requests` to understand the traffic pattern you want to mock
|
|
93
|
+
2. `htpx_get_request` to capture a real response as a template
|
|
94
|
+
3. Write a `.ts` file to `.htpx/interceptors/` (see interceptor patterns below)
|
|
95
|
+
4. `htpx_reload_interceptors` to activate
|
|
96
|
+
5. `htpx_list_interceptors` to verify it loaded without errors
|
|
97
|
+
|
|
98
|
+
### Pattern 3: Analyse API Usage
|
|
99
|
+
|
|
100
|
+
1. `htpx_count_requests` with various filters to understand volume
|
|
101
|
+
2. `htpx_query_json` to extract specific values from JSON bodies
|
|
102
|
+
3. `htpx_list_requests` with `format: "json"` for structured analysis
|
|
103
|
+
|
|
104
|
+
### Pattern 4: Debug Auth Issues
|
|
105
|
+
|
|
106
|
+
1. `htpx_list_requests` with `header_name: "authorization", header_target: "request"` to find authed requests
|
|
107
|
+
2. `htpx_list_requests` with `status_range: "401"` to find failures
|
|
108
|
+
3. `htpx_get_request` to compare auth headers between successful and failed requests
|
|
109
|
+
|
|
110
|
+
## Writing Interceptors
|
|
111
|
+
|
|
112
|
+
Interceptor files are TypeScript files placed in `.htpx/interceptors/`. Each file exports a default `Interceptor` object.
|
|
113
|
+
|
|
114
|
+
### Mock -- Return a Canned Response
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import type { Interceptor } from "htpx-cli/interceptors";
|
|
118
|
+
|
|
119
|
+
export default {
|
|
120
|
+
name: "mock-users",
|
|
121
|
+
match: (req) => req.path === "/api/users",
|
|
122
|
+
handler: async () => ({
|
|
123
|
+
status: 200,
|
|
124
|
+
headers: { "content-type": "application/json" },
|
|
125
|
+
body: JSON.stringify([{ id: 1, name: "Alice" }]),
|
|
126
|
+
}),
|
|
127
|
+
} satisfies Interceptor;
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Do not call `ctx.forward()` -- the request never reaches upstream. This is recorded as `interceptionType: "mocked"`.
|
|
131
|
+
|
|
132
|
+
### Modify -- Forward, Then Alter the Response
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import type { Interceptor } from "htpx-cli/interceptors";
|
|
136
|
+
|
|
137
|
+
export default {
|
|
138
|
+
name: "inject-header",
|
|
139
|
+
match: (req) => req.host.includes("example.com"),
|
|
140
|
+
handler: async (ctx) => {
|
|
141
|
+
const response = await ctx.forward();
|
|
142
|
+
return { ...response, headers: { ...response.headers, "x-debug": "htpx" } };
|
|
143
|
+
},
|
|
144
|
+
} satisfies Interceptor;
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Calls `ctx.forward()` but returns a modified response. Recorded as `interceptionType: "modified"`.
|
|
148
|
+
|
|
149
|
+
### Observe -- Log Without Altering
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import type { Interceptor } from "htpx-cli/interceptors";
|
|
153
|
+
|
|
154
|
+
export default {
|
|
155
|
+
name: "log-api",
|
|
156
|
+
match: (req) => req.path.startsWith("/api/"),
|
|
157
|
+
handler: async (ctx) => {
|
|
158
|
+
ctx.log(`${ctx.request.method} ${ctx.request.url}`);
|
|
159
|
+
const response = await ctx.forward();
|
|
160
|
+
ctx.log(` -> ${response.status}`);
|
|
161
|
+
return response;
|
|
162
|
+
},
|
|
163
|
+
} satisfies Interceptor;
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Calls `ctx.forward()` and returns the response unchanged. Useful for debugging.
|
|
167
|
+
|
|
168
|
+
### InterceptorContext Properties
|
|
169
|
+
|
|
170
|
+
| Property | Type | Description |
|
|
171
|
+
|----------|------|-------------|
|
|
172
|
+
| `ctx.request` | `Readonly<InterceptorRequest>` | The incoming request (read-only) |
|
|
173
|
+
| `ctx.forward()` | `() => Promise<InterceptorResponse>` | Forward to upstream server, returns response |
|
|
174
|
+
| `ctx.log(msg)` | `(message: string) => void` | Write to `.htpx/htpx.log` (`console.log` is `/dev/null` in daemon) |
|
|
175
|
+
| `ctx.htpx` | `HtpxClient` | Full query API (see below) |
|
|
176
|
+
|
|
177
|
+
### InterceptorRequest Shape
|
|
178
|
+
|
|
179
|
+
| Property | Type |
|
|
180
|
+
|----------|------|
|
|
181
|
+
| `method` | `string` |
|
|
182
|
+
| `url` | `string` |
|
|
183
|
+
| `host` | `string` |
|
|
184
|
+
| `path` | `string` |
|
|
185
|
+
| `headers` | `Record<string, string>` |
|
|
186
|
+
| `body` | `Buffer \| undefined` |
|
|
187
|
+
|
|
188
|
+
### InterceptorResponse Shape
|
|
189
|
+
|
|
190
|
+
| Property | Type |
|
|
191
|
+
|----------|------|
|
|
192
|
+
| `status` | `number` |
|
|
193
|
+
| `headers` | `Record<string, string> \| undefined` |
|
|
194
|
+
| `body` | `string \| Buffer \| undefined` |
|
|
195
|
+
|
|
196
|
+
### HtpxClient API (available as `ctx.htpx`)
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
ctx.htpx.countRequests(filter?) // Promise<number>
|
|
200
|
+
ctx.htpx.listRequests({ filter, limit, offset }) // Promise<CapturedRequestSummary[]>
|
|
201
|
+
ctx.htpx.getRequest(id) // Promise<CapturedRequest | null>
|
|
202
|
+
ctx.htpx.searchBodies({ query, filter, limit }) // Promise<CapturedRequestSummary[]>
|
|
203
|
+
ctx.htpx.queryJsonBodies({ jsonPath, filter }) // Promise<JsonQueryResult[]>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
This allows interceptors to make decisions based on previously captured traffic.
|
|
207
|
+
|
|
208
|
+
### Interceptor Rules
|
|
209
|
+
|
|
210
|
+
- Any `.ts` file in `.htpx/interceptors/` is loaded as an interceptor
|
|
211
|
+
- Files are loaded alphabetically; **first matching interceptor wins**
|
|
212
|
+
- `match` is optional -- omit it to match all requests
|
|
213
|
+
- `name` is optional but strongly recommended (used in `intercepted_by` filter)
|
|
214
|
+
- Use `satisfies Interceptor` for full type checking and intellisense
|
|
215
|
+
- Handler timeout: 30 seconds. Match timeout: 5 seconds.
|
|
216
|
+
- Errors in handlers result in graceful pass-through -- never crashes the proxy
|
|
217
|
+
- `ctx.log()` writes to `.htpx/htpx.log` (since `console.log` goes nowhere in the daemon)
|
|
218
|
+
- Hot-reload on file changes, or run `htpx interceptors reload` / `htpx_reload_interceptors` / `htpx daemon restart`
|
|
219
|
+
|
|
220
|
+
## Tips
|
|
221
|
+
|
|
222
|
+
- After writing an interceptor, always `htpx_reload_interceptors` then `htpx_list_interceptors` to verify it loaded without errors
|
|
223
|
+
- The `search` filter matches URL substrings -- useful for quick filtering when you do not know the exact host or path
|
|
224
|
+
- `htpx_query_json` uses SQLite `json_extract` syntax (e.g. `$.user.name`, `$.items[0].id`)
|
|
225
|
+
- Use `limit` and `offset` for pagination when there are many results (default limit: 50, max: 500)
|
|
226
|
+
- `htpx_get_request` accepts comma-separated IDs for batch fetching (e.g. `id: "id1,id2,id3"`)
|
|
227
|
+
- Host suffix matching requires a leading dot: `.example.com` matches `api.example.com` and `www.example.com`
|
|
228
|
+
- Time filters use ISO 8601 format: `since: "2024-01-15T10:30:00Z"`
|