chrome-devtools-mcp 1.2.0 → 1.4.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 +59 -4
- package/build/src/HeapSnapshotManager.js +25 -16
- package/build/src/McpContext.js +35 -1
- package/build/src/McpResponse.js +77 -7
- package/build/src/PageCollector.js +1 -1
- package/build/src/bin/check-latest-version.js +1 -0
- package/build/src/bin/chrome-devtools-cli-options.js +84 -0
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +47 -3
- package/build/src/{DevToolsConnectionAdapter.js → devtools/DevToolsConnectionAdapter.js} +1 -1
- package/build/src/{DevtoolsUtils.js → devtools/DevtoolsUtils.js} +75 -71
- package/build/src/devtools/McpHostBindingAdapter.js +165 -0
- package/build/src/formatters/ConsoleFormatter.js +1 -1
- package/build/src/formatters/HeapSnapshotFormatter.js +22 -0
- package/build/src/formatters/NetworkFormatter.js +3 -1
- package/build/src/third_party/THIRD_PARTY_NOTICES +4 -4
- package/build/src/third_party/bundled-packages.json +3 -3
- package/build/src/third_party/devtools-formatter-worker.js +0 -1
- package/build/src/third_party/devtools-heap-snapshot-worker.js +67 -3
- package/build/src/third_party/index.js +1971 -426
- package/build/src/tools/memory.js +76 -0
- package/build/src/tools/screencast.js +30 -9
- package/build/src/tools/screenshot.js +158 -76
- package/build/src/utils/check-for-updates.js +1 -0
- package/build/src/version.js +1 -1
- package/package.json +7 -6
- package/skills/a11y-debugging/SKILL.md +89 -0
- package/skills/a11y-debugging/references/a11y-snippets.md +92 -0
- package/skills/chrome-devtools/SKILL.md +72 -0
- package/skills/chrome-devtools-cli/SKILL.md +153 -0
- package/skills/chrome-devtools-cli/references/installation.md +14 -0
- package/skills/debug-optimize-lcp/SKILL.md +121 -0
- package/skills/debug-optimize-lcp/references/elements-and-size.md +27 -0
- package/skills/debug-optimize-lcp/references/lcp-breakdown.md +23 -0
- package/skills/debug-optimize-lcp/references/lcp-snippets.md +79 -0
- package/skills/debug-optimize-lcp/references/optimization-strategies.md +38 -0
- package/skills/memory-leak-debugging/SKILL.md +50 -0
- package/skills/memory-leak-debugging/references/common-leaks.md +33 -0
- package/skills/memory-leak-debugging/references/compare_snapshots.js +109 -0
- package/skills/memory-leak-debugging/references/memlab.md +29 -0
- package/skills/troubleshooting/SKILL.md +98 -0
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
+
import { Mutex } from '../Mutex.js';
|
|
7
|
+
import { DevTools } from '../third_party/index.js';
|
|
6
8
|
import { PuppeteerDevToolsConnection } from './DevToolsConnectionAdapter.js';
|
|
7
|
-
import {
|
|
8
|
-
import { DevTools } from './third_party/index.js';
|
|
9
|
+
import { McpHostBindingAdapter } from './McpHostBindingAdapter.js';
|
|
9
10
|
/**
|
|
10
11
|
* A mock implementation of an issues manager that only implements the methods
|
|
11
12
|
* that are actually used by the IssuesAggregator
|
|
@@ -16,79 +17,82 @@ export class FakeIssuesManager extends DevTools.Common.ObjectWrapper
|
|
|
16
17
|
return [];
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
DevTools.
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
20
|
+
export function overrideDevToolsGlobals({ loadResource, }) {
|
|
21
|
+
DevTools.Host.InspectorFrontendHost.installInspectorFrontendHost(new McpHostBindingAdapter(loadResource));
|
|
22
|
+
// DevTools CDP errors can get noisy.
|
|
23
|
+
DevTools.ProtocolClient.InspectorBackend.test.suppressRequestErrors = true;
|
|
24
|
+
// Stub out Network emulation commands on the DevTools Agent prototype globally.
|
|
25
|
+
// This prevents the DevTools Frontend from ever resetting/clearing Puppeteer's
|
|
26
|
+
// active network blocking/throttling rules during target setup or session lifetime.
|
|
27
|
+
const networkAgentPrototype = DevTools.ProtocolClient.InspectorBackend.inspectorBackend.agentPrototypes.get('Network');
|
|
28
|
+
if (networkAgentPrototype) {
|
|
29
|
+
Object.defineProperty(networkAgentPrototype, 'invoke_emulateNetworkConditionsByRule', {
|
|
30
|
+
value: () => {
|
|
31
|
+
return Promise.resolve({
|
|
32
|
+
ruleIds: [],
|
|
33
|
+
getError: () => undefined,
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
writable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
enumerable: true,
|
|
39
|
+
});
|
|
40
|
+
Object.defineProperty(networkAgentPrototype, 'invoke_overrideNetworkState', {
|
|
41
|
+
value: () => {
|
|
42
|
+
return Promise.resolve({
|
|
43
|
+
getError: () => undefined,
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
writable: true,
|
|
47
|
+
configurable: true,
|
|
48
|
+
enumerable: true,
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(networkAgentPrototype, 'invoke_enable', {
|
|
51
|
+
value: () => {
|
|
52
|
+
return Promise.resolve({
|
|
53
|
+
getError: () => undefined,
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
writable: true,
|
|
57
|
+
configurable: true,
|
|
58
|
+
enumerable: true,
|
|
59
|
+
});
|
|
60
|
+
Object.defineProperty(networkAgentPrototype, 'invoke_disable', {
|
|
61
|
+
value: () => {
|
|
62
|
+
return Promise.resolve({
|
|
63
|
+
getError: () => undefined,
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
writable: true,
|
|
67
|
+
configurable: true,
|
|
68
|
+
enumerable: true,
|
|
69
|
+
});
|
|
70
|
+
Object.defineProperty(networkAgentPrototype, 'invoke_setBlockedURLs', {
|
|
71
|
+
value: () => {
|
|
72
|
+
return Promise.resolve({
|
|
73
|
+
getError: () => undefined,
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
writable: true,
|
|
77
|
+
configurable: true,
|
|
78
|
+
enumerable: true,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
DevTools.I18n.DevToolsLocale.DevToolsLocale.instance({
|
|
82
|
+
create: true,
|
|
83
|
+
data: {
|
|
84
|
+
navigatorLanguage: 'en-US',
|
|
85
|
+
settingLanguage: 'en-US',
|
|
86
|
+
lookupClosestDevToolsLocale: l => l,
|
|
62
87
|
},
|
|
63
|
-
writable: true,
|
|
64
|
-
configurable: true,
|
|
65
|
-
enumerable: true,
|
|
66
88
|
});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
},
|
|
73
|
-
writable: true,
|
|
74
|
-
configurable: true,
|
|
75
|
-
enumerable: true,
|
|
89
|
+
DevTools.I18n.i18n.registerLocaleDataForTest('en-US', {});
|
|
90
|
+
DevTools.Formatter.FormatterWorkerPool.FormatterWorkerPool.instance({
|
|
91
|
+
forceNew: true,
|
|
92
|
+
entrypointURL: import.meta
|
|
93
|
+
.resolve('../third_party/devtools-formatter-worker.js'),
|
|
76
94
|
});
|
|
77
95
|
}
|
|
78
|
-
DevTools.I18n.DevToolsLocale.DevToolsLocale.instance({
|
|
79
|
-
create: true,
|
|
80
|
-
data: {
|
|
81
|
-
navigatorLanguage: 'en-US',
|
|
82
|
-
settingLanguage: 'en-US',
|
|
83
|
-
lookupClosestDevToolsLocale: l => l,
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
DevTools.I18n.i18n.registerLocaleDataForTest('en-US', {});
|
|
87
|
-
DevTools.Formatter.FormatterWorkerPool.FormatterWorkerPool.instance({
|
|
88
|
-
forceNew: true,
|
|
89
|
-
entrypointURL: import.meta
|
|
90
|
-
.resolve('./third_party/devtools-formatter-worker.js'),
|
|
91
|
-
});
|
|
92
96
|
export class UniverseManager {
|
|
93
97
|
#browser;
|
|
94
98
|
#createUniverseFor;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
7
|
+
import { DevTools } from '../third_party/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* BaseClass that is noop or throws for methods.
|
|
10
|
+
* the McpHostBindingAdapter should only implement methods
|
|
11
|
+
* that it needs to support.
|
|
12
|
+
*/
|
|
13
|
+
class BaseMcpHostBindingAdapter {
|
|
14
|
+
connectAutomaticFileSystem() { }
|
|
15
|
+
disconnectAutomaticFileSystem() { }
|
|
16
|
+
addFileSystem() { }
|
|
17
|
+
loadCompleted() { }
|
|
18
|
+
indexPath() { }
|
|
19
|
+
setInspectedPageBounds() { }
|
|
20
|
+
showCertificateViewer() { }
|
|
21
|
+
setWhitelistedShortcuts() { }
|
|
22
|
+
setEyeDropperActive() { }
|
|
23
|
+
inspectElementCompleted() { }
|
|
24
|
+
openInNewTab() { }
|
|
25
|
+
openSearchResultsInNewTab() { }
|
|
26
|
+
showItemInFolder() { }
|
|
27
|
+
removeFileSystem() { }
|
|
28
|
+
requestFileSystems() { }
|
|
29
|
+
save() { }
|
|
30
|
+
append() { }
|
|
31
|
+
close() { }
|
|
32
|
+
searchInPath() { }
|
|
33
|
+
stopIndexing() { }
|
|
34
|
+
bringToFront() { }
|
|
35
|
+
closeWindow() { }
|
|
36
|
+
copyText() { }
|
|
37
|
+
inspectedURLChanged() { }
|
|
38
|
+
isolatedFileSystem() {
|
|
39
|
+
throw new Error('Not implemented');
|
|
40
|
+
}
|
|
41
|
+
registerPreference() { }
|
|
42
|
+
getPreferences() { }
|
|
43
|
+
getPreference() { }
|
|
44
|
+
setPreference() { }
|
|
45
|
+
removePreference() { }
|
|
46
|
+
clearPreferences() { }
|
|
47
|
+
getSyncInformation() { }
|
|
48
|
+
getHostConfig() { }
|
|
49
|
+
upgradeDraggedFileSystemPermissions() { }
|
|
50
|
+
platform() {
|
|
51
|
+
throw new Error('Not implemented');
|
|
52
|
+
}
|
|
53
|
+
recordCountHistogram() { }
|
|
54
|
+
recordEnumeratedHistogram() { }
|
|
55
|
+
recordPerformanceHistogram() { }
|
|
56
|
+
recordPerformanceHistogramMedium() { }
|
|
57
|
+
recordUserMetricsAction() { }
|
|
58
|
+
recordNewBadgeUsage() { }
|
|
59
|
+
sendMessageToBackend() { }
|
|
60
|
+
setDevicesDiscoveryConfig() { }
|
|
61
|
+
setDevicesUpdatesEnabled() { }
|
|
62
|
+
openRemotePage() { }
|
|
63
|
+
openNodeFrontend() { }
|
|
64
|
+
setInjectedScriptForOrigin() { }
|
|
65
|
+
setIsDocked() { }
|
|
66
|
+
showSurvey() { }
|
|
67
|
+
canShowSurvey() { }
|
|
68
|
+
zoomFactor() {
|
|
69
|
+
throw new Error('Not implemented');
|
|
70
|
+
}
|
|
71
|
+
zoomIn() { }
|
|
72
|
+
zoomOut() { }
|
|
73
|
+
resetZoom() { }
|
|
74
|
+
showContextMenuAtPoint() { }
|
|
75
|
+
reattach() { }
|
|
76
|
+
readyForTest() { }
|
|
77
|
+
connectionReady() { }
|
|
78
|
+
setOpenNewWindowForPopups() { }
|
|
79
|
+
isHostedMode() {
|
|
80
|
+
throw new Error('Not implemented');
|
|
81
|
+
}
|
|
82
|
+
setAddExtensionCallback() { }
|
|
83
|
+
initialTargetId() {
|
|
84
|
+
throw new Error('Not implemented');
|
|
85
|
+
}
|
|
86
|
+
doAidaConversation(_request, _streamId, cb) {
|
|
87
|
+
cb({
|
|
88
|
+
error: 'Not implemented',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
registerAidaClientEvent(_request, cb) {
|
|
92
|
+
cb({
|
|
93
|
+
error: 'Not implemented',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
aidaCodeComplete(_request, cb) {
|
|
97
|
+
cb({
|
|
98
|
+
error: 'Not implemented',
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
dispatchHttpRequest(_request, cb) {
|
|
102
|
+
cb({
|
|
103
|
+
error: 'Not implemented',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
recordImpression() { }
|
|
107
|
+
recordResize() { }
|
|
108
|
+
recordClick() { }
|
|
109
|
+
recordHover() { }
|
|
110
|
+
recordDrag() { }
|
|
111
|
+
recordChange() { }
|
|
112
|
+
recordKeyDown() { }
|
|
113
|
+
recordSettingAccess() { }
|
|
114
|
+
recordFunctionCall() { }
|
|
115
|
+
setChromeFlag() { }
|
|
116
|
+
requestRestart() { }
|
|
117
|
+
loadNetworkResource(_urlString, _headers, _streamId, _callback) { }
|
|
118
|
+
}
|
|
119
|
+
export class McpHostBindingAdapter extends BaseMcpHostBindingAdapter {
|
|
120
|
+
#loadResource;
|
|
121
|
+
constructor(loadResource) {
|
|
122
|
+
super();
|
|
123
|
+
this.#loadResource = loadResource;
|
|
124
|
+
}
|
|
125
|
+
isolatedFileSystem() {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
platform() {
|
|
129
|
+
switch (process.platform) {
|
|
130
|
+
case 'darwin':
|
|
131
|
+
return 'mac';
|
|
132
|
+
case 'win32':
|
|
133
|
+
return 'windows';
|
|
134
|
+
default:
|
|
135
|
+
return 'linux';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
zoomFactor() {
|
|
139
|
+
return 1;
|
|
140
|
+
}
|
|
141
|
+
isHostedMode() {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
initialTargetId() {
|
|
145
|
+
return Promise.resolve(null);
|
|
146
|
+
}
|
|
147
|
+
loadNetworkResource(urlString, _headers, streamId, callback) {
|
|
148
|
+
if (!URL.canParse(urlString)) {
|
|
149
|
+
callback({
|
|
150
|
+
statusCode: 404,
|
|
151
|
+
urlValid: false,
|
|
152
|
+
});
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.#loadResource(urlString)
|
|
156
|
+
.then(content => {
|
|
157
|
+
DevTools.Host.ResourceLoader.streamWrite(streamId, content);
|
|
158
|
+
callback({ statusCode: 200 });
|
|
159
|
+
})
|
|
160
|
+
.catch(() => {
|
|
161
|
+
callback({ statusCode: 404 });
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=McpHostBindingAdapter.js.map
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright 2026 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { createStackTraceForConsoleMessage, SymbolizedError, } from '../DevtoolsUtils.js';
|
|
6
|
+
import { createStackTraceForConsoleMessage, SymbolizedError, } from '../devtools/DevtoolsUtils.js';
|
|
7
7
|
import { UncaughtError } from '../PageCollector.js';
|
|
8
8
|
import * as DevTools from '../third_party/index.js';
|
|
9
9
|
export class ConsoleFormatter {
|
|
@@ -45,6 +45,28 @@ export class HeapSnapshotFormatter {
|
|
|
45
45
|
}
|
|
46
46
|
return lines.join('\n');
|
|
47
47
|
}
|
|
48
|
+
static formatRetainingPaths(retainingPaths) {
|
|
49
|
+
const lines = [];
|
|
50
|
+
function formatEdge(edge, depth) {
|
|
51
|
+
const indent = ' '.repeat(depth);
|
|
52
|
+
lines.push(`${indent}<- @${edge.nodeId} ${edge.nodeName} via ${edge.edgeType} ${edge.edgeName} (distance: ${edge.distance})`);
|
|
53
|
+
for (const child of edge.children) {
|
|
54
|
+
formatEdge(child, depth + 1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const path of retainingPaths) {
|
|
58
|
+
formatEdge(path, 0);
|
|
59
|
+
}
|
|
60
|
+
return lines.join('\n');
|
|
61
|
+
}
|
|
62
|
+
static formatDominators(dominators) {
|
|
63
|
+
const lines = [];
|
|
64
|
+
lines.push('nodeId,nodeName,selfSize,retainedSize');
|
|
65
|
+
for (const node of dominators) {
|
|
66
|
+
lines.push(`${node.nodeId},${node.nodeName},${DevTools.I18n.ByteUtilities.formatBytesToKb(node.selfSize)},${DevTools.I18n.ByteUtilities.formatBytesToKb(node.retainedSize)}`);
|
|
67
|
+
}
|
|
68
|
+
return lines.join('\n');
|
|
69
|
+
}
|
|
48
70
|
#getSortedAggregates() {
|
|
49
71
|
return Object.values(this.#aggregates).sort((a, b) => b.maxRet - a.maxRet);
|
|
50
72
|
}
|
|
@@ -226,7 +226,9 @@ function converNetworkRequestDetailedToStringDetailed(data) {
|
|
|
226
226
|
if (redirectChain?.length) {
|
|
227
227
|
response.push(`### Redirect chain`);
|
|
228
228
|
let indent = 0;
|
|
229
|
-
|
|
229
|
+
// `redirectChain` is already ordered by toJSONDetailed(); don't reverse it
|
|
230
|
+
// again here or the text output contradicts structuredContent (the JSON).
|
|
231
|
+
for (const request of redirectChain) {
|
|
230
232
|
response.push(`${' '.repeat(indent)}${convertNetworkRequestConciseToString(request)}`);
|
|
231
233
|
indent++;
|
|
232
234
|
}
|
|
@@ -324,7 +324,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE
|
|
|
324
324
|
|
|
325
325
|
Name: semver
|
|
326
326
|
URL: git+https://github.com/npm/node-semver.git
|
|
327
|
-
Version: 7.8.
|
|
327
|
+
Version: 7.8.5
|
|
328
328
|
License: ISC
|
|
329
329
|
|
|
330
330
|
The ISC License
|
|
@@ -867,14 +867,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
867
867
|
|
|
868
868
|
Name: puppeteer-core
|
|
869
869
|
URL: https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer-core
|
|
870
|
-
Version: 25.
|
|
870
|
+
Version: 25.2.0
|
|
871
871
|
License: Apache-2.0
|
|
872
872
|
|
|
873
873
|
-------------------- DEPENDENCY DIVIDER --------------------
|
|
874
874
|
|
|
875
875
|
Name: @puppeteer/browsers
|
|
876
876
|
URL: https://github.com/puppeteer/puppeteer/tree/main/packages/browsers
|
|
877
|
-
Version: 3.0.
|
|
877
|
+
Version: 3.0.5
|
|
878
878
|
License: Apache-2.0
|
|
879
879
|
|
|
880
880
|
-------------------- DEPENDENCY DIVIDER --------------------
|
|
@@ -910,7 +910,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
910
910
|
|
|
911
911
|
Name: @toon-format/toon
|
|
912
912
|
URL: https://toonformat.dev
|
|
913
|
-
Version: 2.
|
|
913
|
+
Version: 2.3.0
|
|
914
914
|
License: MIT
|
|
915
915
|
|
|
916
916
|
MIT License
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
3
3
|
"@toon-format/toon": "^2.2.0",
|
|
4
|
-
"chrome-devtools-frontend": "1.0.
|
|
4
|
+
"chrome-devtools-frontend": "1.0.1650035",
|
|
5
5
|
"core-js": "3.49.0",
|
|
6
6
|
"debug": "4.4.3",
|
|
7
|
-
"lighthouse": "13.
|
|
7
|
+
"lighthouse": "13.4.0",
|
|
8
8
|
"semver": "^7.7.4",
|
|
9
9
|
"urlpattern-polyfill": "^10.1.0",
|
|
10
10
|
"yargs": "18.0.0",
|
|
11
|
-
"puppeteer-core": "25.
|
|
11
|
+
"puppeteer-core": "25.2.0"
|
|
12
12
|
}
|
|
@@ -2645,7 +2645,6 @@ var ExperimentName;
|
|
|
2645
2645
|
ExperimentName["ALL"] = "*";
|
|
2646
2646
|
ExperimentName["PROTOCOL_MONITOR"] = "protocol-monitor";
|
|
2647
2647
|
ExperimentName["INSTRUMENTATION_BREAKPOINTS"] = "instrumentation-breakpoints";
|
|
2648
|
-
ExperimentName["USE_SOURCE_MAP_SCOPES"] = "use-source-map-scopes";
|
|
2649
2648
|
ExperimentName["DURABLE_MESSAGES"] = "durable-messages";
|
|
2650
2649
|
ExperimentName["JPEG_XL"] = "jpeg-xl";
|
|
2651
2650
|
ExperimentName["PLUS_BUTTON"] = "plus-button";
|
|
@@ -642,10 +642,14 @@ class Diff {
|
|
|
642
642
|
removedCount = 0;
|
|
643
643
|
addedSize = 0;
|
|
644
644
|
removedSize = 0;
|
|
645
|
-
deletedIndexes = [];
|
|
646
|
-
addedIndexes = [];
|
|
647
645
|
countDelta;
|
|
648
646
|
sizeDelta;
|
|
647
|
+
addedIndexes = [];
|
|
648
|
+
addedIds = [];
|
|
649
|
+
addedSelfSizes = [];
|
|
650
|
+
deletedIndexes = [];
|
|
651
|
+
deletedIds = [];
|
|
652
|
+
deletedSelfSizes = [];
|
|
649
653
|
constructor(name) {
|
|
650
654
|
this.name = name;
|
|
651
655
|
}
|
|
@@ -2840,7 +2844,6 @@ var ExperimentName;
|
|
|
2840
2844
|
ExperimentName["ALL"] = "*";
|
|
2841
2845
|
ExperimentName["PROTOCOL_MONITOR"] = "protocol-monitor";
|
|
2842
2846
|
ExperimentName["INSTRUMENTATION_BREAKPOINTS"] = "instrumentation-breakpoints";
|
|
2843
|
-
ExperimentName["USE_SOURCE_MAP_SCOPES"] = "use-source-map-scopes";
|
|
2844
2847
|
ExperimentName["DURABLE_MESSAGES"] = "durable-messages";
|
|
2845
2848
|
ExperimentName["JPEG_XL"] = "jpeg-xl";
|
|
2846
2849
|
ExperimentName["PLUS_BUTTON"] = "plus-button";
|
|
@@ -5936,6 +5939,9 @@ class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
|
5936
5939
|
nodeClassKey(snapshotObjectId) {
|
|
5937
5940
|
return this.callMethodPromise('nodeClassKey', snapshotObjectId);
|
|
5938
5941
|
}
|
|
5942
|
+
nodeIndexForId(nodeId) {
|
|
5943
|
+
return this.callMethodPromise('nodeIndexForId', nodeId);
|
|
5944
|
+
}
|
|
5939
5945
|
createEdgesProvider(nodeIndex) {
|
|
5940
5946
|
return this.callFactoryMethod('createEdgesProvider', HeapSnapshotProviderProxy, nodeIndex);
|
|
5941
5947
|
}
|
|
@@ -5996,6 +6002,9 @@ class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
|
5996
6002
|
getRetainingPaths(nodeIndex, maxDepth, maxNodes, maxSiblings) {
|
|
5997
6003
|
return this.callMethodPromise('getRetainingPaths', nodeIndex, maxDepth, maxNodes, maxSiblings);
|
|
5998
6004
|
}
|
|
6005
|
+
getDominatorsOf(nodeIndex) {
|
|
6006
|
+
return this.callMethodPromise('getDominatorsOf', nodeIndex);
|
|
6007
|
+
}
|
|
5999
6008
|
unignoreNodeInRetainersView(nodeIndex) {
|
|
6000
6009
|
return this.callMethodPromise('unignoreNodeInRetainersView', nodeIndex);
|
|
6001
6010
|
}
|
|
@@ -7064,6 +7073,16 @@ class HeapSnapshot {
|
|
|
7064
7073
|
}
|
|
7065
7074
|
this.#progress.updateStatus('Finished processing.');
|
|
7066
7075
|
}
|
|
7076
|
+
nodeIndexForId(nodeId) {
|
|
7077
|
+
const nodesLength = this.nodes.length;
|
|
7078
|
+
const { nodes, nodeFieldCount, nodeIdOffset } = this;
|
|
7079
|
+
for (let nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
|
|
7080
|
+
if (nodes.getValue(nodeIndex + nodeIdOffset) === nodeId) {
|
|
7081
|
+
return nodeIndex;
|
|
7082
|
+
}
|
|
7083
|
+
}
|
|
7084
|
+
return undefined;
|
|
7085
|
+
}
|
|
7067
7086
|
startInitStep1InSecondThread(secondWorker) {
|
|
7068
7087
|
const resultsFromSecondWorker = new Promise((resolve, reject) => {
|
|
7069
7088
|
const listener = (e) => {
|
|
@@ -7315,6 +7334,12 @@ class HeapSnapshot {
|
|
|
7315
7334
|
}
|
|
7316
7335
|
};
|
|
7317
7336
|
switch (filterName) {
|
|
7337
|
+
case 'objectsRetainedByContexts':
|
|
7338
|
+
traverse((_node, edge) => {
|
|
7339
|
+
return !this.isContextObject(edge.node());
|
|
7340
|
+
});
|
|
7341
|
+
markUnreachableNodes();
|
|
7342
|
+
return (node) => !getBit(node);
|
|
7318
7343
|
case 'objectsRetainedByDetachedDomNodes':
|
|
7319
7344
|
traverse((_node, edge) => {
|
|
7320
7345
|
return edge.node().detachedness() !== 2 ;
|
|
@@ -7458,6 +7483,9 @@ class HeapSnapshot {
|
|
|
7458
7483
|
isUserRoot(_node) {
|
|
7459
7484
|
return true;
|
|
7460
7485
|
}
|
|
7486
|
+
isContextObject(_node) {
|
|
7487
|
+
return false;
|
|
7488
|
+
}
|
|
7461
7489
|
calculateShallowSizes() {
|
|
7462
7490
|
}
|
|
7463
7491
|
calculateDistances(isForRetainersView, filter) {
|
|
@@ -8287,6 +8315,8 @@ class HeapSnapshot {
|
|
|
8287
8315
|
const nodeAId = baseIds[i];
|
|
8288
8316
|
if (nodeAId < nodeB.id()) {
|
|
8289
8317
|
diff.deletedIndexes.push(baseIndexes[i]);
|
|
8318
|
+
diff.deletedIds.push(nodeAId);
|
|
8319
|
+
diff.deletedSelfSizes.push(baseSelfSizes[i]);
|
|
8290
8320
|
diff.removedCount++;
|
|
8291
8321
|
diff.removedSize += baseSelfSizes[i];
|
|
8292
8322
|
++i;
|
|
@@ -8294,6 +8324,8 @@ class HeapSnapshot {
|
|
|
8294
8324
|
else if (nodeAId >
|
|
8295
8325
|
nodeB.id()) {
|
|
8296
8326
|
diff.addedIndexes.push(indexes[j]);
|
|
8327
|
+
diff.addedIds.push(nodeB.id());
|
|
8328
|
+
diff.addedSelfSizes.push(nodeB.selfSize());
|
|
8297
8329
|
diff.addedCount++;
|
|
8298
8330
|
diff.addedSize += nodeB.selfSize();
|
|
8299
8331
|
nodeB.nodeIndex = indexes[++j];
|
|
@@ -8305,12 +8337,16 @@ class HeapSnapshot {
|
|
|
8305
8337
|
}
|
|
8306
8338
|
while (i < l) {
|
|
8307
8339
|
diff.deletedIndexes.push(baseIndexes[i]);
|
|
8340
|
+
diff.deletedIds.push(baseIds[i]);
|
|
8341
|
+
diff.deletedSelfSizes.push(baseSelfSizes[i]);
|
|
8308
8342
|
diff.removedCount++;
|
|
8309
8343
|
diff.removedSize += baseSelfSizes[i];
|
|
8310
8344
|
++i;
|
|
8311
8345
|
}
|
|
8312
8346
|
while (j < m) {
|
|
8313
8347
|
diff.addedIndexes.push(indexes[j]);
|
|
8348
|
+
diff.addedIds.push(nodeB.id());
|
|
8349
|
+
diff.addedSelfSizes.push(nodeB.selfSize());
|
|
8314
8350
|
diff.addedCount++;
|
|
8315
8351
|
diff.addedSize += nodeB.selfSize();
|
|
8316
8352
|
nodeB.nodeIndex = indexes[++j];
|
|
@@ -8466,6 +8502,30 @@ class HeapSnapshot {
|
|
|
8466
8502
|
const paths = buildForest(nodeIndex, 0);
|
|
8467
8503
|
return { paths, limitsReached };
|
|
8468
8504
|
}
|
|
8505
|
+
getDominatorsOf(nodeIndex) {
|
|
8506
|
+
const chain = [];
|
|
8507
|
+
let currentIndex = nodeIndex;
|
|
8508
|
+
const rootIndex = this.rootNodeIndex;
|
|
8509
|
+
while (currentIndex !== undefined) {
|
|
8510
|
+
const node = this.createNode(currentIndex);
|
|
8511
|
+
chain.push({
|
|
8512
|
+
nodeId: node.id(),
|
|
8513
|
+
nodeIndex: currentIndex,
|
|
8514
|
+
nodeName: node.name(),
|
|
8515
|
+
retainedSize: node.retainedSize(),
|
|
8516
|
+
selfSize: node.selfSize(),
|
|
8517
|
+
});
|
|
8518
|
+
if (currentIndex === rootIndex) {
|
|
8519
|
+
break;
|
|
8520
|
+
}
|
|
8521
|
+
const nextIndex = node.dominatorIndex();
|
|
8522
|
+
if (nextIndex === currentIndex) {
|
|
8523
|
+
break;
|
|
8524
|
+
}
|
|
8525
|
+
currentIndex = nextIndex;
|
|
8526
|
+
}
|
|
8527
|
+
return chain;
|
|
8528
|
+
}
|
|
8469
8529
|
createAddedNodesProvider(baseSnapshotId, classKey) {
|
|
8470
8530
|
const snapshotDiff = this.#snapshotDiffs[baseSnapshotId];
|
|
8471
8531
|
const diffForClass = snapshotDiff[classKey];
|
|
@@ -8960,6 +9020,10 @@ class JSHeapSnapshot extends HeapSnapshot {
|
|
|
8960
9020
|
isUserRoot(node) {
|
|
8961
9021
|
return node.isUserRoot() || node.isDocumentDOMTreesRoot();
|
|
8962
9022
|
}
|
|
9023
|
+
isContextObject(node) {
|
|
9024
|
+
const name = node.rawName();
|
|
9025
|
+
return name === 'system / Context' || name.startsWith('system / Context / ');
|
|
9026
|
+
}
|
|
8963
9027
|
userObjectsMapAndFlag() {
|
|
8964
9028
|
return { map: this.flags, flag: this.nodeFlags.pageObject };
|
|
8965
9029
|
}
|