browser-debugger-cli 0.11.0 → 0.13.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 +4 -4
- package/README.md +143 -79
- package/dist/commands/cdp.d.ts +22 -1
- package/dist/commands/cdp.js +100 -43
- package/dist/commands/console.d.ts +12 -0
- package/dist/commands/console.js +62 -12
- package/dist/commands/css.d.ts +13 -0
- package/dist/commands/css.js +53 -0
- package/dist/commands/dom/DomElementResolver.d.ts +3 -1
- package/dist/commands/dom/DomElementResolver.js +10 -3
- package/dist/commands/dom/a11y.js +3 -2
- package/dist/commands/dom/audit.d.ts +14 -0
- package/dist/commands/dom/audit.js +87 -0
- package/dist/commands/dom/eval.d.ts +3 -2
- package/dist/commands/dom/eval.js +11 -5
- package/dist/commands/dom/form.js +10 -9
- package/dist/commands/dom/formInteraction.js +42 -11
- package/dist/commands/dom/get.js +8 -8
- package/dist/commands/dom/helpers/index.d.ts +1 -1
- package/dist/commands/dom/helpers/index.js +1 -1
- package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
- package/dist/commands/dom/helpers/keyAttributes.js +6 -4
- package/dist/commands/dom/helpers/query.d.ts +27 -3
- package/dist/commands/dom/helpers/query.js +152 -64
- package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
- package/dist/commands/dom/helpers/screenshot.js +169 -49
- package/dist/commands/dom/index.js +7 -2
- package/dist/commands/dom/query.d.ts +19 -2
- package/dist/commands/dom/query.js +37 -6
- package/dist/commands/dom/screenshot.js +12 -7
- package/dist/commands/dom/semanticUtils.d.ts +3 -2
- package/dist/commands/dom/semanticUtils.js +40 -9
- package/dist/commands/dom/wait.js +5 -3
- package/dist/commands/helpJson.d.ts +82 -19
- package/dist/commands/helpJson.js +112 -41
- package/dist/commands/helpTopic.d.ts +16 -1
- package/dist/commands/helpTopic.js +59 -1
- package/dist/commands/installSkill.d.ts +15 -5
- package/dist/commands/installSkill.js +86 -16
- package/dist/commands/network/list.js +22 -12
- package/dist/commands/optionBehaviors.js +53 -16
- package/dist/commands/page.js +7 -4
- package/dist/commands/peek.d.ts +7 -0
- package/dist/commands/peek.js +65 -23
- package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
- package/dist/commands/shared/daemonErrorHandler.js +20 -9
- package/dist/commands/shared/dataFetcher.d.ts +12 -4
- package/dist/commands/shared/dataFetcher.js +12 -4
- package/dist/commands/shared/followMode.d.ts +9 -1
- package/dist/commands/shared/followMode.js +22 -4
- package/dist/commands/shared/optionTypes.d.ts +9 -2
- package/dist/commands/shared/outputFile.js +6 -1
- package/dist/commands/start.d.ts +20 -5
- package/dist/commands/start.js +84 -23
- package/dist/commands/stop.d.ts +11 -0
- package/dist/commands/stop.js +24 -1
- package/dist/commands/tail.d.ts +7 -1
- package/dist/commands/tail.js +13 -62
- package/dist/commands.js +2 -0
- package/dist/connection/cdp.d.ts +7 -0
- package/dist/connection/cdp.js +9 -0
- package/dist/connection/launcher.js +3 -2
- package/dist/daemon/SessionController.js +6 -1
- package/dist/daemon/launcher.d.ts +3 -2
- package/dist/daemon/launcher.js +47 -3
- package/dist/daemon/session/Session.d.ts +4 -1
- package/dist/daemon/session/Session.js +33 -2
- package/dist/daemon/session/TelemetryStore.d.ts +8 -1
- package/dist/daemon/session/TelemetryStore.js +13 -1
- package/dist/daemon/session/commandRegistry.js +36 -14
- package/dist/daemon/session/interactions.d.ts +2 -1
- package/dist/daemon/session/interactions.js +13 -1
- package/dist/daemon/session/plugins.js +19 -53
- package/dist/daemon/session/teardown.js +1 -1
- package/dist/daemon.js +9234 -7222
- package/dist/errors/messages.d.ts +88 -15
- package/dist/errors/messages.js +177 -27
- package/dist/index.js +19322 -13961
- package/dist/ipc/client.d.ts +22 -2
- package/dist/ipc/client.js +34 -5
- package/dist/ipc/protocol/auditTypes.d.ts +135 -0
- package/dist/ipc/protocol/auditTypes.js +6 -0
- package/dist/ipc/protocol/commands.d.ts +35 -0
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +16 -0
- package/dist/ipc/protocol/inspectTypes.d.ts +73 -8
- package/dist/ipc/session/types.d.ts +2 -0
- package/dist/runtime/css/search.d.ts +39 -0
- package/dist/runtime/css/search.js +122 -0
- package/dist/runtime/dom/actionEffects.d.ts +9 -2
- package/dist/runtime/dom/actionEffects.js +30 -14
- package/dist/runtime/dom/audit.d.ts +19 -0
- package/dist/runtime/dom/audit.js +37 -0
- package/dist/runtime/dom/auditModel.d.ts +45 -0
- package/dist/runtime/dom/auditModel.js +220 -0
- package/dist/runtime/dom/auditScripts.d.ts +113 -0
- package/dist/runtime/dom/auditScripts.js +148 -0
- package/dist/runtime/dom/elementGeometry.d.ts +16 -3
- package/dist/runtime/dom/elementGeometry.js +49 -10
- package/dist/runtime/dom/elementInfo.d.ts +74 -17
- package/dist/runtime/dom/elementInfo.js +187 -34
- package/dist/runtime/dom/evalHelpers.d.ts +12 -2
- package/dist/runtime/dom/evalHelpers.js +67 -7
- package/dist/runtime/dom/formDiscovery.d.ts +6 -2
- package/dist/runtime/dom/formDiscovery.js +20 -3
- package/dist/runtime/dom/formFillHelpers/fill.js +8 -12
- package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
- package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
- package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
- package/dist/runtime/dom/formSubmitHelpers.js +4 -3
- package/dist/runtime/dom/frameLayout.js +1 -0
- package/dist/runtime/dom/inspect.d.ts +7 -0
- package/dist/runtime/dom/inspect.js +92 -28
- package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
- package/dist/runtime/dom/inspectAllStyles.js +90 -7
- package/dist/runtime/dom/inspectCascade.d.ts +19 -2
- package/dist/runtime/dom/inspectCascade.js +214 -44
- package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
- package/dist/runtime/dom/inspectCascadeModel.js +108 -34
- package/dist/runtime/dom/inspectHints.d.ts +26 -3
- package/dist/runtime/dom/inspectHints.js +125 -9
- package/dist/runtime/dom/inspectModel.d.ts +5 -1
- package/dist/runtime/dom/inspectModel.js +37 -10
- package/dist/runtime/dom/inspectPaintModel.d.ts +50 -22
- package/dist/runtime/dom/inspectPaintModel.js +182 -68
- package/dist/runtime/dom/inspectRules.d.ts +19 -0
- package/dist/runtime/dom/inspectRules.js +21 -5
- package/dist/runtime/dom/inspectScripts.d.ts +112 -12
- package/dist/runtime/dom/inspectScripts.js +357 -32
- package/dist/runtime/dom/inspectTree.js +10 -2
- package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
- package/dist/runtime/dom/inspectWhyModel.js +52 -10
- package/dist/runtime/dom/layout.js +40 -16
- package/dist/runtime/dom/reactEventHelpers.d.ts +21 -4
- package/dist/runtime/dom/reactEventHelpers.js +90 -36
- package/dist/runtime/dom/targetNode.d.ts +18 -5
- package/dist/runtime/dom/targetNode.js +268 -8
- package/dist/runtime/dom/wait.js +2 -1
- package/dist/runtime/page/bdgWorld.d.ts +57 -0
- package/dist/runtime/page/bdgWorld.js +180 -0
- package/dist/runtime/page/emulation.d.ts +13 -4
- package/dist/runtime/page/emulation.js +69 -4
- package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
- package/dist/runtime/page/replacedBuiltins.js +136 -0
- package/dist/runtime/page/userAgent.d.ts +17 -0
- package/dist/runtime/page/userAgent.js +57 -0
- package/dist/session/QueryCacheManager.d.ts +4 -1
- package/dist/session/QueryCacheManager.js +5 -2
- package/dist/session/chrome.d.ts +4 -1
- package/dist/session/chrome.js +7 -1
- package/dist/session/cleanup/staleSession.d.ts +21 -4
- package/dist/session/cleanup/staleSession.js +79 -9
- package/dist/session/cleanup/userCommands.d.ts +4 -1
- package/dist/session/cleanup/userCommands.js +10 -5
- package/dist/session/daemonSocket.d.ts +10 -0
- package/dist/session/daemonSocket.js +22 -0
- package/dist/session/lastSession.d.ts +6 -3
- package/dist/session/lastSession.js +11 -5
- package/dist/session/paths.d.ts +3 -1
- package/dist/session/paths.js +5 -5
- package/dist/session/portClaims.js +4 -3
- package/dist/session/sessionList.d.ts +13 -5
- package/dist/session/sessionList.js +31 -7
- package/dist/telemetry/a11y.js +2 -2
- package/dist/telemetry/console.d.ts +2 -1
- package/dist/telemetry/console.js +30 -21
- package/dist/telemetry/pageCrash.d.ts +26 -0
- package/dist/telemetry/pageCrash.js +53 -0
- package/dist/types.d.ts +20 -0
- package/dist/ui/formatters/audit.d.ts +19 -0
- package/dist/ui/formatters/audit.js +115 -0
- package/dist/ui/formatters/cdp.d.ts +138 -0
- package/dist/ui/formatters/cdp.js +131 -0
- package/dist/ui/formatters/console/chronological.js +3 -1
- package/dist/ui/formatters/console/follow.d.ts +2 -1
- package/dist/ui/formatters/console/follow.js +2 -2
- package/dist/ui/formatters/console/json.d.ts +2 -2
- package/dist/ui/formatters/console/json.js +11 -5
- package/dist/ui/formatters/console/shared.d.ts +30 -0
- package/dist/ui/formatters/console/shared.js +16 -0
- package/dist/ui/formatters/console/summarize.d.ts +9 -2
- package/dist/ui/formatters/console/summarize.js +40 -9
- package/dist/ui/formatters/console.d.ts +2 -1
- package/dist/ui/formatters/console.js +7 -5
- package/dist/ui/formatters/details.js +3 -1
- package/dist/ui/formatters/dom.d.ts +2 -2
- package/dist/ui/formatters/dom.js +10 -8
- package/dist/ui/formatters/helpFormatters.js +1 -1
- package/dist/ui/formatters/inspect.js +50 -17
- package/dist/ui/formatters/installSkill.d.ts +9 -1
- package/dist/ui/formatters/installSkill.js +32 -6
- package/dist/ui/formatters/layout.js +2 -1
- package/dist/ui/formatters/networkList.d.ts +1 -1
- package/dist/ui/formatters/networkList.js +1 -2
- package/dist/ui/formatters/preview.d.ts +2 -0
- package/dist/ui/formatters/preview.js +17 -7
- package/dist/ui/formatters/sessions.d.ts +2 -2
- package/dist/ui/formatters/sessions.js +9 -2
- package/dist/ui/formatters/status.js +1 -1
- package/dist/ui/logging/logger.d.ts +1 -1
- package/dist/ui/messages/commands.d.ts +168 -11
- package/dist/ui/messages/commands.js +245 -18
- package/dist/ui/messages/consoleMessages.d.ts +24 -0
- package/dist/ui/messages/consoleMessages.js +32 -0
- package/dist/ui/messages/preview.d.ts +12 -0
- package/dist/ui/messages/preview.js +18 -2
- package/dist/ui/messages/session.d.ts +13 -2
- package/dist/ui/messages/session.js +22 -3
- package/dist/utils/cssValues.js +36 -4
- package/dist/utils/decisionTrees.js +0 -5
- package/dist/utils/directories.d.ts +34 -0
- package/dist/utils/directories.js +88 -0
- package/dist/utils/display.d.ts +16 -0
- package/dist/utils/display.js +42 -0
- package/dist/utils/exitCodes.d.ts +1 -0
- package/dist/utils/exitCodes.js +6 -0
- package/dist/utils/process.d.ts +12 -0
- package/dist/utils/process.js +25 -0
- package/dist/utils/suggestions.d.ts +4 -2
- package/dist/utils/suggestions.js +7 -5
- package/dist/utils/taskMappings.js +1 -1
- package/package.json +3 -2
|
@@ -75,15 +75,23 @@ function createMessage(type, text, timestamp, args, context) {
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
78
|
-
* Insert a message in timestamp order
|
|
79
|
-
*
|
|
78
|
+
* Insert a message in timestamp order (async expansion can deliver a message
|
|
79
|
+
* late). At {@link MAX_CONSOLE_MESSAGES} the oldest message is dropped to
|
|
80
|
+
* make room, so the newest are kept; a late message older than all kept ones
|
|
81
|
+
* is dropped itself.
|
|
80
82
|
*
|
|
81
|
-
* @
|
|
83
|
+
* @param messages - Messages, oldest first (updated)
|
|
84
|
+
* @param message - Message to add
|
|
85
|
+
* @param onDropped - Called for each message dropped
|
|
86
|
+
* @returns False when the message itself was dropped
|
|
82
87
|
*/
|
|
83
|
-
function insertMessageByTimestamp(messages, message) {
|
|
88
|
+
function insertMessageByTimestamp(messages, message, onDropped) {
|
|
84
89
|
if (messages.length >= MAX_CONSOLE_MESSAGES) {
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
const oldest = messages[0];
|
|
91
|
+
onDropped();
|
|
92
|
+
if (oldest && message.timestamp < oldest.timestamp)
|
|
93
|
+
return false;
|
|
94
|
+
messages.shift();
|
|
87
95
|
}
|
|
88
96
|
const insertIndex = findInsertIndex(messages, message.timestamp);
|
|
89
97
|
messages.splice(insertIndex, 0, message);
|
|
@@ -111,32 +119,31 @@ function findInsertIndex(messages, timestamp) {
|
|
|
111
119
|
/**
|
|
112
120
|
* Handle a console API call event with object expansion.
|
|
113
121
|
*/
|
|
114
|
-
function handleConsoleAPICall(cdp,
|
|
122
|
+
function handleConsoleAPICall(cdp, insert, params, context, includeAll) {
|
|
115
123
|
const basicText = formatConsoleArgs(params.args);
|
|
116
124
|
if (shouldExcludeConsoleMessage(basicText, params.type, includeAll)) {
|
|
117
125
|
return;
|
|
118
126
|
}
|
|
119
127
|
if (hasArgsNeedingExpansion(params.args) && !usesFormatSpecifiers(params.args)) {
|
|
120
|
-
handleExpandableMessage(cdp,
|
|
128
|
+
handleExpandableMessage(cdp, insert, params, context, basicText);
|
|
121
129
|
}
|
|
122
130
|
else {
|
|
123
|
-
|
|
124
|
-
insertMessageByTimestamp(messages, message);
|
|
131
|
+
insert(createMessage(params.type, basicText, params.timestamp, params.args, context));
|
|
125
132
|
}
|
|
126
133
|
}
|
|
127
134
|
/**
|
|
128
135
|
* Handle a message with expandable objects.
|
|
129
136
|
*/
|
|
130
|
-
function handleExpandableMessage(cdp,
|
|
137
|
+
function handleExpandableMessage(cdp, insert, params, context, fallbackText) {
|
|
131
138
|
void expandConsoleArgs(cdp, params.args)
|
|
132
139
|
.then((expandedText) => {
|
|
133
140
|
const message = createMessage(params.type, expandedText, params.timestamp, params.args, context);
|
|
134
|
-
|
|
141
|
+
insert(message);
|
|
135
142
|
})
|
|
136
143
|
.catch((error) => {
|
|
137
144
|
log.debug(`Object expansion failed, using basic text: ${String(error)}`);
|
|
138
145
|
const message = createMessage(params.type, fallbackText, params.timestamp, params.args, context);
|
|
139
|
-
|
|
146
|
+
insert(message);
|
|
140
147
|
});
|
|
141
148
|
}
|
|
142
149
|
/**
|
|
@@ -178,14 +185,14 @@ export function formatExceptionText(details) {
|
|
|
178
185
|
*
|
|
179
186
|
* @returns The message added, undefined when filtered out or over the limit
|
|
180
187
|
*/
|
|
181
|
-
function handleExceptionThrown(
|
|
188
|
+
function handleExceptionThrown(insert, params, context, includeAll) {
|
|
182
189
|
const exception = params.exceptionDetails;
|
|
183
190
|
const text = formatExceptionText(exception);
|
|
184
191
|
if (shouldExcludeConsoleMessage(text, 'error', includeAll)) {
|
|
185
192
|
return undefined;
|
|
186
193
|
}
|
|
187
194
|
const message = createMessage('error', text, params.timestamp, undefined, context);
|
|
188
|
-
return
|
|
195
|
+
return insert(message) ? message : undefined;
|
|
189
196
|
}
|
|
190
197
|
/** CDP's text of an unhandled promise rejection (the only kind Chrome revokes) */
|
|
191
198
|
const UNHANDLED_REJECTION_TEXT = 'Uncaught (in promise)';
|
|
@@ -270,7 +277,7 @@ class RevocableRejections {
|
|
|
270
277
|
* Worker entries are skipped: workers are attached directly, so their console
|
|
271
278
|
* calls already arrive (with arguments) from the worker's own session.
|
|
272
279
|
*/
|
|
273
|
-
function handleLogEntry(
|
|
280
|
+
function handleLogEntry(insert, entry, navigationId, includeAll) {
|
|
274
281
|
const type = LOG_LEVEL_TYPES[entry.level];
|
|
275
282
|
if (entry.source === 'worker' || shouldExcludeConsoleMessage(entry.text, type, includeAll)) {
|
|
276
283
|
return;
|
|
@@ -287,7 +294,7 @@ function handleLogEntry(messages, entry, navigationId, includeAll) {
|
|
|
287
294
|
stackTrace: convertStackTrace(entry.stackTrace) ?? location,
|
|
288
295
|
source: entry.source,
|
|
289
296
|
};
|
|
290
|
-
|
|
297
|
+
insert(createMessage(type, entry.text, entry.timestamp, undefined, context));
|
|
291
298
|
}
|
|
292
299
|
/**
|
|
293
300
|
* Enable console and log events on an attached target's session.
|
|
@@ -325,17 +332,19 @@ async function startOptionalSources(cdp, typed) {
|
|
|
325
332
|
* @param messages - Array to populate with console messages
|
|
326
333
|
* @param includeAll - If true, disable default pattern filtering
|
|
327
334
|
* @param getCurrentNavigationId - Function to get current navigation ID
|
|
335
|
+
* @param onDropped - Called for each message dropped at the limit (the oldest go first)
|
|
328
336
|
* @returns Cleanup function to remove event handlers
|
|
329
337
|
*/
|
|
330
|
-
export async function startConsoleCollection(cdp, messages, includeAll = false, getCurrentNavigationId) {
|
|
338
|
+
export async function startConsoleCollection(cdp, messages, includeAll = false, getCurrentNavigationId, onDropped = () => undefined) {
|
|
331
339
|
const registry = new CDPHandlerRegistry();
|
|
332
340
|
const typed = new TypedCDPConnection(cdp);
|
|
341
|
+
const insert = (message) => insertMessageByTimestamp(messages, message, onDropped);
|
|
333
342
|
registry.registerTyped(typed, 'Runtime.consoleAPICalled', (params, sessionId) => {
|
|
334
343
|
const context = {
|
|
335
344
|
navigationId: getCurrentNavigationId?.(),
|
|
336
345
|
stackTrace: convertStackTrace(params.stackTrace),
|
|
337
346
|
};
|
|
338
|
-
handleConsoleAPICall(senderFor(cdp, sessionId),
|
|
347
|
+
handleConsoleAPICall(senderFor(cdp, sessionId), insert, params, context, includeAll);
|
|
339
348
|
});
|
|
340
349
|
const rejections = new RevocableRejections();
|
|
341
350
|
registry.registerTyped(typed, 'Runtime.exceptionThrown', (params, sessionId) => {
|
|
@@ -343,7 +352,7 @@ export async function startConsoleCollection(cdp, messages, includeAll = false,
|
|
|
343
352
|
navigationId: getCurrentNavigationId?.(),
|
|
344
353
|
stackTrace: convertStackTrace(params.exceptionDetails.stackTrace),
|
|
345
354
|
};
|
|
346
|
-
const message = handleExceptionThrown(
|
|
355
|
+
const message = handleExceptionThrown(insert, params, context, includeAll);
|
|
347
356
|
if (message)
|
|
348
357
|
rejections.track(params.exceptionDetails, message, sessionId);
|
|
349
358
|
});
|
|
@@ -357,7 +366,7 @@ export async function startConsoleCollection(cdp, messages, includeAll = false,
|
|
|
357
366
|
rejections.forgetSession(sessionId);
|
|
358
367
|
});
|
|
359
368
|
registry.registerTyped(typed, 'Log.entryAdded', ({ entry }) => {
|
|
360
|
-
handleLogEntry(
|
|
369
|
+
handleLogEntry(insert, entry, getCurrentNavigationId?.(), includeAll);
|
|
361
370
|
});
|
|
362
371
|
try {
|
|
363
372
|
await typed.send('Runtime.enable', {});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renderer crash tracking: Chrome reports a crashed page with
|
|
3
|
+
* `Inspector.targetCrashed` and keeps the connection open, so without this a
|
|
4
|
+
* session looks active while every page command waits for a timeout. A
|
|
5
|
+
* reload (or any main-frame navigation) brings the page back.
|
|
6
|
+
*/
|
|
7
|
+
import type { CDPConnection } from '../connection/cdp.js';
|
|
8
|
+
import { CommandError } from '../errors/index.js';
|
|
9
|
+
import type { CleanupFunction } from '../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Start tracking renderer crashes of the page.
|
|
12
|
+
*
|
|
13
|
+
* @param cdp - CDP connection to the page
|
|
14
|
+
* @param onChange - Called with the crash time when the page crashes, and
|
|
15
|
+
* with undefined when it is loaded again
|
|
16
|
+
* @returns Cleanup that stops tracking
|
|
17
|
+
*/
|
|
18
|
+
export declare function startCrashTracking(cdp: CDPConnection, onChange: (crashedAt: number | undefined) => void): Promise<CleanupFunction>;
|
|
19
|
+
/**
|
|
20
|
+
* Error for a page command after the page's renderer crashed (exit 107).
|
|
21
|
+
*
|
|
22
|
+
* @param crashedAt - When it crashed (epoch ms)
|
|
23
|
+
* @returns Error with the way back
|
|
24
|
+
*/
|
|
25
|
+
export declare function pageCrashedCommandError(crashedAt: number): CommandError;
|
|
26
|
+
//# sourceMappingURL=pageCrash.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renderer crash tracking: Chrome reports a crashed page with
|
|
3
|
+
* `Inspector.targetCrashed` and keeps the connection open, so without this a
|
|
4
|
+
* session looks active while every page command waits for a timeout. A
|
|
5
|
+
* reload (or any main-frame navigation) brings the page back.
|
|
6
|
+
*/
|
|
7
|
+
import { CDPHandlerRegistry } from '../connection/handlers.js';
|
|
8
|
+
import { TypedCDPConnection } from '../connection/typed-cdp.js';
|
|
9
|
+
import { CommandError } from '../errors/index.js';
|
|
10
|
+
import { pageCrashedError } from '../errors/messages.js';
|
|
11
|
+
import { createLogger } from '../ui/logging/index.js';
|
|
12
|
+
import { getErrorMessage } from '../utils/errors.js';
|
|
13
|
+
import { EXIT_CODES } from '../utils/exitCodes.js';
|
|
14
|
+
const log = createLogger('page-crash');
|
|
15
|
+
/**
|
|
16
|
+
* Start tracking renderer crashes of the page.
|
|
17
|
+
*
|
|
18
|
+
* @param cdp - CDP connection to the page
|
|
19
|
+
* @param onChange - Called with the crash time when the page crashes, and
|
|
20
|
+
* with undefined when it is loaded again
|
|
21
|
+
* @returns Cleanup that stops tracking
|
|
22
|
+
*/
|
|
23
|
+
export async function startCrashTracking(cdp, onChange) {
|
|
24
|
+
const registry = new CDPHandlerRegistry();
|
|
25
|
+
const typed = new TypedCDPConnection(cdp);
|
|
26
|
+
registry.registerTyped(typed, 'Inspector.targetCrashed', () => {
|
|
27
|
+
log.info('The page crashed (renderer gone)');
|
|
28
|
+
onChange(Date.now());
|
|
29
|
+
});
|
|
30
|
+
registry.registerTyped(typed, 'Inspector.targetReloadedAfterCrash', () => onChange(undefined));
|
|
31
|
+
registry.registerTyped(typed, 'Page.frameNavigated', ({ frame }) => {
|
|
32
|
+
if (frame.parentId === undefined)
|
|
33
|
+
onChange(undefined);
|
|
34
|
+
});
|
|
35
|
+
try {
|
|
36
|
+
await cdp.send('Inspector.enable');
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
log.debug(`Crash reports unavailable: ${getErrorMessage(error)}`);
|
|
40
|
+
}
|
|
41
|
+
return () => registry.cleanup();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Error for a page command after the page's renderer crashed (exit 107).
|
|
45
|
+
*
|
|
46
|
+
* @param crashedAt - When it crashed (epoch ms)
|
|
47
|
+
* @returns Error with the way back
|
|
48
|
+
*/
|
|
49
|
+
export function pageCrashedCommandError(crashedAt) {
|
|
50
|
+
const err = pageCrashedError(crashedAt);
|
|
51
|
+
return new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.PAGE_CRASHED);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=pageCrash.js.map
|
package/dist/types.d.ts
CHANGED
|
@@ -226,10 +226,14 @@ export interface BdgOutput {
|
|
|
226
226
|
};
|
|
227
227
|
/** Navigation id of the page currently loaded (live previews) */
|
|
228
228
|
currentNavigationId?: number;
|
|
229
|
+
/** When the page's renderer crashed (epoch ms), while it is not loaded again */
|
|
230
|
+
pageCrashedAt?: number;
|
|
229
231
|
/** Counts of all captured items matching the request (e.g. `peek --type`), when `data` holds only the most recent ones */
|
|
230
232
|
totals?: {
|
|
231
233
|
network: number;
|
|
232
234
|
console: number;
|
|
235
|
+
/** Console messages dropped at the limit, oldest first (indices start after them) */
|
|
236
|
+
consoleDropped?: number;
|
|
233
237
|
};
|
|
234
238
|
error?: string;
|
|
235
239
|
partial?: boolean;
|
|
@@ -327,6 +331,8 @@ export interface DomContext {
|
|
|
327
331
|
children?: string[];
|
|
328
332
|
/** Number of child elements, for an element without text */
|
|
329
333
|
childCount?: number;
|
|
334
|
+
/** The children listed are those of its shadow root (a web component) */
|
|
335
|
+
shadowChildren?: boolean;
|
|
330
336
|
/** Attributes that identify it by its type (see {@link KeyAttributes}) */
|
|
331
337
|
attributes?: KeyAttributes;
|
|
332
338
|
/** A field holding a secret (password, card, one-time code): its value is shown masked */
|
|
@@ -370,6 +376,8 @@ export type ColorScheme = 'light' | 'dark';
|
|
|
370
376
|
export interface ViewportSize {
|
|
371
377
|
width: number;
|
|
372
378
|
height: number;
|
|
379
|
+
/** A phone: mobile viewport (meta viewport, overlay scrollbars), touch and a mobile user agent */
|
|
380
|
+
mobile?: true;
|
|
373
381
|
}
|
|
374
382
|
/**
|
|
375
383
|
* The page (document) request an action sent, as far as it got: still
|
|
@@ -436,6 +444,14 @@ export interface DomQueryResult {
|
|
|
436
444
|
/** Unique selector for this node (set by form discovery) */
|
|
437
445
|
selector?: string;
|
|
438
446
|
}>;
|
|
447
|
+
/** Matches not listed (`--limit`); `count` is all of them */
|
|
448
|
+
omitted?: number;
|
|
449
|
+
/** Matches usable by index (described and cached), when fewer than `count` */
|
|
450
|
+
indexed?: number;
|
|
451
|
+
/** First matches whose viewport position was checked (`inViewport`), when more are listed */
|
|
452
|
+
viewportChecked?: number;
|
|
453
|
+
/** Identity of the page document the matches belong to (cached results only) */
|
|
454
|
+
document?: string;
|
|
439
455
|
}
|
|
440
456
|
/**
|
|
441
457
|
* Result of a DOM get operation.
|
|
@@ -483,6 +499,8 @@ export interface ScreenshotResult {
|
|
|
483
499
|
* descendants) made it larger than the border box
|
|
484
500
|
*/
|
|
485
501
|
captured?: ElementBounds;
|
|
502
|
+
/** `--padding` given: CSS px of page added around the captured area */
|
|
503
|
+
padding?: number;
|
|
486
504
|
};
|
|
487
505
|
/** Capture mode used */
|
|
488
506
|
captureMode?: 'full_page' | 'viewport';
|
|
@@ -675,5 +693,7 @@ export interface InstalledSkill {
|
|
|
675
693
|
target: SkillTarget;
|
|
676
694
|
path: string;
|
|
677
695
|
status: 'installed' | 'updated' | 'unchanged';
|
|
696
|
+
/** Where the replaced copy was kept (`updated` only) */
|
|
697
|
+
backup?: string;
|
|
678
698
|
}
|
|
679
699
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human output of `bdg dom audit` and `bdg css search`.
|
|
3
|
+
*/
|
|
4
|
+
import type { AuditResult, CssSearchResult } from '../../ipc/protocol/auditTypes.js';
|
|
5
|
+
/**
|
|
6
|
+
* Format `bdg dom audit`.
|
|
7
|
+
*
|
|
8
|
+
* @param data - Audit result
|
|
9
|
+
* @returns Output
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatAudit(data: AuditResult): string;
|
|
12
|
+
/**
|
|
13
|
+
* Format `bdg css search`.
|
|
14
|
+
*
|
|
15
|
+
* @param data - Search result
|
|
16
|
+
* @returns Output
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatCssSearch(data: CssSearchResult): string;
|
|
19
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human output of `bdg dom audit` and `bdg css search`.
|
|
3
|
+
*/
|
|
4
|
+
import { auditCanvasNote, auditUncertainContrastNote } from '../messages/commands.js';
|
|
5
|
+
import { truncateByLength } from '../../utils/strings.js';
|
|
6
|
+
/** Width of the text quoted in a finding */
|
|
7
|
+
const TEXT_WIDTH = 50;
|
|
8
|
+
/**
|
|
9
|
+
* Format `bdg dom audit`.
|
|
10
|
+
*
|
|
11
|
+
* @param data - Audit result
|
|
12
|
+
* @returns Output
|
|
13
|
+
*/
|
|
14
|
+
export function formatAudit(data) {
|
|
15
|
+
const sections = [
|
|
16
|
+
data.contrast && contrastSection(data.contrast),
|
|
17
|
+
data.overflow && overflowSection(data.overflow),
|
|
18
|
+
data.layers && layersSection(data.layers),
|
|
19
|
+
data.animations && animationsSection(data.animations, data.canvases),
|
|
20
|
+
].filter((section) => section !== undefined);
|
|
21
|
+
const capped = data.capped ? [`(stopped after ${data.walked} elements; the page has more)`] : [];
|
|
22
|
+
return [...sections.flatMap((lines) => [...lines, '']), ...capped].join('\n').trimEnd();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The contrast section.
|
|
26
|
+
*
|
|
27
|
+
* @param contrast - Contrast findings
|
|
28
|
+
* @returns Lines
|
|
29
|
+
*/
|
|
30
|
+
function contrastSection(contrast) {
|
|
31
|
+
const head = `Contrast (${contrast.level}): ${contrast.failing} of ${contrast.checked} text elements below`;
|
|
32
|
+
const rows = contrast.items.map((item) => ` ${item.ratio.toFixed(2).padStart(5)} ${item.color} on ${item.background} ${item.element} "${truncateByLength(item.text, TEXT_WIDTH)}" ${item.size}px${item.weight >= 700 ? ' bold' : ''}${item.opacity !== undefined ? ` (faded: opacity ${item.opacity})` : ''}${item.inView ? '' : ' (out of view)'}`);
|
|
33
|
+
const more = contrast.failing - contrast.items.length;
|
|
34
|
+
return [
|
|
35
|
+
head,
|
|
36
|
+
...rows,
|
|
37
|
+
...(more > 0 ? [` (+${more} more; --limit to list them)`] : []),
|
|
38
|
+
...(contrast.uncertain ? [` ${auditUncertainContrastNote(contrast.uncertain)}`] : []),
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The overflow section.
|
|
43
|
+
*
|
|
44
|
+
* @param overflow - Overflow findings
|
|
45
|
+
* @returns Lines
|
|
46
|
+
*/
|
|
47
|
+
function overflowSection(overflow) {
|
|
48
|
+
const head = overflow.scrollsSideways
|
|
49
|
+
? `Overflow: the page is ${overflow.pageWidth} wide in a ${overflow.viewportWidth} viewport (it scrolls sideways)`
|
|
50
|
+
: `Overflow: nothing makes the page scroll sideways (${overflow.viewportWidth} wide)`;
|
|
51
|
+
return [
|
|
52
|
+
head,
|
|
53
|
+
...overflow.wide.map((item) => ` past the right edge: ${item.element} (to ${item.right}, ${item.width} wide)`),
|
|
54
|
+
...overflow.truncated.map((item) => ` cut off (${item.kind}): ${item.element}${times(item.count)} "${truncateByLength(item.text, TEXT_WIDTH)}"`),
|
|
55
|
+
...overflow.scrollers.map((item) => ` scrolls sideways inside: ${item.element} (${item.scrollWidth} of content in ${item.width})`),
|
|
56
|
+
...overflow.images.map((image) => ` image ${[image.upscaled && `upscaled ${image.scale}x${overflow.pixelRatio > 1 ? ` at pixel ratio ${overflow.pixelRatio}` : ''}`, image.distorted && 'distorted'].filter(Boolean).join(', ')}: ${image.element}${times(image.count)} ${image.natural.w}x${image.natural.h} pixels drawn at ${image.rendered.w}x${image.rendered.h} CSS px`),
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* How many identical findings a row stands for.
|
|
61
|
+
*
|
|
62
|
+
* @param count - Count, when 2 or more
|
|
63
|
+
* @returns e.g. ` ×5`, or empty
|
|
64
|
+
*/
|
|
65
|
+
function times(count) {
|
|
66
|
+
return count ? ` ×${count}` : '';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The layers section.
|
|
70
|
+
*
|
|
71
|
+
* @param layers - Fixed and sticky elements
|
|
72
|
+
* @returns Lines
|
|
73
|
+
*/
|
|
74
|
+
function layersSection(layers) {
|
|
75
|
+
if (layers.length === 0)
|
|
76
|
+
return ['Layers: no fixed or sticky elements'];
|
|
77
|
+
return [
|
|
78
|
+
`Layers: ${layers.length} fixed or sticky`,
|
|
79
|
+
...layers.map((layer) => ` ${layer.position} z ${layer.zIndex} ${layer.element} ${layer.rect.w}x${layer.rect.h} at ${layer.rect.x},${layer.rect.y} of the viewport${layer.inView ? '' : ' (not in view now)'}`),
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The animations section.
|
|
84
|
+
*
|
|
85
|
+
* @param animations - Running animations
|
|
86
|
+
* @param canvases - Visible canvas elements
|
|
87
|
+
* @returns Lines
|
|
88
|
+
*/
|
|
89
|
+
function animationsSection(animations, canvases) {
|
|
90
|
+
const note = canvases ? [` ${auditCanvasNote(canvases)}`] : [];
|
|
91
|
+
if (animations.length === 0)
|
|
92
|
+
return ['Animations: none running', ...note];
|
|
93
|
+
return [
|
|
94
|
+
`Animations: ${animations.length} running`,
|
|
95
|
+
...animations.map((animation) => ` ${animation.name} on ${animation.element}${times(animation.count)} (${animation.type}, ${typeof animation.duration === 'number' ? `${animation.duration}ms` : animation.duration}, ${animation.iterations === 'infinite' ? 'infinite' : `${animation.iterations}x`}${animation.scrollDriven ? ', scroll-driven' : ''})`),
|
|
96
|
+
...note,
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Format `bdg css search`.
|
|
101
|
+
*
|
|
102
|
+
* @param data - Search result
|
|
103
|
+
* @returns Output
|
|
104
|
+
*/
|
|
105
|
+
export function formatCssSearch(data) {
|
|
106
|
+
if (data.total === 0)
|
|
107
|
+
return `"${data.query}" is not in the page's ${data.sheets} stylesheets`;
|
|
108
|
+
const more = data.total - data.matches.length;
|
|
109
|
+
return [
|
|
110
|
+
`"${data.query}": ${data.total} matches in ${data.sheets} stylesheets`,
|
|
111
|
+
...data.matches.flatMap((match) => [` ${match.source}`, ` ${match.text}`]),
|
|
112
|
+
...(more > 0 ? [` (+${more} more; --limit to list them)`] : []),
|
|
113
|
+
].join('\n');
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human-readable output of `bdg cdp`: search results, domain and method
|
|
3
|
+
* lists, method schemas and method results (`--json` prints the data as is).
|
|
4
|
+
*/
|
|
5
|
+
import type { ParameterSchema, ReturnSchema } from '../../cdp/schema.js';
|
|
6
|
+
/** Protocol description and flags shared by domains and methods */
|
|
7
|
+
interface ProtocolEntry {
|
|
8
|
+
description?: string | undefined;
|
|
9
|
+
experimental?: boolean | undefined;
|
|
10
|
+
deprecated?: boolean | undefined;
|
|
11
|
+
}
|
|
12
|
+
/** A method in `bdg cdp --search` results */
|
|
13
|
+
interface CdpSearchMethod extends ProtocolEntry {
|
|
14
|
+
name: string;
|
|
15
|
+
domain: string;
|
|
16
|
+
method: string;
|
|
17
|
+
parameterCount: number;
|
|
18
|
+
example?: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
/** `bdg cdp --search <query>` result */
|
|
21
|
+
export interface CdpSearchData {
|
|
22
|
+
query: string;
|
|
23
|
+
count: number;
|
|
24
|
+
methods: CdpSearchMethod[];
|
|
25
|
+
}
|
|
26
|
+
/** A domain in `bdg cdp --list` */
|
|
27
|
+
interface CdpDomainEntry extends ProtocolEntry {
|
|
28
|
+
name: string;
|
|
29
|
+
commands: number;
|
|
30
|
+
events: number;
|
|
31
|
+
dependencies?: string[] | undefined;
|
|
32
|
+
}
|
|
33
|
+
/** `bdg cdp --list` result */
|
|
34
|
+
export interface CdpDomainListData {
|
|
35
|
+
count: number;
|
|
36
|
+
domains: CdpDomainEntry[];
|
|
37
|
+
}
|
|
38
|
+
/** A method in `bdg cdp <Domain> --list` */
|
|
39
|
+
interface CdpDomainMethod extends ProtocolEntry {
|
|
40
|
+
name: string;
|
|
41
|
+
fullName: string;
|
|
42
|
+
parameterCount: number;
|
|
43
|
+
parameters: Pick<ParameterSchema, 'name' | 'type' | 'required'>[];
|
|
44
|
+
returns: Pick<ReturnSchema, 'name' | 'type'>[];
|
|
45
|
+
example?: string | undefined;
|
|
46
|
+
}
|
|
47
|
+
/** `bdg cdp <Domain> --list` result */
|
|
48
|
+
export interface CdpDomainMethodsData {
|
|
49
|
+
domain: string;
|
|
50
|
+
description?: string | undefined;
|
|
51
|
+
count: number;
|
|
52
|
+
methods: CdpDomainMethod[];
|
|
53
|
+
}
|
|
54
|
+
/** `bdg cdp <Domain> --describe` result */
|
|
55
|
+
export interface CdpDomainDescription extends ProtocolEntry {
|
|
56
|
+
type: 'domain';
|
|
57
|
+
domain: string;
|
|
58
|
+
commands: number;
|
|
59
|
+
events: number;
|
|
60
|
+
note?: string | undefined;
|
|
61
|
+
nextStep: string;
|
|
62
|
+
}
|
|
63
|
+
/** A parameter or return value in `bdg cdp <Domain.method> --describe` */
|
|
64
|
+
interface CdpField {
|
|
65
|
+
name: string;
|
|
66
|
+
type: string;
|
|
67
|
+
description?: string | undefined;
|
|
68
|
+
items?: string | undefined;
|
|
69
|
+
}
|
|
70
|
+
/** `bdg cdp <Domain.method> --describe` result */
|
|
71
|
+
export interface CdpMethodDescription extends ProtocolEntry {
|
|
72
|
+
type: 'method';
|
|
73
|
+
name: string;
|
|
74
|
+
domain: string;
|
|
75
|
+
method: string;
|
|
76
|
+
note?: string | undefined;
|
|
77
|
+
parameters: (CdpField & {
|
|
78
|
+
required: boolean;
|
|
79
|
+
enum?: string[] | undefined;
|
|
80
|
+
deprecated?: boolean | undefined;
|
|
81
|
+
})[];
|
|
82
|
+
returns: (CdpField & {
|
|
83
|
+
optional: boolean;
|
|
84
|
+
})[];
|
|
85
|
+
example?: {
|
|
86
|
+
command: string;
|
|
87
|
+
params?: Record<string, unknown> | undefined;
|
|
88
|
+
} | undefined;
|
|
89
|
+
}
|
|
90
|
+
/** `bdg cdp <Domain.method>` result */
|
|
91
|
+
export interface CdpExecuteData {
|
|
92
|
+
method: string;
|
|
93
|
+
result: unknown;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Format `bdg cdp --search <query>`.
|
|
97
|
+
*
|
|
98
|
+
* @param data - Search result
|
|
99
|
+
* @returns Matching methods with their first description sentence
|
|
100
|
+
*/
|
|
101
|
+
export declare function formatCdpSearch(data: CdpSearchData): string;
|
|
102
|
+
/**
|
|
103
|
+
* Format `bdg cdp --list`.
|
|
104
|
+
*
|
|
105
|
+
* @param data - All domains
|
|
106
|
+
* @returns One line per domain with its method and event counts
|
|
107
|
+
*/
|
|
108
|
+
export declare function formatCdpDomains(data: CdpDomainListData): string;
|
|
109
|
+
/**
|
|
110
|
+
* Format `bdg cdp <Domain> --list`.
|
|
111
|
+
*
|
|
112
|
+
* @param data - The domain's methods
|
|
113
|
+
* @returns One line per method with the first sentence of its description
|
|
114
|
+
*/
|
|
115
|
+
export declare function formatCdpDomainMethods(data: CdpDomainMethodsData): string;
|
|
116
|
+
/**
|
|
117
|
+
* Format `bdg cdp <Domain.method> --describe` or `bdg cdp <Domain> --describe`.
|
|
118
|
+
*
|
|
119
|
+
* @param data - Method or domain description
|
|
120
|
+
* @returns Description, parameters (`?` = optional), returns, note and example
|
|
121
|
+
*/
|
|
122
|
+
export declare function formatCdpDescription(data: CdpMethodDescription | CdpDomainDescription): string;
|
|
123
|
+
/**
|
|
124
|
+
* Whether a CDP method returned nothing (null, undefined or an empty object).
|
|
125
|
+
*
|
|
126
|
+
* @param result - Method result
|
|
127
|
+
* @returns True for an empty result
|
|
128
|
+
*/
|
|
129
|
+
export declare function isEmptyCdpResult(result: unknown): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Format a CDP method's result: the result object as indented JSON.
|
|
132
|
+
*
|
|
133
|
+
* @param data - Method and its result
|
|
134
|
+
* @returns The result, or a line saying the method returned nothing
|
|
135
|
+
*/
|
|
136
|
+
export declare function formatCdpResult(data: CdpExecuteData): string;
|
|
137
|
+
export {};
|
|
138
|
+
//# sourceMappingURL=cdp.d.ts.map
|