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.
Files changed (40) hide show
  1. package/README.md +59 -4
  2. package/build/src/HeapSnapshotManager.js +25 -16
  3. package/build/src/McpContext.js +35 -1
  4. package/build/src/McpResponse.js +77 -7
  5. package/build/src/PageCollector.js +1 -1
  6. package/build/src/bin/check-latest-version.js +1 -0
  7. package/build/src/bin/chrome-devtools-cli-options.js +84 -0
  8. package/build/src/bin/chrome-devtools-mcp-cli-options.js +47 -3
  9. package/build/src/{DevToolsConnectionAdapter.js → devtools/DevToolsConnectionAdapter.js} +1 -1
  10. package/build/src/{DevtoolsUtils.js → devtools/DevtoolsUtils.js} +75 -71
  11. package/build/src/devtools/McpHostBindingAdapter.js +165 -0
  12. package/build/src/formatters/ConsoleFormatter.js +1 -1
  13. package/build/src/formatters/HeapSnapshotFormatter.js +22 -0
  14. package/build/src/formatters/NetworkFormatter.js +3 -1
  15. package/build/src/third_party/THIRD_PARTY_NOTICES +4 -4
  16. package/build/src/third_party/bundled-packages.json +3 -3
  17. package/build/src/third_party/devtools-formatter-worker.js +0 -1
  18. package/build/src/third_party/devtools-heap-snapshot-worker.js +67 -3
  19. package/build/src/third_party/index.js +1971 -426
  20. package/build/src/tools/memory.js +76 -0
  21. package/build/src/tools/screencast.js +30 -9
  22. package/build/src/tools/screenshot.js +158 -76
  23. package/build/src/utils/check-for-updates.js +1 -0
  24. package/build/src/version.js +1 -1
  25. package/package.json +7 -6
  26. package/skills/a11y-debugging/SKILL.md +89 -0
  27. package/skills/a11y-debugging/references/a11y-snippets.md +92 -0
  28. package/skills/chrome-devtools/SKILL.md +72 -0
  29. package/skills/chrome-devtools-cli/SKILL.md +153 -0
  30. package/skills/chrome-devtools-cli/references/installation.md +14 -0
  31. package/skills/debug-optimize-lcp/SKILL.md +121 -0
  32. package/skills/debug-optimize-lcp/references/elements-and-size.md +27 -0
  33. package/skills/debug-optimize-lcp/references/lcp-breakdown.md +23 -0
  34. package/skills/debug-optimize-lcp/references/lcp-snippets.md +79 -0
  35. package/skills/debug-optimize-lcp/references/optimization-strategies.md +38 -0
  36. package/skills/memory-leak-debugging/SKILL.md +50 -0
  37. package/skills/memory-leak-debugging/references/common-leaks.md +33 -0
  38. package/skills/memory-leak-debugging/references/compare_snapshots.js +109 -0
  39. package/skills/memory-leak-debugging/references/memlab.md +29 -0
  40. 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 { Mutex } from './Mutex.js';
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
- // DevTools CDP errors can get noisy.
20
- DevTools.ProtocolClient.InspectorBackend.test.suppressRequestErrors = true;
21
- // Stub out Network emulation commands on the DevTools Agent prototype globally.
22
- // This prevents the DevTools Frontend from ever resetting/clearing Puppeteer's
23
- // active network blocking/throttling rules during target setup or session lifetime.
24
- const networkAgentPrototype = DevTools.ProtocolClient.InspectorBackend.inspectorBackend.agentPrototypes.get('Network');
25
- if (networkAgentPrototype) {
26
- Object.defineProperty(networkAgentPrototype, 'invoke_emulateNetworkConditionsByRule', {
27
- value: () => {
28
- return Promise.resolve({
29
- ruleIds: [],
30
- getError: () => undefined,
31
- });
32
- },
33
- writable: true,
34
- configurable: true,
35
- enumerable: true,
36
- });
37
- Object.defineProperty(networkAgentPrototype, 'invoke_overrideNetworkState', {
38
- value: () => {
39
- return Promise.resolve({
40
- getError: () => undefined,
41
- });
42
- },
43
- writable: true,
44
- configurable: true,
45
- enumerable: true,
46
- });
47
- Object.defineProperty(networkAgentPrototype, 'invoke_enable', {
48
- value: () => {
49
- return Promise.resolve({
50
- getError: () => undefined,
51
- });
52
- },
53
- writable: true,
54
- configurable: true,
55
- enumerable: true,
56
- });
57
- Object.defineProperty(networkAgentPrototype, 'invoke_disable', {
58
- value: () => {
59
- return Promise.resolve({
60
- getError: () => undefined,
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
- Object.defineProperty(networkAgentPrototype, 'invoke_setBlockedURLs', {
68
- value: () => {
69
- return Promise.resolve({
70
- getError: () => undefined,
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
- for (const request of redirectChain.reverse()) {
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.1
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.1.0
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.4
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.2.0
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.1641723",
4
+ "chrome-devtools-frontend": "1.0.1650035",
5
5
  "core-js": "3.49.0",
6
6
  "debug": "4.4.3",
7
- "lighthouse": "13.3.0",
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.1.0"
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
  }