chrome-devtools-frontend 1.0.1672388 → 1.0.1674545

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 (232) hide show
  1. package/eslint.config.mjs +3 -3
  2. package/front_end/core/common/SettingRegistration.ts +1 -26
  3. package/front_end/core/common/Settings.ts +4 -53
  4. package/front_end/core/host/UserMetrics.ts +127 -117
  5. package/front_end/core/protocol_client/PuppeteerDevToolsConnection.ts +42 -9
  6. package/front_end/core/root/Runtime.ts +7 -2
  7. package/front_end/core/sdk/NetworkManager.ts +0 -35
  8. package/front_end/core/sdk/SourceMap.ts +1 -19
  9. package/front_end/core/sdk/SourceMapManager.ts +75 -48
  10. package/front_end/core/sdk/SourceMapScopesInfo.ts +0 -62
  11. package/front_end/devtools_compatibility.js +1 -1
  12. package/front_end/generated/InspectorBackendCommands.ts +4 -3
  13. package/front_end/generated/{SupportedCSSProperties.js → SupportedCSSProperties.ts} +32 -1
  14. package/front_end/generated/protocol-mapping.d.ts +8 -0
  15. package/front_end/generated/protocol-proxy-api.d.ts +6 -0
  16. package/front_end/generated/protocol.ts +16 -2
  17. package/front_end/models/ai_assistance/AiSetting.ts +66 -3
  18. package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +1 -1
  19. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +4 -3
  20. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +1 -1
  21. package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
  22. package/front_end/models/emulation/DeviceModeModel.ts +25 -34
  23. package/front_end/models/emulation/EmulatedDevices.ts +1 -1
  24. package/front_end/models/javascript_metadata/NativeFunctions.js +4 -4
  25. package/front_end/models/trace/ModelImpl.ts +5 -0
  26. package/front_end/models/trace/Processor.ts +47 -10
  27. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +18 -19
  28. package/front_end/models/trace/handlers/MetaHandler.ts +46 -9
  29. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +11 -0
  30. package/front_end/models/trace/insights/CLSCulprits.ts +1 -2
  31. package/front_end/models/trace/insights/CharacterSet.ts +1 -1
  32. package/front_end/models/trace/insights/Common.ts +21 -2
  33. package/front_end/models/trace/insights/DocumentLatency.ts +1 -1
  34. package/front_end/models/trace/insights/LCPBreakdown.ts +7 -6
  35. package/front_end/models/trace/insights/LCPDiscovery.ts +1 -1
  36. package/front_end/models/trace/insights/ModernHTTP.ts +7 -3
  37. package/front_end/models/trace/insights/NetworkDependencyTree.ts +1 -1
  38. package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
  39. package/front_end/models/trace/insights/ThirdParties.ts +5 -2
  40. package/front_end/models/trace/insights/types.ts +11 -6
  41. package/front_end/models/trace/types/Configuration.ts +5 -0
  42. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -10
  43. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +3 -45
  44. package/front_end/panels/application/BackgroundServiceView.ts +42 -40
  45. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  46. package/front_end/panels/common/ExtensionServer.ts +7 -1
  47. package/front_end/panels/common/common.ts +0 -1
  48. package/front_end/panels/console/ConsoleInsightTeaser.ts +7 -6
  49. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  50. package/front_end/panels/elements/ClassesPaneWidget.ts +2 -2
  51. package/front_end/panels/elements/ElementsTreeElement.ts +56 -5
  52. package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
  53. package/front_end/panels/elements/components/AdornerManager.ts +1 -0
  54. package/front_end/panels/emulation/AdvancedApp.ts +3 -3
  55. package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -11
  56. package/front_end/panels/emulation/DeviceModeView.ts +234 -75
  57. package/front_end/panels/emulation/InspectedPagePlaceholder.ts +1 -1
  58. package/front_end/panels/emulation/deviceModeView.css +4 -21
  59. package/front_end/panels/emulation/emulation-meta.ts +4 -30
  60. package/front_end/panels/emulation/emulation.ts +0 -3
  61. package/front_end/panels/explain/components/ConsoleInsight.ts +11 -7
  62. package/front_end/panels/layers/LayersPanel.ts +2 -2
  63. package/front_end/panels/layers/layers-meta.ts +2 -2
  64. package/front_end/panels/lighthouse/LighthouseController.ts +3 -7
  65. package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +313 -0
  66. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +0 -10
  67. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +23 -10
  68. package/front_end/panels/mobile_throttling/mobile_throttling.ts +3 -0
  69. package/front_end/panels/network/NetworkConfigView.ts +1 -71
  70. package/front_end/panels/network/networkConfigView.css +1 -2
  71. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +3 -3
  72. package/front_end/panels/profiler/HeapDetachedElementsView.ts +5 -5
  73. package/front_end/panels/profiler/HeapProfileView.ts +32 -32
  74. package/front_end/panels/profiler/HeapProfilerPanel.ts +2 -2
  75. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +33 -37
  76. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +26 -27
  77. package/front_end/panels/profiler/HeapSnapshotView.ts +48 -48
  78. package/front_end/panels/profiler/IsolateSelector.ts +10 -10
  79. package/front_end/panels/profiler/ModuleUIStrings.ts +25 -25
  80. package/front_end/panels/profiler/ProfileLauncherView.ts +6 -6
  81. package/front_end/panels/profiler/ProfilesPanel.ts +6 -6
  82. package/front_end/panels/profiler/WritableProfileHeader.ts +6 -6
  83. package/front_end/panels/profiler/profiler-meta.ts +7 -7
  84. package/front_end/panels/recorder/RecorderPanel.ts +1 -1
  85. package/front_end/panels/settings/AISettingsTab.ts +27 -23
  86. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +463 -13
  87. package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +12 -17
  88. package/front_end/panels/timeline/TimelinePanel.ts +22 -35
  89. package/front_end/panels/timeline/components/CWVMetrics.ts +16 -3
  90. package/front_end/panels/timeline/components/LiveMetricsView.ts +27 -6
  91. package/front_end/panels/timeline/components/NetworkTrackWidget.ts +1 -1
  92. package/front_end/panels/timeline/components/components.ts +0 -4
  93. package/front_end/panels/timeline/components/cwvMetrics.css +4 -0
  94. package/front_end/panels/timeline/components/liveMetricsView.css +7 -17
  95. package/front_end/panels/timeline/components/metricValueStyles.css +17 -0
  96. package/front_end/third_party/chromium/README.chromium +1 -1
  97. package/front_end/third_party/puppeteer/README.chromium +2 -2
  98. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +64 -15
  99. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +65 -16
  100. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts +50 -7
  101. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js.map +1 -1
  103. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.d.ts +2 -1
  104. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.d.ts.map +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.js +5 -5
  106. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.js.map +1 -1
  107. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Connection.d.ts +2 -1
  108. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Connection.d.ts.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Connection.js +8 -6
  110. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Connection.js.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Dialog.d.ts.map +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Dialog.js +3 -0
  113. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Dialog.js.map +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts.map +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js +16 -1
  116. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js.map +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Connection.d.ts +5 -1
  118. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Connection.d.ts.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Connection.js +11 -6
  120. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Connection.js.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Dialog.d.ts.map +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Dialog.js +5 -0
  123. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Dialog.js.map +1 -1
  124. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.js +10 -0
  126. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserConnector.js +4 -3
  128. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserConnector.js.map +1 -1
  129. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts +27 -2
  130. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts.map +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js +12 -1
  132. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js.map +1 -1
  133. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.d.ts +2 -2
  134. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.d.ts.map +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.js +2 -2
  136. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.js.map +1 -1
  137. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
  138. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ChromeLauncher.js +2 -0
  139. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ChromeLauncher.js.map +1 -1
  140. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.d.ts +2 -1
  141. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.d.ts.map +1 -1
  142. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.js +5 -4
  143. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.js.map +1 -1
  144. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  145. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  146. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  147. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  148. package/front_end/third_party/puppeteer/package/lib/types.d.ts +64 -15
  149. package/front_end/third_party/puppeteer/package/package.json +2 -2
  150. package/front_end/third_party/puppeteer/package/src/api/Page.ts +50 -7
  151. package/front_end/third_party/puppeteer/package/src/bidi/BidiOverCdp.ts +9 -7
  152. package/front_end/third_party/puppeteer/package/src/bidi/Connection.ts +9 -6
  153. package/front_end/third_party/puppeteer/package/src/bidi/Dialog.ts +4 -0
  154. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +24 -1
  155. package/front_end/third_party/puppeteer/package/src/cdp/Connection.ts +11 -6
  156. package/front_end/third_party/puppeteer/package/src/cdp/Dialog.ts +7 -0
  157. package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +11 -0
  158. package/front_end/third_party/puppeteer/package/src/common/BrowserConnector.ts +7 -3
  159. package/front_end/third_party/puppeteer/package/src/common/Debug.ts +30 -5
  160. package/front_end/third_party/puppeteer/package/src/common/util.ts +2 -2
  161. package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +2 -0
  162. package/front_end/third_party/puppeteer/package/src/node/ScreenRecorder.ts +6 -4
  163. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  164. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  165. package/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +0 -0
  166. package/front_end/third_party/source-map-scopes-codec/package/LICENSE +0 -0
  167. package/front_end/third_party/source-map-scopes-codec/package/README.md +0 -0
  168. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +0 -0
  169. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
  170. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +0 -0
  171. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +0 -0
  172. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +0 -0
  173. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +0 -0
  174. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +0 -0
  175. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +0 -0
  176. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +0 -0
  177. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +0 -0
  178. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +0 -0
  179. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +0 -0
  180. package/front_end/third_party/source-map-scopes-codec/package/deno.json +1 -1
  181. package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
  182. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +2 -0
  183. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -1
  184. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +2 -0
  185. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +0 -0
  186. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +0 -0
  187. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +0 -0
  188. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +0 -0
  189. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +0 -0
  190. package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +0 -0
  191. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +0 -0
  192. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +0 -0
  193. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +0 -0
  194. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +0 -0
  195. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +0 -0
  196. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +0 -0
  197. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +0 -0
  198. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +0 -0
  199. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +0 -0
  200. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js +0 -0
  201. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js.map +0 -0
  202. package/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +0 -0
  203. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +0 -0
  204. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js.map +0 -0
  205. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.ts +0 -0
  206. package/front_end/third_party/source-map-scopes-codec/package/src/util.js +0 -0
  207. package/front_end/third_party/source-map-scopes-codec/package/src/util.js.map +0 -0
  208. package/front_end/third_party/source-map-scopes-codec/package/src/util.ts +0 -0
  209. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +0 -0
  210. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +0 -0
  211. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +0 -0
  212. package/front_end/ui/components/dialogs/ShortcutDialog.ts +2 -0
  213. package/front_end/ui/components/settings/SettingCheckbox.ts +4 -12
  214. package/front_end/ui/components/settings/settingCheckbox.css +0 -7
  215. package/front_end/ui/legacy/Treeoutline.ts +14 -14
  216. package/front_end/ui/legacy/UIUtils.ts +2 -47
  217. package/front_end/ui/legacy/Widget.ts +10 -2
  218. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
  219. package/front_end/ui/lit/Directives.ts +80 -0
  220. package/front_end/ui/lit/lit.ts +1 -0
  221. package/front_end/ui/lit/render.ts +8 -0
  222. package/front_end/ui/visual_logging/KnownContextValues.ts +18 -0
  223. package/mcp/mcp.ts +1 -0
  224. package/package.json +1 -1
  225. package/front_end/panels/common/ThrottlingUtils.ts +0 -51
  226. package/front_end/panels/emulation/DeviceModeWrapper.ts +0 -248
  227. package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +0 -235
  228. package/front_end/panels/timeline/components/NetworkThrottlingSelector.ts +0 -245
  229. package/front_end/panels/timeline/components/cpuThrottlingSelector.css +0 -30
  230. package/front_end/panels/timeline/components/networkThrottlingSelector.css +0 -24
  231. /package/front_end/core/host/{UserMetricsEnums.d.ts → UserMetricsEnums.ts} +0 -0
  232. /package/front_end/generated/{ARIAProperties.js → ARIAProperties.ts} +0 -0
@@ -8,7 +8,11 @@ import * as Types from '../types/types.js';
8
8
 
9
9
  import type {FinalizeOptions} from './types.js';
10
10
 
11
- let config: {showAllEvents: boolean};
11
+ let config: Types.Configuration.Configuration = Types.Configuration.defaults();
12
+
13
+ export function handleUserConfig(userConfig: Types.Configuration.Configuration): void {
14
+ config = userConfig;
15
+ }
12
16
 
13
17
  // We track the renderer processes we see in each frame on the way through the trace.
14
18
  let rendererProcessesByFrameId: FrameProcessData = new Map();
@@ -62,6 +66,7 @@ let navigationsByNavigationId = new Map<string, Types.Events.NavigationStart>();
62
66
  let softNavigationsById = new Map<number, Types.Events.SoftNavigationStart>();
63
67
  let finalDisplayUrlByNavigationId = new Map<string, string>();
64
68
  let mainFrameNavigations: Types.Events.NavigationStart[] = [];
69
+ let sameDocumentNavigations: Types.Events.DidCommitSameDocumentNavigation[] = [];
65
70
 
66
71
  // Represents all the threads in the trace, organized by process. This is mostly for internal
67
72
  // bookkeeping so that during the finalize pass we can obtain the main and browser thread IDs.
@@ -97,6 +102,7 @@ export function reset(): void {
97
102
  finalDisplayUrlByNavigationId = new Map();
98
103
  processNames = new Map();
99
104
  mainFrameNavigations = [];
105
+ sameDocumentNavigations = [];
100
106
 
101
107
  browserProcessId = Types.Events.ProcessID(-1);
102
108
  browserThreadId = Types.Events.ThreadID(-1);
@@ -326,7 +332,7 @@ export function handleEvent(event: Types.Events.Event): void {
326
332
  return;
327
333
  }
328
334
 
329
- if (Types.Events.isSoftNavigationStart(event)) {
335
+ if (config.enableSoftNavigation && Types.Events.isSoftNavigationStart(event)) {
330
336
  softNavigationsById.set(event.args.context.performanceTimelineNavigationId, event);
331
337
  }
332
338
 
@@ -346,21 +352,18 @@ export function handleEvent(event: Types.Events.Event): void {
346
352
  return;
347
353
  }
348
354
 
349
- // Update `finalDisplayUrlByNavigationId` to reflect history API navigations.
355
+ // Track history API navigations to compute final display URLs in finalize.
350
356
  if (Types.Events.isDidCommitSameDocumentNavigation(event)) {
351
357
  if (event.args.render_frame_host.frame_type !== 'PRIMARY_MAIN_FRAME') {
352
358
  return;
353
359
  }
354
-
355
- const navigation = mainFrameNavigations.at(-1);
356
- const key = navigation?.args.data?.navigationId ?? '';
357
- finalDisplayUrlByNavigationId.set(key, event.args.url);
360
+ sameDocumentNavigations.push(event);
358
361
  return;
359
362
  }
360
363
  }
361
364
 
362
365
  export async function finalize(options?: FinalizeOptions): Promise<void> {
363
- config = {showAllEvents: Boolean(options?.showAllEvents)};
366
+ config.showAllEvents = Boolean(options?.showAllEvents);
364
367
 
365
368
  // We try to set the minimum time by finding the event with the smallest
366
369
  // timestamp. However, if we also got a timestamp from the
@@ -440,10 +443,44 @@ export async function finalize(options?: FinalizeOptions): Promise<void> {
440
443
  mainFrameURL = firstMainFrameNav.args.data.documentLoaderURL;
441
444
  }
442
445
  }
446
+
447
+ // Compute final display URLs for each hard navigation.
448
+ // A hard navigation's final URL is updated by history API navigations (e.g. pushState).
449
+ // However, if a soft navigation occurs, subsequent history API navigations belong to the
450
+ // soft navigation and should not update the hard navigation's URL.
451
+ const softNavs = Array.from(softNavigationsById.values()).sort((a, b) => a.ts - b.ts);
452
+
453
+ // Create an array of intervals for each hard navigation.
454
+ const hardNavs = [...mainFrameNavigations];
455
+
456
+ // Add a faux navigation to cover the time before the first hard navigation, or the whole trace if there are none.
457
+ const intervals = [
458
+ {minTs: 0, maxTs: hardNavs.length > 0 ? hardNavs[0].ts : Infinity, key: ''},
459
+ ...hardNavs.map((nav, i) => ({
460
+ minTs: nav.ts,
461
+ maxTs: i + 1 < hardNavs.length ? hardNavs[i + 1].ts : Infinity,
462
+ key: nav.args.data?.navigationId ?? '',
463
+ })),
464
+ ];
465
+
466
+ for (const {minTs, maxTs, key} of intervals) {
467
+ // Find the first soft navigation within this hard navigation's time window.
468
+ const firstSoftNav = softNavs.find(sn => sn.ts >= minTs && sn.ts < maxTs);
469
+ // If a soft navigation occurred, we only consider history events before it.
470
+ const effectiveMaxTs = firstSoftNav ? firstSoftNav.ts : maxTs;
471
+
472
+ // Find the last history API navigation in the effective window.
473
+ const historyEvents = sameDocumentNavigations.filter(hn => hn.ts >= minTs && hn.ts < effectiveMaxTs);
474
+
475
+ const lastHistoryEvent = historyEvents.at(-1);
476
+ if (lastHistoryEvent) {
477
+ finalDisplayUrlByNavigationId.set(key, lastHistoryEvent.args.url);
478
+ }
479
+ }
443
480
  }
444
481
 
445
482
  export interface MetaHandlerData {
446
- config: {showAllEvents: boolean};
483
+ config: Types.Configuration.Configuration;
447
484
  traceIsGeneric: boolean;
448
485
  traceBounds: Types.Timing.TraceWindowMicro;
449
486
  browserProcessId: Types.Events.ProcessID;
@@ -53,6 +53,11 @@ export function reset(): void {
53
53
  metaCharsetCheckEventsArray = [];
54
54
  }
55
55
 
56
+ let enableSoftNavigation = true;
57
+ export function handleUserConfig(userConfig: Types.Configuration.Configuration): void {
58
+ enableSoftNavigation = userConfig.enableSoftNavigation;
59
+ }
60
+
56
61
  let pageLoadEventsArray: Types.Events.PageLoadEvent[] = [];
57
62
 
58
63
  // Once we've found the LCP events in the trace we want to fetch their DOM Node
@@ -74,6 +79,12 @@ export function handleEvent(event: Types.Events.Event): void {
74
79
  if (!Types.Events.eventIsPageLoadEvent(event)) {
75
80
  return;
76
81
  }
82
+ if (!enableSoftNavigation &&
83
+ (Types.Events.isSoftNavigationStart(event) ||
84
+ event.name === Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION ||
85
+ Types.Events.isSoftFirstContentfulPaint(event))) {
86
+ return;
87
+ }
77
88
  pageLoadEventsArray.push(event);
78
89
 
79
90
  // A soft nav entry includes the Soft FCP details but we want to process both
@@ -599,8 +599,7 @@ export function generateInsight(data: Handlers.Types.HandlerData, context: Insig
599
599
  const domLoadingEvents = data.LayoutShifts.domLoadingEvents.filter(isWithinContext);
600
600
  const unsizedImageEvents = data.LayoutShifts.layoutImageUnsizedEvents.filter(isWithinContext);
601
601
 
602
- const clusterKey = context.navigation ? context.navigationId : Types.Events.NO_NAVIGATION;
603
- const clusters = data.LayoutShifts.clustersByNavigationId.get(clusterKey) ?? [];
602
+ const clusters = data.LayoutShifts.clusters.filter(isWithinContext);
604
603
  const clustersByScore = clusters.toSorted((a, b) => b.clusterCumulativeScore - a.clusterCumulativeScore);
605
604
  const worstCluster = clustersByScore.at(0);
606
605
  const layoutShifts = clusters.flatMap(cluster => cluster.events);
@@ -127,7 +127,7 @@ function metaCharsetLabel(disposition: Types.Events.MetaCharsetDisposition|undef
127
127
 
128
128
  export function generateInsight(
129
129
  data: Handlers.Types.HandlerData, context: InsightSetContext): CharacterSetInsightModel {
130
- if (!context.navigation) {
130
+ if (!context.navigation || !('navigationId' in context)) {
131
131
  return finalize({});
132
132
  }
133
133
 
@@ -160,7 +160,26 @@ export function getFieldMetricsForInsightSet(
160
160
  return null;
161
161
  }
162
162
 
163
- const pageResult = getPageResult(cruxFieldData, insightSet.url.href, insightSet.url.origin, scope);
163
+ let pageResult = getPageResult(cruxFieldData, insightSet.url.href, insightSet.url.origin, scope);
164
+
165
+ if (!pageResult && insightSet.navigation && Types.Events.isSoftNavigationStart(insightSet.navigation)) {
166
+ pageResult = cruxFieldData.find(result => {
167
+ const key = scope ? result[`${scope.pageScope}-${scope.deviceScope}`]?.record.key :
168
+ (result['url-ALL'] || result['origin-ALL'])?.record.key;
169
+ if (!key) {
170
+ return false;
171
+ }
172
+ if (key.url) {
173
+ try {
174
+ return new URL(key.url).origin === insightSet.url.origin;
175
+ } catch {
176
+ return false;
177
+ }
178
+ }
179
+ return key.origin === insightSet.url.origin;
180
+ });
181
+ }
182
+
164
183
  if (!pageResult) {
165
184
  return null;
166
185
  }
@@ -266,7 +285,7 @@ function estimateSavingsWithGraphs(
266
285
  */
267
286
  export function metricSavingsForWastedBytes(
268
287
  wastedBytesByRequestId: Map<string, number>, context: InsightSetContext): MetricSavings|undefined {
269
- if (!context.navigation || !context.lantern) {
288
+ if (!context.navigation || !('lantern' in context) || !context.lantern) {
270
289
  return;
271
290
  }
272
291
 
@@ -191,7 +191,7 @@ function finalize(partialModel: PartialInsightModel<DocumentLatencyInsightModel>
191
191
 
192
192
  export function generateInsight(
193
193
  data: Handlers.Types.HandlerData, context: InsightSetContext): DocumentLatencyInsightModel {
194
- if (!context.navigation) {
194
+ if (!context.navigation || !('navigationId' in context)) {
195
195
  return finalize({});
196
196
  }
197
197
 
@@ -110,10 +110,10 @@ function anyValuesNaN(...values: number[]): boolean {
110
110
  * them to be missing on newer traces, but old trace files may lack some of the
111
111
  * data we rely on, so we want to handle that case.
112
112
  */
113
- function determineSubparts(
114
- nav: Types.Events.NavigationStart, docRequest: Types.Events.SyntheticNetworkRequest,
115
- lcpEvent: Types.Events.AnyLargestContentfulPaintCandidate,
116
- lcpRequest: Types.Events.SyntheticNetworkRequest|undefined): LCPSubparts|null {
113
+ function determineSubparts(nav: Types.Events.NavigationStart|Types.Events.SoftNavigationStart,
114
+ docRequest: Types.Events.SyntheticNetworkRequest,
115
+ lcpEvent: Types.Events.AnyLargestContentfulPaintCandidate,
116
+ lcpRequest: Types.Events.SyntheticNetworkRequest|undefined): LCPSubparts|null {
117
117
  const firstDocByteTs = calculateDocFirstByteTs(docRequest);
118
118
  if (firstDocByteTs === null) {
119
119
  return null;
@@ -232,9 +232,10 @@ export function generateInsight(
232
232
  const lcpMs = Helpers.Timing.microToMilli(metricScore.timing);
233
233
  // This helps position things on the timeline's UI accurately for a trace.
234
234
  const lcpTs = metricScore.event?.ts ? Helpers.Timing.microToMilli(metricScore.event?.ts) : undefined;
235
- const lcpRequest = data.LargestImagePaint.lcpRequestByNavigationId.get(context.navigationId);
235
+ const lcpRequest =
236
+ 'navigationId' in context ? data.LargestImagePaint.lcpRequestByNavigationId.get(context.navigationId) : undefined;
236
237
 
237
- const docRequest = networkRequests.byId.get(context.navigationId);
238
+ const docRequest = 'navigationId' in context ? networkRequests.byId.get(context.navigationId) : undefined;
238
239
  if (!docRequest) {
239
240
  return finalize({lcpMs, lcpTs, lcpEvent, lcpRequest, warnings: [InsightWarning.NO_DOCUMENT_REQUEST]});
240
241
  }
@@ -101,7 +101,7 @@ function finalize(partialModel: PartialInsightModel<LCPDiscoveryInsightModel>):
101
101
 
102
102
  export function generateInsight(
103
103
  data: Handlers.Types.HandlerData, context: InsightSetContext): LCPDiscoveryInsightModel {
104
- if (!context.navigation) {
104
+ if (!context.navigation || !('navigationId' in context)) {
105
105
  return finalize({});
106
106
  }
107
107
 
@@ -7,7 +7,7 @@ import * as Platform from '../../../core/platform/platform.js';
7
7
  import * as Handlers from '../handlers/handlers.js';
8
8
  import * as Helpers from '../helpers/helpers.js';
9
9
  import type * as Lantern from '../lantern/lantern.js';
10
- import type * as Types from '../types/types.js';
10
+ import * as Types from '../types/types.js';
11
11
 
12
12
  import {
13
13
  InsightCategory,
@@ -199,7 +199,7 @@ function computeWasteWithGraph(
199
199
 
200
200
  function computeMetricSavings(
201
201
  http1Requests: Types.Events.SyntheticNetworkRequest[], context: InsightSetContext): MetricSavings|undefined {
202
- if (!context.navigation || !context.lantern) {
202
+ if (!context.navigation || !('lantern' in context) || !context.lantern) {
203
203
  return;
204
204
  }
205
205
 
@@ -234,7 +234,11 @@ export function generateInsight(data: Handlers.Types.HandlerData, context: Insig
234
234
  const contextRequests = data.NetworkRequests.byTime.filter(isWithinContext);
235
235
 
236
236
  const entityMappings = data.NetworkRequests.entityMappings;
237
- const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? data.Meta.mainFrameURL;
237
+ let firstPartyUrl = data.Meta.mainFrameURL;
238
+ if (context.navigation && !Types.Events.isSoftNavigationStart(context.navigation)) {
239
+ firstPartyUrl = context.navigation.args.data?.documentLoaderURL ?? firstPartyUrl;
240
+ }
241
+
238
242
  const firstPartyEntity = Handlers.Helpers.getEntityForUrl(firstPartyUrl, entityMappings);
239
243
  const http1Requests = determineHttp1Requests(contextRequests, entityMappings, firstPartyEntity ?? null);
240
244
 
@@ -674,7 +674,7 @@ export function isNetworkDependencyTreeInsight(model: InsightModel): model is Ne
674
674
 
675
675
  export function generateInsight(
676
676
  data: Handlers.Types.HandlerData, context: InsightSetContext): NetworkDependencyTreeInsightModel {
677
- if (!context.navigation) {
677
+ if (!context.navigation || !('navigationId' in context)) {
678
678
  return finalize({
679
679
  rootNodes: [],
680
680
  maxTime: 0 as Types.Timing.Micro,
@@ -178,7 +178,7 @@ function finalize(partialModel: PartialInsightModel<RenderBlockingInsightModel>)
178
178
 
179
179
  export function generateInsight(
180
180
  data: Handlers.Types.HandlerData, context: InsightSetContext): RenderBlockingInsightModel {
181
- if (!context.navigation) {
181
+ if (!context.navigation || !('navigationId' in context)) {
182
182
  return finalize({
183
183
  renderBlockingRequests: [],
184
184
  });
@@ -6,7 +6,7 @@ import * as i18n from '../../../core/i18n/i18n.js';
6
6
  import * as ThirdPartyWeb from '../../../third_party/third-party-web/third-party-web.js';
7
7
  import * as Extras from '../extras/extras.js';
8
8
  import * as Handlers from '../handlers/handlers.js';
9
- import type * as Types from '../types/types.js';
9
+ import * as Types from '../types/types.js';
10
10
 
11
11
  import {
12
12
  InsightCategory,
@@ -82,7 +82,10 @@ export function generateInsight(
82
82
  data: Handlers.Types.HandlerData, context: InsightSetContext): ThirdPartiesInsightModel {
83
83
  const entitySummaries = Extras.ThirdParties.summarizeByThirdParty(data as Handlers.Types.HandlerData, context.bounds);
84
84
 
85
- const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? data.Meta.mainFrameURL;
85
+ let firstPartyUrl = data.Meta.mainFrameURL;
86
+ if (context.navigation && !Types.Events.isSoftNavigationStart(context.navigation)) {
87
+ firstPartyUrl = context.navigation.args.data?.documentLoaderURL ?? firstPartyUrl;
88
+ }
86
89
  const firstPartyEntity = ThirdPartyWeb.ThirdPartyWeb.getEntity(firstPartyUrl) ||
87
90
  Handlers.Helpers.makeUpEntity(data.Renderer.entityMappings.createdEntityCache, firstPartyUrl);
88
91
 
@@ -11,7 +11,8 @@ import type * as Models from './Models.js';
11
11
  /**
12
12
  * Context for the portion of the trace an insight should look at.
13
13
  */
14
- export type InsightSetContext = InsightSetContextWithoutNavigation|InsightSetContextWithNavigation;
14
+ export type InsightSetContext =
15
+ InsightSetContextWithoutNavigation|InsightSetContextWithNavigation|InsightSetContextWithSoftNavigation;
15
16
 
16
17
  export interface InsightSetContextWithoutNavigation {
17
18
  options: Types.Configuration.ParseOptions;
@@ -29,6 +30,13 @@ export interface InsightSetContextWithNavigation {
29
30
  lantern?: LanternContext;
30
31
  }
31
32
 
33
+ export interface InsightSetContextWithSoftNavigation {
34
+ options: Types.Configuration.ParseOptions;
35
+ bounds: Types.Timing.TraceWindowMicro;
36
+ frameId: string;
37
+ navigation: Types.Events.SoftNavigationStart;
38
+ }
39
+
32
40
  export interface LanternContext {
33
41
  requests: Array<Lantern.Types.NetworkRequest<Types.Events.SyntheticNetworkRequest>>;
34
42
  graph: Lantern.Graph.Node<Types.Events.SyntheticNetworkRequest>;
@@ -93,10 +101,7 @@ export type InsightModel<UIStrings extends Record<string, string> = Record<strin
93
101
  */
94
102
  wastedBytes?: number,
95
103
  frameId?: string,
96
- /**
97
- * If this insight is attached to a navigation, this stores its ID.
98
- */
99
- navigation?: Types.Events.NavigationStart,
104
+ navigation?: Types.Events.NavigationStart | Types.Events.SoftNavigationStart,
100
105
  /** This is lazily-generated because some insights may create many overlays. */
101
106
  createOverlays?: () => Types.Overlays.Overlay[],
102
107
  };
@@ -120,7 +125,7 @@ export interface InsightSet {
120
125
  model: InsightModels;
121
126
  /** Contains errors for all insights that had an internal error. */
122
127
  modelErrors: InsightModelErrors;
123
- navigation?: Types.Events.NavigationStart;
128
+ navigation?: Types.Events.NavigationStart|Types.Events.SoftNavigationStart;
124
129
  }
125
130
 
126
131
  /**
@@ -42,6 +42,10 @@ export interface Configuration {
42
42
  * from the model, but the contents will be empty.
43
43
  */
44
44
  enableAnimationsFrameHandler: boolean;
45
+ /**
46
+ * Whether soft-navs are used in the model/insights.
47
+ */
48
+ enableSoftNavigation: boolean;
45
49
  }
46
50
 
47
51
  export const defaults = (): Configuration => ({
@@ -49,6 +53,7 @@ export const defaults = (): Configuration => ({
49
53
  debugMode: false,
50
54
  maxInvalidationEventsPerEvent: 20,
51
55
  enableAnimationsFrameHandler: false,
56
+ enableSoftNavigation: true,
52
57
  });
53
58
 
54
59
  /**
@@ -594,7 +594,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
594
594
  #conversationSummary?: AiAssistanceModel.ConversationSummary.ConversationSummary;
595
595
  #viewOutput: PanelViewOutput = {};
596
596
  #serverSideLoggingEnabled = isAiAssistanceServerSideLoggingEnabled();
597
- #aiAssistanceEnabledSetting: Common.Settings.Setting<boolean>|undefined;
597
+ #aiAssistanceEnabledSetting: AiAssistanceModel.AiSetting.AiSetting<boolean>;
598
598
  #changeManager = new AiAssistanceModel.ChangeManager.ChangeManager();
599
599
  #mutex = new Common.Mutex.Mutex();
600
600
 
@@ -860,13 +860,12 @@ export class AiAssistancePanel extends UI.Panel.Panel {
860
860
  this.requestUpdate();
861
861
  }
862
862
 
863
- #getAiAssistanceEnabledSetting(): Common.Settings.Setting<boolean>|undefined {
864
- try {
865
- return Common.Settings.Settings.instance().moduleSetting('ai-assistance-enabled') as
866
- Common.Settings.Setting<boolean>;
867
- } catch {
868
- return;
869
- }
863
+ #getAiAssistanceEnabledSetting(): AiAssistanceModel.AiSetting.AiSetting<boolean> {
864
+ return new AiAssistanceModel.AiSetting.AiSetting(
865
+ AiAssistanceModel.AiUtils.aiAssistanceEnabledSettingDescriptor,
866
+ Host.AidaClient.HostConfigTracker.instance(),
867
+ Common.Settings.Settings.instance(),
868
+ );
870
869
  }
871
870
 
872
871
  static async instance(opts: {
@@ -1061,7 +1060,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1061
1060
 
1062
1061
  AiAssistanceModel.AiHistoryStorage.AiHistoryStorage.instance().addEventListener(
1063
1062
  AiAssistanceModel.AiHistoryStorage.Events.HISTORY_DELETED, this.#onHistoryDeleted, this);
1064
- this.#aiAssistanceEnabledSetting?.addChangeListener(this.requestUpdate, this);
1063
+ this.#aiAssistanceEnabledSetting.addEventListener(AiAssistanceModel.AiSetting.Events.CHANGED, this.requestUpdate,
1064
+ this);
1065
1065
  Host.AidaClient.HostConfigTracker.instance().addEventListener(
1066
1066
  Host.AidaClient.Events.AIDA_AVAILABILITY_CHANGED, this.#handleAidaAvailabilityChange);
1067
1067
  const initialAvailability = Host.AidaClient.HostConfigTracker.instance().aidaAvailability;
@@ -1107,7 +1107,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1107
1107
  super.willHide();
1108
1108
  AiAssistanceModel.AiHistoryStorage.AiHistoryStorage.instance().removeEventListener(
1109
1109
  AiAssistanceModel.AiHistoryStorage.Events.HISTORY_DELETED, this.#onHistoryDeleted, this);
1110
- this.#aiAssistanceEnabledSetting?.removeChangeListener(this.requestUpdate, this);
1110
+ this.#aiAssistanceEnabledSetting.removeEventListener(AiAssistanceModel.AiSetting.Events.CHANGED, this.requestUpdate,
1111
+ this);
1111
1112
  Host.AidaClient.HostConfigTracker.instance().removeEventListener(
1112
1113
  Host.AidaClient.Events.AIDA_AVAILABILITY_CHANGED, this.#handleAidaAvailabilityChange);
1113
1114
  this.#toggleSearchElementAction?.removeEventListener(
@@ -4,9 +4,10 @@
4
4
 
5
5
  import * as Common from '../../core/common/common.js';
6
6
  import * as i18n from '../../core/i18n/i18n.js';
7
- import type * as Platform from '../../core/platform/platform.js';
8
7
  import * as Root from '../../core/root/root.js';
8
+ import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
9
9
  import * as UI from '../../ui/legacy/legacy.js';
10
+ import * as SettingUIRegistration from '../../ui/settings/settings.js';
10
11
 
11
12
  import type * as AiAssistance from './ai_assistance.js';
12
13
 
@@ -50,21 +51,6 @@ const UIStrings = {
50
51
  * @description Text of a context menu item to redirect to the Gemini panel with the current context.
51
52
  */
52
53
  debugWithGemini: 'Debug with Gemini',
53
- /**
54
- * @description Message shown to the user if the DevTools locale is not
55
- * supported.
56
- */
57
- wrongLocale: 'To use this feature, set your language preference to English in DevTools settings.',
58
- /**
59
- * @description Message shown to the user if the user's region is not
60
- * supported.
61
- */
62
- geoRestricted: 'This feature is unavailable in your region.',
63
- /**
64
- * @description Message shown to the user if the enterprise policy does
65
- * not allow this feature.
66
- */
67
- policyRestricted: 'This setting is managed by your administrator.',
68
54
  } as const;
69
55
 
70
56
  const str_ = i18n.i18n.registerUIStrings('panels/ai_assistance/ai_assistance-meta.ts', UIStrings);
@@ -76,13 +62,6 @@ function i18nAiBrandedString(gemini: string, assistance: string) {
76
62
  return () => Root.Runtime.hostConfig.devToolsGeminiRebranding?.enabled ? i18nString(gemini) : i18nString(assistance);
77
63
  }
78
64
 
79
- const setting = 'ai-assistance-enabled';
80
-
81
- function isLocaleRestricted(): boolean {
82
- const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
83
- return !devtoolsLocale.locale.startsWith('en-');
84
- }
85
-
86
65
  function isGeoRestricted(config?: Root.Runtime.HostConfig): boolean {
87
66
  return config?.aidaAvailability?.blockedByGeo === true;
88
67
  }
@@ -140,30 +119,9 @@ UI.ViewManager.registerViewExtension({
140
119
  },
141
120
  });
142
121
 
143
- Common.Settings.registerSettingExtension({
122
+ SettingUIRegistration.SettingUIRegistration.register(AiAssistanceModel.AiUtils.aiAssistanceEnabledSettingDescriptor, {
144
123
  category: Common.Settings.SettingCategory.AI,
145
- settingName: setting,
146
- settingType: Common.Settings.SettingType.BOOLEAN,
147
124
  title: i18nAiBrandedString(UIStrings.enableGemini, UIStrings.enableAiAssistance),
148
- defaultValue: false,
149
- reloadRequired: false,
150
- condition: isAnyFeatureAvailable,
151
- disabledCondition: config => {
152
- const reasons: Platform.UIString.LocalizedString[] = [];
153
- if (isGeoRestricted(config)) {
154
- reasons.push(i18nString(UIStrings.geoRestricted));
155
- }
156
- if (isPolicyRestricted(config)) {
157
- reasons.push(i18nString(UIStrings.policyRestricted));
158
- }
159
- if (isLocaleRestricted()) {
160
- reasons.push(i18nString(UIStrings.wrongLocale));
161
- }
162
- if (reasons.length > 0) {
163
- return {disabled: true, reasons};
164
- }
165
- return {disabled: false};
166
- },
167
125
  });
168
126
 
169
127
  UI.ActionRegistration.registerActionExtension({