browser-debugger-cli 0.12.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.
Files changed (180) hide show
  1. package/.claude/skills/bdg/SKILL.md +4 -4
  2. package/README.md +1 -0
  3. package/dist/commands/cdp.d.ts +22 -1
  4. package/dist/commands/cdp.js +100 -43
  5. package/dist/commands/console.d.ts +12 -0
  6. package/dist/commands/console.js +62 -12
  7. package/dist/commands/dom/DomElementResolver.d.ts +3 -1
  8. package/dist/commands/dom/DomElementResolver.js +10 -3
  9. package/dist/commands/dom/a11y.js +3 -2
  10. package/dist/commands/dom/eval.d.ts +3 -2
  11. package/dist/commands/dom/eval.js +11 -5
  12. package/dist/commands/dom/form.js +10 -9
  13. package/dist/commands/dom/formInteraction.js +8 -7
  14. package/dist/commands/dom/get.js +8 -8
  15. package/dist/commands/dom/helpers/index.d.ts +1 -1
  16. package/dist/commands/dom/helpers/index.js +1 -1
  17. package/dist/commands/dom/helpers/query.d.ts +27 -3
  18. package/dist/commands/dom/helpers/query.js +152 -64
  19. package/dist/commands/dom/helpers/screenshot.js +13 -13
  20. package/dist/commands/dom/index.js +4 -2
  21. package/dist/commands/dom/query.d.ts +19 -2
  22. package/dist/commands/dom/query.js +37 -6
  23. package/dist/commands/dom/screenshot.js +2 -1
  24. package/dist/commands/dom/semanticUtils.d.ts +3 -2
  25. package/dist/commands/dom/semanticUtils.js +40 -9
  26. package/dist/commands/helpJson.d.ts +82 -19
  27. package/dist/commands/helpJson.js +111 -40
  28. package/dist/commands/helpTopic.d.ts +16 -1
  29. package/dist/commands/helpTopic.js +59 -1
  30. package/dist/commands/installSkill.d.ts +15 -5
  31. package/dist/commands/installSkill.js +86 -16
  32. package/dist/commands/network/list.js +22 -12
  33. package/dist/commands/optionBehaviors.js +33 -11
  34. package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
  35. package/dist/commands/shared/daemonErrorHandler.js +20 -9
  36. package/dist/commands/shared/dataFetcher.d.ts +12 -4
  37. package/dist/commands/shared/dataFetcher.js +12 -4
  38. package/dist/commands/shared/followMode.d.ts +9 -1
  39. package/dist/commands/shared/followMode.js +22 -4
  40. package/dist/commands/shared/optionTypes.d.ts +4 -1
  41. package/dist/commands/shared/outputFile.js +6 -1
  42. package/dist/commands/start.d.ts +7 -5
  43. package/dist/commands/start.js +65 -21
  44. package/dist/commands/stop.d.ts +11 -0
  45. package/dist/commands/stop.js +24 -1
  46. package/dist/commands.js +1 -1
  47. package/dist/connection/cdp.d.ts +7 -0
  48. package/dist/connection/cdp.js +9 -0
  49. package/dist/connection/launcher.js +3 -2
  50. package/dist/daemon/SessionController.js +6 -1
  51. package/dist/daemon/launcher.d.ts +3 -2
  52. package/dist/daemon/launcher.js +47 -3
  53. package/dist/daemon/session/Session.d.ts +4 -1
  54. package/dist/daemon/session/Session.js +33 -2
  55. package/dist/daemon/session/TelemetryStore.d.ts +8 -1
  56. package/dist/daemon/session/TelemetryStore.js +13 -1
  57. package/dist/daemon/session/commandRegistry.js +29 -13
  58. package/dist/daemon/session/interactions.d.ts +2 -1
  59. package/dist/daemon/session/interactions.js +13 -1
  60. package/dist/daemon/session/plugins.js +16 -2
  61. package/dist/daemon/session/teardown.js +1 -1
  62. package/dist/daemon.js +1622 -748
  63. package/dist/errors/messages.d.ts +54 -11
  64. package/dist/errors/messages.js +109 -22
  65. package/dist/index.js +13733 -8796
  66. package/dist/ipc/client.d.ts +18 -2
  67. package/dist/ipc/client.js +26 -5
  68. package/dist/ipc/protocol/auditTypes.d.ts +8 -2
  69. package/dist/ipc/protocol/commands.d.ts +12 -0
  70. package/dist/ipc/protocol/domTypes.d.ts +12 -0
  71. package/dist/ipc/protocol/inspectTypes.d.ts +2 -0
  72. package/dist/ipc/session/types.d.ts +2 -0
  73. package/dist/runtime/dom/actionEffects.d.ts +5 -1
  74. package/dist/runtime/dom/actionEffects.js +26 -14
  75. package/dist/runtime/dom/audit.js +3 -2
  76. package/dist/runtime/dom/auditModel.js +6 -1
  77. package/dist/runtime/dom/auditScripts.d.ts +9 -3
  78. package/dist/runtime/dom/auditScripts.js +41 -5
  79. package/dist/runtime/dom/elementGeometry.d.ts +10 -3
  80. package/dist/runtime/dom/elementGeometry.js +27 -4
  81. package/dist/runtime/dom/elementInfo.d.ts +74 -18
  82. package/dist/runtime/dom/elementInfo.js +187 -40
  83. package/dist/runtime/dom/evalHelpers.d.ts +12 -2
  84. package/dist/runtime/dom/evalHelpers.js +67 -7
  85. package/dist/runtime/dom/formDiscovery.d.ts +6 -2
  86. package/dist/runtime/dom/formDiscovery.js +20 -3
  87. package/dist/runtime/dom/formFillHelpers/fill.js +7 -11
  88. package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
  89. package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
  90. package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
  91. package/dist/runtime/dom/formSubmitHelpers.js +4 -3
  92. package/dist/runtime/dom/frameLayout.js +1 -0
  93. package/dist/runtime/dom/inspect.js +5 -6
  94. package/dist/runtime/dom/inspectAllStyles.js +1 -0
  95. package/dist/runtime/dom/inspectHints.d.ts +1 -1
  96. package/dist/runtime/dom/inspectModel.d.ts +2 -1
  97. package/dist/runtime/dom/inspectModel.js +7 -3
  98. package/dist/runtime/dom/inspectPaintModel.d.ts +2 -0
  99. package/dist/runtime/dom/inspectPaintModel.js +3 -1
  100. package/dist/runtime/dom/inspectScripts.d.ts +29 -2
  101. package/dist/runtime/dom/inspectScripts.js +49 -10
  102. package/dist/runtime/dom/layout.js +9 -7
  103. package/dist/runtime/dom/reactEventHelpers.d.ts +14 -4
  104. package/dist/runtime/dom/reactEventHelpers.js +63 -27
  105. package/dist/runtime/dom/targetNode.d.ts +18 -5
  106. package/dist/runtime/dom/targetNode.js +268 -8
  107. package/dist/runtime/dom/wait.js +2 -1
  108. package/dist/runtime/page/bdgWorld.d.ts +57 -0
  109. package/dist/runtime/page/bdgWorld.js +180 -0
  110. package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
  111. package/dist/runtime/page/replacedBuiltins.js +136 -0
  112. package/dist/session/QueryCacheManager.d.ts +4 -1
  113. package/dist/session/QueryCacheManager.js +5 -2
  114. package/dist/session/chrome.d.ts +4 -1
  115. package/dist/session/chrome.js +7 -1
  116. package/dist/session/cleanup/staleSession.d.ts +21 -4
  117. package/dist/session/cleanup/staleSession.js +79 -9
  118. package/dist/session/cleanup/userCommands.d.ts +4 -1
  119. package/dist/session/cleanup/userCommands.js +10 -5
  120. package/dist/session/daemonSocket.d.ts +10 -0
  121. package/dist/session/daemonSocket.js +22 -0
  122. package/dist/session/lastSession.d.ts +6 -3
  123. package/dist/session/lastSession.js +11 -5
  124. package/dist/session/paths.d.ts +3 -1
  125. package/dist/session/paths.js +5 -5
  126. package/dist/session/portClaims.js +4 -3
  127. package/dist/session/sessionList.d.ts +13 -5
  128. package/dist/session/sessionList.js +31 -7
  129. package/dist/telemetry/a11y.js +2 -2
  130. package/dist/telemetry/console.d.ts +2 -1
  131. package/dist/telemetry/console.js +30 -21
  132. package/dist/telemetry/pageCrash.d.ts +26 -0
  133. package/dist/telemetry/pageCrash.js +53 -0
  134. package/dist/types.d.ts +16 -0
  135. package/dist/ui/formatters/audit.js +14 -5
  136. package/dist/ui/formatters/cdp.d.ts +138 -0
  137. package/dist/ui/formatters/cdp.js +131 -0
  138. package/dist/ui/formatters/console/chronological.js +3 -1
  139. package/dist/ui/formatters/console/follow.d.ts +2 -1
  140. package/dist/ui/formatters/console/follow.js +2 -2
  141. package/dist/ui/formatters/console/json.d.ts +2 -2
  142. package/dist/ui/formatters/console/json.js +11 -5
  143. package/dist/ui/formatters/console/shared.d.ts +30 -0
  144. package/dist/ui/formatters/console/shared.js +16 -0
  145. package/dist/ui/formatters/console/summarize.d.ts +9 -2
  146. package/dist/ui/formatters/console/summarize.js +40 -9
  147. package/dist/ui/formatters/console.d.ts +2 -1
  148. package/dist/ui/formatters/console.js +7 -5
  149. package/dist/ui/formatters/details.js +3 -1
  150. package/dist/ui/formatters/dom.d.ts +1 -1
  151. package/dist/ui/formatters/dom.js +5 -6
  152. package/dist/ui/formatters/helpFormatters.js +1 -1
  153. package/dist/ui/formatters/inspect.js +9 -3
  154. package/dist/ui/formatters/installSkill.d.ts +9 -1
  155. package/dist/ui/formatters/installSkill.js +32 -6
  156. package/dist/ui/formatters/layout.js +2 -1
  157. package/dist/ui/formatters/networkList.d.ts +1 -1
  158. package/dist/ui/formatters/networkList.js +1 -2
  159. package/dist/ui/formatters/preview.d.ts +2 -0
  160. package/dist/ui/formatters/preview.js +17 -7
  161. package/dist/ui/formatters/sessions.d.ts +2 -2
  162. package/dist/ui/formatters/sessions.js +9 -2
  163. package/dist/ui/logging/logger.d.ts +1 -1
  164. package/dist/ui/messages/commands.d.ts +124 -4
  165. package/dist/ui/messages/commands.js +162 -7
  166. package/dist/ui/messages/consoleMessages.d.ts +24 -0
  167. package/dist/ui/messages/consoleMessages.js +32 -0
  168. package/dist/ui/messages/preview.d.ts +6 -0
  169. package/dist/ui/messages/preview.js +9 -1
  170. package/dist/ui/messages/session.d.ts +13 -2
  171. package/dist/ui/messages/session.js +22 -3
  172. package/dist/utils/directories.d.ts +34 -0
  173. package/dist/utils/directories.js +88 -0
  174. package/dist/utils/display.d.ts +16 -0
  175. package/dist/utils/display.js +42 -0
  176. package/dist/utils/exitCodes.d.ts +1 -0
  177. package/dist/utils/exitCodes.js +6 -0
  178. package/dist/utils/process.d.ts +12 -0
  179. package/dist/utils/process.js +25 -0
  180. package/package.json +1 -1
@@ -18,6 +18,7 @@ import { readPageLoadingState } from '../../runtime/page/loadingState.js';
18
18
  import { reapOrphanedChrome, removeSessionFiles } from '../../session/cleanup/staleSession.js';
19
19
  import { writeSessionMetadata } from '../../session/metadata.js';
20
20
  import { getSessionPort } from '../../session/port.js';
21
+ import { pageCrashedCommandError } from '../../telemetry/pageCrash.js';
21
22
  import { createLogger } from '../../ui/logging/index.js';
22
23
  import { formatChromeNotice } from '../../ui/messages/chrome.js';
23
24
  import { delay } from '../../utils/async.js';
@@ -31,6 +32,26 @@ const log = createLogger('session');
31
32
  const CRASH_SETTLE_MS = 500;
32
33
  /** Ports tried when automatically chosen ports turn out to be taken */
33
34
  const PORT_ATTEMPTS = 3;
35
+ /**
36
+ * Commands that still work after the page's renderer crashed: they read what
37
+ * the session collected, load the page again (`page reload`/`navigate`) or
38
+ * send raw CDP. Every other command needs the page and fails at once.
39
+ */
40
+ const RUN_ON_CRASHED_PAGE = new Set([
41
+ 'session_peek',
42
+ 'session_details',
43
+ 'session_status',
44
+ 'session_har_data',
45
+ 'session_network_headers',
46
+ 'page_navigate',
47
+ 'cdp_call',
48
+ ]);
49
+ /**
50
+ * CDP methods `bdg cdp` may still send after a renderer crash: loading the
51
+ * page again, and domains the browser process answers. Others wait for the
52
+ * renderer, which never answers.
53
+ */
54
+ const CRASH_SAFE_CDP = /^(Page\.(navigate|reload|getNavigationHistory|navigateToHistoryEntry)|Target\.|Browser\.|Inspector\.|Network\.(?!getResponseBody|getRequestPostData)|Storage\.|SystemInfo\.)/;
34
55
  /**
35
56
  * Whether a launch failed because another process holds the port.
36
57
  *
@@ -127,7 +148,10 @@ export class Session {
127
148
  }
128
149
  }
129
150
  /**
130
- * Execute a registered command against this session.
151
+ * Execute a registered command against this session. After a renderer
152
+ * crash only {@link RUN_ON_CRASHED_PAGE} commands run (`bdg cdp` only for
153
+ * {@link CRASH_SAFE_CDP} methods); others fail with exit 107 instead of
154
+ * waiting for a page that cannot answer.
131
155
  *
132
156
  * @param name - Command name
133
157
  * @param params - Command parameters
@@ -137,6 +161,13 @@ export class Session {
137
161
  if (!this.cdp || !this.started || this.stopping) {
138
162
  return Promise.reject(new Error('No active session'));
139
163
  }
164
+ const crashedAt = this.store.pageCrashedAt;
165
+ const cdpMethod = name === 'cdp_call' ? params.method : undefined;
166
+ const needsPage = !RUN_ON_CRASHED_PAGE.has(name) ||
167
+ (cdpMethod !== undefined && !CRASH_SAFE_CDP.test(cdpMethod));
168
+ if (crashedAt !== undefined && needsPage) {
169
+ return Promise.reject(pageCrashedCommandError(crashedAt));
170
+ }
140
171
  return this.registry[name](this.cdp, params);
141
172
  }
142
173
  /**
@@ -223,7 +254,7 @@ export class Session {
223
254
  await this.releaseResources();
224
255
  if (!this.started)
225
256
  return;
226
- removeSessionFiles();
257
+ removeSessionFiles(process.pid);
227
258
  this.onEnded(reason);
228
259
  })();
229
260
  return this.stopping;
@@ -7,11 +7,18 @@ export declare class TelemetryStore {
7
7
  /** Requests still in flight, keyed by CDP requestId */
8
8
  readonly pendingNetworkRequests: Map<string, PendingRequest>;
9
9
  readonly consoleMessages: ConsoleMessage[];
10
+ /**
11
+ * Console messages dropped at the limit, oldest first: the index of
12
+ * `consoleMessages[i]` in the session is `consoleDropped + i`
13
+ */
14
+ consoleDropped: number;
10
15
  readonly navigationEvents: NavigationEvent[];
11
16
  readonly websocketConnections: WebSocketConnection[];
12
17
  /** JavaScript dialogs accepted during the session */
13
18
  readonly dialogs: DialogInfo[];
14
19
  activeTelemetry: TelemetryType[];
20
+ /** When the page's renderer crashed (epoch ms); undefined while the page is alive */
21
+ pageCrashedAt: number | undefined;
15
22
  getCurrentNavigationId: (() => number) | null;
16
23
  sessionStartTime: number;
17
24
  targetInfo: CDPTarget | null;
@@ -21,7 +28,7 @@ export declare class TelemetryStore {
21
28
  /**
22
29
  * Record an accepted dialog, and show it among the console messages when
23
30
  * console telemetry is collected (it is otherwise invisible: bdg accepts it
24
- * before anyone could see it).
31
+ * before anyone could see it), dropping the oldest message at the limit.
25
32
  *
26
33
  * @param dialog - Dialog type and text
27
34
  */
@@ -1,14 +1,22 @@
1
+ import { MAX_CONSOLE_MESSAGES } from '../../constants.js';
1
2
  import { dialogConsoleText } from '../../ui/messages/commands.js';
2
3
  export class TelemetryStore {
3
4
  networkRequests = [];
4
5
  /** Requests still in flight, keyed by CDP requestId */
5
6
  pendingNetworkRequests = new Map();
6
7
  consoleMessages = [];
8
+ /**
9
+ * Console messages dropped at the limit, oldest first: the index of
10
+ * `consoleMessages[i]` in the session is `consoleDropped + i`
11
+ */
12
+ consoleDropped = 0;
7
13
  navigationEvents = [];
8
14
  websocketConnections = [];
9
15
  /** JavaScript dialogs accepted during the session */
10
16
  dialogs = [];
11
17
  activeTelemetry = [];
18
+ /** When the page's renderer crashed (epoch ms); undefined while the page is alive */
19
+ pageCrashedAt;
12
20
  getCurrentNavigationId = null;
13
21
  sessionStartTime = Date.now();
14
22
  targetInfo = null;
@@ -24,7 +32,7 @@ export class TelemetryStore {
24
32
  /**
25
33
  * Record an accepted dialog, and show it among the console messages when
26
34
  * console telemetry is collected (it is otherwise invisible: bdg accepts it
27
- * before anyone could see it).
35
+ * before anyone could see it), dropping the oldest message at the limit.
28
36
  *
29
37
  * @param dialog - Dialog type and text
30
38
  */
@@ -32,6 +40,10 @@ export class TelemetryStore {
32
40
  this.dialogs.push(dialog);
33
41
  if (!this.activeTelemetry.includes('console'))
34
42
  return;
43
+ if (this.consoleMessages.length >= MAX_CONSOLE_MESSAGES) {
44
+ this.consoleMessages.shift();
45
+ this.consoleDropped++;
46
+ }
35
47
  this.consoleMessages.push({
36
48
  type: 'info',
37
49
  text: dialogConsoleText(dialog),
@@ -17,10 +17,12 @@ import { inspectElement } from '../../runtime/dom/inspect.js';
17
17
  import { inspectLayout } from '../../runtime/dom/layout.js';
18
18
  import { onScriptTarget } from '../../runtime/dom/targetNode.js';
19
19
  import { waitForCondition } from '../../runtime/dom/wait.js';
20
+ import { evaluateInBdgWorld, sendForBdgScript } from '../../runtime/page/bdgWorld.js';
20
21
  import { emulatePage, pageAppearance } from '../../runtime/page/emulation.js';
21
22
  import { readDocumentReadyState } from '../../runtime/page/loadingState.js';
22
23
  import { navigatePage } from '../../runtime/page/navigation.js';
23
24
  import { skippedBodyReason } from '../../telemetry/network.js';
25
+ import { consoleMessageDroppedError } from '../../ui/messages/consoleMessages.js';
24
26
  import { sessionCommand } from '../../ui/messages/sessionCommand.js';
25
27
  import { EXIT_CODES } from '../../utils/exitCodes.js';
26
28
  import { filterDefined } from '../../utils/objects.js';
@@ -187,24 +189,28 @@ function findNetworkRequestOrThrow(store, id) {
187
189
  return request;
188
190
  }
189
191
  /**
190
- * Find console message by index or throw.
192
+ * Find console message by its session index or throw.
191
193
  *
192
- * @param messages - Array of console messages
194
+ * @param messages - Console messages kept
193
195
  * @param indexStr - Index as string
196
+ * @param dropped - Messages dropped before the first kept one (its index)
194
197
  * @returns Found message
195
- * @throws Error if invalid index or not found
198
+ * @throws CommandError if the index is invalid, dropped or not found
196
199
  */
197
- function findConsoleMessageOrThrow(messages, indexStr) {
200
+ function findConsoleMessageOrThrow(messages, indexStr, dropped) {
198
201
  if (!/^\d+$/.test(indexStr)) {
199
202
  throw new CommandError(`Invalid console message index: ${indexStr}`, { suggestion: `Use a 0-based index from: ${sessionCommand('bdg console --list')}` }, EXIT_CODES.INVALID_ARGUMENTS);
200
203
  }
201
204
  const index = parseInt(indexStr, 10);
202
- if (index >= messages.length) {
205
+ if (index < dropped) {
206
+ throw new CommandError(consoleMessageDroppedError(index, dropped), { suggestion: `List messages with: ${sessionCommand('bdg console --list')}` }, EXIT_CODES.RESOURCE_NOT_FOUND);
207
+ }
208
+ if (index - dropped >= messages.length) {
203
209
  throw new CommandError(messages.length === 0
204
210
  ? `Console message not found at index: ${indexStr} (no messages captured yet)`
205
- : `Console message not found at index: ${indexStr} (available: 0-${messages.length - 1})`, { suggestion: `List messages with: ${sessionCommand('bdg console --list')}` }, EXIT_CODES.RESOURCE_NOT_FOUND);
211
+ : `Console message not found at index: ${indexStr} (available: ${dropped}-${dropped + messages.length - 1})`, { suggestion: `List messages with: ${sessionCommand('bdg console --list')}` }, EXIT_CODES.RESOURCE_NOT_FOUND);
206
212
  }
207
- const message = messages[index];
213
+ const message = messages[index - dropped];
208
214
  if (!message) {
209
215
  throw new CommandError(`Console message not found at index: ${indexStr}`, {}, EXIT_CODES.RESOURCE_NOT_FOUND);
210
216
  }
@@ -312,6 +318,7 @@ export function createCommandRegistry(store, emulation) {
312
318
  const allNetwork = allNetworkRequests(store);
313
319
  const totalNetwork = allNetwork.length;
314
320
  const totalConsole = store.consoleMessages.length;
321
+ const dropped = store.consoleDropped;
315
322
  const networkBounds = calculateSliceBounds(totalNetwork, lastN, offset);
316
323
  const consoleBounds = calculateSliceBounds(totalConsole, lastN, offset);
317
324
  const recentNetwork = params.only === 'console'
@@ -323,7 +330,7 @@ export function createCommandRegistry(store, emulation) {
323
330
  ? []
324
331
  : store.consoleMessages
325
332
  .slice(consoleBounds.start, consoleBounds.end)
326
- .map((msg, i) => mapConsoleMessageToPreview(msg, consoleBounds.start + i));
333
+ .map((msg, i) => mapConsoleMessageToPreview(msg, dropped + consoleBounds.start + i));
327
334
  return Promise.resolve({
328
335
  version: VERSION,
329
336
  startTime: store.sessionStartTime,
@@ -334,10 +341,12 @@ export function createCommandRegistry(store, emulation) {
334
341
  },
335
342
  activeTelemetry: store.activeTelemetry,
336
343
  currentNavigationId: store.getCurrentNavigationId?.() ?? 0,
344
+ ...(store.pageCrashedAt !== undefined && { pageCrashedAt: store.pageCrashedAt }),
337
345
  network: recentNetwork,
338
346
  console: recentConsole,
339
347
  totalNetwork,
340
348
  totalConsole,
349
+ ...(dropped > 0 && { droppedConsole: dropped }),
341
350
  hasMoreNetwork: networkBounds.start > 0,
342
351
  hasMoreConsole: consoleBounds.start > 0,
343
352
  });
@@ -348,7 +357,7 @@ export function createCommandRegistry(store, emulation) {
348
357
  return Promise.resolve({ item: withBodyNotCaptured(request) });
349
358
  }
350
359
  if (params.itemType === 'console') {
351
- const message = findConsoleMessageOrThrow(store.consoleMessages, params.id);
360
+ const message = findConsoleMessageOrThrow(store.consoleMessages, params.id, store.consoleDropped);
352
361
  return Promise.resolve({ item: message });
353
362
  }
354
363
  return Promise.reject(new Error(`Unknown itemType: ${String(params.itemType)}. Expected 'network' or 'console'.`));
@@ -363,7 +372,9 @@ export function createCommandRegistry(store, emulation) {
363
372
  target: {
364
373
  url: store.targetInfo?.url ?? '',
365
374
  title: store.targetInfo?.title ?? '',
366
- ...(await pageAppearance(cdp)),
375
+ ...(store.pageCrashedAt === undefined
376
+ ? await pageAppearance(cdp)
377
+ : { crashedAt: store.pageCrashedAt }),
367
378
  },
368
379
  activeTelemetry: store.activeTelemetry,
369
380
  activity: filterDefined({
@@ -401,10 +412,15 @@ export function createCommandRegistry(store, emulation) {
401
412
  });
402
413
  },
403
414
  cdp_call: async (cdp, params) => {
404
- const result = await withBusyPageRecovery(cdp, cdp.send(params.method, params.params ?? {}).catch((error) => {
415
+ const send = params.isolated
416
+ ? sendForBdgScript(cdp, params.method, params.params ?? {})
417
+ : cdp.send(params.method, params.params ?? {});
418
+ const result = await withBusyPageRecovery(cdp, send.catch((error) => {
405
419
  throw callerError(params.method, error) ?? error;
406
420
  }));
407
- const detectionResult = patternDetector.trackCommand(params.method);
421
+ const detectionResult = params.isolated
422
+ ? { shouldShow: false, pattern: undefined }
423
+ : patternDetector.trackCommand(params.method);
408
424
  let hint;
409
425
  if (detectionResult.shouldShow && detectionResult.pattern) {
410
426
  hint = {
@@ -475,7 +491,7 @@ export function createCommandRegistry(store, emulation) {
475
491
  return { emulated, ...(await pageAppearance(cdp)) };
476
492
  },
477
493
  dom_form_discover: async (cdp) => {
478
- const response = await withBusyPageRecovery(cdp, cdp.send('Runtime.evaluate', {
494
+ const response = await withBusyPageRecovery(cdp, evaluateInBdgWorld(cdp, {
479
495
  expression: FORM_DISCOVERY_SCRIPT,
480
496
  returnByValue: true,
481
497
  }));
@@ -51,7 +51,8 @@ export type InteractionRunner = <T extends object>(cdp: CDPConnection, action: (
51
51
  * queued. After each one, the bound target (`window.__bdgTarget`) is removed
52
52
  * from the page (without waiting: during a pending navigation that takes until
53
53
  * the new page commits), and the dialogs it opened, what it changed on the
54
- * page (see {@link watchActionEffects}) and the network requests it
54
+ * page (see {@link watchActionEffects}; a console message logged meanwhile
55
+ * counts as an effect) and the network requests it
55
56
  * triggered (see {@link watchTriggeredRequests}) are added to its result,
56
57
  * and, when asked, what the page was still working on (see
57
58
  * {@link pendingChanges}). They are attributed by time: a dialog or request
@@ -18,6 +18,15 @@ const log = createLogger('dom');
18
18
  function succeeded(result) {
19
19
  return !('success' in result) || result.success !== false;
20
20
  }
21
+ /**
22
+ * Console messages the session has logged, dropped ones included.
23
+ *
24
+ * @param store - Session store
25
+ * @returns Count that only grows
26
+ */
27
+ function consoleMessagesLogged(store) {
28
+ return store.consoleDropped + store.consoleMessages.length;
29
+ }
21
30
  /**
22
31
  * Create the runner for a session's interactions.
23
32
  *
@@ -26,7 +35,8 @@ function succeeded(result) {
26
35
  * queued. After each one, the bound target (`window.__bdgTarget`) is removed
27
36
  * from the page (without waiting: during a pending navigation that takes until
28
37
  * the new page commits), and the dialogs it opened, what it changed on the
29
- * page (see {@link watchActionEffects}) and the network requests it
38
+ * page (see {@link watchActionEffects}; a console message logged meanwhile
39
+ * counts as an effect) and the network requests it
30
40
  * triggered (see {@link watchTriggeredRequests}) are added to its result,
31
41
  * and, when asked, what the page was still working on (see
32
42
  * {@link pendingChanges}). They are attributed by time: a dialog or request
@@ -41,6 +51,7 @@ export function createInteractionRunner(store) {
41
51
  return (cdp, action, options = {}) => {
42
52
  const run = queue.then(async () => {
43
53
  const firstDialog = store.dialogs.length;
54
+ const firstConsoleMessage = consoleMessagesLogged(store);
44
55
  const collectRequests = options.reportRequests === false ? undefined : watchTriggeredRequests(store);
45
56
  const effects = options.reportEffects === false ? undefined : watchActionEffects(cdp);
46
57
  try {
@@ -50,6 +61,7 @@ export function createInteractionRunner(store) {
50
61
  return { ...result, ...(dialogs.length > 0 && { dialogs }) };
51
62
  const collected = await effects?.collect({
52
63
  dialogs: dialogs.length,
64
+ consoleMessages: () => consoleMessagesLogged(store) - firstConsoleMessage,
53
65
  detectNoEffect: options.detectNoEffect === true,
54
66
  reportShown: options.reportShown === true,
55
67
  detectUnsettled: options.detectUnsettled === true,
@@ -1,10 +1,11 @@
1
+ import { hideHeadlessUserAgent } from '../../runtime/page/userAgent.js';
1
2
  import { startConsoleCollection } from '../../telemetry/console.js';
2
3
  import { startDialogHandling } from '../../telemetry/dialogs.js';
3
4
  import { prepareDOMCollection } from '../../telemetry/dom.js';
4
5
  import { startNavigationTracking } from '../../telemetry/navigation.js';
5
6
  import { startNetworkCollection, startWebSocketCollection } from '../../telemetry/network.js';
7
+ import { pageCrashedCommandError, startCrashTracking } from '../../telemetry/pageCrash.js';
6
8
  import { getErrorMessage } from '../../utils/errors.js';
7
- import { hideHeadlessUserAgent } from '../../runtime/page/userAgent.js';
8
9
  import { filterDefined } from '../../utils/objects.js';
9
10
  /** Delay before reading the title after a same-document navigation */
10
11
  const TITLE_REFRESH_DELAY_MS = 300;
@@ -103,6 +104,17 @@ export function createDefaultTelemetryPlugins() {
103
104
  return () => undefined;
104
105
  },
105
106
  },
107
+ {
108
+ name: 'page-crash',
109
+ runAlways: true,
110
+ async start({ cdp, store }) {
111
+ return startCrashTracking(cdp, (crashedAt) => {
112
+ store.pageCrashedAt = crashedAt;
113
+ if (crashedAt !== undefined)
114
+ cdp.rejectPending(pageCrashedCommandError(crashedAt));
115
+ });
116
+ },
117
+ },
106
118
  {
107
119
  name: 'navigation',
108
120
  runAlways: true,
@@ -143,7 +155,9 @@ export function createDefaultTelemetryPlugins() {
143
155
  name: 'console',
144
156
  telemetry: 'console',
145
157
  async start({ cdp, config, store }) {
146
- return startConsoleCollection(cdp, store.consoleMessages, config.includeAll ?? false, store.getCurrentNavigationId ?? undefined);
158
+ return startConsoleCollection(cdp, store.consoleMessages, config.includeAll ?? false, store.getCurrentNavigationId ?? undefined, () => {
159
+ store.consoleDropped++;
160
+ });
147
161
  },
148
162
  },
149
163
  {
@@ -123,6 +123,6 @@ async function terminateChrome(chrome, log) {
123
123
  log.info(`Chrome (PID ${pid}) survived SIGKILL`);
124
124
  return;
125
125
  }
126
- clearChromePid();
126
+ clearChromePid(pid);
127
127
  }
128
128
  //# sourceMappingURL=teardown.js.map