chrome-devtools-frontend 1.0.1661063 → 1.0.1662965

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 (131) hide show
  1. package/.agents/skills/devtools-unicode-escaping/SKILL.md +64 -0
  2. package/.agents/skills/evaluate-ai-css-completion/SKILL.md +19 -9
  3. package/.agents/skills/evaluate-ai-css-completion/scripts/evaluate.js +44 -16
  4. package/.agents/skills/migrate-chromium-test/SKILL.md +32 -2
  5. package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +7 -1
  6. package/docs/ui_engineering.md +75 -42
  7. package/front_end/core/common/SettingRegistration.ts +0 -10
  8. package/front_end/core/common/Settings.ts +69 -3
  9. package/front_end/core/platform/ArrayUtilities.ts +10 -0
  10. package/front_end/core/platform/StringUtilities.ts +38 -6
  11. package/front_end/core/sdk/ServiceWorkerCacheModel.ts +0 -10
  12. package/front_end/core/sdk/StorageBucketsModel.ts +0 -10
  13. package/front_end/core/sdk/sdk-meta.ts +0 -1
  14. package/front_end/entrypoints/inspector_main/OutermostTargetSelector.ts +0 -13
  15. package/front_end/entrypoints/inspector_main/RenderingOptions.ts +8 -3
  16. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +3 -3
  17. package/front_end/entrypoints/main/MainImpl.ts +7 -2
  18. package/front_end/foundation/README.md +86 -0
  19. package/front_end/foundation/Universe.ts +16 -0
  20. package/front_end/generated/InspectorBackendCommands.ts +6 -19
  21. package/front_end/generated/protocol-mapping.d.ts +0 -53
  22. package/front_end/generated/protocol-proxy-api.d.ts +0 -46
  23. package/front_end/generated/protocol.ts +20 -186
  24. package/front_end/models/ai_assistance/AiAgent2.ts +3 -3
  25. package/front_end/models/ai_assistance/AiConversation.ts +21 -10
  26. package/front_end/models/ai_assistance/AiHistoryStorage.ts +21 -10
  27. package/front_end/models/ai_assistance/ChangeManager.ts +2 -2
  28. package/front_end/models/ai_assistance/ExtensionScope.ts +6 -2
  29. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +1 -1
  30. package/front_end/models/ai_assistance/agents/AiAgent.ts +8 -1
  31. package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
  32. package/front_end/models/badges/UserBadges.ts +31 -17
  33. package/front_end/models/bindings/CompilerScriptMapping.ts +5 -4
  34. package/front_end/models/bindings/ContentProviderBasedProject.ts +2 -3
  35. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +4 -3
  36. package/front_end/models/bindings/DefaultScriptMapping.ts +3 -3
  37. package/front_end/models/bindings/NetworkProject.ts +22 -1
  38. package/front_end/models/bindings/ResourceMapping.ts +4 -3
  39. package/front_end/models/bindings/ResourceScriptMapping.ts +2 -1
  40. package/front_end/models/bindings/SASSSourceMapping.ts +4 -3
  41. package/front_end/models/bindings/StylesSourceMapping.ts +3 -3
  42. package/front_end/models/emulation/DeviceModeModel.ts +67 -5
  43. package/front_end/models/extensions/RecorderExtensionEndpoint.ts +7 -5
  44. package/front_end/models/extensions/RecorderPluginManager.ts +10 -6
  45. package/front_end/models/har/Log.snapshot.txt +193 -0
  46. package/front_end/models/har/Log.ts +3 -2
  47. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +14 -5
  48. package/front_end/models/issues_manager/CheckFormsIssuesTrigger.ts +8 -9
  49. package/front_end/models/issues_manager/RelatedIssue.ts +10 -8
  50. package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
  51. package/front_end/models/logs/RequestResolver.ts +2 -2
  52. package/front_end/models/persistence/AutomaticFileSystemWorkspaceBinding.ts +0 -5
  53. package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +8 -6
  54. package/front_end/models/source_map_scopes/NamesResolver.ts +36 -30
  55. package/front_end/models/stack_trace/StackTrace.ts +17 -0
  56. package/front_end/models/trace/handlers/FramesHandler.ts +4 -7
  57. package/front_end/models/trace/handlers/ModelHandlers.ts +0 -1
  58. package/front_end/models/trace/handlers/RendererHandler.ts +2 -15
  59. package/front_end/models/trace/handlers/Threads.ts +4 -11
  60. package/front_end/models/trace/insights/DOMSize.ts +1 -1
  61. package/front_end/models/workspace/WorkspaceImpl.ts +1 -10
  62. package/front_end/panels/application/ApplicationPanelSidebar.ts +0 -44
  63. package/front_end/panels/application/CookieItemsView.ts +1 -1
  64. package/front_end/panels/application/FrameDetailsView.ts +1 -1
  65. package/front_end/panels/application/IndexedDBModel.ts +0 -10
  66. package/front_end/panels/application/IndexedDBViews.ts +240 -164
  67. package/front_end/panels/application/ServiceWorkersView.ts +494 -411
  68. package/front_end/panels/application/SharedStorageModel.ts +0 -10
  69. package/front_end/panels/application/application.ts +0 -6
  70. package/front_end/panels/application/components/AdsView.ts +23 -0
  71. package/front_end/panels/application/components/SharedStorageAccessGrid.ts +1 -1
  72. package/front_end/panels/application/components/adsView.css +21 -1
  73. package/front_end/panels/application/components/components.ts +0 -2
  74. package/front_end/panels/application/indexedDBViews.css +1 -1
  75. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +1 -1
  76. package/front_end/panels/application/serviceWorkersView.css +40 -4
  77. package/front_end/panels/browser_debugger/XHRBreakpointsSidebarPane.ts +147 -123
  78. package/front_end/panels/common/ExtensionServer.ts +3 -3
  79. package/front_end/panels/console/ConsoleView.ts +1 -1
  80. package/front_end/panels/emulation/DeviceModeView.ts +139 -70
  81. package/front_end/panels/issues/AffectedResourcesView.ts +1 -1
  82. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +53 -12
  83. package/front_end/panels/network/NetworkDataGridNode.ts +43 -1
  84. package/front_end/panels/network/RequestInitiatorView.ts +24 -2
  85. package/front_end/panels/network/RequestPayloadView.ts +77 -39
  86. package/front_end/panels/network/components/ResponseHeaderSection.ts +5 -3
  87. package/front_end/panels/network/networkLogView.css +5 -0
  88. package/front_end/panels/network/requestInitiatorViewTree.css +5 -0
  89. package/front_end/panels/profiler/HeapProfileView.ts +198 -79
  90. package/front_end/panels/profiler/HeapSnapshotView.ts +2 -2
  91. package/front_end/panels/recorder/README.md +1 -2
  92. package/front_end/panels/recorder/RecorderPanel.ts +1749 -17
  93. package/front_end/panels/recorder/recorder.ts +0 -2
  94. package/front_end/panels/settings/AISettingsTab.ts +13 -0
  95. package/front_end/panels/sources/SourcesNavigator.ts +3 -2
  96. package/front_end/panels/sources/SourcesView.ts +0 -17
  97. package/front_end/panels/sources/UISourceCodeFrame.ts +42 -0
  98. package/front_end/panels/sources/sources.ts +0 -2
  99. package/front_end/panels/timeline/CompatibilityTracksAppender.ts +0 -17
  100. package/front_end/panels/timeline/ThreadAppender.ts +0 -106
  101. package/front_end/third_party/chromium/README.chromium +1 -1
  102. package/front_end/ui/components/report_view/ReportView.ts +11 -5
  103. package/front_end/ui/components/report_view/report.css +4 -1
  104. package/front_end/ui/components/spinners/Spinner.ts +29 -32
  105. package/front_end/ui/components/spinners/spinner.css +32 -84
  106. package/front_end/ui/legacy/TextPrompt.ts +49 -1
  107. package/front_end/ui/legacy/Treeoutline.ts +14 -6
  108. package/front_end/ui/legacy/UIUtils.ts +36 -11
  109. package/front_end/ui/legacy/Widget.ts +17 -10
  110. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +2 -2
  111. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +36 -7
  112. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +63 -68
  113. package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +1 -1
  114. package/front_end/ui/legacy/components/object_ui/objectValue.css +2 -1
  115. package/front_end/ui/legacy/inspectorCommon.css +4 -4
  116. package/front_end/ui/legacy/textPrompt.css +10 -0
  117. package/front_end/ui/lit/lit.ts +1 -0
  118. package/front_end/ui/lit/render.ts +44 -10
  119. package/front_end/ui/lit/strip-whitespace.ts +23 -2
  120. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  121. package/package.json +1 -1
  122. package/front_end/models/trace/handlers/AuctionWorkletsHandler.ts +0 -183
  123. package/front_end/panels/application/InterestGroupStorageModel.ts +0 -81
  124. package/front_end/panels/application/InterestGroupStorageView.ts +0 -151
  125. package/front_end/panels/application/InterestGroupTreeElement.ts +0 -65
  126. package/front_end/panels/application/components/InterestGroupAccessGrid.ts +0 -135
  127. package/front_end/panels/application/components/interestGroupAccessGrid.css +0 -27
  128. package/front_end/panels/application/interestGroupStorageView.css +0 -9
  129. package/front_end/panels/recorder/RecorderController.ts +0 -1595
  130. package/front_end/panels/sources/InplaceFormatterEditorAction.ts +0 -149
  131. /package/front_end/panels/recorder/{recorderController.css → recorderPanel.css} +0 -0
@@ -23,6 +23,75 @@ import {
23
23
  } from './SettingRegistration.js';
24
24
  import {VersionController} from './VersionController.js';
25
25
 
26
+ /**
27
+ * Describes and configures a Setting.
28
+ *
29
+ * Use `Settings#resolve` to get the concrete `Setting` instance for a descriptor.
30
+ */
31
+ export interface SettingDescriptor<ValueT> {
32
+ /** The unique identifier of a setting */
33
+ readonly name: string;
34
+
35
+ /**
36
+ * Determines how the possible values of the setting are expressed.
37
+ *
38
+ * - If the setting can only be enabled and disabled use BOOLEAN
39
+ * - If the setting has a list of possible values use ENUM
40
+ * - If each setting value is a set of objects use ARRAY
41
+ * - If the setting value is a regular expression use REGEX
42
+ */
43
+ readonly type: SettingType;
44
+
45
+ /**
46
+ * The default value for this setting.
47
+ *
48
+ * Can be computed based on the `hostConfig` (but NOTHING ELSE).
49
+ */
50
+ readonly defaultValue: ValueT|((hostConfig: Root.Runtime.HostConfig) => ValueT);
51
+
52
+ /**
53
+ * Determines if the setting value is stored in the global, local or session storage.
54
+ */
55
+ readonly storageType?: SettingStorageType;
56
+ }
57
+
58
+ /**
59
+ * Describes and configures a Setting that might be unavailable or disabled depending on the HostConfig.
60
+ *
61
+ * See {@link SettingAvailability} for details.
62
+ *
63
+ * Use `Settings#maybeResolve` to get the concrete `Setting` instance (or a reason why it's not available).
64
+ */
65
+ export interface ConditionalSettingDescriptor<ValueT, ReasonT> extends SettingDescriptor<ValueT> {
66
+ /** The function used as `isAvailable` must only read the host config, NOTHING ELSE. */
67
+ isAvailable: (hostConfig: Root.Runtime.HostConfig) => SettingAvailabilityStatus<ReasonT>;
68
+ }
69
+
70
+ export type SettingAvailabilityStatus<ReasonT> = {
71
+ status: SettingAvailability.AVAILABLE,
72
+ }|{
73
+ status: SettingAvailability.UNAVAILABLE | SettingAvailability.DISABLED,
74
+ reason: ReasonT,
75
+ };
76
+
77
+ export const enum SettingAvailability {
78
+ /**
79
+ * Setting is available and can be changed by the user or programmatically.
80
+ */
81
+ AVAILABLE = 1,
82
+
83
+ /**
84
+ * Setting is not available at all. Any `maybeResolve` or `resolve` call will fail.
85
+ * The setting should be hidden from the user.
86
+ */
87
+ UNAVAILABLE = 2,
88
+
89
+ /**
90
+ * Setting is available, but its value can't be read or written.
91
+ */
92
+ DISABLED = 3,
93
+ }
94
+
26
95
  export interface SettingsCreationOptions {
27
96
  syncedStorage: SettingsStorage;
28
97
  globalStorage: SettingsStorage;
@@ -75,9 +144,6 @@ export class Settings {
75
144
  this.createSetting(settingName, evaluatedDefaultValue, storageType);
76
145
 
77
146
  setting.setTitleFunction(registration.title);
78
- if (registration.userActionCondition) {
79
- setting.setRequiresUserAction(Boolean(Root.Runtime.Runtime.queryParam(registration.userActionCondition)));
80
- }
81
147
  setting.setRegistration(registration);
82
148
 
83
149
  this.registerModuleSetting(setting);
@@ -152,6 +152,16 @@ export function lowerBound<S, T, A extends S[]>(
152
152
  return r;
153
153
  }
154
154
 
155
+ /**
156
+ * Inserts a value into a sorted array in O(n) time (O(log n) search using the provided comparator and O(n) insertion).
157
+ * Returns the index at which the value was inserted.
158
+ */
159
+ export function insertWithComparator<T>(array: T[], value: T, comparator: (a: T, b: T) => number): number {
160
+ const index = lowerBound(array, value, comparator);
161
+ array.splice(index, 0, value);
162
+ return index;
163
+ }
164
+
155
165
  /**
156
166
  * Returns the index of the element closest to the needle that is greater than
157
167
  * it. Assumes that the provided array is sorted.
@@ -50,8 +50,40 @@ const escapedReplacements = new Map([
50
50
  ['</script', '\\x3C/script'],
51
51
  ]);
52
52
 
53
- export const escapeUnicode = (content: string): string => {
54
- return content.replaceAll(/[\p{Format}\p{Surrogate}]/gu, match => {
53
+ const UNICODE_ESCAPE_SOURCE = '[\\p{Format}\\p{Surrogate}]';
54
+ const UNICODE_ESCAPE_REGEX = new RegExp(UNICODE_ESCAPE_SOURCE, 'u');
55
+ const UNICODE_ESCAPE_GLOBAL_REGEX = new RegExp(UNICODE_ESCAPE_SOURCE, 'gu');
56
+
57
+ const UNICODE_ESCAPE_EXCEPT_ZWSP_SOURCE = '(?![\\u200B\\u200C\\u200D])[\\p{Format}]|\\p{Surrogate}';
58
+ const UNICODE_ESCAPE_EXCEPT_ZWSP_REGEX = new RegExp(UNICODE_ESCAPE_EXCEPT_ZWSP_SOURCE, 'u');
59
+ const UNICODE_ESCAPE_EXCEPT_ZWSP_GLOBAL_REGEX = new RegExp(UNICODE_ESCAPE_EXCEPT_ZWSP_SOURCE, 'gu');
60
+
61
+ /**
62
+ * Escapes formatting and surrogate characters in the string into literal Unicode escape sequences (e.g. \u200B).
63
+ * Use this when displaying strings to developers for inspection (e.g. in the Console or Object properties)
64
+ * where you want hidden or invisible characters to be explicitly visible as literal text.
65
+ */
66
+ export const escapeUnicodeAsText = (content: string): string => {
67
+ if (!UNICODE_ESCAPE_REGEX.test(content)) {
68
+ return content;
69
+ }
70
+ return content.replaceAll(UNICODE_ESCAPE_GLOBAL_REGEX, match => {
71
+ return match.split('').map(char => '\\u' + toHexadecimal(char.charCodeAt(0), 4)).join('');
72
+ });
73
+ };
74
+
75
+ /**
76
+ * Escapes dangerous formatting and surrogate characters (like bidi override characters) to prevent
77
+ * security and layout issues, but leaves safe, layout-critical zero-width formatting characters
78
+ * (Zero Width Space \u200B, Zero Width Non-Joiner \u200C, and Zero Width Joiner \u200D) untouched.
79
+ * Use this when rendering user-controlled content inside templates or HTML markup where you want formatting
80
+ * characters to function normally for word wrapping or rendering layout, rather than showing as literal text.
81
+ */
82
+ export const safeEscapeUnicode = (content: string): string => {
83
+ if (!UNICODE_ESCAPE_EXCEPT_ZWSP_REGEX.test(content)) {
84
+ return content;
85
+ }
86
+ return content.replaceAll(UNICODE_ESCAPE_EXCEPT_ZWSP_GLOBAL_REGEX, match => {
55
87
  return match.split('').map(char => '\\u' + toHexadecimal(char.charCodeAt(0), 4)).join('');
56
88
  });
57
89
  };
@@ -176,8 +208,8 @@ export const toBase64 = (inputString: string): string => {
176
208
  shift = i % 3;
177
209
  v |= data[i] << (16 >>> shift & 24);
178
210
  if (shift === 2) {
179
- encoded += String.fromCharCode(
180
- encodeBits(v >>> 18 & 63), encodeBits(v >>> 12 & 63), encodeBits(v >>> 6 & 63), encodeBits(v & 63));
211
+ encoded += String.fromCharCode(encodeBits(v >>> 18 & 63), encodeBits(v >>> 12 & 63), encodeBits(v >>> 6 & 63),
212
+ encodeBits(v & 63));
181
213
  v = 0;
182
214
  }
183
215
  }
@@ -312,8 +344,8 @@ export const filterRegex = function(query: string): RegExp {
312
344
  return new RegExp(regexString, 'i');
313
345
  };
314
346
 
315
- export const createSearchRegex = function(
316
- query: string, caseSensitive: boolean, isRegex: boolean, matchWholeWord = false): RegExp {
347
+ export const createSearchRegex = function(query: string, caseSensitive: boolean, isRegex: boolean,
348
+ matchWholeWord = false): RegExp {
317
349
  const regexFlags = caseSensitive ? 'g' : 'gi';
318
350
  let regexObject;
319
351
 
@@ -273,16 +273,6 @@ export class ServiceWorkerCacheModel extends SDKModel<EventTypes> implements Pro
273
273
  indexedDBContentUpdated(_event: Protocol.Storage.IndexedDBContentUpdatedEvent): void {
274
274
  }
275
275
 
276
- interestGroupAuctionEventOccurred(_event: Protocol.Storage.InterestGroupAuctionEventOccurredEvent): void {
277
- }
278
-
279
- interestGroupAccessed(_event: Protocol.Storage.InterestGroupAccessedEvent): void {
280
- }
281
-
282
- interestGroupAuctionNetworkRequestCreated(_event: Protocol.Storage.InterestGroupAuctionNetworkRequestCreatedEvent):
283
- void {
284
- }
285
-
286
276
  sharedStorageAccessed(_event: Protocol.Storage.SharedStorageAccessedEvent): void {
287
277
  }
288
278
 
@@ -142,16 +142,6 @@ export class StorageBucketsModel extends SDKModel<EventTypes> implements Protoco
142
142
  }
143
143
  }
144
144
 
145
- interestGroupAccessed(_event: Protocol.Storage.InterestGroupAccessedEvent): void {
146
- }
147
-
148
- interestGroupAuctionEventOccurred(_event: Protocol.Storage.InterestGroupAuctionEventOccurredEvent): void {
149
- }
150
-
151
- interestGroupAuctionNetworkRequestCreated(_event: Protocol.Storage.InterestGroupAuctionNetworkRequestCreatedEvent):
152
- void {
153
- }
154
-
155
145
  indexedDBListUpdated(_event: Protocol.Storage.IndexedDBListUpdatedEvent): void {
156
146
  }
157
147
 
@@ -1355,7 +1355,6 @@ Common.Settings.registerSettingExtension({
1355
1355
  settingType: Common.Settings.SettingType.BOOLEAN,
1356
1356
  order: 0,
1357
1357
  defaultValue: false,
1358
- userActionCondition: 'hasOtherClients',
1359
1358
  options: [
1360
1359
  {
1361
1360
  value: true,
@@ -27,8 +27,6 @@ const UIStrings = {
27
27
  const str_ = i18n.i18n.registerUIStrings('entrypoints/inspector_main/OutermostTargetSelector.ts', UIStrings);
28
28
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
29
29
 
30
- let outermostTargetSelectorInstance: OutermostTargetSelector;
31
-
32
30
  export class OutermostTargetSelector implements SDK.TargetManager.Observer, UI.SoftDropDown.Delegate<SDK.Target.Target>,
33
31
  UI.Toolbar.Provider {
34
32
  readonly listItems = new UI.ListModel.ListModel<SDK.Target.Target>();
@@ -54,17 +52,6 @@ export class OutermostTargetSelector implements SDK.TargetManager.Observer, UI.S
54
52
  UI.Context.Context.instance().addFlavorChangeListener(SDK.Target.Target, this.#targetChanged, this);
55
53
  }
56
54
 
57
- static instance(opts: {
58
- forceNew: boolean|null,
59
- } = {forceNew: null}): OutermostTargetSelector {
60
- const {forceNew} = opts;
61
- if (!outermostTargetSelectorInstance || forceNew) {
62
- outermostTargetSelectorInstance = new OutermostTargetSelector();
63
- }
64
-
65
- return outermostTargetSelectorInstance;
66
- }
67
-
68
55
  item(): UI.Toolbar.ToolbarItem {
69
56
  return this.#toolbarItem;
70
57
  }
@@ -216,9 +216,14 @@ export class RenderingOptionsView extends UI.Widget.VBox {
216
216
  this.#appendCheckbox(
217
217
  i18nString(UIStrings.scrollingPerformanceIssues), i18nString(UIStrings.highlightsElementsTealThatCan),
218
218
  Common.Settings.Settings.instance().moduleSetting('show-scroll-bottleneck-rects'));
219
- this.#appendCheckbox(
220
- i18nString(UIStrings.highlightAds), i18nString(UIStrings.highlightsElementsRedDetectedToBe),
221
- Common.Settings.Settings.instance().moduleSetting('show-ad-highlights'));
219
+
220
+ // The 'Highlight ads' setting now lives in the Ads panel under Application.
221
+ // We display this legacy setting only when the Ads panel isn't enabled.
222
+ if (!Root.Runtime.hostConfig.devToolsAdsPanel?.enabled) {
223
+ this.#appendCheckbox(i18nString(UIStrings.highlightAds), i18nString(UIStrings.highlightsElementsRedDetectedToBe),
224
+ Common.Settings.Settings.instance().moduleSetting('show-ad-highlights'));
225
+ }
226
+
222
227
  this.#appendCheckbox(
223
228
  i18nString(UIStrings.disableLocalFonts), i18nString(UIStrings.disablesLocalSourcesInFontface),
224
229
  Common.Settings.Settings.instance().moduleSetting('local-fonts-disabled'));
@@ -246,10 +246,10 @@ UI.Toolbar.registerToolbarItem({
246
246
  });
247
247
 
248
248
  UI.Toolbar.registerToolbarItem({
249
- async loadItem() {
249
+ loadItem: Common.Lazy.lazy(async () => {
250
250
  const InspectorMain = await loadInspectorMainModule();
251
- return InspectorMain.OutermostTargetSelector.OutermostTargetSelector.instance();
252
- },
251
+ return new InspectorMain.OutermostTargetSelector.OutermostTargetSelector();
252
+ }) as () => Promise<UI.Toolbar.Provider>,
253
253
  order: 97,
254
254
  location: UI.Toolbar.ToolbarItemLocation.MAIN_TOOLBAR_RIGHT,
255
255
  });
@@ -215,6 +215,11 @@ export class MainImpl {
215
215
  this.#universe = new Foundation.Universe.Universe(creationOptions);
216
216
  Root.DevToolsContext.setGlobalInstance(this.#universe.context as Root.DevToolsContext.WritableDevToolsContext);
217
217
 
218
+ // Mark 'cache-disabled' as requiring user interaction when multiple CDP clients are attached.
219
+ if (Root.Runtime.Runtime.queryParam('hasOtherClients')) {
220
+ this.#universe.settings.moduleSetting('cache-disabled').setRequiresUserAction(true);
221
+ }
222
+
218
223
  Root.Runtime.experiments.cleanUpStaleExperiments();
219
224
 
220
225
  await this.requestAndRegisterLocaleData();
@@ -503,8 +508,8 @@ export class MainImpl {
503
508
  'no-profile-and-not-eligible';
504
509
  void VisualLogging.logFunctionCall('gdp-client-initialize', contextString);
505
510
  });
506
- void Badges.UserBadges.instance().initialize();
507
- Badges.UserBadges.instance().addEventListener(Badges.Events.BADGE_TRIGGERED, async ev => {
511
+ void this.#universe.userBadges.initialize();
512
+ this.#universe.userBadges.addEventListener(Badges.Events.BADGE_TRIGGERED, async ev => {
508
513
  loadedPanelCommonModule ??= await import('../../panels/common/common.js') as typeof PanelCommon;
509
514
  const badgeNotification = new loadedPanelCommonModule.BadgeNotification();
510
515
  const {badge, reason} = ev.data;
@@ -8,3 +8,89 @@ As such, allowed use of APIs is restricted to what is available in both runtimes
8
8
  A `DevToolsUniverse` is a concrete, encapsulated instance of "foundation" scoped
9
9
  to a single root CDP target. It is valid to create multiple `DevToolsUniverse`
10
10
  instances simultaneously.
11
+
12
+ ## Architecture Shortcomings & Code Health Projects
13
+
14
+ The following is a prioritized list of architectural shortcomings and refactoring projects aimed at reducing coupling, eliminating global state, and improving the modularity of the DevTools foundation.
15
+
16
+ ### Priority 1: Move `models/text_utils` to `core/text_utils`
17
+ * **Problem**: 22 files in `front_end/core/sdk` depend directly on `front_end/models/text_utils` for basic text structures (layering violation).
18
+ * **Rationale**: `text_utils` contains fundamental, non-business-logic utilities (`TextRange`, `TextCursor`, `ContentData`, `ContentProvider`) that represent the base data structures of the editor, debugger, and network panels. It only depends on `core/common` and `core/platform`. Moving it to `core` is a natural fit and resolves the majority of `core` -> `models` layering violations.
19
+ * **Action**:
20
+ 1. Move the directory `front_end/models/text_utils` to `front_end/core/text_utils`.
21
+ 2. Update all imports across the codebase.
22
+
23
+ ### Priority 2: Break Circular Dependencies in Bindings (`ResourceMapping` <-> Bindings)
24
+ * **Problem**: Bidirectional dependencies between `ResourceMapping` and `DebuggerWorkspaceBinding`/`CSSWorkspaceBinding` prevent isolated testing.
25
+ * **Rationale**: Decoupling `ResourceMapping` from concrete bindings allows better testing and modularity.
26
+ * **Action**: Introduce abstract listener interfaces in `ResourceMapping` (Dependency Inversion). `DebuggerWorkspaceBinding` and `CSSWorkspaceBinding` should implement these interfaces and register themselves, allowing `ResourceMapping` to invoke them without depending on concrete classes.
27
+
28
+ ### Priority 3: Move `IgnoreListManager` from `workspace` to `bindings`
29
+ * **Problem**: `models/workspace` depends on `core/sdk` via `IgnoreListManager.ts`.
30
+ * **Rationale**: Ignore-listing is conceptually a debugger-binding concern, not a basic workspace/file-system concern.
31
+ * **Action**:
32
+ 1. Remove the convenience helper `UISourceCode.isIgnoreListed()` (and related methods in `UILocation`) from `models/workspace`.
33
+ 2. Update callers to query `IgnoreListManager` directly.
34
+ 3. Move `IgnoreListManager.ts` to `models/bindings`.
35
+ 4. This removes the value-level dependency of `workspace` on `sdk`.
36
+
37
+ ### Priority 4: Decouple `Workspace.Project` from `SDK.Target`
38
+ * **Problem**: `Workspace.Project` exposes `target()`, coupling the VFS to runtime targets.
39
+ * **Rationale**: A workspace should be able to exist without knowing about browser targets.
40
+ * **Action**:
41
+ 1. Remove `target()` from the `Project` interface and `ProjectStore` in `front_end/models/workspace/WorkspaceImpl.ts`.
42
+ 2. In the `bindings` module, maintain a private `WeakMap<Workspace.Project, SDK.Target.Target>` to associate projects with targets.
43
+ 3. Update `NetworkProject.targetForUISourceCode(uiSourceCode)` to look up the target from this `WeakMap`.
44
+
45
+ ### Priority 5: Decouple `core/sdk` from `models/formatter` (AST Scope Fallback)
46
+ * **Problem**: `SDK/SourceMap.ts` depends on `models/formatter` for fallback scope calculation.
47
+ * **Rationale**: `SDK` should not depend on high-level formatting/parsing worker pools.
48
+ * **Action**:
49
+ 1. Remove the fallback scope calculation logic from `SourceMap.ts` and expose a clean API (e.g., `setScopesInfo(...)`).
50
+ 2. Move the AST fallback scope calculation logic to `front_end/models/bindings` (e.g., in `DebuggerWorkspaceBinding`), which coordinates script and source map loading.
51
+ 3. Have the bindings layer calculate the fallback scopes and attach them to the `SourceMap` object.
52
+
53
+ ### Priority 6: Refactor Mapping Engines & Inner Helpers in Bindings
54
+ * **Problem**: Engines and helpers query global `DebuggerWorkspaceBinding.instance()` directly.
55
+ * **Rationale**: High coupling hinders testing and isolation.
56
+ * **Action**: Eliminate direct global singleton queries. Update helpers to access parent mapping engines or pass references via constructors.
57
+
58
+ ### Priority 7: Universe-scoped Embedder Host and HostConfig
59
+ * **Problem**: `InspectorFrontendHostInstance` and `Root.Runtime.hostConfig` are treated as global mutable singletons. Core classes (`Connections`, `IsolatedFileSystemManager`, `FileManager`) and UI components access them directly, leading to global state pollution and state leaks in tests.
60
+ * **Rationale**: The host interface and its configuration represent the boundary between DevTools and the Chromium browser. To support multiple isolated `DevToolsUniverse` instances, both the host interface and host configuration must be scoped to the universe context.
61
+ * **Action**:
62
+ 1. Store the scoped `InspectorFrontendHostAPI` (wrapped in `ScopedInspectorFrontendHost`) in the `DevToolsUniverse` context.
63
+ 2. Refactor core classes (`Connections`, `IsolatedFileSystemManager`, `FileManager`, `UserMetrics`) to receive the scoped host via constructor injection.
64
+ 3. Introduce a scoped `HostConfigProvider` service in the `Universe` context to manage `HostConfig` fetching and caching.
65
+ 4. Move polling and configuration update logic from `HostConfigTracker` in `AidaClient.ts` to `HostConfigProvider`.
66
+ 5. Provide a compatibility Proxy for `Root.Runtime.hostConfig` to allow gradual migration of the 200+ call sites.
67
+ 6. Remove the global side-effect initialization in `InspectorFrontendHost.ts`.
68
+
69
+ ### Priority 8: View-Level Dependency Injection (Universe-ification)
70
+ * **Problem**: UI panels query global `.instance()` for bindings, causing state leaks in tests.
71
+ * **Rationale**: DevTools is transitioning to a scoped "Universe" architecture where dependencies are injected. UI panels should receive their dependencies rather than querying globals.
72
+ * **Action**:
73
+ 1. Expose bindings on `Universe` and inject them via the view loading pipeline.
74
+ 2. Leverage the view loading pipeline (`-meta.ts` files) to pass these bindings to panel constructors upon initialization, avoiding global calls in UI panels.
75
+
76
+ ### Priority 9: Decouple `persistence` from `bindings`
77
+ * **Problem**: `models/persistence` depends on `models/bindings` to check if a target is Node.js.
78
+ * **Rationale**: `persistence` (which maps network files to local files) should ideally only depend on `workspace` and not on the complex debugger/bindings layer.
79
+ * **Action**: Introduce a capability/property on `Workspace.Project` (e.g., `isNodeProject`) to avoid direct target queries.
80
+
81
+ ### Priority 10: Move `SourceFrameIssuesManager` to `bindings`
82
+ * **Problem**: `models/issues_manager` depends on `workspace` and `bindings` only for placing issue badges.
83
+ * **Rationale**: Showing badges on source frames is a binding/presentation concern, similar to showing console messages. `issues_manager` itself should be a clean, independent leaf module.
84
+ * **Action**: Move `SourceFrameIssuesManager.ts` to `models/bindings/` and remove `workspace` and `bindings` dependencies from `issues_manager/BUILD.gn`.
85
+
86
+ ### Priority 11: Decouple UI via Interfaces / Revealers
87
+ * **Problem**: General UI components (like `Linkifier`) depend on heavy concrete bindings.
88
+ * **Rationale**: UI components should not be tightly coupled to complex mapping logic.
89
+ * **Action**: Use light interfaces or `Common.Revealer`.
90
+
91
+ ### Priority 12: Decouple Core Modules from `i18n` (UI Localization)
92
+ * **Problem**: Core infra/parser modules import `i18n` for localized strings.
93
+ * **Rationale**: Business logic and core infrastructure should not be tied to UI localization libraries.
94
+ * **Action**:
95
+ 1. Refactor parsers to return structured error data and let UI handle localization.
96
+ 2. Update registries to use string IDs/keys.
@@ -6,7 +6,9 @@ import * as Common from '../core/common/common.js';
6
6
  import * as Host from '../core/host/host.js';
7
7
  import * as Root from '../core/root/root.js';
8
8
  import * as SDK from '../core/sdk/sdk.js';
9
+ import * as AiAssistance from '../models/ai_assistance/ai_assistance.js';
9
10
  import * as AutofillManager from '../models/autofill_manager/autofill_manager.js';
11
+ import * as Badges from '../models/badges/badges.js';
10
12
  import * as Bindings from '../models/bindings/bindings.js';
11
13
  import * as Breakpoints from '../models/breakpoints/breakpoints.js';
12
14
  import * as CrUXManager from '../models/crux-manager/crux-manager.js';
@@ -186,6 +188,12 @@ export class Universe {
186
188
  const liveMetrics = new LiveMetrics.LiveMetrics(targetManager, deviceModeModel);
187
189
  context.set(LiveMetrics.LiveMetrics, liveMetrics);
188
190
 
191
+ const userBadges = new Badges.UserBadges(settings, gdpClient);
192
+ context.set(Badges.UserBadges, userBadges);
193
+
194
+ const aiHistoryStorage = new AiAssistance.AiHistoryStorage.AiHistoryStorage(settings);
195
+ context.set(AiAssistance.AiHistoryStorage.AiHistoryStorage, aiHistoryStorage);
196
+
189
197
  this.autofillManager = new AutofillManager.AutofillManager.AutofillManager(targetManager, frameManager);
190
198
  }
191
199
 
@@ -198,6 +206,10 @@ export class Universe {
198
206
  return this.context.get(Persistence.AutomaticFileSystemWorkspaceBinding.AutomaticFileSystemWorkspaceBinding);
199
207
  }
200
208
 
209
+ get aiHistoryStorage(): AiAssistance.AiHistoryStorage.AiHistoryStorage {
210
+ return this.context.get(AiAssistance.AiHistoryStorage.AiHistoryStorage);
211
+ }
212
+
201
213
  get breakpointManager(): Breakpoints.BreakpointManager.BreakpointManager {
202
214
  return this.context.get(Breakpoints.BreakpointManager.BreakpointManager);
203
215
  }
@@ -286,6 +298,10 @@ export class Universe {
286
298
  return this.context.get(SDK.TargetManager.TargetManager);
287
299
  }
288
300
 
301
+ get userBadges(): Badges.UserBadges {
302
+ return this.context.get(Badges.UserBadges);
303
+ }
304
+
289
305
  get workspace(): Workspace.Workspace.WorkspaceImpl {
290
306
  return this.context.get(Workspace.Workspace.WorkspaceImpl);
291
307
  }