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.
- package/README.md +79 -5
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Gzip.js +8 -6
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Settings.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Worker.js +10 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/core/host/UserMetrics.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/ArrayUtilities.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/ConnectionTransport.js +12 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/InspectorBackend.js +15 -27
- package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/protocol_client.js +2 -8
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMatchedStyles.js +42 -7
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSRule.js +34 -6
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ChildTargetManager.js +3 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/Connections.js +2 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DOMModel.js +3 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DebuggerModel.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkManager.js +336 -40
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/PreloadingModel.js +56 -13
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RehydratingConnection.js +32 -7
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ResourceTreeModel.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/{models/source_map_scopes → core/sdk}/ScopeTreeCache.js +9 -5
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMap.js +48 -11
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapManager.js +8 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapScopesInfo.js +131 -8
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TargetManager.js +0 -21
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TraceObject.js +9 -6
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/sdk.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/ARIAProperties.js +1301 -174
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/Deprecation.js +7 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/InspectorBackendCommands.js +8 -6
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/SupportedCSSProperties.js +16 -19
- package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.js +50 -34
- package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AICallTree.js +2 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CompilerScriptMapping.js +45 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +14 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/NamesResolver.js +5 -11
- package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/source_map_scopes.js +1 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/Trie.js +8 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/ModelImpl.js +6 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/TraceTree.js +10 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/MetaHandler.js +4 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/UserTimingsHandler.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/CLSCulprits.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Cache.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DOMSize.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DocumentLatency.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DuplicatedJavaScript.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/FontDisplay.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ForcedReflow.js +3 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/INPBreakdown.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ImageDelivery.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPDiscovery.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LegacyJavaScript.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ModernHTTP.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/RenderBlocking.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/SlowCSSSelector.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ThirdParties.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Viewport.js +2 -1
- package/build/src/DevToolsConnectionAdapter.js +32 -0
- package/build/src/McpContext.js +81 -31
- package/build/src/McpResponse.js +149 -45
- package/build/src/PageCollector.js +110 -26
- package/build/src/WaitForHelper.js +5 -0
- package/build/src/browser.js +17 -7
- package/build/src/cli.js +82 -6
- package/build/src/formatters/consoleFormatter.js +29 -62
- package/build/src/formatters/networkFormatter.js +5 -6
- package/build/src/formatters/snapshotFormatter.js +23 -51
- package/build/src/logger.js +1 -1
- package/build/src/main.js +27 -26
- package/build/src/polyfill.js +2 -2
- package/build/src/third_party/THIRD_PARTY_NOTICES +1393 -0
- package/build/src/third_party/index.js +76159 -0
- package/build/src/tools/ToolDefinition.js +2 -2
- package/build/src/tools/categories.js +17 -9
- package/build/src/tools/console.js +71 -6
- package/build/src/tools/emulation.js +6 -7
- package/build/src/tools/input.js +78 -41
- package/build/src/tools/network.js +18 -10
- package/build/src/tools/pages.js +21 -21
- package/build/src/tools/performance.js +8 -8
- package/build/src/tools/screenshot.js +8 -8
- package/build/src/tools/script.js +29 -15
- package/build/src/tools/snapshot.js +15 -20
- package/build/src/utils/types.js +6 -0
- 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** (
|
|
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://
|
|
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://
|
|
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
|
|
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 {@
|
|
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["
|
|
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;
|
|
@@ -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
|
-
|
|
247
|
-
|
|
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 (
|
|
341
|
-
throw new Error('
|
|
328
|
+
if (parentTarget && !sessionId) {
|
|
329
|
+
throw new Error('Specifying a parent target requires a session ID');
|
|
342
330
|
}
|
|
343
331
|
let router;
|
|
344
|
-
if (
|
|
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(
|
|
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
|
|
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
|
-
|
|
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, {
|
|
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, {
|
|
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, {
|
|
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, {
|
|
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, {
|
|
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);
|
package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ChildTargetManager.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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);
|