chrome-devtools-mcp 0.8.0 → 0.9.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 (87) hide show
  1. package/README.md +79 -5
  2. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Gzip.js +8 -6
  3. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Settings.js +1 -1
  4. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Worker.js +10 -2
  5. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/UserMetrics.js +2 -1
  6. package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/ArrayUtilities.js +1 -1
  7. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/ConnectionTransport.js +12 -0
  8. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/InspectorBackend.js +15 -27
  9. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/protocol_client.js +2 -8
  10. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMatchedStyles.js +42 -7
  11. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSRule.js +34 -6
  12. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ChildTargetManager.js +3 -0
  13. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/Connections.js +2 -2
  14. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DOMModel.js +3 -0
  15. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DebuggerModel.js +2 -1
  16. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkManager.js +336 -40
  17. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/PreloadingModel.js +56 -13
  18. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RehydratingConnection.js +32 -7
  19. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ResourceTreeModel.js +1 -1
  20. package/build/node_modules/chrome-devtools-frontend/front_end/{models/source_map_scopes → core/sdk}/ScopeTreeCache.js +9 -5
  21. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMap.js +48 -11
  22. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapManager.js +8 -2
  23. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapScopesInfo.js +131 -8
  24. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TargetManager.js +0 -21
  25. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TraceObject.js +9 -6
  26. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/sdk.js +2 -1
  27. package/build/node_modules/chrome-devtools-frontend/front_end/generated/ARIAProperties.js +1301 -174
  28. package/build/node_modules/chrome-devtools-frontend/front_end/generated/Deprecation.js +7 -0
  29. package/build/node_modules/chrome-devtools-frontend/front_end/generated/InspectorBackendCommands.js +8 -6
  30. package/build/node_modules/chrome-devtools-frontend/front_end/generated/SupportedCSSProperties.js +16 -19
  31. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.js +50 -34
  32. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AICallTree.js +2 -3
  33. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CompilerScriptMapping.js +45 -2
  34. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +14 -0
  35. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/NamesResolver.js +5 -11
  36. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/source_map_scopes.js +1 -2
  37. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/Trie.js +8 -0
  38. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/ModelImpl.js +6 -3
  39. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/TraceTree.js +10 -3
  40. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/MetaHandler.js +4 -1
  41. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/UserTimingsHandler.js +1 -1
  42. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/CLSCulprits.js +2 -1
  43. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Cache.js +2 -1
  44. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DOMSize.js +2 -1
  45. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DocumentLatency.js +2 -1
  46. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DuplicatedJavaScript.js +2 -1
  47. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/FontDisplay.js +2 -1
  48. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ForcedReflow.js +3 -2
  49. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/INPBreakdown.js +2 -1
  50. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ImageDelivery.js +2 -1
  51. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +2 -1
  52. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPDiscovery.js +2 -1
  53. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LegacyJavaScript.js +2 -1
  54. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ModernHTTP.js +2 -1
  55. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +2 -1
  56. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/RenderBlocking.js +2 -1
  57. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/SlowCSSSelector.js +2 -1
  58. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ThirdParties.js +2 -1
  59. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Viewport.js +2 -1
  60. package/build/src/DevToolsConnectionAdapter.js +32 -0
  61. package/build/src/McpContext.js +81 -31
  62. package/build/src/McpResponse.js +149 -45
  63. package/build/src/PageCollector.js +110 -26
  64. package/build/src/WaitForHelper.js +5 -0
  65. package/build/src/browser.js +17 -7
  66. package/build/src/cli.js +82 -6
  67. package/build/src/formatters/consoleFormatter.js +29 -62
  68. package/build/src/formatters/networkFormatter.js +5 -6
  69. package/build/src/formatters/snapshotFormatter.js +23 -51
  70. package/build/src/logger.js +1 -1
  71. package/build/src/main.js +27 -26
  72. package/build/src/polyfill.js +2 -2
  73. package/build/src/third_party/THIRD_PARTY_NOTICES +1393 -0
  74. package/build/src/third_party/index.js +76159 -0
  75. package/build/src/tools/ToolDefinition.js +2 -2
  76. package/build/src/tools/categories.js +17 -9
  77. package/build/src/tools/console.js +71 -6
  78. package/build/src/tools/emulation.js +6 -7
  79. package/build/src/tools/input.js +78 -41
  80. package/build/src/tools/network.js +18 -10
  81. package/build/src/tools/pages.js +21 -21
  82. package/build/src/tools/performance.js +8 -8
  83. package/build/src/tools/screenshot.js +8 -8
  84. package/build/src/tools/script.js +29 -15
  85. package/build/src/tools/snapshot.js +15 -20
  86. package/build/src/utils/types.js +6 -0
  87. package/package.json +17 -14
package/README.md CHANGED
@@ -53,6 +53,16 @@ Add the following config to your MCP client:
53
53
 
54
54
  ### MCP Client configuration
55
55
 
56
+ <details>
57
+ <summary>Amp</summary>
58
+ Follow https://ampcode.com/manual#mcp and use the config provided above. You can also install the Chrome DevTools MCP server using the CLI:
59
+
60
+ ```bash
61
+ amp mcp add chrome-devtools -- npx chrome-devtools-mcp@latest
62
+ ```
63
+
64
+ </details>
65
+
56
66
  <details>
57
67
  <summary>Claude Code</summary>
58
68
  Use the Claude Code CLI to add the Chrome DevTools MCP server (<a href="https://docs.anthropic.com/en/docs/claude-code/mcp">guide</a>):
@@ -115,8 +125,7 @@ Configure the following fields and press `CTRL+S` to save the configuration:
115
125
 
116
126
  - **Server name:** `chrome-devtools`
117
127
  - **Server Type:** `[1] Local`
118
- - **Command:** `npx`
119
- - **Arguments:** `-y, chrome-devtools-mcp@latest`
128
+ - **Command:** `npx -y chrome-devtools-mcp@latest`
120
129
 
121
130
  </details>
122
131
 
@@ -177,6 +186,24 @@ The same way chrome-devtools-mcp can be configured for JetBrains Junie in `Setti
177
186
 
178
187
  </details>
179
188
 
189
+ <details>
190
+ <summary>Kiro</summary>
191
+
192
+ In **Kiro Settings**, go to `Configure MCP` > `Open Workspace or User MCP Config` > Use the configuration snippet provided above.
193
+
194
+ Or, from the IDE **Activity Bar** > `Kiro` > `MCP Servers` > `Click Open MCP Config`. Use the configuration snippet provided above.
195
+
196
+ </details>
197
+
198
+ <details>
199
+ <summary>Qoder</summary>
200
+
201
+ In **Qoder Settings**, go to `MCP Server` > `+ Add` > Use the configuration snippet provided above.
202
+
203
+ Alternatively, follow the <a href="https://docs.qoder.com/user-guide/chat/model-context-protocol">MCP guide</a> and use the standard config from above.
204
+
205
+ </details>
206
+
180
207
  <details>
181
208
  <summary>Visual Studio</summary>
182
209
 
@@ -238,8 +265,9 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
238
265
  - **Network** (2 tools)
239
266
  - [`get_network_request`](docs/tool-reference.md#get_network_request)
240
267
  - [`list_network_requests`](docs/tool-reference.md#list_network_requests)
241
- - **Debugging** (4 tools)
268
+ - **Debugging** (5 tools)
242
269
  - [`evaluate_script`](docs/tool-reference.md#evaluate_script)
270
+ - [`get_console_message`](docs/tool-reference.md#get_console_message)
243
271
  - [`list_console_messages`](docs/tool-reference.md#list_console_messages)
244
272
  - [`take_screenshot`](docs/tool-reference.md#take_screenshot)
245
273
  - [`take_snapshot`](docs/tool-reference.md#take_snapshot)
@@ -256,6 +284,14 @@ The Chrome DevTools MCP server supports the following configuration option:
256
284
  Connect to a running Chrome instance using port forwarding. For more details see: https://developer.chrome.com/docs/devtools/remote-debugging/local-server.
257
285
  - **Type:** string
258
286
 
287
+ - **`--wsEndpoint`, `-w`**
288
+ WebSocket endpoint to connect to a running Chrome instance (e.g., ws://127.0.0.1:9222/devtools/browser/<id>). Alternative to --browserUrl.
289
+ - **Type:** string
290
+
291
+ - **`--wsHeaders`**
292
+ Custom headers for WebSocket connection in JSON format (e.g., '{"Authorization":"Bearer token"}'). Only works with --wsEndpoint.
293
+ - **Type:** string
294
+
259
295
  - **`--headless`**
260
296
  Whether to run in headless (no UI) mode.
261
297
  - **Type:** boolean
@@ -295,6 +331,21 @@ The Chrome DevTools MCP server supports the following configuration option:
295
331
  Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.
296
332
  - **Type:** array
297
333
 
334
+ - **`--categoryEmulation`**
335
+ Set to false to exlcude tools related to emulation.
336
+ - **Type:** boolean
337
+ - **Default:** `true`
338
+
339
+ - **`--categoryPerformance`**
340
+ Set to false to exlcude tools related to performance.
341
+ - **Type:** boolean
342
+ - **Default:** `true`
343
+
344
+ - **`--categoryNetwork`**
345
+ Set to false to exlcude tools related to network.
346
+ - **Type:** boolean
347
+ - **Default:** `true`
348
+
298
349
  <!-- END AUTO GENERATED OPTIONS -->
299
350
 
300
351
  Pass them via the `args` property in the JSON configuration. For example:
@@ -315,6 +366,27 @@ Pass them via the `args` property in the JSON configuration. For example:
315
366
  }
316
367
  ```
317
368
 
369
+ ### Connecting via WebSocket with custom headers
370
+
371
+ You can connect directly to a Chrome WebSocket endpoint and include custom headers (e.g., for authentication):
372
+
373
+ ```json
374
+ {
375
+ "mcpServers": {
376
+ "chrome-devtools": {
377
+ "command": "npx",
378
+ "args": [
379
+ "chrome-devtools-mcp@latest",
380
+ "--wsEndpoint=ws://127.0.0.1:9222/devtools/browser/<id>",
381
+ "--wsHeaders={\"Authorization\":\"Bearer YOUR_TOKEN\"}"
382
+ ]
383
+ }
384
+ }
385
+ }
386
+ ```
387
+
388
+ To get the WebSocket endpoint from a running Chrome instance, visit `http://127.0.0.1:9222/json/version` and look for the `webSocketDebuggerUrl` field.
389
+
318
390
  You can also run `npx chrome-devtools-mcp@latest --help` to see all available configuration options.
319
391
 
320
392
  ## Concepts
@@ -340,7 +412,7 @@ Here is a step-by-step guide on how to connect to a running Chrome Stable instan
340
412
 
341
413
  **Step 1: Configure the MCP client**
342
414
 
343
- Add the `--browser-url` option to your MCP client configuration. The value of this option should be the URL of the running Chrome instance. `http://localhost:9222` is a common default.
415
+ Add the `--browser-url` option to your MCP client configuration. The value of this option should be the URL of the running Chrome instance. `http://127.0.0.1:9222` is a common default.
344
416
 
345
417
  ```json
346
418
  {
@@ -349,7 +421,7 @@ Add the `--browser-url` option to your MCP client configuration. The value of th
349
421
  "command": "npx",
350
422
  "args": [
351
423
  "chrome-devtools-mcp@latest",
352
- "--browser-url=http://localhost:9222"
424
+ "--browser-url=http://127.0.0.1:9222"
353
425
  ]
354
426
  }
355
427
  }
@@ -393,6 +465,8 @@ Check the performance of https://developers.chrome.com
393
465
 
394
466
  Your MCP client should connect to the running Chrome instance and receive a performance report.
395
467
 
468
+ If you hit VM-to-host port forwarding issues, see the “Remote debugging between virtual machine (VM) and host fails” section in [`docs/troubleshooting.md`](./docs/troubleshooting.md#remote-debugging-between-virtual-machine-vm-and-host-fails).
469
+
396
470
  For more details on remote debugging, see the [Chrome DevTools documentation](https://developer.chrome.com/docs/devtools/remote-debugging/).
397
471
 
398
472
  ## Known limitations
@@ -44,14 +44,16 @@ export async function compress(str) {
44
44
  return buffer;
45
45
  }
46
46
  /** Private coder/decoder **/
47
- function gzipCodec(buffer, codecStream) {
48
- const { readable, writable } = new TransformStream();
47
+ async function gzipCodec(buffer, codecStream) {
48
+ const readable = new ReadableStream({
49
+ start(controller) {
50
+ controller.enqueue(buffer);
51
+ controller.close();
52
+ }
53
+ });
49
54
  const codecReadable = readable.pipeThrough(codecStream);
50
- const writer = writable.getWriter();
51
- void writer.write(buffer);
52
- void writer.close();
53
55
  // A response is a convenient way to get an ArrayBuffer from a ReadableStream.
54
- return new Response(codecReadable).arrayBuffer();
56
+ return await new Response(codecReadable).arrayBuffer();
55
57
  }
56
58
  export function decompressStream(stream) {
57
59
  // https://github.com/wicg/compression/blob/main/explainer.md#deflate-compress-an-arraybuffer
@@ -93,7 +93,7 @@ export class Settings {
93
93
  * to store UI state such as how a user choses to position a split widget or
94
94
  * which panel they last opened.
95
95
  * If you are creating a setting that you expect the user to control, and
96
- * sync, prefer {@see createSetting}
96
+ * sync, prefer {@link Settings.createSetting}
97
97
  */
98
98
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
99
  moduleSetting(settingName) {
@@ -4,9 +4,14 @@
4
4
  export class WorkerWrapper {
5
5
  #workerPromise;
6
6
  #disposed;
7
+ #rejectWorkerPromise;
7
8
  constructor(workerLocation) {
8
- this.#workerPromise = new Promise(fulfill => {
9
+ this.#workerPromise = new Promise((fulfill, reject) => {
10
+ this.#rejectWorkerPromise = reject;
9
11
  const worker = new Worker(workerLocation, { type: 'module' });
12
+ worker.onerror = event => {
13
+ console.error(`Failed to load worker for ${workerLocation.href}:`, event);
14
+ };
10
15
  worker.onmessage = (event) => {
11
16
  console.assert(event.data === 'workerReady');
12
17
  worker.onmessage = null;
@@ -28,7 +33,10 @@ export class WorkerWrapper {
28
33
  this.#disposed = true;
29
34
  void this.#workerPromise.then(worker => worker.terminate());
30
35
  }
31
- terminate() {
36
+ terminate(immediately = false) {
37
+ if (immediately) {
38
+ this.#rejectWorkerPromise?.(new Error('Worker terminated'));
39
+ }
32
40
  this.dispose();
33
41
  }
34
42
  set onmessage(listener) {
@@ -425,7 +425,8 @@ export var Action;
425
425
  Action[Action["AiCodeCompletionSuggestionAccepted"] = 187] = "AiCodeCompletionSuggestionAccepted";
426
426
  Action[Action["AiCodeCompletionError"] = 188] = "AiCodeCompletionError";
427
427
  Action[Action["AttributeLinkClicked"] = 189] = "AttributeLinkClicked";
428
- Action[Action["MAX_VALUE"] = 190] = "MAX_VALUE";
428
+ Action[Action["InsightRequestedViaTeaser"] = 190] = "InsightRequestedViaTeaser";
429
+ Action[Action["MAX_VALUE"] = 191] = "MAX_VALUE";
429
430
  /* eslint-enable @typescript-eslint/naming-convention */
430
431
  })(Action || (Action = {}));
431
432
  export var PanelCodes;
@@ -18,7 +18,7 @@ export const removeElement = (array, element, firstOnly) => {
18
18
  array.length = index;
19
19
  return true;
20
20
  };
21
- function swap(array, i1, i2) {
21
+ export function swap(array, i1, i2) {
22
22
  const temp = array[i1];
23
23
  array[i1] = array[i2];
24
24
  array[i2] = temp;
@@ -0,0 +1,12 @@
1
+ // Copyright 2025 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+ let connectionFactory;
5
+ export class ConnectionTransport {
6
+ static setFactory(factory) {
7
+ connectionFactory = factory;
8
+ }
9
+ static getFactory() {
10
+ return connectionFactory;
11
+ }
12
+ }
@@ -1,6 +1,8 @@
1
1
  // Copyright 2011 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
+ import * as InspectorBackendCommands from '../../generated/InspectorBackendCommands.js';
5
+ import { ConnectionTransport } from './ConnectionTransport.js';
4
6
  import { NodeURL } from './NodeURL.js';
5
7
  export const DevToolsStubErrorCode = -32015;
6
8
  // TODO(dgozman): we are not reporting generic errors in tests, but we should
@@ -20,6 +22,13 @@ export class InspectorBackend {
20
22
  #eventParameterNamesForDomain = new Map();
21
23
  typeMap = new Map();
22
24
  enumMap = new Map();
25
+ constructor() {
26
+ // Create the global here because registering commands will involve putting
27
+ // items onto the global.
28
+ // @ts-expect-error Global namespace instantiation
29
+ globalThis.Protocol ||= {};
30
+ InspectorBackendCommands.registerCommands(this);
31
+ }
23
32
  getOrCreateEventParameterNamesForDomain(domain) {
24
33
  let map = this.#eventParameterNamesForDomain.get(domain);
25
34
  if (!map) {
@@ -79,26 +88,6 @@ export class InspectorBackend {
79
88
  this.#initialized = true;
80
89
  }
81
90
  }
82
- let connectionFactory;
83
- export class Connection {
84
- // on message from browser
85
- setOnMessage(_onMessage) {
86
- }
87
- setOnDisconnect(_onDisconnect) {
88
- }
89
- // send raw CDP message to browser
90
- sendRawMessage(_message) {
91
- }
92
- disconnect() {
93
- throw new Error('not implemented');
94
- }
95
- static setFactory(factory) {
96
- connectionFactory = factory;
97
- }
98
- static getFactory() {
99
- return connectionFactory;
100
- }
101
- }
102
91
  export const test = {
103
92
  /**
104
93
  * This will get called for every protocol message.
@@ -243,9 +232,8 @@ export class SessionRouter {
243
232
  const sessionId = messageObject.sessionId || '';
244
233
  const session = this.#sessions.get(sessionId);
245
234
  if (!session) {
246
- if (!suppressUnknownMessageErrors) {
247
- InspectorBackend.reportProtocolError('Protocol Error: the message with wrong session id', messageObject);
248
- }
235
+ // In the DevTools MCP case, we may share the transport with puppeteer so we silently
236
+ // ignore unknown sessions.
249
237
  return;
250
238
  }
251
239
  // If this message is directly for the target controlled by the proxy connection, don't handle it.
@@ -337,18 +325,18 @@ export class TargetBase {
337
325
  constructor(needsNodeJSPatching, parentTarget, sessionId, connection) {
338
326
  this.needsNodeJSPatching = needsNodeJSPatching;
339
327
  this.sessionId = sessionId;
340
- if ((!parentTarget && connection) || (!parentTarget && sessionId) || (connection && sessionId)) {
341
- throw new Error('Either connection or sessionId (but not both) must be supplied for a child target');
328
+ if (parentTarget && !sessionId) {
329
+ throw new Error('Specifying a parent target requires a session ID');
342
330
  }
343
331
  let router;
344
- if (sessionId && parentTarget && parentTarget.#router) {
332
+ if (parentTarget && parentTarget.#router) {
345
333
  router = parentTarget.#router;
346
334
  }
347
335
  else if (connection) {
348
336
  router = new SessionRouter(connection);
349
337
  }
350
338
  else {
351
- router = new SessionRouter(connectionFactory());
339
+ router = new SessionRouter(ConnectionTransport.getFactory()());
352
340
  }
353
341
  this.#router = router;
354
342
  router.registerSession(this, this.sessionId);
@@ -1,13 +1,7 @@
1
1
  // Copyright 2019 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
- import * as InspectorBackendCommands from '../../generated/InspectorBackendCommands.js';
4
+ import * as ConnectionTransport from './ConnectionTransport.js';
5
5
  import * as InspectorBackend from './InspectorBackend.js';
6
6
  import * as NodeURL from './NodeURL.js';
7
- export { InspectorBackend, NodeURL, };
8
- // Create the global here because registering commands will involve putting
9
- // items onto the global.
10
- // @ts-expect-error Global namespace instantiation
11
-
12
- // FIXME: This instance of InspectorBackend should not be a side effect of importing this module.
13
-
7
+ export { ConnectionTransport, InspectorBackend, NodeURL, };
@@ -305,7 +305,7 @@ export class CSSMatchedStyles {
305
305
  if (!addedAttributesStyle) {
306
306
  addAttributesStyle.call(this);
307
307
  }
308
- nodeCascades.push(new NodeCascade(this, nodeStyles, false /* #isInherited */));
308
+ nodeCascades.push(new NodeCascade(this, nodeStyles, this.#node, false /* #isInherited */));
309
309
  // Walk the node structure and identify styles with inherited properties.
310
310
  let parentNode = this.#node.parentNode;
311
311
  const traverseParentInFlatTree = async (node) => {
@@ -361,8 +361,9 @@ export class CSSMatchedStyles {
361
361
  inheritedStyles.push(inheritedRule.style);
362
362
  this.#inheritedStyles.add(inheritedRule.style);
363
363
  }
364
+ const node = parentNode;
364
365
  parentNode = await traverseParentInFlatTree(parentNode);
365
- nodeCascades.push(new NodeCascade(this, inheritedStyles, true /* #isInherited */));
366
+ nodeCascades.push(new NodeCascade(this, inheritedStyles, node, true /* #isInherited */));
366
367
  }
367
368
  return new DOMInheritanceCascade(this, nodeCascades, this.#registeredProperties);
368
369
  }
@@ -396,7 +397,7 @@ export class CSSMatchedStyles {
396
397
  }
397
398
  }
398
399
  for (const [highlightName, highlightStyles] of splitHighlightRules) {
399
- const nodeCascade = new NodeCascade(this, highlightStyles, isInherited, true /* #isHighlightPseudoCascade*/);
400
+ const nodeCascade = new NodeCascade(this, highlightStyles, node, isInherited, true /* #isHighlightPseudoCascade*/);
400
401
  const cascadeListForHighlightName = pseudoCascades.get(highlightName);
401
402
  if (cascadeListForHighlightName) {
402
403
  cascadeListForHighlightName.push(nodeCascade);
@@ -434,7 +435,7 @@ export class CSSMatchedStyles {
434
435
  }
435
436
  }
436
437
  const isHighlightPseudoCascade = cssMetadata().isHighlightPseudoType(entryPayload.pseudoType);
437
- const nodeCascade = new NodeCascade(this, pseudoStyles, false /* #isInherited */, isHighlightPseudoCascade /* #isHighlightPseudoCascade*/);
438
+ const nodeCascade = new NodeCascade(this, pseudoStyles, this.#node, false /* #isInherited */, isHighlightPseudoCascade /* #isHighlightPseudoCascade*/);
438
439
  pseudoCascades.set(entryPayload.pseudoType, [nodeCascade]);
439
440
  }
440
441
  }
@@ -458,7 +459,7 @@ export class CSSMatchedStyles {
458
459
  this.addMatchingSelectors(parentNode, pseudoRule, rules[k].matchingSelectors);
459
460
  }
460
461
  const isHighlightPseudoCascade = cssMetadata().isHighlightPseudoType(inheritedEntryPayload.pseudoType);
461
- const nodeCascade = new NodeCascade(this, pseudoStyles, true /* #isInherited */, isHighlightPseudoCascade /* #isHighlightPseudoCascade*/);
462
+ const nodeCascade = new NodeCascade(this, pseudoStyles, parentNode, true /* #isInherited */, isHighlightPseudoCascade /* #isHighlightPseudoCascade*/);
462
463
  const cascadeListForPseudoType = pseudoCascades.get(inheritedEntryPayload.pseudoType);
463
464
  if (cascadeListForPseudoType) {
464
465
  cascadeListForPseudoType.push(nodeCascade);
@@ -736,11 +737,13 @@ class NodeCascade {
736
737
  #isHighlightPseudoCascade;
737
738
  propertiesState = new Map();
738
739
  activeProperties = new Map();
739
- constructor(matchedStyles, styles, isInherited, isHighlightPseudoCascade = false) {
740
+ #node;
741
+ constructor(matchedStyles, styles, node, isInherited, isHighlightPseudoCascade = false) {
740
742
  this.#matchedStyles = matchedStyles;
741
743
  this.styles = styles;
742
744
  this.#isInherited = isInherited;
743
745
  this.#isHighlightPseudoCascade = isHighlightPseudoCascade;
746
+ this.#node = node;
744
747
  }
745
748
  computeActiveProperties() {
746
749
  this.propertiesState.clear();
@@ -791,9 +794,41 @@ class NodeCascade {
791
794
  }
792
795
  }
793
796
  }
797
+ #treeScopeDistance(property) {
798
+ if (!property.ownerStyle.parentRule && property.ownerStyle.type !== Type.Inline) {
799
+ return -1;
800
+ }
801
+ const root = this.#node.getTreeRoot();
802
+ const nodeId = property.ownerStyle.parentRule?.treeScope ?? root?.backendNodeId();
803
+ if (nodeId === undefined) {
804
+ return -1;
805
+ }
806
+ let distance = 0;
807
+ for (let ancestor = this.#node; ancestor; ancestor = ancestor.parentNode) {
808
+ if (ancestor.backendNodeId() === nodeId) {
809
+ return distance;
810
+ }
811
+ distance++;
812
+ }
813
+ return -1;
814
+ }
815
+ #needsCascadeContextStep() {
816
+ if (!this.#node.isInShadowTree()) {
817
+ return false;
818
+ }
819
+ if (this.#node.ancestorShadowRoot()?.shadowRootType() === 'user-agent') {
820
+ // In UA shadow dom, only standards-track pseudo elements override style attributes. -webkit-* and -internal-*
821
+ // pseudos are still exempt from that to retain legacy behavior.
822
+ const pseudoElement = this.#node.getAttribute('pseudo');
823
+ return !pseudoElement?.startsWith('-webkit-') && !pseudoElement?.startsWith('-internal-');
824
+ }
825
+ return true;
826
+ }
794
827
  updatePropertyState(propertyWithHigherSpecificity, canonicalName) {
795
828
  const activeProperty = this.activeProperties.get(canonicalName);
796
- if (activeProperty?.important && !propertyWithHigherSpecificity.important) {
829
+ if (activeProperty?.important && !propertyWithHigherSpecificity.important ||
830
+ activeProperty && this.#needsCascadeContextStep() &&
831
+ this.#treeScopeDistance(activeProperty) > this.#treeScopeDistance(propertyWithHigherSpecificity)) {
797
832
  this.propertiesState.set(propertyWithHigherSpecificity, "Overloaded" /* PropertyState.OVERLOADED */);
798
833
  return;
799
834
  }
@@ -18,10 +18,12 @@ export class CSSRule {
18
18
  origin;
19
19
  style;
20
20
  header;
21
+ treeScope;
21
22
  constructor(cssModel, payload) {
22
23
  this.header = payload.header;
23
24
  this.cssModelInternal = cssModel;
24
25
  this.origin = payload.origin;
26
+ this.treeScope = payload.originTreeScopeNodeId;
25
27
  this.style = new CSSStyleDeclaration(this.cssModelInternal, this, payload.style, Type.Regular);
26
28
  }
27
29
  get sourceURL() {
@@ -87,7 +89,12 @@ export class CSSStyleRule extends CSSRule {
87
89
  startingStyles;
88
90
  wasUsed;
89
91
  constructor(cssModel, payload, wasUsed) {
90
- super(cssModel, { origin: payload.origin, style: payload.style, header: styleSheetHeaderForRule(cssModel, payload) });
92
+ super(cssModel, {
93
+ origin: payload.origin,
94
+ style: payload.style,
95
+ header: styleSheetHeaderForRule(cssModel, payload),
96
+ originTreeScopeNodeId: payload.originTreeScopeNodeId
97
+ });
91
98
  this.reinitializeSelectors(payload.selectorList);
92
99
  this.nestingSelectors = payload.nestingSelectors;
93
100
  this.media = payload.media ? CSSMedia.parseMediaArrayPayload(cssModel, payload.media) : [];
@@ -188,7 +195,12 @@ export class CSSStyleRule extends CSSRule {
188
195
  export class CSSPropertyRule extends CSSRule {
189
196
  #name;
190
197
  constructor(cssModel, payload) {
191
- super(cssModel, { origin: payload.origin, style: payload.style, header: styleSheetHeaderForRule(cssModel, payload) });
198
+ super(cssModel, {
199
+ origin: payload.origin,
200
+ style: payload.style,
201
+ header: styleSheetHeaderForRule(cssModel, payload),
202
+ originTreeScopeNodeId: undefined,
203
+ });
192
204
  this.#name = new CSSValue(payload.propertyName);
193
205
  }
194
206
  propertyName() {
@@ -218,7 +230,12 @@ export class CSSPropertyRule extends CSSRule {
218
230
  export class CSSFontPaletteValuesRule extends CSSRule {
219
231
  #paletteName;
220
232
  constructor(cssModel, payload) {
221
- super(cssModel, { origin: payload.origin, style: payload.style, header: styleSheetHeaderForRule(cssModel, payload) });
233
+ super(cssModel, {
234
+ origin: payload.origin,
235
+ style: payload.style,
236
+ header: styleSheetHeaderForRule(cssModel, payload),
237
+ originTreeScopeNodeId: undefined
238
+ });
222
239
  this.#paletteName = new CSSValue(payload.fontPaletteName);
223
240
  }
224
241
  name() {
@@ -244,7 +261,12 @@ export class CSSKeyframeRule extends CSSRule {
244
261
  #keyText;
245
262
  #parentRuleName;
246
263
  constructor(cssModel, payload, parentRuleName) {
247
- super(cssModel, { origin: payload.origin, style: payload.style, header: styleSheetHeaderForRule(cssModel, payload) });
264
+ super(cssModel, {
265
+ origin: payload.origin,
266
+ style: payload.style,
267
+ header: styleSheetHeaderForRule(cssModel, payload),
268
+ originTreeScopeNodeId: undefined
269
+ });
248
270
  this.reinitializeKey(payload.keyText);
249
271
  this.#parentRuleName = parentRuleName;
250
272
  }
@@ -288,7 +310,12 @@ export class CSSPositionTryRule extends CSSRule {
288
310
  #name;
289
311
  #active;
290
312
  constructor(cssModel, payload) {
291
- super(cssModel, { origin: payload.origin, style: payload.style, header: styleSheetHeaderForRule(cssModel, payload) });
313
+ super(cssModel, {
314
+ origin: payload.origin,
315
+ style: payload.style,
316
+ header: styleSheetHeaderForRule(cssModel, payload),
317
+ originTreeScopeNodeId: undefined
318
+ });
292
319
  this.#name = new CSSValue(payload.name);
293
320
  this.#active = payload.active;
294
321
  }
@@ -307,7 +334,8 @@ export class CSSFunctionRule extends CSSRule {
307
334
  super(cssModel, {
308
335
  origin: payload.origin,
309
336
  style: { cssProperties: [], shorthandEntries: [] },
310
- header: styleSheetHeaderForRule(cssModel, payload)
337
+ header: styleSheetHeaderForRule(cssModel, payload),
338
+ originTreeScopeNodeId: undefined
311
339
  });
312
340
  this.#name = new CSSValue(payload.name);
313
341
  this.#parameters = payload.parameters.map(({ name }) => name);
@@ -156,6 +156,9 @@ export class ChildTargetManager extends SDKModel {
156
156
  else if (targetInfo.type === 'page') {
157
157
  type = Type.FRAME;
158
158
  }
159
+ else if (targetInfo.type === 'browser_ui') {
160
+ type = Type.FRAME;
161
+ }
159
162
  else if (targetInfo.type === 'worker') {
160
163
  type = Type.Worker;
161
164
  }
@@ -219,12 +219,12 @@ export class ParallelConnection {
219
219
  }
220
220
  }
221
221
  export async function initMainConnection(createRootTarget, onConnectionLost) {
222
- ProtocolClient.InspectorBackend.Connection.setFactory(createMainConnection.bind(null, onConnectionLost));
222
+ ProtocolClient.ConnectionTransport.ConnectionTransport.setFactory(createMainConnection.bind(null, onConnectionLost));
223
223
  await createRootTarget();
224
224
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.connectionReady();
225
225
  }
226
226
  function createMainConnection(onConnectionLost) {
227
- if (Root.Runtime.getPathName().includes('rehydrated_devtools_app')) {
227
+ if (Root.Runtime.Runtime.isTraceApp()) {
228
228
  return new RehydratingConnection(onConnectionLost);
229
229
  }
230
230
  const wsParam = Root.Runtime.Runtime.queryParam('ws');
@@ -381,6 +381,9 @@ export class DOMNode {
381
381
  isInShadowTree() {
382
382
  return this.#isInShadowTree;
383
383
  }
384
+ getTreeRoot() {
385
+ return this.isShadowRoot() ? this : (this.ancestorShadowRoot() ?? this.ownerDocument ?? this);
386
+ }
384
387
  ancestorShadowHost() {
385
388
  const ancestorShadowRoot = this.ancestorShadowRoot();
386
389
  return ancestorShadowRoot ? ancestorShadowRoot.parentNode : null;
@@ -11,6 +11,7 @@ import { Events as ResourceTreeModelEvents, ResourceTreeModel } from './Resource
11
11
  import { RuntimeModel } from './RuntimeModel.js';
12
12
  import { Script } from './Script.js';
13
13
  import { SDKModel } from './SDKModel.js';
14
+ import { SourceMap } from './SourceMap.js';
14
15
  import { SourceMapManager } from './SourceMapManager.js';
15
16
  import { Type } from './Target.js';
16
17
  const UIStrings = {
@@ -146,7 +147,7 @@ export class DebuggerModel extends SDKModel {
146
147
  target.registerDebuggerDispatcher(new DebuggerDispatcher(this));
147
148
  this.agent = target.debuggerAgent();
148
149
  this.#runtimeModel = target.model(RuntimeModel);
149
- this.#sourceMapManager = new SourceMapManager(target);
150
+ this.#sourceMapManager = new SourceMapManager(target, (compiledURL, sourceMappingURL, payload, script) => new SourceMap(compiledURL, sourceMappingURL, payload, script));
150
151
  Common.Settings.Settings.instance()
151
152
  .moduleSetting('pause-on-exception-enabled')
152
153
  .addChangeListener(this.pauseOnExceptionStateChanged, this);