browser-debugger-cli 0.14.0 → 0.16.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/.claude/skills/bdg/SKILL.md +3 -2
- package/dist/cdp/methodTarget.d.ts +92 -0
- package/dist/cdp/methodTarget.js +159 -0
- package/dist/cdp/protocol.d.ts +16 -1
- package/dist/cdp/protocol.js +21 -0
- package/dist/cdp/schema.d.ts +55 -1
- package/dist/cdp/schema.js +134 -25
- package/dist/cdp/types.d.ts +3 -1
- package/dist/commands/cdp.d.ts +38 -1
- package/dist/commands/cdp.js +201 -133
- package/dist/commands/cleanup.js +21 -4
- package/dist/commands/dom/eval.d.ts +2 -1
- package/dist/commands/dom/eval.js +6 -21
- package/dist/commands/dom/formInteraction.js +8 -4
- package/dist/commands/dom/helpers/evalResult.d.ts +36 -0
- package/dist/commands/dom/helpers/evalResult.js +59 -0
- package/dist/commands/dom/helpers/index.d.ts +4 -4
- package/dist/commands/dom/helpers/index.js +3 -3
- package/dist/commands/dom/helpers/query.d.ts +2 -2
- package/dist/commands/dom/helpers/query.js +2 -2
- package/dist/commands/dom/helpers/screenshot.d.ts +21 -26
- package/dist/commands/dom/helpers/screenshot.js +50 -668
- package/dist/commands/dom/screenshot.js +56 -36
- package/dist/commands/helpJson.d.ts +1 -1
- package/dist/commands/helpJson.js +3 -3
- package/dist/commands/helpTopic.js +10 -4
- package/dist/commands/network/har.js +18 -14
- package/dist/commands/optionBehaviors.js +24 -9
- package/dist/commands/shared/CommandRunner.d.ts +5 -0
- package/dist/commands/shared/CommandRunner.js +18 -3
- package/dist/commands/shared/interrupt.d.ts +40 -0
- package/dist/commands/shared/interrupt.js +73 -0
- package/dist/commands/shared/optionTypes.d.ts +3 -0
- package/dist/commands/shared/outputFile.d.ts +2 -1
- package/dist/commands/shared/outputFile.js +7 -4
- package/dist/commands/shared/startHelpers.d.ts +26 -3
- package/dist/commands/shared/startHelpers.js +145 -23
- package/dist/commands/status.js +3 -1
- package/dist/commands/stop.js +2 -1
- package/dist/commands/types.d.ts +5 -0
- package/dist/connection/cdp.js +1 -16
- package/dist/connection/chromeIdentity.d.ts +24 -5
- package/dist/connection/chromeIdentity.js +53 -22
- package/dist/connection/launcher/flagsBuilder.d.ts +46 -0
- package/dist/connection/launcher/flagsBuilder.js +107 -23
- package/dist/connection/launcher.d.ts +35 -2
- package/dist/connection/launcher.js +99 -12
- package/dist/connection/typed-cdp.d.ts +3 -2
- package/dist/constants.d.ts +3 -5
- package/dist/constants.js +3 -5
- package/dist/daemon/SessionController.d.ts +10 -5
- package/dist/daemon/SessionController.js +15 -8
- package/dist/daemon/ipcServer.js +1 -1
- package/dist/daemon/launcher.d.ts +22 -3
- package/dist/daemon/launcher.js +45 -8
- package/dist/daemon/session/Session.d.ts +5 -1
- package/dist/daemon/session/Session.js +9 -8
- package/dist/daemon/session/TelemetryStore.d.ts +5 -0
- package/dist/daemon/session/TelemetryStore.js +4 -0
- package/dist/daemon/session/captureGate.d.ts +59 -0
- package/dist/daemon/session/captureGate.js +96 -0
- package/dist/daemon/session/chromeConnection.d.ts +16 -1
- package/dist/daemon/session/chromeConnection.js +34 -4
- package/dist/daemon/session/collectors.d.ts +15 -0
- package/dist/daemon/session/collectors.js +39 -2
- package/dist/daemon/session/commandRegistry.d.ts +14 -1
- package/dist/daemon/session/commandRegistry.js +48 -13
- package/dist/daemon/session/downloads.d.ts +32 -0
- package/dist/daemon/session/downloads.js +96 -0
- package/dist/daemon/session/interactions.d.ts +3 -2
- package/dist/daemon/session/interactions.js +7 -2
- package/dist/daemon/session/plugins.js +6 -0
- package/dist/daemon.js +18520 -17014
- package/dist/errors/CommandError.d.ts +2 -0
- package/dist/errors/issues.d.ts +1 -1
- package/dist/errors/messages.d.ts +81 -0
- package/dist/errors/messages.js +198 -6
- package/dist/index.js +1446 -1078
- package/dist/ipc/client.d.ts +20 -2
- package/dist/ipc/client.js +32 -6
- package/dist/ipc/protocol/commands.d.ts +36 -2
- package/dist/ipc/protocol/commands.js +1 -0
- package/dist/ipc/protocol/domTypes.d.ts +24 -1
- package/dist/ipc/session/queries.d.ts +3 -0
- package/dist/ipc/session/types.d.ts +5 -0
- package/dist/ipc/transport/IPCError.d.ts +9 -0
- package/dist/ipc/transport/IPCError.js +12 -0
- package/dist/ipc/transport/errors.d.ts +2 -1
- package/dist/ipc/transport/errors.js +4 -1
- package/dist/ipc/transport/index.d.ts +10 -2
- package/dist/ipc/transport/index.js +29 -4
- package/dist/runtime/dom/actionEffects.d.ts +48 -9
- package/dist/runtime/dom/actionEffects.js +269 -34
- package/dist/runtime/dom/actionEffectsScripts.d.ts +45 -0
- package/dist/runtime/dom/actionEffectsScripts.js +101 -2
- package/dist/runtime/dom/captureArea.d.ts +35 -0
- package/dist/runtime/dom/captureArea.js +203 -0
- package/dist/runtime/dom/elementInfo.d.ts +13 -4
- package/dist/runtime/dom/elementInfo.js +12 -3
- package/dist/runtime/dom/evalHelpers.d.ts +24 -4
- package/dist/runtime/dom/evalHelpers.js +40 -12
- package/dist/runtime/dom/formDiscovery.d.ts +1 -1
- package/dist/runtime/dom/frames.d.ts +2 -1
- package/dist/runtime/dom/frames.js +3 -1
- package/dist/runtime/page/bdgWorld.d.ts +9 -0
- package/dist/runtime/page/bdgWorld.js +11 -0
- package/dist/runtime/page/captureEmulation.d.ts +119 -0
- package/dist/runtime/page/captureEmulation.js +189 -0
- package/dist/runtime/page/captureScroll.d.ts +24 -0
- package/dist/runtime/page/captureScroll.js +124 -0
- package/dist/runtime/page/emulation.js +6 -5
- package/dist/runtime/page/screenshot.d.ts +41 -0
- package/dist/runtime/page/screenshot.js +394 -0
- package/dist/runtime/page/userAgent.d.ts +86 -2
- package/dist/runtime/page/userAgent.js +154 -33
- package/dist/session/paths.d.ts +52 -3
- package/dist/session/paths.js +179 -7
- package/dist/session/portClaims.d.ts +0 -8
- package/dist/session/portClaims.js +1 -22
- package/dist/session/sessionList.d.ts +5 -1
- package/dist/session/sessionList.js +5 -1
- package/dist/telemetry/downloads.d.ts +127 -0
- package/dist/telemetry/downloads.js +265 -0
- package/dist/telemetry/har/builder.d.ts +12 -1
- package/dist/telemetry/har/builder.js +32 -9
- package/dist/telemetry/har/sanitize.d.ts +28 -0
- package/dist/telemetry/har/sanitize.js +184 -0
- package/dist/telemetry/har/sanitizeBody.d.ts +78 -0
- package/dist/telemetry/har/sanitizeBody.js +541 -0
- package/dist/telemetry/har/types.d.ts +2 -0
- package/dist/telemetry/network.d.ts +4 -4
- package/dist/telemetry/network.js +38 -4
- package/dist/telemetry/networkRetention.d.ts +35 -14
- package/dist/telemetry/networkRetention.js +62 -26
- package/dist/types.d.ts +9 -14
- package/dist/ui/OutputBuilder.d.ts +3 -2
- package/dist/ui/OutputBuilder.js +4 -3
- package/dist/ui/formatters/cdp.d.ts +32 -9
- package/dist/ui/formatters/cdp.js +77 -6
- package/dist/ui/formatters/details.js +7 -15
- package/dist/ui/formatters/preview.d.ts +2 -0
- package/dist/ui/formatters/preview.js +7 -1
- package/dist/ui/formatters/sessions.d.ts +3 -2
- package/dist/ui/formatters/sessions.js +10 -3
- package/dist/ui/formatters/status.js +6 -1
- package/dist/ui/formatting.d.ts +7 -0
- package/dist/ui/formatting.js +13 -0
- package/dist/ui/logging/logger.d.ts +1 -1
- package/dist/ui/messages/chrome.d.ts +27 -6
- package/dist/ui/messages/chrome.js +78 -12
- package/dist/ui/messages/commands.d.ts +71 -3
- package/dist/ui/messages/commands.js +98 -3
- package/dist/ui/messages/networkMessages.d.ts +50 -5
- package/dist/ui/messages/networkMessages.js +50 -6
- package/dist/ui/messages/session.d.ts +8 -0
- package/dist/ui/messages/session.js +10 -0
- package/dist/utils/async.d.ts +3 -2
- package/dist/utils/async.js +16 -3
- package/dist/utils/atomicFile.d.ts +2 -1
- package/dist/utils/atomicFile.js +5 -2
- package/dist/utils/directories.d.ts +41 -0
- package/dist/utils/directories.js +48 -0
- package/dist/utils/http.d.ts +11 -4
- package/dist/utils/http.js +5 -3
- package/package.json +18 -4
- /package/dist/{commands/dom → runtime/page}/screenshotResize.d.ts +0 -0
- /package/dist/{commands/dom → runtime/page}/screenshotResize.js +0 -0
|
@@ -15,18 +15,41 @@ function megabytes(bytes) {
|
|
|
15
15
|
return `${Math.round(bytes / (1024 * 1024))} MB`;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* Why a stored response body was replaced by a placeholder
|
|
19
|
-
* `bdg details network <id>` as `
|
|
18
|
+
* Why a stored request or response body was replaced by a placeholder
|
|
19
|
+
* (shown by `bdg details network <id>` as `requestBodyNotCaptured` or
|
|
20
|
+
* `bodyNotCaptured`).
|
|
20
21
|
*
|
|
21
22
|
* @param budgetBytes - Total body budget of the session
|
|
22
|
-
* @returns e.g. `evicted: total body budget (bdg keeps the newest 100 MB of response bodies)`
|
|
23
|
+
* @returns e.g. `evicted: total body budget (bdg keeps the newest 100 MB of request and response bodies)`
|
|
23
24
|
*/
|
|
24
25
|
export function bodyEvictedReason(budgetBytes) {
|
|
25
|
-
return `evicted: total body budget (bdg keeps the newest ${megabytes(budgetBytes)} of response bodies)`;
|
|
26
|
+
return `evicted: total body budget (bdg keeps the newest ${megabytes(budgetBytes)} of request and response bodies)`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Why a response body is missing when Chrome no longer had it
|
|
30
|
+
* (`Network.getResponseBody` failed with "No resource with given identifier
|
|
31
|
+
* found" or "No data found for resource with given identifier"), shown by
|
|
32
|
+
* `bdg details network <id>` as `bodyNotCaptured` and in the HAR as the
|
|
33
|
+
* content comment.
|
|
34
|
+
*
|
|
35
|
+
* @returns Reason text
|
|
36
|
+
*/
|
|
37
|
+
export function bodyGoneReason() {
|
|
38
|
+
return 'Chrome no longer had the body (its network buffer evicted it, or the request was cancelled)';
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Why a response body is missing when `Network.getResponseBody` failed for
|
|
42
|
+
* another reason (a CDP timeout, the connection closing mid-fetch).
|
|
43
|
+
*
|
|
44
|
+
* @param errorMessage - The error Chrome or the connection gave
|
|
45
|
+
* @returns e.g. `Chrome did not return the body: CDP command timeout`
|
|
46
|
+
*/
|
|
47
|
+
export function bodyFetchFailedReason(errorMessage) {
|
|
48
|
+
return `Chrome did not return the body: ${errorMessage}`;
|
|
26
49
|
}
|
|
27
50
|
/**
|
|
28
51
|
* Note that the session dropped its oldest requests or evicted its oldest
|
|
29
|
-
* response bodies at its limits.
|
|
52
|
+
* request and response bodies at its limits.
|
|
30
53
|
*
|
|
31
54
|
* @param counts - Requests dropped and bodies evicted
|
|
32
55
|
* @returns e.g. `⚠ 2000 older network requests were dropped: bdg keeps the newest 10000`;
|
|
@@ -35,7 +58,7 @@ export function bodyEvictedReason(budgetBytes) {
|
|
|
35
58
|
export function networkEvictedNote(counts) {
|
|
36
59
|
const { requestsDropped, bodiesEvicted } = counts;
|
|
37
60
|
const requests = pluralize(requestsDropped, 'older network request');
|
|
38
|
-
const bodies = pluralize(bodiesEvicted, 'older response body', 'older response bodies');
|
|
61
|
+
const bodies = pluralize(bodiesEvicted, 'older request/response body', 'older request/response bodies');
|
|
39
62
|
const budget = megabytes(MAX_TOTAL_BODY_BYTES);
|
|
40
63
|
if (requestsDropped > 0 && bodiesEvicted > 0) {
|
|
41
64
|
return `⚠ ${requests} dropped, ${bodies} evicted: bdg keeps the newest ${MAX_NETWORK_REQUESTS} requests and ${budget} of bodies`;
|
|
@@ -82,4 +105,25 @@ export function headerRepeatedNote(count) {
|
|
|
82
105
|
export function localProxyNote() {
|
|
83
106
|
return '(loopback; likely a local proxy)';
|
|
84
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* HAR log comment of a sanitized export.
|
|
110
|
+
*
|
|
111
|
+
* @returns Comment naming what was redacted and the flag that keeps it
|
|
112
|
+
*/
|
|
113
|
+
export function harSanitizedComment() {
|
|
114
|
+
return 'Sanitized by bdg: values of auth, cookie, API key, token and session headers, cookies, credential query parameters in URLs, password/token/secret fields of JSON and form request and response bodies and WebSocket messages (also truncated JSON, JSON encoded in strings, socket.io, SockJS, server-sent events, NDJSON, and base64 bodies and binary messages that are UTF-8 text), and any JWT (also inside longer strings and form values) are [redacted] in place (by name, so some harmless values are too); everything else stays byte for byte. Not sanitized: other binary data, text that is not JSON or a form, and non-JSON syntax (single quotes, unquoted keys, JSONP, bare values with spaces); a body that could not be sanitized is [redacted] whole. Export with --include-sensitive to keep everything';
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Success message of `bdg network har`.
|
|
118
|
+
*
|
|
119
|
+
* @param result - Export result
|
|
120
|
+
* @returns e.g. `✓ Exported 4 requests to /tmp/out.har` and a line on sanitization
|
|
121
|
+
*/
|
|
122
|
+
export function harExportedMessage(result) {
|
|
123
|
+
const filterNote = result.filtered ? ' (filtered)' : '';
|
|
124
|
+
const note = result.sanitized
|
|
125
|
+
? 'Credentials sanitized (auth/cookie/API key/token headers, cookies, URL tokens, password and token fields of bodies and WebSocket messages are [redacted]); --include-sensitive keeps them'
|
|
126
|
+
: '⚠ Includes credentials (--include-sensitive): share this file with care';
|
|
127
|
+
return `✓ Exported ${result.entries} requests${filterNote} to ${result.file}\n ${note}`;
|
|
128
|
+
}
|
|
85
129
|
//# sourceMappingURL=networkMessages.js.map
|
|
@@ -88,6 +88,14 @@ export declare function endedSessionText(label: string, end: {
|
|
|
88
88
|
reason: string;
|
|
89
89
|
endedAt: number;
|
|
90
90
|
}): string;
|
|
91
|
+
/**
|
|
92
|
+
* A session whose directory is not safe to use, for `bdg sessions`.
|
|
93
|
+
*
|
|
94
|
+
* @param label - Session name as listed
|
|
95
|
+
* @param why - Untrusted directory and why
|
|
96
|
+
* @returns One line
|
|
97
|
+
*/
|
|
98
|
+
export declare function untrustedSessionText(label: string, why: string): string;
|
|
91
99
|
/**
|
|
92
100
|
* Note after a failed start or a stop whose daemon had not exited when bdg stopped waiting.
|
|
93
101
|
*
|
|
@@ -101,6 +101,16 @@ export function lastSessionEndText(end) {
|
|
|
101
101
|
export function endedSessionText(label, end) {
|
|
102
102
|
return `${label} ended ${sessionEndText(end)}`;
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* A session whose directory is not safe to use, for `bdg sessions`.
|
|
106
|
+
*
|
|
107
|
+
* @param label - Session name as listed
|
|
108
|
+
* @param why - Untrusted directory and why
|
|
109
|
+
* @returns One line
|
|
110
|
+
*/
|
|
111
|
+
export function untrustedSessionText(label, why) {
|
|
112
|
+
return `${label}: ${why}`;
|
|
113
|
+
}
|
|
104
114
|
/**
|
|
105
115
|
* When and why a session ended without `bdg stop`.
|
|
106
116
|
*
|
package/dist/utils/async.d.ts
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* Async utilities for common patterns.
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
* Delay execution for a specified duration.
|
|
5
|
+
* Delay execution for a specified duration, ending early when `signal` aborts.
|
|
6
6
|
*
|
|
7
7
|
* @param ms - Milliseconds to delay
|
|
8
|
+
* @param signal - Optional abort signal (the delay resolves, not rejects, on abort)
|
|
8
9
|
*/
|
|
9
|
-
export declare function delay(ms: number): Promise<void>;
|
|
10
|
+
export declare function delay(ms: number, signal?: AbortSignal): Promise<void>;
|
|
10
11
|
/**
|
|
11
12
|
* Wait for a promise, giving up after a time; the timer is cleared either way.
|
|
12
13
|
*
|
package/dist/utils/async.js
CHANGED
|
@@ -2,12 +2,25 @@
|
|
|
2
2
|
* Async utilities for common patterns.
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
* Delay execution for a specified duration.
|
|
5
|
+
* Delay execution for a specified duration, ending early when `signal` aborts.
|
|
6
6
|
*
|
|
7
7
|
* @param ms - Milliseconds to delay
|
|
8
|
+
* @param signal - Optional abort signal (the delay resolves, not rejects, on abort)
|
|
8
9
|
*/
|
|
9
|
-
export function delay(ms) {
|
|
10
|
-
return new Promise((resolve) =>
|
|
10
|
+
export function delay(ms, signal) {
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
if (signal?.aborted) {
|
|
13
|
+
resolve();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const done = () => {
|
|
17
|
+
clearTimeout(timer);
|
|
18
|
+
signal?.removeEventListener('abort', done);
|
|
19
|
+
resolve();
|
|
20
|
+
};
|
|
21
|
+
const timer = setTimeout(done, ms);
|
|
22
|
+
signal?.addEventListener('abort', done, { once: true });
|
|
23
|
+
});
|
|
11
24
|
}
|
|
12
25
|
/**
|
|
13
26
|
* Wait for a promise, giving up after a time; the timer is cleared either way.
|
|
@@ -38,12 +38,13 @@ export declare class AtomicFileWriter {
|
|
|
38
38
|
*
|
|
39
39
|
* @param filePath - Target file path
|
|
40
40
|
* @param data - Data to write
|
|
41
|
-
* @param options - Write options
|
|
41
|
+
* @param options - Write options (`mode`: permissions of the new file, less the umask)
|
|
42
42
|
* @returns Promise that resolves when write completes
|
|
43
43
|
* @throws Error if write operation fails
|
|
44
44
|
*/
|
|
45
45
|
static writeAsync(filePath: string, data: string, options?: {
|
|
46
46
|
encoding?: BufferEncoding;
|
|
47
|
+
mode?: number;
|
|
47
48
|
}): Promise<void>;
|
|
48
49
|
/**
|
|
49
50
|
* Write binary data (Buffer) to a file atomically (asynchronous).
|
package/dist/utils/atomicFile.js
CHANGED
|
@@ -59,14 +59,17 @@ export class AtomicFileWriter {
|
|
|
59
59
|
*
|
|
60
60
|
* @param filePath - Target file path
|
|
61
61
|
* @param data - Data to write
|
|
62
|
-
* @param options - Write options
|
|
62
|
+
* @param options - Write options (`mode`: permissions of the new file, less the umask)
|
|
63
63
|
* @returns Promise that resolves when write completes
|
|
64
64
|
* @throws Error if write operation fails
|
|
65
65
|
*/
|
|
66
66
|
static async writeAsync(filePath, data, options = {}) {
|
|
67
67
|
const tmpPath = this.getTempPath(filePath);
|
|
68
68
|
try {
|
|
69
|
-
await fs.promises.writeFile(tmpPath, data, {
|
|
69
|
+
await fs.promises.writeFile(tmpPath, data, {
|
|
70
|
+
encoding: options.encoding ?? 'utf-8',
|
|
71
|
+
...(options.mode !== undefined && { mode: options.mode }),
|
|
72
|
+
});
|
|
70
73
|
await fs.promises.rename(tmpPath, filePath);
|
|
71
74
|
}
|
|
72
75
|
catch (error) {
|
|
@@ -31,4 +31,45 @@ export declare function directoryProblem(dir: string): DirectoryProblem | null;
|
|
|
31
31
|
* file on the path), `EACCES` (not writable), or the `mkdir` error
|
|
32
32
|
*/
|
|
33
33
|
export declare function makeDirectory(dir: string, mode?: number): void;
|
|
34
|
+
/**
|
|
35
|
+
* Kind of untrusted directory: a symlink, not a directory, another user's,
|
|
36
|
+
* a shared sticky directory such as `/tmp` (others may create entries in
|
|
37
|
+
* it), or writable by others
|
|
38
|
+
*/
|
|
39
|
+
export type DirTrustKind = 'symlink' | 'not-directory' | 'owner' | 'shared' | 'writable';
|
|
40
|
+
/** Why a directory cannot be trusted */
|
|
41
|
+
export interface DirTrustProblem {
|
|
42
|
+
/** e.g. `owned by uid 1001`, `writable by others (mode 777)` */
|
|
43
|
+
reason: string;
|
|
44
|
+
kind: DirTrustKind;
|
|
45
|
+
}
|
|
46
|
+
/** Options of {@link dirTrustProblem} */
|
|
47
|
+
export interface DirTrustOptions {
|
|
48
|
+
/**
|
|
49
|
+
* Accept a directory its group may write to (only others' write access is
|
|
50
|
+
* refused): under umask 002, common with per-user groups, directories are
|
|
51
|
+
* created 0775 and the group holds only the user
|
|
52
|
+
*/
|
|
53
|
+
allowGroupWrite?: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Whether a path is a directory the current user can trust: a real directory
|
|
57
|
+
* (not a symlink), owned by the user, not writable by group or others (by
|
|
58
|
+
* others only, with `allowGroupWrite`).
|
|
59
|
+
*
|
|
60
|
+
* @param dir - Existing path
|
|
61
|
+
* @param options - What else to accept
|
|
62
|
+
* @returns Why it cannot be trusted, or null if it can
|
|
63
|
+
* @throws Error from `lstat` (e.g. `ENOENT` for a missing path)
|
|
64
|
+
*/
|
|
65
|
+
export declare function dirTrustProblem(dir: string, options?: DirTrustOptions): DirTrustProblem | null;
|
|
66
|
+
/**
|
|
67
|
+
* Strict form of {@link dirTrustProblem}: not a symlink, owned by the user,
|
|
68
|
+
* not writable by group or others.
|
|
69
|
+
*
|
|
70
|
+
* @param dir - Existing path
|
|
71
|
+
* @returns Why it cannot be trusted, or null if it can
|
|
72
|
+
* @throws Error from `lstat` (e.g. `ENOENT` for a missing path)
|
|
73
|
+
*/
|
|
74
|
+
export declare function untrustedDirReason(dir: string): string | null;
|
|
34
75
|
//# sourceMappingURL=directories.d.ts.map
|
|
@@ -85,4 +85,52 @@ export function makeDirectory(dir, mode) {
|
|
|
85
85
|
}
|
|
86
86
|
fs.mkdirSync(dir, { recursive: true, ...(mode !== undefined && { mode }) });
|
|
87
87
|
}
|
|
88
|
+
/** Permission bits that let group or others write */
|
|
89
|
+
const GROUP_OTHER_WRITE = 0o022;
|
|
90
|
+
/** Permission bit that lets others (not the group) write */
|
|
91
|
+
const OTHER_WRITE = 0o002;
|
|
92
|
+
/** Sticky bit: a shared directory like `/tmp` where only owners remove their entries */
|
|
93
|
+
const STICKY = 0o1000;
|
|
94
|
+
/**
|
|
95
|
+
* Whether a path is a directory the current user can trust: a real directory
|
|
96
|
+
* (not a symlink), owned by the user, not writable by group or others (by
|
|
97
|
+
* others only, with `allowGroupWrite`).
|
|
98
|
+
*
|
|
99
|
+
* @param dir - Existing path
|
|
100
|
+
* @param options - What else to accept
|
|
101
|
+
* @returns Why it cannot be trusted, or null if it can
|
|
102
|
+
* @throws Error from `lstat` (e.g. `ENOENT` for a missing path)
|
|
103
|
+
*/
|
|
104
|
+
export function dirTrustProblem(dir, options = {}) {
|
|
105
|
+
const stat = fs.lstatSync(dir);
|
|
106
|
+
const problem = (reason, kind) => ({ reason, kind });
|
|
107
|
+
if (stat.isSymbolicLink())
|
|
108
|
+
return problem('it is a symbolic link', 'symlink');
|
|
109
|
+
if (!stat.isDirectory())
|
|
110
|
+
return problem('not a directory', 'not-directory');
|
|
111
|
+
const uid = process.getuid?.();
|
|
112
|
+
if (uid !== undefined && stat.uid !== uid)
|
|
113
|
+
return problem(`owned by uid ${stat.uid}`, 'owner');
|
|
114
|
+
if (process.platform === 'win32')
|
|
115
|
+
return null;
|
|
116
|
+
const writeBits = options.allowGroupWrite ? OTHER_WRITE : GROUP_OTHER_WRITE;
|
|
117
|
+
if ((stat.mode & writeBits) === 0)
|
|
118
|
+
return null;
|
|
119
|
+
const mode = (stat.mode & 0o7777).toString(8);
|
|
120
|
+
if ((stat.mode & STICKY) !== 0 && (stat.mode & OTHER_WRITE) !== 0) {
|
|
121
|
+
return problem(`a shared sticky directory (mode ${mode})`, 'shared');
|
|
122
|
+
}
|
|
123
|
+
return problem(`writable by others (mode ${mode})`, 'writable');
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Strict form of {@link dirTrustProblem}: not a symlink, owned by the user,
|
|
127
|
+
* not writable by group or others.
|
|
128
|
+
*
|
|
129
|
+
* @param dir - Existing path
|
|
130
|
+
* @returns Why it cannot be trusted, or null if it can
|
|
131
|
+
* @throws Error from `lstat` (e.g. `ENOENT` for a missing path)
|
|
132
|
+
*/
|
|
133
|
+
export function untrustedDirReason(dir) {
|
|
134
|
+
return dirTrustProblem(dir)?.reason ?? null;
|
|
135
|
+
}
|
|
88
136
|
//# sourceMappingURL=directories.js.map
|
package/dist/utils/http.d.ts
CHANGED
|
@@ -37,6 +37,13 @@ export interface FetchCDPTargetsOptions {
|
|
|
37
37
|
* - Network errors are logged to help diagnose Chrome connectivity issues
|
|
38
38
|
*/
|
|
39
39
|
export declare function fetchCDPTargets(port?: number, logger?: Logger, options?: FetchCDPTargetsOptions): Promise<CDPTarget[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Options for a DevTools endpoint probe.
|
|
42
|
+
*/
|
|
43
|
+
export interface DevToolsProbeOptions extends FetchCDPTargetsOptions {
|
|
44
|
+
/** Ends a pending request early (the probe then reports `unreachable`) */
|
|
45
|
+
signal?: AbortSignal | undefined;
|
|
46
|
+
}
|
|
40
47
|
/**
|
|
41
48
|
* What answers on a DevTools HTTP endpoint: a Chrome (with its browser-level
|
|
42
49
|
* WebSocket URL), an HTTP server that is not DevTools, or nothing.
|
|
@@ -54,19 +61,19 @@ export type DevToolsProbe = {
|
|
|
54
61
|
*
|
|
55
62
|
* @param port - Chrome debugging port
|
|
56
63
|
* @param logger - Optional logger for debug output
|
|
57
|
-
* @param options - Host, HTTPS and
|
|
64
|
+
* @param options - Host, HTTPS, request timeout and abort signal
|
|
58
65
|
* @returns What answered
|
|
59
66
|
*/
|
|
60
|
-
export declare function probeDevToolsEndpoint(port: number, logger?: Logger, options?:
|
|
67
|
+
export declare function probeDevToolsEndpoint(port: number, logger?: Logger, options?: DevToolsProbeOptions): Promise<DevToolsProbe>;
|
|
61
68
|
/**
|
|
62
69
|
* The browser-level DevTools WebSocket URL of a Chrome (`/json/version`).
|
|
63
70
|
*
|
|
64
71
|
* @param port - Chrome debugging port
|
|
65
72
|
* @param logger - Optional logger for debug output
|
|
66
|
-
* @param options - Host and
|
|
73
|
+
* @param options - Host, HTTPS and abort signal
|
|
67
74
|
* @returns The URL, or null if no Chrome answered
|
|
68
75
|
*/
|
|
69
|
-
export declare function fetchBrowserWsUrl(port: number, logger?: Logger, options?: Pick<
|
|
76
|
+
export declare function fetchBrowserWsUrl(port: number, logger?: Logger, options?: Pick<DevToolsProbeOptions, 'host' | 'secure' | 'signal'>): Promise<string | null>;
|
|
70
77
|
/**
|
|
71
78
|
* Fetch specific CDP target by ID from Chrome's HTTP API.
|
|
72
79
|
*
|
package/dist/utils/http.js
CHANGED
|
@@ -67,15 +67,17 @@ export async function fetchCDPTargets(port = DEFAULT_CDP_PORT, logger, options)
|
|
|
67
67
|
*
|
|
68
68
|
* @param port - Chrome debugging port
|
|
69
69
|
* @param logger - Optional logger for debug output
|
|
70
|
-
* @param options - Host, HTTPS and
|
|
70
|
+
* @param options - Host, HTTPS, request timeout and abort signal
|
|
71
71
|
* @returns What answered
|
|
72
72
|
*/
|
|
73
73
|
export async function probeDevToolsEndpoint(port, logger, options) {
|
|
74
74
|
const url = `${options?.secure ? 'https' : 'http'}://${options?.host ?? HTTP_LOCALHOST}:${port}/json/version`;
|
|
75
75
|
const timeoutMs = options?.timeoutMs ?? CDP_HTTP_TIMEOUT_MS;
|
|
76
|
+
const timeout = AbortSignal.timeout(timeoutMs);
|
|
77
|
+
const signal = options?.signal ? AbortSignal.any([timeout, options.signal]) : timeout;
|
|
76
78
|
let response;
|
|
77
79
|
try {
|
|
78
|
-
response = await fetch(url, { signal
|
|
80
|
+
response = await fetch(url, { signal });
|
|
79
81
|
}
|
|
80
82
|
catch (error) {
|
|
81
83
|
logger?.debug(`Chrome version request failed: ${getErrorMessage(error)} (${url})`);
|
|
@@ -97,7 +99,7 @@ export async function probeDevToolsEndpoint(port, logger, options) {
|
|
|
97
99
|
*
|
|
98
100
|
* @param port - Chrome debugging port
|
|
99
101
|
* @param logger - Optional logger for debug output
|
|
100
|
-
* @param options - Host and
|
|
102
|
+
* @param options - Host, HTTPS and abort signal
|
|
101
103
|
* @returns The URL, or null if no Chrome answered
|
|
102
104
|
*/
|
|
103
105
|
export async function fetchBrowserWsUrl(port, logger, options) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "browser-debugger-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.16.0",
|
|
4
|
+
"description": "Let Claude Code and other coding agents drive and debug Chrome from the shell. DOM, network, console and raw CDP as short commands, no screenshots and no MCP needed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"bdg": "dist/index.js"
|
|
@@ -37,10 +37,24 @@
|
|
|
37
37
|
"keywords": [
|
|
38
38
|
"cdp",
|
|
39
39
|
"chrome-devtools-protocol",
|
|
40
|
+
"chrome",
|
|
41
|
+
"devtools",
|
|
42
|
+
"debugging",
|
|
40
43
|
"browser",
|
|
41
|
-
"
|
|
44
|
+
"browser-automation",
|
|
45
|
+
"headless-chrome",
|
|
42
46
|
"cli",
|
|
43
|
-
"
|
|
47
|
+
"claude",
|
|
48
|
+
"claude-code",
|
|
49
|
+
"coding-agent",
|
|
50
|
+
"ai-agent",
|
|
51
|
+
"agent-skill",
|
|
52
|
+
"codex",
|
|
53
|
+
"css",
|
|
54
|
+
"figma",
|
|
55
|
+
"telemetry",
|
|
56
|
+
"puppeteer-alternative",
|
|
57
|
+
"playwright-alternative"
|
|
44
58
|
],
|
|
45
59
|
"license": "MIT",
|
|
46
60
|
"dependencies": {
|
|
File without changes
|
|
File without changes
|