chrome-devtools-frontend 1.0.1652307 → 1.0.1654411

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 (94) hide show
  1. package/.agents/skills/fixing-skipped-tests/SKILL.md +32 -0
  2. package/.agents/skills/migrate-chromium-test/SKILL.md +144 -0
  3. package/docs/get_the_code.md +1 -2
  4. package/docs/ui_engineering.md +3 -1
  5. package/eslint.config.mjs +0 -5
  6. package/front_end/core/sdk/CPUThrottlingManager.ts +13 -8
  7. package/front_end/core/sdk/CSSMetadata.ts +23 -0
  8. package/front_end/core/sdk/CompilerSourceMappingContentProvider.ts +8 -4
  9. package/front_end/core/sdk/DOMModel.ts +4 -0
  10. package/front_end/core/sdk/EmulationModel.ts +4 -0
  11. package/front_end/core/sdk/ResourceTreeModel.ts +3 -2
  12. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +459 -74
  13. package/front_end/entrypoints/main/MainImpl.ts +0 -6
  14. package/front_end/foundation/Universe.ts +18 -0
  15. package/front_end/generated/InspectorBackendCommands.ts +6 -5
  16. package/front_end/generated/SupportedCSSProperties.js +122 -28
  17. package/front_end/generated/protocol.ts +58 -0
  18. package/front_end/models/ai_assistance/AiConversation.ts +2 -1
  19. package/front_end/models/ai_assistance/README.md +4 -3
  20. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +1 -1
  21. package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +2 -2
  22. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +11 -164
  23. package/front_end/models/ai_assistance/ai_assistance.ts +6 -2
  24. package/front_end/models/ai_assistance/contexts/PerformanceTraceContext.ts +295 -0
  25. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +10 -10
  26. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +12 -11
  27. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +6 -6
  28. package/front_end/models/ai_assistance/skills/accessibility.md +4 -2
  29. package/front_end/models/ai_assistance/tools/GetElementAccessibilityDetails.ts +142 -0
  30. package/front_end/models/ai_assistance/tools/GetStyles.ts +1 -1
  31. package/front_end/models/ai_assistance/tools/README.md +21 -1
  32. package/front_end/models/ai_assistance/tools/{ResolveLighthousePath.ts → ResolveDevtoolsNodePath.ts} +18 -17
  33. package/front_end/models/ai_assistance/tools/Tool.ts +6 -1
  34. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +4 -2
  35. package/front_end/models/autofill_manager/AutofillManager.ts +7 -15
  36. package/front_end/models/bindings/NetworkProject.ts +4 -8
  37. package/front_end/models/breakpoints/BreakpointManager.ts +9 -9
  38. package/front_end/models/emulation/DeviceModeModel.ts +24 -0
  39. package/front_end/models/emulation/EmulatedDevices.ts +108 -0
  40. package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +36 -0
  41. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +8 -0
  42. package/front_end/models/issues_manager/IssuesManager.ts +10 -6
  43. package/front_end/models/javascript_metadata/JavaScriptMetadata.ts +4 -5
  44. package/front_end/models/live-metrics/LiveMetrics.ts +6 -6
  45. package/front_end/models/live-metrics/web-vitals-injected/spec/spec.ts +5 -5
  46. package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +3 -3
  47. package/front_end/models/logs/LogManager.ts +25 -10
  48. package/front_end/models/logs/NetworkLog.ts +24 -19
  49. package/front_end/models/persistence/AutomaticFileSystemWorkspaceBinding.ts +14 -5
  50. package/front_end/models/persistence/IsolatedFileSystem.ts +9 -11
  51. package/front_end/models/persistence/IsolatedFileSystemManager.ts +5 -3
  52. package/front_end/models/persistence/NetworkPersistenceManager.ts +73 -44
  53. package/front_end/models/persistence/PersistenceImpl.ts +4 -5
  54. package/front_end/models/trace/EntityMapper.ts +1 -1
  55. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +9 -9
  56. package/front_end/panels/ai_assistance/ExportConversation.ts +4 -1
  57. package/front_end/panels/ai_assistance/components/ChatInput.ts +2 -2
  58. package/front_end/panels/application/IndexedDBViews.ts +38 -36
  59. package/front_end/panels/application/components/AdsView.ts +4 -0
  60. package/front_end/panels/autofill/AutofillView.ts +1 -1
  61. package/front_end/panels/autofill/autofill-meta.ts +3 -2
  62. package/front_end/panels/elements/AccessibilityTreeUtils.ts +26 -15
  63. package/front_end/panels/elements/AccessibilityTreeView.ts +12 -9
  64. package/front_end/panels/elements/ElementsTreeOutline.ts +5 -0
  65. package/front_end/panels/layer_viewer/LayerTreeOutline.ts +118 -68
  66. package/front_end/panels/layer_viewer/Layers3DView.ts +1 -1
  67. package/front_end/panels/layer_viewer/layerTreeOutline.css +20 -13
  68. package/front_end/panels/layers/LayersPanel.ts +1 -1
  69. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +64 -17
  70. package/front_end/panels/mobile_throttling/throttlingSettingsTab.css +5 -0
  71. package/front_end/panels/network/LinkPreloadGenerator.ts +101 -0
  72. package/front_end/panels/network/NetworkLogView.ts +28 -0
  73. package/front_end/panels/network/network.ts +2 -0
  74. package/front_end/panels/profiler/HeapSnapshotView.ts +121 -33
  75. package/front_end/panels/profiler/ModuleUIStrings.ts +4 -0
  76. package/front_end/panels/timeline/TimelineHistoryManager.ts +38 -37
  77. package/front_end/panels/timeline/TimelinePanel.ts +32 -8
  78. package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +7 -6
  79. package/front_end/panels/timeline/components/LiveMetricsView.ts +38 -38
  80. package/front_end/panels/timeline/components/MetricCard.ts +18 -18
  81. package/front_end/panels/timeline/components/liveMetricsView.css +6 -6
  82. package/front_end/panels/timeline/components/metricCard.css +4 -4
  83. package/front_end/panels/whats_new/ReleaseNoteText.ts +3 -3
  84. package/front_end/panels/whats_new/resources/WNDT.md +1 -1
  85. package/front_end/third_party/chromium/README.chromium +1 -1
  86. package/front_end/ui/legacy/InspectorDrawerView.ts +7 -5
  87. package/front_end/ui/legacy/ListWidget.ts +12 -0
  88. package/front_end/ui/legacy/SplitWidget.ts +12 -11
  89. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +23 -19
  90. package/front_end/ui/legacy/components/object_ui/CustomPreviewComponent.ts +8 -1
  91. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +110 -17
  92. package/front_end/ui/legacy/treeoutline.css +1 -1
  93. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  94. package/package.json +4 -3
@@ -17,12 +17,30 @@ Instead of passing a monolithic "grab-bag" context object to all tool handlers,
17
17
  - `PageExecutionCapability`: For tools executing JavaScript code on the inspected page.
18
18
  - `StyleMutationCapability`: For tools managing and applying style mutations via a `ChangeManager`.
19
19
  - `TargetCapability`: For tools requiring access to the page's current SDK `Target`.
20
- - `OriginLockCapability`: For tools enforcing cross-origin security via origin locks. Tools that fetch resources or state from the inspected page (such as styling or source code) must use this capability to verify that the target resource matches the conversation's established origin. This prevents the LLM from executing tools against out-of-origin elements or documents.
20
+ - `OriginLockCapability`: For tools enforcing cross-origin security via origin locks. Tools that fetch resources or state from the inspected page (such as styling or source code) must use this capability to verify that the target resource matches the conversation's established origin. This prevents the LLM from executing tools against out-of-origin elements or documents. Verification should be done by wrapping resolved resources in helper context classes (e.g., `DOMNodeContext`) and calling `isOriginAllowed(establishedOrigin)`.
21
21
 
22
22
  ### Unified Context
23
23
 
24
24
  The Agent (e.g., `AiAgent2`) builds the complete dependency union (`AllToolsCapabilities`) and fulfills all capabilities. When the handler is invoked, TypeScript validates that the provided context matches the intersection of capabilities requested by that tool.
25
25
 
26
+ ## Returning UI Widgets
27
+
28
+ Tools can return rich UI components (widgets) to be rendered directly in the AI Assistance panel alongside text results. To do this, include the widget payload in the `widgets` field of the returned `FunctionCallHandlerResult`:
29
+
30
+ ```typescript
31
+ return {
32
+ result: JSON.stringify(properties, null, 2),
33
+ widgets: [{
34
+ name: 'DOM_TREE',
35
+ data: {
36
+ root: snapshot,
37
+ title: i18n.i18n.lockedString('Element details'),
38
+ accessibleRevealLabel: i18n.i18n.lockedString('Reveal element'),
39
+ },
40
+ }],
41
+ };
42
+ ```
43
+
26
44
  ## Authoring a New Tool
27
45
 
28
46
  To author a new tool:
@@ -35,6 +53,8 @@ To author a new tool:
35
53
  See concrete, production examples of capability-based tools in this directory:
36
54
  - [ExecuteJavaScript.ts](ExecuteJavaScript.ts): Demonstrates use of `PageExecutionCapability` and `StyleMutationCapability`.
37
55
  - [GetStyles.ts](GetStyles.ts): Demonstrates use of `TargetCapability` and `OriginLockCapability`.
56
+ - [GetElementAccessibilityDetails.ts](GetElementAccessibilityDetails.ts): Demonstrates returning UI widgets (`DOM_TREE`) and origin checks with context wrappers.
57
+ - [ResolveDevtoolsNodePath.ts](ResolveDevtoolsNodePath.ts): Demonstrates path resolution input validation and origin lock checks.
38
58
 
39
59
  ## ToolRegistry Lookup
40
60
 
@@ -17,11 +17,11 @@ import {
17
17
  } from './Tool.js';
18
18
 
19
19
  /**
20
- * Arguments for resolving a Lighthouse path to a backend node ID.
20
+ * Arguments for resolving a DevTools node path to a backend node ID.
21
21
  */
22
- export interface ResolveLighthousePathArgs extends ToolArgs {
22
+ export interface ResolveDevtoolsNodePathArgs extends ToolArgs {
23
23
  /**
24
- * A Lighthouse-style element path.
24
+ * A DevTools node path.
25
25
  * This is typically a comma-separated list of child indices and tag names
26
26
  * representing the path from the root to the target element (e.g., "1,HTML,1,BODY").
27
27
  */
@@ -30,19 +30,20 @@ export interface ResolveLighthousePathArgs extends ToolArgs {
30
30
  }
31
31
 
32
32
  /**
33
- * A tool that resolves a Lighthouse-style element path to a backend node ID.
33
+ * A tool that resolves a DevTools node path to a backend node ID.
34
34
  *
35
35
  * This is used by the AI assistant to identify specific DOM nodes referred to in
36
- * Lighthouse reports. It ensures the resolved node belongs to the locked origin.
36
+ * Lighthouse reports or other sources using node paths. It ensures the resolved node
37
+ * belongs to the locked origin.
37
38
  */
38
- export class ResolveLighthousePathTool implements
39
- Tool<ResolveLighthousePathArgs, {backendNodeId: number}, BaseToolCapability&TargetCapability&OriginLockCapability> {
40
- readonly name = ToolName.RESOLVE_LIGHTHOUSE_PATH;
41
- readonly description = 'Resolves a Lighthouse path to a backend node ID.';
39
+ export class ResolveDevtoolsNodePathTool implements Tool<ResolveDevtoolsNodePathArgs, {backendNodeId: number},
40
+ BaseToolCapability&TargetCapability&OriginLockCapability> {
41
+ readonly name = ToolName.RESOLVE_DEVTOOLS_NODE_PATH;
42
+ readonly description = 'Resolves a DevTools node path to a backend node ID.';
42
43
 
43
- readonly parameters: Host.AidaClient.FunctionObjectParam<keyof ResolveLighthousePathArgs> = {
44
+ readonly parameters: Host.AidaClient.FunctionObjectParam<keyof ResolveDevtoolsNodePathArgs> = {
44
45
  type: Host.AidaClient.ParametersTypes.OBJECT,
45
- description: 'Arguments for resolving a Lighthouse path to a backend node ID.',
46
+ description: 'Arguments for resolving a DevTools node path to a backend node ID.',
46
47
  nullable: false,
47
48
  properties: {
48
49
  explanation: {
@@ -52,14 +53,14 @@ export class ResolveLighthousePathTool implements
52
53
  },
53
54
  path: {
54
55
  type: Host.AidaClient.ParametersTypes.STRING,
55
- description: 'Lighthouse path string.',
56
+ description: 'DevTools node path string.',
56
57
  nullable: false,
57
58
  },
58
59
  },
59
60
  required: ['explanation', 'path'],
60
61
  };
61
62
 
62
- displayInfoFromArgs(params: ResolveLighthousePathArgs): {
63
+ displayInfoFromArgs(params: ResolveDevtoolsNodePathArgs): {
63
64
  title: string,
64
65
  thought: string,
65
66
  action: string,
@@ -67,7 +68,7 @@ export class ResolveLighthousePathTool implements
67
68
  return {
68
69
  title: 'Resolving element path',
69
70
  thought: params.explanation,
70
- action: `resolveLighthousePath('${params.path}')`,
71
+ action: `resolveDevtoolsNodePath('${params.path}')`,
71
72
  };
72
73
  }
73
74
 
@@ -79,7 +80,7 @@ export class ResolveLighthousePathTool implements
79
80
  * access to nodes from other origins.
80
81
  */
81
82
  async handler(
82
- params: ResolveLighthousePathArgs,
83
+ params: ResolveDevtoolsNodePathArgs,
83
84
  context: BaseToolCapability&TargetCapability&OriginLockCapability,
84
85
  ): Promise<FunctionCallHandlerResult<{backendNodeId: number}>> {
85
86
  const establishedOrigin = context.getEstablishedOrigin();
@@ -95,11 +96,11 @@ export class ResolveLighthousePathTool implements
95
96
 
96
97
  let nodeId;
97
98
  try {
98
- // Resolves the Lighthouse path (a representation of the path to a node)
99
+ // Resolves the DevTools node path (a representation of the path to a node)
99
100
  // and ensures the node is loaded into the frontend DOM model, returning its ID.
100
101
  nodeId = await domModel.pushNodeByPathToFrontend(params.path);
101
102
  } catch {
102
- return {error: 'Error: Could not find node by path.'};
103
+ // pushNodeByPathToFrontend can fail or return undefined
103
104
  }
104
105
  if (!nodeId) {
105
106
  return {error: 'Error: Could not find node by path.'};
@@ -98,7 +98,8 @@ export const enum ToolName {
98
98
  LIST_NETWORK_REQUESTS = 'listNetworkRequests',
99
99
  GET_NETWORK_REQUEST_DETAILS = 'getNetworkRequestDetails',
100
100
  GET_LIGHTHOUSE_AUDITS = 'getLighthouseAudits',
101
- RESOLVE_LIGHTHOUSE_PATH = 'resolveLighthousePath',
101
+ RESOLVE_DEVTOOLS_NODE_PATH = 'resolveDevtoolsNodePath',
102
+ GET_ELEMENT_ACCESSIBILITY_DETAILS = 'getElementAccessibilityDetails',
102
103
  }
103
104
 
104
105
  /**
@@ -125,6 +126,10 @@ export interface BaseTool {
125
126
  export interface Tool<Args extends ToolArgs = ToolArgs, ReturnType = unknown,
126
127
  ContextType extends BaseToolCapability = BaseToolCapability> extends BaseTool {
127
128
  readonly parameters: Host.AidaClient.FunctionObjectParam<keyof Args>;
129
+ /**
130
+ * Converts the tool arguments into user-friendly display information.
131
+ * This is used by the UI to show what the agent is doing (e.g., in the history/steps log).
132
+ */
128
133
  readonly displayInfoFromArgs?: (
129
134
  args: Args,
130
135
  ) => {
@@ -3,11 +3,12 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import {ExecuteJavaScriptTool} from './ExecuteJavaScript.js';
6
+ import {GetElementAccessibilityDetailsTool} from './GetElementAccessibilityDetails.js';
6
7
  import {GetLighthouseAuditsTool} from './GetLighthouseAudits.js';
7
8
  import {GetNetworkRequestDetailsTool} from './GetNetworkRequestDetails.js';
8
9
  import {GetStylesTool} from './GetStyles.js';
9
10
  import {ListNetworkRequestsTool} from './ListNetworkRequests.js';
10
- import {ResolveLighthousePathTool} from './ResolveLighthousePath.js';
11
+ import {ResolveDevtoolsNodePathTool} from './ResolveDevtoolsNodePath.js';
11
12
  import {type AllToolsCapabilities, type Tool, type ToolArgs, ToolName} from './Tool.js';
12
13
 
13
14
  /**
@@ -24,7 +25,8 @@ export const TOOLS = {
24
25
  [ToolName.LIST_NETWORK_REQUESTS]: new ListNetworkRequestsTool(),
25
26
  [ToolName.GET_NETWORK_REQUEST_DETAILS]: new GetNetworkRequestDetailsTool(),
26
27
  [ToolName.GET_LIGHTHOUSE_AUDITS]: new GetLighthouseAuditsTool(),
27
- [ToolName.RESOLVE_LIGHTHOUSE_PATH]: new ResolveLighthousePathTool(),
28
+ [ToolName.RESOLVE_DEVTOOLS_NODE_PATH]: new ResolveDevtoolsNodePathTool(),
29
+ [ToolName.GET_ELEMENT_ACCESSIBILITY_DETAILS]: new GetElementAccessibilityDetailsTool(),
28
30
  };
29
31
 
30
32
  /**
@@ -7,27 +7,19 @@ import * as Platform from '../../core/platform/platform.js';
7
7
  import * as SDK from '../../core/sdk/sdk.js';
8
8
  import type * as Protocol from '../../generated/protocol.js';
9
9
 
10
- let autofillManagerInstance: AutofillManager;
11
-
12
10
  export class AutofillManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
13
11
  #address = '';
14
12
  #filledFields: Protocol.Autofill.FilledField[] = [];
15
13
  #matches: Match[] = [];
16
14
  #autofillModel: SDK.AutofillModel.AutofillModel|null = null;
15
+ #frameManager: SDK.FrameManager.FrameManager;
17
16
 
18
- private constructor() {
17
+ constructor(targetManager: SDK.TargetManager.TargetManager,
18
+ frameManager: SDK.FrameManager.FrameManager = SDK.FrameManager.FrameManager.instance()) {
19
19
  super();
20
- SDK.TargetManager.TargetManager.instance().addModelListener(
21
- SDK.AutofillModel.AutofillModel, SDK.AutofillModel.Events.ADDRESS_FORM_FILLED, this.#addressFormFilled, this,
22
- {scoped: true});
23
- }
24
-
25
- static instance(opts: {forceNew: boolean|null} = {forceNew: null}): AutofillManager {
26
- const {forceNew} = opts;
27
- if (!autofillManagerInstance || forceNew) {
28
- autofillManagerInstance = new AutofillManager();
29
- }
30
- return autofillManagerInstance;
20
+ this.#frameManager = frameManager;
21
+ targetManager.addModelListener(SDK.AutofillModel.AutofillModel, SDK.AutofillModel.Events.ADDRESS_FORM_FILLED,
22
+ this.#addressFormFilled, this, {scoped: true});
31
23
  }
32
24
 
33
25
  async #addressFormFilled({data}: Common.EventTarget.EventTargetEvent<
@@ -56,7 +48,7 @@ export class AutofillManager extends Common.ObjectWrapper.ObjectWrapper<EventTyp
56
48
 
57
49
  highlightFilledField(filledField: Protocol.Autofill.FilledField): void {
58
50
  const backendNodeId = filledField.fieldId;
59
- const target = SDK.FrameManager.FrameManager.instance().getFrame(filledField.frameId)?.resourceTreeModel().target();
51
+ const target = this.#frameManager.getFrame(filledField.frameId)?.resourceTreeModel().target();
60
52
  if (target) {
61
53
  const deferredNode = new SDK.DOMModel.DeferredDOMNode(target, backendNodeId);
62
54
  const domModel = target.model(SDK.DOMModel.DOMModel);
@@ -3,6 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import * as Common from '../../core/common/common.js';
6
+ import * as Root from '../../core/root/root.js';
6
7
  import * as SDK from '../../core/sdk/sdk.js';
7
8
  import type * as Protocol from '../../generated/protocol.js';
8
9
  import type * as Workspace from '../workspace/workspace.js';
@@ -13,21 +14,16 @@ const uiSourceCodeToAttributionMap = new WeakMap<Workspace.UISourceCode.UISource
13
14
  }>>();
14
15
  const projectToTargetMap = new WeakMap<Workspace.Workspace.Project, SDK.Target.Target>();
15
16
 
16
- let networkProjectManagerInstance: NetworkProjectManager;
17
-
18
17
  export class NetworkProjectManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
19
- private constructor() {
20
- super();
21
- }
22
18
 
23
19
  static instance({forceNew}: {
24
20
  forceNew: boolean,
25
21
  } = {forceNew: false}): NetworkProjectManager {
26
- if (!networkProjectManagerInstance || forceNew) {
27
- networkProjectManagerInstance = new NetworkProjectManager();
22
+ if (!Root.DevToolsContext.globalInstance().has(NetworkProjectManager) || forceNew) {
23
+ Root.DevToolsContext.globalInstance().set(NetworkProjectManager, new NetworkProjectManager());
28
24
  }
29
25
 
30
- return networkProjectManagerInstance;
26
+ return Root.DevToolsContext.globalInstance().get(NetworkProjectManager);
31
27
  }
32
28
  }
33
29
 
@@ -14,7 +14,6 @@ import * as SourceMapScopes from '../source_map_scopes/source_map_scopes.js';
14
14
  import type * as TextUtils from '../text_utils/text_utils.js';
15
15
  import * as Workspace from '../workspace/workspace.js';
16
16
 
17
- let breakpointManagerInstance: BreakpointManager;
18
17
  const INITIAL_RESTORE_BREAKPOINT_COUNT = 100;
19
18
 
20
19
  export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> implements
@@ -35,10 +34,9 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
35
34
  readonly #breakpointByStorageId = new Map<string, Breakpoint>();
36
35
  #updateBindingsCallbacks: Array<(uiSourceCode: Workspace.UISourceCode.UISourceCode) => Promise<void>> = [];
37
36
 
38
- private constructor(
39
- targetManager: SDK.TargetManager.TargetManager, workspace: Workspace.Workspace.WorkspaceImpl,
40
- debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding,
41
- settings: Common.Settings.Settings, restoreInitialBreakpointCount?: number) {
37
+ constructor(targetManager: SDK.TargetManager.TargetManager, workspace: Workspace.Workspace.WorkspaceImpl,
38
+ debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding,
39
+ settings: Common.Settings.Settings, restoreInitialBreakpointCount?: number) {
42
40
  super();
43
41
  this.#workspace = workspace;
44
42
  this.targetManager = targetManager;
@@ -85,18 +83,20 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
85
83
  }): BreakpointManager {
86
84
  const {forceNew, targetManager, workspace, debuggerWorkspaceBinding, settings, restoreInitialBreakpointCount} =
87
85
  opts;
88
- if (!breakpointManagerInstance || forceNew) {
86
+ if (!Root.DevToolsContext.globalInstance().has(BreakpointManager) || forceNew) {
89
87
  if (!targetManager || !workspace || !debuggerWorkspaceBinding || !settings) {
90
88
  throw new Error(
91
89
  `Unable to create settings: targetManager, workspace, debuggerWorkspaceBinding, and settings must be provided: ${
92
90
  new Error().stack}`);
93
91
  }
94
92
 
95
- breakpointManagerInstance = new BreakpointManager(
96
- targetManager, workspace, debuggerWorkspaceBinding, settings, restoreInitialBreakpointCount);
93
+ Root.DevToolsContext.globalInstance().set(
94
+ BreakpointManager,
95
+ new BreakpointManager(targetManager, workspace, debuggerWorkspaceBinding, settings,
96
+ restoreInitialBreakpointCount));
97
97
  }
98
98
 
99
- return breakpointManagerInstance;
99
+ return Root.DevToolsContext.globalInstance().get(BreakpointManager);
100
100
  }
101
101
 
102
102
  modelAdded(debuggerModel: SDK.DebuggerModel.DebuggerModel): void {
@@ -200,6 +200,10 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
200
200
  }
201
201
  }
202
202
 
203
+ static removeInstance(): void {
204
+ deviceModeModelInstance = null;
205
+ }
206
+
203
207
  dispose(): void {
204
208
  SDK.TargetManager.TargetManager.instance().unobserveModels(SDK.EmulationModel.EmulationModel, this);
205
209
  }
@@ -573,6 +577,25 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
573
577
  return this.#mode.insets;
574
578
  }
575
579
 
580
+ private currentSafeAreaInsets(): Insets|null {
581
+ if (this.#type !== Type.Device || !this.#mode) {
582
+ return null;
583
+ }
584
+ return this.#mode.safeAreaInsets ?? null;
585
+ }
586
+
587
+ private applySafeAreaInsets(insets: Insets|null): void {
588
+ if (!this.#emulationModel) {
589
+ return;
590
+ }
591
+ if (insets) {
592
+ void this.#emulationModel.setSafeAreaInsets(
593
+ {top: insets.top, left: insets.left, bottom: insets.bottom, right: insets.right});
594
+ } else {
595
+ void this.#emulationModel.setSafeAreaInsets({});
596
+ }
597
+ }
598
+
576
599
  private getScreenOrientationType(): Protocol.Emulation.ScreenOrientationType {
577
600
  if (!this.#mode) {
578
601
  throw new Error('Mode required to get orientation type.');
@@ -649,6 +672,7 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
649
672
  if (overlayModel) {
650
673
  overlayModel.setShowViewportSizeOnResize(this.#type === Type.None);
651
674
  }
675
+ this.applySafeAreaInsets(this.currentSafeAreaInsets());
652
676
  this.dispatchEventToListeners(Events.UPDATED);
653
677
  }
654
678
 
@@ -103,6 +103,15 @@ export class EmulatedDevice {
103
103
  parseIntValue(json, 'bottom'));
104
104
  }
105
105
 
106
+ function parseCutoutShape(json: any): CutoutShape {
107
+ const shape = parseValue(json, 'shape', 'string');
108
+ if (shape !== CutoutShape.PILL && shape !== CutoutShape.NOTCH && shape !== CutoutShape.CIRCLE &&
109
+ shape !== CutoutShape.RECTANGLE) {
110
+ throw new Error('Emulated device mode has unsupported cutout shape: ' + shape);
111
+ }
112
+ return shape;
113
+ }
114
+
106
115
  function parseRGBA(json: any): SDK.OverlayModel.HighlightColor {
107
116
  const result = {} as SDK.OverlayModel.HighlightColor;
108
117
  result.r = parseIntValue(json, 'r');
@@ -257,6 +266,40 @@ export class EmulatedDevice {
257
266
  throw new Error('Emulated device mode \'' + mode.title + '\'has wrong mode insets');
258
267
  }
259
268
  mode.image = (parseValue(modes[i], 'image', 'string', null) as string);
269
+ const safeAreaInsets = parseValue(modes[i], 'safe-area-insets', 'object', null);
270
+ if (safeAreaInsets) {
271
+ mode.safeAreaInsets = parseInsets(safeAreaInsets);
272
+ }
273
+ const cutout = parseValue(modes[i], 'cutout', 'object', null);
274
+ if (cutout) {
275
+ const shape = parseCutoutShape(cutout);
276
+ const baseCutout = {
277
+ x: parseIntValue(cutout, 'x'),
278
+ y: parseIntValue(cutout, 'y'),
279
+ width: parseIntValue(cutout, 'width'),
280
+ height: parseIntValue(cutout, 'height'),
281
+ };
282
+ if (shape === CutoutShape.PILL) {
283
+ mode.cutout = {shape, ...baseCutout, borderRadius: parseIntValue(cutout, 'border-radius')};
284
+ } else if (shape === CutoutShape.NOTCH) {
285
+ mode.cutout = {
286
+ shape,
287
+ ...baseCutout,
288
+ upperRadius: parseIntValue(cutout, 'upper-radius'),
289
+ lowerRadius: parseIntValue(cutout, 'lower-radius'),
290
+ };
291
+ } else if (shape === CutoutShape.CIRCLE) {
292
+ mode.cutout = {
293
+ shape,
294
+ ...baseCutout,
295
+ cx: parseIntValue(cutout, 'cx'),
296
+ cy: parseIntValue(cutout, 'cy'),
297
+ radius: parseIntValue(cutout, 'radius'),
298
+ };
299
+ } else {
300
+ mode.cutout = {shape, ...baseCutout};
301
+ }
302
+ }
260
303
  result.modes.push(mode);
261
304
  }
262
305
  result.#showByDefault = (parseValue(json, 'show-by-default', 'boolean', undefined) as boolean);
@@ -359,6 +402,35 @@ export class EmulatedDevice {
359
402
  },
360
403
  image: this.modes[i].image || undefined,
361
404
  };
405
+ const safeAreaInsets = this.modes[i].safeAreaInsets;
406
+ if (safeAreaInsets) {
407
+ mode['safe-area-insets'] = {
408
+ left: safeAreaInsets.left,
409
+ top: safeAreaInsets.top,
410
+ right: safeAreaInsets.right,
411
+ bottom: safeAreaInsets.bottom,
412
+ };
413
+ }
414
+ const cutout = this.modes[i].cutout;
415
+ if (cutout) {
416
+ mode.cutout = {
417
+ shape: cutout.shape,
418
+ x: cutout.x,
419
+ y: cutout.y,
420
+ width: cutout.width,
421
+ height: cutout.height,
422
+ };
423
+ if (cutout.shape === CutoutShape.PILL) {
424
+ mode.cutout['border-radius'] = cutout.borderRadius;
425
+ } else if (cutout.shape === CutoutShape.NOTCH) {
426
+ mode.cutout['upper-radius'] = cutout.upperRadius;
427
+ mode.cutout['lower-radius'] = cutout.lowerRadius;
428
+ } else if (cutout.shape === CutoutShape.CIRCLE) {
429
+ mode.cutout.cx = cutout.cx;
430
+ mode.cutout.cy = cutout.cy;
431
+ mode.cutout.radius = cutout.radius;
432
+ }
433
+ }
362
434
  json['modes'].push(mode);
363
435
  }
364
436
 
@@ -637,7 +709,24 @@ export interface Mode {
637
709
  orientation: string;
638
710
  insets: Insets;
639
711
  image: string|null;
712
+ safeAreaInsets?: Insets;
713
+ cutout?: Cutout;
640
714
  }
715
+ export const enum CutoutShape {
716
+ PILL = 'pill',
717
+ NOTCH = 'notch',
718
+ CIRCLE = 'circle',
719
+ RECTANGLE = 'rectangle',
720
+ }
721
+ export interface BaseCutout {
722
+ x: number;
723
+ y: number;
724
+ width: number;
725
+ height: number;
726
+ }
727
+ export type Cutout = BaseCutout&({shape: CutoutShape.RECTANGLE}|{shape: CutoutShape.PILL, borderRadius: number}|
728
+ {shape: CutoutShape.NOTCH, upperRadius: number, lowerRadius: number}|
729
+ {shape: CutoutShape.CIRCLE, cx: number, cy: number, radius: number});
641
730
  export interface Orientation {
642
731
  width: number;
643
732
  height: number;
@@ -655,6 +744,25 @@ export interface JSONMode {
655
744
  top: number,
656
745
  bottom: number,
657
746
  };
747
+ 'safe-area-insets'?: {
748
+ left: number,
749
+ right: number,
750
+ top: number,
751
+ bottom: number,
752
+ };
753
+ cutout?: {
754
+ shape: string,
755
+ x: number,
756
+ y: number,
757
+ width: number,
758
+ height: number,
759
+ 'border-radius'?: number,
760
+ 'upper-radius'?: number,
761
+ 'lower-radius'?: number,
762
+ cx?: number,
763
+ cy?: number,
764
+ radius?: number,
765
+ };
658
766
  }
659
767
 
660
768
  // These props should quoted for the script to work properly
@@ -316,4 +316,40 @@ export interface DuplicateStringGroup {
316
316
  distance: number,
317
317
  }>;
318
318
  truncated?: boolean;
319
+ length?: number;
320
+ hash?: number;
321
+ }
322
+
323
+ export interface NativeContextSize {
324
+ nodeId: number;
325
+ nodeIndex: number;
326
+ nodeName: string;
327
+ attributedSize: number;
328
+ retainedSize: number;
329
+ selfSize: number;
330
+ }
331
+
332
+ export interface NativeContextSizes {
333
+ nativeContexts: NativeContextSize[];
334
+ sharedSize: number;
335
+ noAttributionSize: number;
336
+ }
337
+
338
+ export const enum DOMLinkState {
339
+ UNKNOWN = 0,
340
+ ATTACHED = 1,
341
+ DETACHED = 2,
342
+ }
343
+
344
+ export interface ObjectInfo {
345
+ id: number;
346
+ name: string;
347
+ type: string;
348
+ nodeIndex: number;
349
+ detachedness: DOMLinkState;
350
+ selfSize: number;
351
+ retainedSize: number;
352
+ distance: number;
353
+ edgeCount: number;
354
+ retainerCount: number;
319
355
  }
@@ -267,6 +267,10 @@ export class HeapSnapshotProxy extends HeapSnapshotProxyObject {
267
267
  return this.callMethodPromise('interfaceDefinitions');
268
268
  }
269
269
 
270
+ getNativeContextSizes(): Promise<HeapSnapshotModel.NativeContextSizes> {
271
+ return this.callMethodPromise('getNativeContextSizes');
272
+ }
273
+
270
274
  aggregatesWithFilter(filter: HeapSnapshotModel.NodeFilter):
271
275
  Promise<Record<string, HeapSnapshotModel.AggregatedInfo>> {
272
276
  return this.callMethodPromise('aggregatesWithFilter', filter);
@@ -295,6 +299,10 @@ export class HeapSnapshotProxy extends HeapSnapshotProxyObject {
295
299
  return this.callMethodPromise('nodeIndexForId', nodeId);
296
300
  }
297
301
 
302
+ getObjectInfo(nodeIndex: number): Promise<HeapSnapshotModel.ObjectInfo> {
303
+ return this.callMethodPromise('getObjectInfo', nodeIndex);
304
+ }
305
+
298
306
  createEdgesProvider(nodeIndex: number): HeapSnapshotProviderProxy {
299
307
  return this.callFactoryMethod('createEdgesProvider', HeapSnapshotProviderProxy, nodeIndex);
300
308
  }
@@ -180,6 +180,7 @@ export function createIssuesFromProtocolIssue(
180
180
 
181
181
  export interface IssuesManagerCreationOptions {
182
182
  forceNew: boolean;
183
+ frameManager?: SDK.FrameManager.FrameManager;
183
184
  /** Throw an error if this is not the first instance created */
184
185
  ensureFirst: boolean;
185
186
  showThirdPartyIssuesSetting?: Common.Settings.Setting<boolean>;
@@ -224,18 +225,20 @@ export class IssuesManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes
224
225
  #thirdPartyCookiePhaseoutIssueCount = new Map<IssueKind, number>();
225
226
  #issuesById = new Map<string, Issue>();
226
227
  #issuesByOutermostTarget: WeakMap<SDK.Target.Target, Set<Issue>> = new Map();
228
+ #frameManager: SDK.FrameManager.FrameManager;
227
229
 
228
- constructor(
229
- private readonly showThirdPartyIssuesSetting?: Common.Settings.Setting<boolean>,
230
- private readonly hideIssueSetting?: Common.Settings.Setting<HideIssueMenuSetting>) {
230
+ constructor(private readonly showThirdPartyIssuesSetting?: Common.Settings.Setting<boolean>,
231
+ private readonly hideIssueSetting?: Common.Settings.Setting<HideIssueMenuSetting>,
232
+ frameManager: SDK.FrameManager.FrameManager = SDK.FrameManager.FrameManager.instance()) {
231
233
  super();
234
+ this.#frameManager = frameManager;
232
235
  new SourceFrameIssuesManager(this);
233
236
  SDK.TargetManager.TargetManager.instance().observeModels(SDK.IssuesModel.IssuesModel, this);
234
237
  SDK.TargetManager.TargetManager.instance().addModelListener(
235
238
  SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.PrimaryPageChanged,
236
239
  this.#onPrimaryPageChanged, this);
237
- SDK.FrameManager.FrameManager.instance().addEventListener(
238
- SDK.FrameManager.Events.FRAME_ADDED_TO_TARGET, this.#onFrameAddedToTarget, this);
240
+ this.#frameManager.addEventListener(SDK.FrameManager.Events.FRAME_ADDED_TO_TARGET, this.#onFrameAddedToTarget,
241
+ this);
239
242
 
240
243
  // issueFilter uses the 'show-third-party-issues' setting. Clients of IssuesManager need
241
244
  // a full update when the setting changes to get an up-to-date issues list.
@@ -263,7 +266,8 @@ export class IssuesManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes
263
266
  }
264
267
 
265
268
  if (!issuesManagerInstance || opts.forceNew) {
266
- issuesManagerInstance = new IssuesManager(opts.showThirdPartyIssuesSetting, opts.hideIssueSetting);
269
+ issuesManagerInstance =
270
+ new IssuesManager(opts.showThirdPartyIssuesSetting, opts.hideIssueSetting, opts.frameManager);
267
271
  }
268
272
 
269
273
  return issuesManagerInstance;
@@ -3,11 +3,10 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import type * as Common from '../../core/common/common.js';
6
+ import * as Root from '../../core/root/root.js';
6
7
 
7
8
  import {NativeFunctions} from './NativeFunctions.js';
8
9
 
9
- let javaScriptMetadataInstance: JavaScriptMetadataImpl;
10
-
11
10
  export class JavaScriptMetadataImpl implements Common.JavaScriptMetaData.JavaScriptMetaData {
12
11
  private readonly uniqueFunctions: Map<string, string[][]>;
13
12
  private readonly receiverMethods: Map<string, Map<string, string[][]>>;
@@ -15,11 +14,11 @@ export class JavaScriptMetadataImpl implements Common.JavaScriptMetaData.JavaScr
15
14
  forceNew: boolean|null,
16
15
  } = {forceNew: null}): JavaScriptMetadataImpl {
17
16
  const {forceNew} = opts;
18
- if (!javaScriptMetadataInstance || forceNew) {
19
- javaScriptMetadataInstance = new JavaScriptMetadataImpl();
17
+ if (!Root.DevToolsContext.globalInstance().has(JavaScriptMetadataImpl) || forceNew) {
18
+ Root.DevToolsContext.globalInstance().set(JavaScriptMetadataImpl, new JavaScriptMetadataImpl());
20
19
  }
21
20
 
22
- return javaScriptMetadataInstance;
21
+ return Root.DevToolsContext.globalInstance().get(JavaScriptMetadataImpl);
23
22
  }
24
23
  constructor() {
25
24
  this.uniqueFunctions = new Map();