chrome-devtools-frontend 1.0.1657110 → 1.0.1657855

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 (71) hide show
  1. package/.agents/skills/devtools-ux-writing-refactor/SKILL.md +125 -0
  2. package/.agents/skills/repro-flaky-tests/SKILL.md +53 -0
  3. package/front_end/Images/src/ads.svg +1 -0
  4. package/front_end/core/common/ResourceType.ts +19 -19
  5. package/front_end/core/common/Revealer.ts +15 -15
  6. package/front_end/core/common/SettingRegistration.ts +19 -19
  7. package/front_end/core/sdk/CSSMetadata.ts +110 -16
  8. package/front_end/core/sdk/NetworkManager.ts +1 -3
  9. package/front_end/entrypoints/devtools_app/devtools_app.ts +1 -1
  10. package/front_end/entrypoints/formatter_worker/CSSFormatter.ts +13 -4
  11. package/front_end/entrypoints/formatter_worker/FormatterWorker.ts +23 -4
  12. package/front_end/entrypoints/formatter_worker/HTMLFormatter.ts +7 -6
  13. package/front_end/entrypoints/main/MainImpl.ts +7 -34
  14. package/front_end/entrypoints/main/main-meta.ts +8 -8
  15. package/front_end/entrypoints/node_app/app/NodeConnectionsPanel.ts +5 -5
  16. package/front_end/entrypoints/node_app/app/NodeMain.ts +3 -3
  17. package/front_end/entrypoints/node_app/node_app.ts +7 -7
  18. package/front_end/foundation/Universe.ts +32 -5
  19. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  20. package/front_end/generated/protocol.ts +4 -0
  21. package/front_end/models/ai_assistance/AiUtils.ts +6 -6
  22. package/front_end/models/bindings/CSSWorkspaceBinding.ts +8 -5
  23. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +13 -15
  24. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +6 -4
  25. package/front_end/models/bindings/FileUtils.ts +11 -12
  26. package/front_end/models/emulation/DeviceModeModel.ts +14 -14
  27. package/front_end/models/emulation/EmulatedDevices.ts +3 -3
  28. package/front_end/models/workspace_diff/WorkspaceDiff.ts +23 -12
  29. package/front_end/panels/application/ApplicationPanelSidebar.ts +9 -1
  30. package/front_end/panels/application/BackgroundServiceView.ts +2 -1
  31. package/front_end/panels/application/IndexedDBViews.ts +52 -23
  32. package/front_end/panels/application/components/AdsView.ts +1 -1
  33. package/front_end/panels/application/resourcesSidebar.css +5 -0
  34. package/front_end/panels/console/ConsoleContextSelector.ts +3 -3
  35. package/front_end/panels/console/ConsolePinPane.ts +10 -10
  36. package/front_end/panels/console/ConsolePrompt.ts +4 -4
  37. package/front_end/panels/console/ConsoleSidebar.ts +7 -7
  38. package/front_end/panels/console/ConsoleView.ts +44 -43
  39. package/front_end/panels/console/ConsoleViewMessage.ts +40 -40
  40. package/front_end/panels/console/console-meta.ts +34 -34
  41. package/front_end/panels/coverage/CoverageView.ts +1 -1
  42. package/front_end/panels/developer_resources/DeveloperResourcesListView.ts +19 -20
  43. package/front_end/panels/developer_resources/DeveloperResourcesView.ts +6 -8
  44. package/front_end/panels/developer_resources/developer_resources-meta.ts +2 -2
  45. package/front_end/panels/elements/ElementsTreeElement.ts +45 -1
  46. package/front_end/panels/media/EventDisplayTable.ts +2 -2
  47. package/front_end/panels/media/EventTimelineView.ts +4 -4
  48. package/front_end/panels/media/MainView.ts +4 -4
  49. package/front_end/panels/media/PlayerDetailView.ts +5 -5
  50. package/front_end/panels/media/PlayerListView.ts +1 -1
  51. package/front_end/panels/media/PlayerMessagesView.ts +12 -12
  52. package/front_end/panels/media/PlayerPropertiesView.ts +17 -17
  53. package/front_end/panels/network/NetworkLogView.ts +2 -1
  54. package/front_end/panels/network/NetworkWaterfallColumn.ts +1 -3
  55. package/front_end/panels/network/RequestConditionsDrawer.ts +2 -2
  56. package/front_end/panels/network/networkPanel.css +1 -0
  57. package/front_end/panels/network/networkTimingTable.css +1 -1
  58. package/front_end/panels/profiler/HeapSnapshotView.ts +2 -1
  59. package/front_end/panels/profiler/ProfileView.ts +2 -1
  60. package/front_end/panels/protocol_monitor/JSONEditor.ts +10 -10
  61. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +28 -32
  62. package/front_end/panels/protocol_monitor/protocol_monitor-meta.ts +1 -1
  63. package/front_end/panels/recorder/RecorderController.ts +1 -0
  64. package/front_end/panels/recorder/RecorderEvents.ts +8 -0
  65. package/front_end/panels/webauthn/WebauthnPane.ts +10 -10
  66. package/front_end/third_party/chromium/README.chromium +1 -1
  67. package/front_end/ui/components/dialogs/shortcutDialog.css +15 -12
  68. package/front_end/ui/legacy/Treeoutline.ts +15 -0
  69. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +5 -0
  70. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  71. package/package.json +1 -1
@@ -2,8 +2,6 @@
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
4
 
5
- import * as Platform from '../../core/platform/platform.js';
6
-
7
5
  import type {FormattedContentBuilder} from './FormattedContentBuilder.js';
8
6
  import {createTokenizer} from './FormatterWorker.js';
9
7
 
@@ -19,6 +17,7 @@ export class CSSFormatter {
19
17
  #fromOffset!: number;
20
18
  #lineEndings!: number[];
21
19
  #lastLine = -1;
20
+ #currentLineIndex = 0;
22
21
  #state: {
23
22
  eatWhitespace?: boolean,
24
23
  seenProperty?: boolean,
@@ -35,6 +34,7 @@ export class CSSFormatter {
35
34
  this.#toOffset = toOffset;
36
35
  this.#state = {};
37
36
  this.#lastLine = -1;
37
+ this.#currentLineIndex = 0;
38
38
  const tokenize = createTokenizer('text/css');
39
39
  const oldEnforce = this.#builder.setEnforceSpaceBetweenWords(false);
40
40
  tokenize(text.substring(this.#fromOffset, this.#toOffset), this.#tokenCallback.bind(this));
@@ -42,9 +42,18 @@ export class CSSFormatter {
42
42
  }
43
43
 
44
44
  #tokenCallback(token: string, type: string|null, startPosition: number): void {
45
+ // startPosition is relative to the start of the CSS block.
46
+ // Convert it to an absolute document offset to match this.#lineEndings.
45
47
  startPosition += this.#fromOffset;
46
- const startLine = Platform.ArrayUtilities.lowerBound(
47
- this.#lineEndings, startPosition, Platform.ArrayUtilities.DEFAULT_COMPARATOR);
48
+
49
+ // Find the line index containing startPosition.
50
+ // Since CodeMirror processes tokens sequentially in increasing order of their offset,
51
+ // we can perform an amortized O(1) linear scan forward by tracking the current index.
52
+ while (this.#currentLineIndex < this.#lineEndings.length &&
53
+ this.#lineEndings[this.#currentLineIndex] < startPosition) {
54
+ this.#currentLineIndex++;
55
+ }
56
+ const startLine = this.#currentLineIndex;
48
57
  if (startLine !== this.#lastLine) {
49
58
  this.#state.eatWhitespace = true;
50
59
  }
@@ -25,9 +25,23 @@ export interface Chunk {
25
25
 
26
26
  export type ChunkCallback = (arg0: Chunk) => void;
27
27
 
28
- export function createTokenizer(mimeType: string): (
29
- arg0: string, arg1: (arg0: string, arg1: string|null, arg2: number, arg3: number) => (Object | undefined | void)) =>
30
- void {
28
+ export type TokenizerCallback = (value: string, style: string|null, start: number, end: number) =>
29
+ Object|undefined|void;
30
+
31
+ /**
32
+ * A tokenizer function returned by {@link createTokenizer}.
33
+ *
34
+ * @param line The string content to tokenize.
35
+ * @param callback A callback function invoked for each token parsed.
36
+ * @param startOffset An optional offset pointing to where tokenization should start within
37
+ * the line, avoiding the need to allocate substrings when tokenizing a block inside a larger file.
38
+ */
39
+ export type Tokenizer = (line: string, callback: TokenizerCallback, startOffset?: number) => void;
40
+
41
+ /**
42
+ * Creates a tokenizer for the specified MIME type.
43
+ */
44
+ export function createTokenizer(mimeType: string): Tokenizer {
31
45
  const mode = CodeMirror.getMode({indentUnit: 2}, mimeType);
32
46
  const state = CodeMirror.startState(mode);
33
47
 
@@ -40,8 +54,13 @@ export function createTokenizer(mimeType: string): (
40
54
  }
41
55
 
42
56
  return (line: string,
43
- callback: (arg0: string, arg1: string|null, arg2: number, arg3: number) => void|Object|undefined) => {
57
+ callback: (arg0: string, arg1: string|null, arg2: number, arg3: number) => void|Object|undefined,
58
+ startOffset = 0) => {
44
59
  const stream = new CodeMirror.StringStream(line);
60
+ if (startOffset) {
61
+ stream.pos = startOffset;
62
+ stream.start = startOffset;
63
+ }
45
64
  while (!stream.eol()) {
46
65
  const style = mode.token(stream, state);
47
66
  const value = stream.current();
@@ -252,7 +252,7 @@ export class HTMLModel {
252
252
 
253
253
  #build(text: string): void {
254
254
  const tokenizer = createTokenizer('text/html');
255
- let baseOffset = 0, lastOffset = 0;
255
+ let lastOffset = 0;
256
256
  let pendingToken: Token|null = null;
257
257
 
258
258
  const pushToken = (token: Token): Object|undefined => {
@@ -274,8 +274,6 @@ export class HTMLModel {
274
274
  tokenStart: number,
275
275
  tokenEnd: number,
276
276
  ): Object|undefined => {
277
- tokenStart += baseOffset;
278
- tokenEnd += baseOffset;
279
277
  lastOffset = tokenEnd;
280
278
 
281
279
  const tokenType = type ? new Set<string>(type.split(' ')) : new Set<string>();
@@ -321,8 +319,7 @@ export class HTMLModel {
321
319
  };
322
320
 
323
321
  while (true) {
324
- baseOffset = lastOffset;
325
- tokenizer(text.substring(lastOffset), processToken);
322
+ tokenizer(text, processToken, lastOffset);
326
323
  if (pendingToken) {
327
324
  pushToken(pendingToken);
328
325
  pendingToken = null;
@@ -341,7 +338,11 @@ export class HTMLModel {
341
338
  lastOffset = text.length;
342
339
  break;
343
340
  }
344
- if (text.substring(lastOffset + 2).toLowerCase().startsWith(element.name)) {
341
+ // Check if the tag at lastOffset matches the current element name (e.g. </script>).
342
+ // Slice only the length of the tag name to avoid allocating a large substring
343
+ // of the remainder of the document.
344
+ const sliced = text.slice(lastOffset + 2, lastOffset + 2 + element.name.length);
345
+ if (sliced.toLowerCase() === element.name) {
345
346
  break;
346
347
  }
347
348
  lastOffset += 2;
@@ -47,7 +47,6 @@ import * as Badges from '../../models/badges/badges.js';
47
47
  import * as Bindings from '../../models/bindings/bindings.js';
48
48
  import * as CrUXManager from '../../models/crux-manager/crux-manager.js';
49
49
  import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
50
- import * as LiveMetrics from '../../models/live-metrics/live-metrics.js';
51
50
  import * as Persistence from '../../models/persistence/persistence.js';
52
51
  import * as Workspace from '../../models/workspace/workspace.js';
53
52
  import * as PanelCommon from '../../panels/common/common.js';
@@ -158,9 +157,11 @@ export class MainImpl {
158
157
  #readyForTestPromise = Promise.withResolvers<void>();
159
158
  #veStartPromise!: Promise<void>;
160
159
  #universe!: Foundation.Universe.Universe;
160
+ #supportsEmulation = false;
161
161
 
162
- constructor() {
162
+ constructor(opts?: {supportsEmulation: boolean}) {
163
163
  MainImpl.instanceForTest = this;
164
+ this.#supportsEmulation = opts?.supportsEmulation ?? false;
164
165
  void this.#loaded();
165
166
  }
166
167
 
@@ -209,6 +210,7 @@ export class MainImpl {
209
210
  },
210
211
  hostConfig: Root.Runtime.hostConfig,
211
212
  inspectorFrontendHost: Host.InspectorFrontendHost.InspectorFrontendHostInstance,
213
+ supportsEmulation: this.#supportsEmulation,
212
214
  };
213
215
  this.#universe = new Foundation.Universe.Universe(creationOptions);
214
216
  Root.DevToolsContext.setGlobalInstance(this.#universe.context as Root.DevToolsContext.WritableDevToolsContext);
@@ -469,15 +471,12 @@ export class MainImpl {
469
471
  isolatedFileSystemManager.addPlatformFileSystem(
470
472
  'snippet://' as Platform.DevToolsPath.UrlString, new Snippets.ScriptSnippetFileSystem.SnippetFileSystem());
471
473
 
472
- const persistenceImpl = Persistence.Persistence.PersistenceImpl.instance();
473
- const linkDecorator = new PanelCommon.PersistenceUtils.LinkDecorator(persistenceImpl);
474
+ const linkDecorator = new PanelCommon.PersistenceUtils.LinkDecorator(this.#universe.persistence);
474
475
  Components.Linkifier.Linkifier.setLinkDecorator(linkDecorator);
475
- Persistence.NetworkPersistenceManager.NetworkPersistenceManager.instance(
476
- {forceNew: true, workspace: Workspace.Workspace.WorkspaceImpl.instance()});
477
476
 
478
477
  new ExecutionContextSelector(targetManager, UI.Context.Context.instance());
479
478
 
480
- void LiveMetrics.LiveMetrics.instance().enable();
479
+ void this.#universe.liveMetrics.enable();
481
480
  CrUXManager.CrUXManager.instance();
482
481
 
483
482
  const builtInAi = AiAssistanceModel.BuiltInAi.BuiltInAi.instance();
@@ -761,8 +760,6 @@ export class SearchActionDelegate implements UI.ActionRegistration.ActionDelegat
761
760
  return false;
762
761
  }
763
762
  }
764
- let mainMenuItemInstance: MainMenuItem;
765
-
766
763
  export class MainMenuItem implements UI.Toolbar.Provider {
767
764
  readonly #item: UI.Toolbar.ToolbarMenuButton;
768
765
  constructor() {
@@ -773,17 +770,6 @@ export class MainMenuItem implements UI.Toolbar.Provider {
773
770
  this.#item.setTitle(i18nString(UIStrings.customizeAndControlDevtools));
774
771
  }
775
772
 
776
- static instance(opts: {
777
- forceNew: boolean|null,
778
- } = {forceNew: null}): MainMenuItem {
779
- const {forceNew} = opts;
780
- if (!mainMenuItemInstance || forceNew) {
781
- mainMenuItemInstance = new MainMenuItem();
782
- }
783
-
784
- return mainMenuItemInstance;
785
- }
786
-
787
773
  item(): UI.Toolbar.ToolbarItem|null {
788
774
  return this.#item;
789
775
  }
@@ -945,25 +931,12 @@ export class MainMenuItem implements UI.Toolbar.Provider {
945
931
  }
946
932
  }
947
933
 
948
- let settingsButtonProviderInstance: SettingsButtonProvider;
949
-
950
934
  export class SettingsButtonProvider implements UI.Toolbar.Provider {
951
935
  readonly #settingsButton: UI.Toolbar.ToolbarButton;
952
- private constructor() {
936
+ constructor() {
953
937
  this.#settingsButton = UI.Toolbar.Toolbar.createActionButton('settings.show');
954
938
  }
955
939
 
956
- static instance(opts: {
957
- forceNew: boolean|null,
958
- } = {forceNew: null}): SettingsButtonProvider {
959
- const {forceNew} = opts;
960
- if (!settingsButtonProviderInstance || forceNew) {
961
- settingsButtonProviderInstance = new SettingsButtonProvider();
962
- }
963
-
964
- return settingsButtonProviderInstance;
965
- }
966
-
967
940
  item(): UI.Toolbar.ToolbarItem|null {
968
941
  return this.#settingsButton;
969
942
  }
@@ -911,29 +911,29 @@ UI.Toolbar.registerToolbarItem({
911
911
  const isPolicyRestricted = config?.aidaAvailability?.blockedByEnterprisePolicy === true;
912
912
  return Boolean(isFlagEnabled && !isGeoRestricted && !isPolicyRestricted);
913
913
  },
914
- async loadItem() {
914
+ loadItem: Common.Lazy.lazy(async () => {
915
915
  const Main = await loadMainModule();
916
916
  return new Main.GlobalAiButton.GlobalAiButtonToolbarProvider();
917
- },
917
+ }) as () => Promise<UI.Toolbar.Provider>,
918
918
  order: 98,
919
919
  location: UI.Toolbar.ToolbarItemLocation.MAIN_TOOLBAR_RIGHT,
920
920
  });
921
921
 
922
922
  UI.Toolbar.registerToolbarItem({
923
- async loadItem() {
923
+ loadItem: Common.Lazy.lazy(async () => {
924
924
  const Main = await loadMainModule();
925
- return Main.MainImpl.SettingsButtonProvider.instance();
926
- },
925
+ return new Main.MainImpl.SettingsButtonProvider();
926
+ }) as () => Promise<UI.Toolbar.Provider>,
927
927
  order: 99,
928
928
  location: UI.Toolbar.ToolbarItemLocation.MAIN_TOOLBAR_RIGHT,
929
929
  });
930
930
 
931
931
  UI.Toolbar.registerToolbarItem({
932
932
  condition: () => !Root.Runtime.Runtime.isTraceApp(),
933
- async loadItem() {
933
+ loadItem: Common.Lazy.lazy(async () => {
934
934
  const Main = await loadMainModule();
935
- return Main.MainImpl.MainMenuItem.instance();
936
- },
935
+ return new Main.MainImpl.MainMenuItem();
936
+ }) as () => Promise<UI.Toolbar.Provider>,
937
937
  order: 100,
938
938
  location: UI.Toolbar.ToolbarItemLocation.MAIN_TOOLBAR_RIGHT,
939
939
  });
@@ -15,25 +15,25 @@ import nodeConnectionsPanelStyles from './nodeConnectionsPanel.css.js';
15
15
 
16
16
  const UIStrings = {
17
17
  /**
18
- * @description Text in Node Connections Panel of the Sources panel when debugging a Node.js app
18
+ * @description Text in Node connections panel of the Sources panel when debugging a Node.js app.
19
19
  */
20
20
  nodejsDebuggingGuide: 'Node.js debugging guide',
21
21
  /**
22
- * @description Text in Node Connections Panel of the Sources panel when debugging a Node.js app
22
+ * @description Text in Node connections panel of the Sources panel when debugging a Node.js app.
23
23
  * @example {Node.js debugging guide} PH1
24
24
  */
25
25
  specifyNetworkEndpointAnd:
26
26
  'Specify network endpoint and DevTools will connect to it automatically. Read {PH1} to learn more.',
27
27
  /**
28
- * @description Placeholder text content in Node Connections Panel of the Sources panel when debugging a Node.js app
28
+ * @description Placeholder text content in Node connections panel of the Sources panel when debugging a Node.js app.
29
29
  */
30
30
  noConnectionsSpecified: 'No connections specified',
31
31
  /**
32
- * @description Text of add network target button in Node Connections Panel of the Sources panel when debugging a Node.js app
32
+ * @description Text of add network target button in Node connections panel of the Sources panel when debugging a Node.js app.
33
33
  */
34
34
  addConnection: 'Add connection',
35
35
  /**
36
- * @description Text in Node Connections Panel of the Sources panel when debugging a Node.js app
36
+ * @description Text in Node connections panel of the Sources panel when debugging a Node.js app.
37
37
  */
38
38
  networkAddressEgLocalhost: 'Network address (e.g. localhost:9229)',
39
39
  } as const;
@@ -14,16 +14,16 @@ import * as Components from '../../../ui/legacy/components/utils/utils.js';
14
14
 
15
15
  const UIStrings = {
16
16
  /**
17
- * @description Text that refers to the main target
17
+ * @description Text that refers to the main target.
18
18
  */
19
19
  main: 'Main',
20
20
  /**
21
- * @description Text in Node Main of the Sources panel when debugging a Node.js app
21
+ * @description Text in Node main of the Sources panel when debugging a Node.js app.
22
22
  * @example {example.com} PH1
23
23
  */
24
24
  nodejsS: 'Node.js: {PH1}',
25
25
  /**
26
- * @description Text in DevTools window title when debugging a Node.js app
26
+ * @description Text in DevTools window title when debugging a Node.js app.
27
27
  * @example {example.com} PH1
28
28
  */
29
29
  NodejsTitleS: 'DevTools - Node.js: {PH1}',
@@ -21,31 +21,31 @@ const {NodeMainImpl} = App.NodeMain;
21
21
 
22
22
  const UIStrings = {
23
23
  /**
24
- * @description Text that refers to the network connection
24
+ * @description Text that refers to the network connection.
25
25
  */
26
26
  connection: 'Connection',
27
27
  /**
28
- * @description A tag of Node.js Connection Panel that can be searched in the command menu
28
+ * @description A tag of Node.js connection panel that can be searched in the command menu.
29
29
  */
30
30
  node: 'node',
31
31
  /**
32
- * @description Command for showing the Connection tool
32
+ * @description Command for showing the Connection tool.
33
33
  */
34
34
  showConnection: 'Show Connection',
35
35
  /**
36
- * @description Title of the 'Node' tool in the Network Navigator View, which is part of the Sources tool
36
+ * @description Title of the 'Node' tool in the Network navigator view, which is part of the Sources tool.
37
37
  */
38
38
  networkTitle: 'Node',
39
39
  /**
40
- * @description Command for showing the 'Node' tool in the Network Navigator View, which is part of the Sources tool
40
+ * @description Command for showing the 'Node' tool in the Network navigator view, which is part of the Sources tool.
41
41
  */
42
42
  showNode: 'Show Node',
43
43
  /**
44
- * @description Text in Application Panel Sidebar of the Application panel
44
+ * @description Text in Application panel sidebar of the Application panel.
45
45
  */
46
46
  application: 'Application',
47
47
  /**
48
- * @description Command for showing the 'Application' tool
48
+ * @description Command for showing the Application tool.
49
49
  */
50
50
  showApplication: 'Show Application',
51
51
  } as const;
@@ -12,16 +12,19 @@ import * as Breakpoints from '../models/breakpoints/breakpoints.js';
12
12
  import * as CrUXManager from '../models/crux-manager/crux-manager.js';
13
13
  import * as Emulation from '../models/emulation/emulation.js';
14
14
  import * as JavaScriptMetadata from '../models/javascript_metadata/javascript_metadata.js';
15
+ import * as LiveMetrics from '../models/live-metrics/live-metrics.js';
15
16
  import * as Logs from '../models/logs/logs.js';
16
17
  import * as Persistence from '../models/persistence/persistence.js';
17
18
  import * as ProjectSettings from '../models/project_settings/project_settings.js';
18
19
  import * as Workspace from '../models/workspace/workspace.js';
20
+ import * as WorkspaceDiff from '../models/workspace_diff/workspace_diff.js';
19
21
 
20
22
  export interface CreationOptions {
21
23
  settingsCreationOptions: Omit<Common.Settings.SettingsCreationOptions, 'console'>;
22
24
  overrideAutoStartModels?: Set<SDK.SDKModel.SDKModelConstructor>;
23
25
  hostConfig: Root.Runtime.HostConfig;
24
26
  inspectorFrontendHost: Host.InspectorFrontendHostAPI.InspectorFrontendHostAPI;
27
+ supportsEmulation: boolean;
25
28
  }
26
29
 
27
30
  export class Universe {
@@ -30,6 +33,7 @@ export class Universe {
30
33
  // directly on the `Universe`.
31
34
  readonly context: Root.DevToolsContext.DevToolsContext;
32
35
  readonly autofillManager: AutofillManager.AutofillManager.AutofillManager;
36
+ readonly supportsEmulation: boolean;
33
37
 
34
38
  constructor(options: CreationOptions) {
35
39
  const context = new Root.DevToolsContext.WritableDevToolsContext();
@@ -61,9 +65,13 @@ export class Universe {
61
65
  const multitargetNetworkManager = new SDK.NetworkManager.MultitargetNetworkManager(targetManager);
62
66
  context.set(SDK.NetworkManager.MultitargetNetworkManager, multitargetNetworkManager);
63
67
 
64
- const deviceModeModel =
65
- new Emulation.DeviceModeModel.DeviceModeModel(targetManager, settings, multitargetNetworkManager);
66
- context.set(Emulation.DeviceModeModel.DeviceModeModel, deviceModeModel);
68
+ this.supportsEmulation = options.supportsEmulation;
69
+ let deviceModeModel = null;
70
+ if (options.supportsEmulation) {
71
+ deviceModeModel =
72
+ new Emulation.DeviceModeModel.DeviceModeModel(targetManager, settings, multitargetNetworkManager);
73
+ context.set(Emulation.DeviceModeModel.DeviceModeModel, deviceModeModel);
74
+ }
67
75
 
68
76
  const pageResourceLoader =
69
77
  new SDK.PageResourceLoader.PageResourceLoader(targetManager, settings, multitargetNetworkManager, null);
@@ -140,6 +148,13 @@ export class Universe {
140
148
  );
141
149
  context.set(Persistence.NetworkPersistenceManager.NetworkPersistenceManager, networkPersistenceManager);
142
150
 
151
+ const workspaceDiff = new WorkspaceDiff.WorkspaceDiff.WorkspaceDiffImpl(
152
+ workspace,
153
+ persistence,
154
+ networkPersistenceManager,
155
+ );
156
+ context.set(WorkspaceDiff.WorkspaceDiff.WorkspaceDiffImpl, workspaceDiff);
157
+
143
158
  const networkLog = new Logs.NetworkLog.NetworkLog(targetManager, settings);
144
159
  context.set(Logs.NetworkLog.NetworkLog, networkLog);
145
160
 
@@ -149,6 +164,9 @@ export class Universe {
149
164
  const javaScriptMetadata = new JavaScriptMetadata.JavaScriptMetadata.JavaScriptMetadataImpl();
150
165
  context.set(JavaScriptMetadata.JavaScriptMetadata.JavaScriptMetadataImpl, javaScriptMetadata);
151
166
 
167
+ const liveMetrics = new LiveMetrics.LiveMetrics(targetManager, deviceModeModel);
168
+ context.set(LiveMetrics.LiveMetrics, liveMetrics);
169
+
152
170
  this.autofillManager = new AutofillManager.AutofillManager.AutofillManager(targetManager, frameManager);
153
171
  }
154
172
 
@@ -172,8 +190,9 @@ export class Universe {
172
190
  return this.context.get(CrUXManager.CrUXManager);
173
191
  }
174
192
 
175
- get deviceModeModel(): Emulation.DeviceModeModel.DeviceModeModel {
176
- return this.context.get(Emulation.DeviceModeModel.DeviceModeModel);
193
+ // The DeviceModeModel may not be present, as emulation is only present for the `devtools_app` entrypoint, but not for the others.
194
+ get deviceModeModel(): Emulation.DeviceModeModel.DeviceModeModel|null {
195
+ return this.supportsEmulation ? this.context.get(Emulation.DeviceModeModel.DeviceModeModel) : null;
177
196
  }
178
197
 
179
198
  get domDebuggerManager(): SDK.DOMDebuggerModel.DOMDebuggerManager {
@@ -200,6 +219,10 @@ export class Universe {
200
219
  return this.context.get(Persistence.NetworkPersistenceManager.NetworkPersistenceManager);
201
220
  }
202
221
 
222
+ get liveMetrics(): LiveMetrics.LiveMetrics {
223
+ return this.context.get(LiveMetrics.LiveMetrics);
224
+ }
225
+
203
226
  get pageResourceLoader(): SDK.PageResourceLoader.PageResourceLoader {
204
227
  return this.context.get(SDK.PageResourceLoader.PageResourceLoader);
205
228
  }
@@ -223,4 +246,8 @@ export class Universe {
223
246
  get workspace(): Workspace.Workspace.WorkspaceImpl {
224
247
  return this.context.get(Workspace.Workspace.WorkspaceImpl);
225
248
  }
249
+
250
+ get workspaceDiff(): WorkspaceDiff.WorkspaceDiff.WorkspaceDiffImpl {
251
+ return this.context.get(WorkspaceDiff.WorkspaceDiff.WorkspaceDiffImpl);
252
+ }
226
253
  }
@@ -511,7 +511,7 @@ inspectorBackend.registerCommand("DeviceOrientation.setDeviceOrientationOverride
511
511
 
512
512
  // DigitalCredentials.
513
513
  inspectorBackend.registerEnum("DigitalCredentials.VirtualWalletAction", {Respond: "respond", Decline: "decline", Wait: "wait", Clear: "clear"});
514
- inspectorBackend.registerCommand("DigitalCredentials.setVirtualWalletBehavior", [{"name": "action", "type": "string", "optional": false, "description": "The action of the virtual wallet.", "typeRef": "DigitalCredentials.VirtualWalletAction"}, {"name": "protocol", "type": "string", "optional": true, "description": "The protocol identifier (e.g. \\\"openid4vp\\\"). Required when |action| is \\\"respond\\\", forbidden otherwise.", "typeRef": null}, {"name": "response", "type": "object", "optional": true, "description": "The response data object returned by the wallet. Required when |action| is \\\"respond\\\", forbidden otherwise.", "typeRef": null}], [], "Sets the behavior of the virtual wallet for digital credential requests issued from this frame.");
514
+ inspectorBackend.registerCommand("DigitalCredentials.setVirtualWalletBehavior", [{"name": "action", "type": "string", "optional": false, "description": "The action of the virtual wallet.", "typeRef": "DigitalCredentials.VirtualWalletAction"}, {"name": "protocol", "type": "string", "optional": true, "description": "The protocol identifier (e.g. \\\"openid4vp\\\"). Required when |action| is \\\"respond\\\", forbidden otherwise.", "typeRef": null}, {"name": "response", "type": "object", "optional": true, "description": "The response data object returned by the wallet. Required when |action| is \\\"respond\\\", forbidden otherwise.", "typeRef": null}, {"name": "frameId", "type": "string", "optional": true, "description": "The frame to scope the virtual wallet behavior to.", "typeRef": "Page.FrameId"}], [], "Sets the behavior of the virtual wallet for digital credential requests issued from this frame.");
515
515
 
516
516
  // Emulation.
517
517
  inspectorBackend.registerEnum("Emulation.ScreenOrientationType", {PortraitPrimary: "portraitPrimary", PortraitSecondary: "portraitSecondary", LandscapePrimary: "landscapePrimary", LandscapeSecondary: "landscapeSecondary"});
@@ -7040,6 +7040,10 @@ export namespace DigitalCredentials {
7040
7040
  * Required when |action| is "respond", forbidden otherwise.
7041
7041
  */
7042
7042
  response?: any;
7043
+ /**
7044
+ * The frame to scope the virtual wallet behavior to.
7045
+ */
7046
+ frameId?: Page.FrameId;
7043
7047
  }
7044
7048
  }
7045
7049
 
@@ -12,21 +12,21 @@ import {debugLog} from './debug.js';
12
12
 
13
13
  const UIStrings = {
14
14
  /**
15
- * @description Message shown to the user if the age check is not successful.
15
+ * @description Message shown to the user if the age check isn’t successful.
16
16
  */
17
- ageRestricted: 'This feature is only available to users who are 18 years of age or older.',
17
+ ageRestricted: 'This feature is only available to users 18 years or older.',
18
18
  /**
19
- * @description The error message when the user is not logged in into Chrome.
19
+ * @description The error message when the user isn’t logged in to Chrome.
20
20
  */
21
- notLoggedIn: 'This feature is only available when you sign into Chrome with your Google account.',
21
+ notLoggedIn: 'This feature is only available when you sign in to Chrome with your Google account.',
22
22
  /**
23
23
  * @description Message shown when the user is offline.
24
24
  */
25
25
  offline: 'This feature is only available with an active internet connection.',
26
26
  /**
27
- * @description Text informing the user that AI assistance is not available in Incognito mode or Guest mode.
27
+ * @description Text informing the user that AI assistance isn’t available in Incognito mode or Guest mode.
28
28
  */
29
- notAvailableInIncognitoMode: 'AI assistance is not available in Incognito mode or Guest mode.',
29
+ notAvailableInIncognitoMode: 'AI assistance isn’t available in Incognito mode or Guest mode.',
30
30
  } as const;
31
31
  const str_ = i18n.i18n.registerUIStrings('models/ai_assistance/AiUtils.ts', UIStrings);
32
32
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -152,6 +152,7 @@ export interface SourceMapping {
152
152
 
153
153
  export class ModelInfo {
154
154
  readonly #eventListeners: Common.EventTarget.EventDescriptor[];
155
+ readonly #cssWorkspaceBinding: CSSWorkspaceBinding;
155
156
  readonly #resourceMapping: ResourceMapping;
156
157
  #stylesSourceMapping: StylesSourceMapping;
157
158
  #sassSourceMapping: SASSSourceMapping;
@@ -159,6 +160,7 @@ export class ModelInfo {
159
160
  readonly #unboundLocations: Platform.MapUtilities.Multimap<Platform.DevToolsPath.UrlString, LiveLocation>;
160
161
  constructor(
161
162
  cssModel: SDK.CSSModel.CSSModel, resourceMapping: ResourceMapping, cssWorkspaceBinding: CSSWorkspaceBinding) {
163
+ this.#cssWorkspaceBinding = cssWorkspaceBinding;
162
164
  this.#eventListeners = [
163
165
  cssModel.addEventListener(
164
166
  SDK.CSSModel.Events.StyleSheetAdded,
@@ -191,7 +193,7 @@ export class ModelInfo {
191
193
  async createLiveLocation(
192
194
  rawLocation: SDK.CSSModel.CSSLocation, updateDelegate: (arg0: LiveLocationInterface) => Promise<void>,
193
195
  locationPool: LiveLocationPool): Promise<LiveLocation> {
194
- const location = new LiveLocation(rawLocation, this, updateDelegate, locationPool);
196
+ const location = new LiveLocation(rawLocation, this, this.#cssWorkspaceBinding, updateDelegate, locationPool);
195
197
  const header = rawLocation.header();
196
198
  if (header) {
197
199
  location.setHeader(header);
@@ -286,15 +288,16 @@ export class LiveLocation extends LiveLocationWithPool {
286
288
  readonly #lineNumber: number;
287
289
  readonly #columnNumber: number;
288
290
  readonly #info: ModelInfo;
291
+ readonly #cssWorkspaceBinding: CSSWorkspaceBinding;
289
292
  #header: SDK.CSSStyleSheetHeader.CSSStyleSheetHeader|null;
290
- constructor(
291
- rawLocation: SDK.CSSModel.CSSLocation, info: ModelInfo,
292
- updateDelegate: (arg0: LiveLocationInterface) => Promise<void>, locationPool: LiveLocationPool) {
293
+ constructor(rawLocation: SDK.CSSModel.CSSLocation, info: ModelInfo, cssWorkspaceBinding: CSSWorkspaceBinding,
294
+ updateDelegate: (arg0: LiveLocationInterface) => Promise<void>, locationPool: LiveLocationPool) {
293
295
  super(updateDelegate, locationPool);
294
296
  this.url = rawLocation.url;
295
297
  this.#lineNumber = rawLocation.lineNumber;
296
298
  this.#columnNumber = rawLocation.columnNumber;
297
299
  this.#info = info;
300
+ this.#cssWorkspaceBinding = cssWorkspaceBinding;
298
301
  this.#header = null;
299
302
  }
300
303
 
@@ -311,7 +314,7 @@ export class LiveLocation extends LiveLocationWithPool {
311
314
  return null;
312
315
  }
313
316
  const rawLocation = new SDK.CSSModel.CSSLocation(this.#header, this.#lineNumber, this.#columnNumber);
314
- return CSSWorkspaceBinding.instance().rawLocationToUILocation(rawLocation);
317
+ return this.#cssWorkspaceBinding.rawLocationToUILocation(rawLocation);
315
318
  }
316
319
 
317
320
  override dispose(): void {