chrome-devtools-frontend 1.0.1664496 → 1.0.1665921

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 (407) hide show
  1. package/.agents/skills/devtools-testing-guidance/SKILL.md +48 -0
  2. package/.agents/skills/devtools-ux-writing-refactor/SKILL.md +3 -3
  3. package/.agents/skills/repro-flaky-tests/SKILL.md +2 -2
  4. package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +7 -1
  5. package/.agents/skills/ui-eng-vision-widget-promoter/SKILL.md +2 -0
  6. package/.agents/skills/version-control/SKILL.md +4 -3
  7. package/docs/ui_engineering.md +89 -0
  8. package/eslint.config.mjs +9 -2
  9. package/front_end/Images/rollup.config.mjs +1 -1
  10. package/front_end/Tests.js +15 -16
  11. package/front_end/core/common/Gzip.ts +2 -2
  12. package/front_end/core/common/Settings.ts +4 -20
  13. package/front_end/core/common/Srcset.ts +1 -1
  14. package/front_end/core/common/VersionController.ts +1 -1
  15. package/front_end/core/host/AidaClient.ts +19 -4
  16. package/front_end/core/host/AidaGcaTranslation.ts +2 -2
  17. package/front_end/core/host/GcaClient.ts +2 -2
  18. package/front_end/core/host/GdpClient.ts +3 -3
  19. package/front_end/core/host/InspectorFrontendHostStub.ts +1 -1
  20. package/front_end/core/host/ResourceLoader.ts +15 -15
  21. package/front_end/core/protocol_client/DevToolsCDPConnection.ts +2 -2
  22. package/front_end/core/protocol_client/InspectorBackend.ts +1 -1
  23. package/front_end/core/root/Runtime.ts +0 -1
  24. package/front_end/core/sdk/CSSMatchedStyles.ts +78 -3
  25. package/front_end/core/sdk/CSSMetadata.ts +17 -12
  26. package/front_end/core/sdk/CSSProperty.ts +1 -1
  27. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -2
  28. package/front_end/core/sdk/CSSRule.ts +3 -3
  29. package/front_end/core/sdk/CSSStyleSheetHeader.ts +3 -3
  30. package/front_end/core/sdk/CompilerSourceMappingContentProvider.ts +1 -1
  31. package/front_end/core/sdk/Connections.ts +1 -1
  32. package/front_end/core/sdk/DebuggerModel.ts +13 -13
  33. package/front_end/core/sdk/NetworkManager.ts +19 -19
  34. package/front_end/core/sdk/NetworkRequest.ts +57 -57
  35. package/front_end/core/sdk/OverlayModel.ts +1 -1
  36. package/front_end/core/sdk/PageResourceLoader.ts +2 -2
  37. package/front_end/core/sdk/RehydratingConnection.ts +5 -5
  38. package/front_end/core/sdk/ScreenCaptureModel.ts +1 -1
  39. package/front_end/core/sdk/Script.ts +2 -2
  40. package/front_end/core/sdk/ServerTiming.ts +7 -7
  41. package/front_end/core/sdk/ServiceWorkerCacheModel.ts +1 -1
  42. package/front_end/core/sdk/ServiceWorkerManager.ts +11 -11
  43. package/front_end/core/sdk/SourceMapScopeChainEntry.ts +2 -2
  44. package/front_end/core/sdk/SourceMapScopesInfo.ts +1 -1
  45. package/front_end/core/sdk/StorageKeyManager.ts +1 -1
  46. package/front_end/core/sdk/sdk-meta.ts +98 -98
  47. package/front_end/devtools_compatibility.js +15 -13
  48. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +4 -8
  49. package/front_end/entrypoints/main/MainImpl.ts +2 -3
  50. package/front_end/entrypoints/main/main-meta.ts +1 -16
  51. package/front_end/entrypoints/shell/shell.ts +1 -0
  52. package/front_end/entrypoints/trace_app/trace_app.ts +1 -0
  53. package/front_end/foundation/README.md +1 -1
  54. package/front_end/foundation/Universe.test.api.ts +73 -0
  55. package/front_end/foundation/Universe.ts +22 -0
  56. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  57. package/front_end/generated/SupportedCSSProperties.js +1 -1
  58. package/front_end/generated/protocol.ts +19 -0
  59. package/front_end/models/ai_assistance/AiAgent2.ts +1 -1
  60. package/front_end/models/ai_assistance/AiConversation.ts +1 -1
  61. package/front_end/models/ai_assistance/BuiltInAi.ts +1 -1
  62. package/front_end/models/ai_assistance/ChangeManager.ts +0 -70
  63. package/front_end/models/ai_assistance/ExtensionScope.ts +2 -36
  64. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +9 -9
  65. package/front_end/models/ai_assistance/agents/AiAgent.ts +10 -2
  66. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +4 -4
  67. package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +1 -1
  68. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +21 -21
  69. package/front_end/models/ai_assistance/agents/StorageAgent.ts +4 -4
  70. package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
  71. package/front_end/models/ai_assistance/ai_assistance.ts +0 -5
  72. package/front_end/models/ai_assistance/data_formatters/FileFormatter.ts +11 -4
  73. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +8 -2
  74. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +14 -11
  75. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +2 -2
  76. package/front_end/models/ai_assistance/performance/AICallTree.ts +2 -2
  77. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +1 -1
  78. package/front_end/models/ai_assistance/tools/GetNetworkRequestDetails.ts +9 -2
  79. package/front_end/models/ai_assistance/tools/GetStyles.ts +4 -4
  80. package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +2 -5
  81. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +2 -2
  82. package/front_end/models/ai_code_generation/AiCodeGeneration.ts +2 -2
  83. package/front_end/models/badges/badges-meta.ts +27 -0
  84. package/front_end/models/bindings/CSSWorkspaceBinding.ts +4 -3
  85. package/front_end/models/bindings/ContentProviderBasedProject.ts +1 -1
  86. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +6 -7
  87. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +5 -4
  88. package/front_end/models/bindings/PresentationConsoleMessageHelper.ts +72 -29
  89. package/front_end/models/bindings/ResourceMapping.ts +38 -32
  90. package/front_end/models/bindings/ResourceScriptMapping.ts +5 -7
  91. package/front_end/models/breakpoints/BreakpointManager.ts +2 -1
  92. package/front_end/models/har/Writer.ts +2 -2
  93. package/front_end/models/issues_manager/ElementAccessibilityIssue.ts +1 -1
  94. package/front_end/models/issues_manager/GenericIssue.ts +1 -1
  95. package/front_end/models/issues_manager/IssuesManager.ts +14 -5
  96. package/front_end/models/issues_manager/PartitioningBlobURLIssue.ts +1 -1
  97. package/front_end/models/issues_manager/SRIMessageSignatureIssue.ts +2 -2
  98. package/front_end/models/issues_manager/SourceFrameIssuesManager.ts +13 -2
  99. package/front_end/models/issues_manager/issues_manager.ts +0 -2
  100. package/front_end/models/live-metrics/LiveMetrics.ts +22 -5
  101. package/front_end/models/live-metrics/web-vitals-injected/rollup.config.mjs +1 -1
  102. package/front_end/models/live-metrics/web-vitals-injected/spec/spec.ts +10 -4
  103. package/front_end/models/logs/logs-meta.ts +23 -16
  104. package/front_end/models/persistence/AutomaticFileSystemWorkspaceBinding.ts +2 -2
  105. package/front_end/models/persistence/IsolatedFileSystem.ts +1 -1
  106. package/front_end/models/persistence/IsolatedFileSystemManager.ts +1 -1
  107. package/front_end/models/source_map_scopes/NamesResolver.ts +104 -86
  108. package/front_end/models/source_map_scopes/ScopeChainModel.ts +6 -2
  109. package/front_end/models/stack_trace/StackTraceModel.ts +1 -1
  110. package/front_end/models/trace/handlers/ExtensionTraceDataHandler.ts +1 -1
  111. package/front_end/models/trace/handlers/UserTimingsHandler.ts +17 -6
  112. package/front_end/models/trace/helpers/SamplesIntegrator.ts +1 -1
  113. package/front_end/models/trace/helpers/Timing.ts +1 -1
  114. package/front_end/models/trace/insights/Common.ts +1 -1
  115. package/front_end/models/trace/insights/DocumentLatency.ts +3 -3
  116. package/front_end/models/trace/insights/LCPDiscovery.ts +1 -1
  117. package/front_end/models/trace/insights/ModernHTTP.ts +1 -1
  118. package/front_end/models/trace_source_maps_resolver/SourceMapsResolver.ts +2 -2
  119. package/front_end/models/workspace_diff/WorkspaceDiff.ts +14 -9
  120. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +2 -15
  121. package/front_end/panels/ai_assistance/ai_assistance.ts +1 -2
  122. package/front_end/panels/ai_assistance/components/ChatInput.ts +23 -19
  123. package/front_end/panels/ai_assistance/components/ChatMessage.ts +9 -18
  124. package/front_end/panels/ai_assistance/components/ChatView.ts +2 -35
  125. package/front_end/panels/ai_assistance/components/DisabledWidget.ts +1 -1
  126. package/front_end/panels/ai_assistance/components/ExploreWidget.ts +4 -4
  127. package/front_end/panels/ai_assistance/components/ImageResize.ts +74 -0
  128. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +2 -2
  129. package/front_end/panels/animation/AnimationGroupPreviewUI.ts +28 -29
  130. package/front_end/panels/animation/AnimationTimeline.ts +3 -3
  131. package/front_end/panels/animation/animationTimeline.css +0 -2
  132. package/front_end/panels/application/AppManifestView.ts +1 -1
  133. package/front_end/panels/application/ApplicationPanelSidebar.ts +1 -1
  134. package/front_end/panels/application/CookieItemsView.ts +1 -1
  135. package/front_end/panels/application/CrashReportContextView.ts +3 -3
  136. package/front_end/panels/application/DeviceBoundSessionsModel.ts +1 -1
  137. package/front_end/panels/application/DeviceBoundSessionsTreeElement.ts +1 -1
  138. package/front_end/panels/application/DeviceBoundSessionsView.ts +1 -1
  139. package/front_end/panels/application/IndexedDBViews.ts +1 -1
  140. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -1
  141. package/front_end/panels/application/OriginTrialTreeView.ts +1 -1
  142. package/front_end/panels/application/ServiceWorkersView.ts +6 -6
  143. package/front_end/panels/application/StorageBucketsTreeElement.ts +1 -1
  144. package/front_end/panels/application/StorageItemsToolbar.ts +3 -3
  145. package/front_end/panels/application/WebMCPView.ts +7 -5
  146. package/front_end/panels/application/components/AdsView.ts +21 -6
  147. package/front_end/panels/application/components/BackForwardCacheView.ts +2 -2
  148. package/front_end/panels/application/components/ProtocolHandlersView.ts +1 -1
  149. package/front_end/panels/application/components/StorageMetadataView.ts +1 -1
  150. package/front_end/panels/application/preloading/components/MismatchedPreloadingGrid.ts +2 -2
  151. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +2 -1
  152. package/front_end/panels/application/preloading/components/PreloadingString.ts +3 -3
  153. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +2 -1
  154. package/front_end/panels/autofill/AutofillView.ts +1 -1
  155. package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +1 -1
  156. package/front_end/panels/browser_debugger/XHRBreakpointsSidebarPane.ts +2 -2
  157. package/front_end/panels/changes/ChangesSidebar.ts +2 -2
  158. package/front_end/panels/changes/ChangesView.ts +4 -5
  159. package/front_end/panels/changes/CombinedDiffView.ts +3 -3
  160. package/front_end/panels/changes/changes-meta.ts +2 -2
  161. package/front_end/panels/common/AiCodeCompletionTeaser.ts +1 -1
  162. package/front_end/panels/common/AiCodeGenerationTeaser.ts +3 -3
  163. package/front_end/panels/common/BadgeNotification.ts +8 -8
  164. package/front_end/panels/common/DOMLinkifier.ts +1 -1
  165. package/front_end/panels/common/GdpSignUpDialog.ts +2 -2
  166. package/front_end/panels/common/GeminiRebrandPromoDialog.ts +1 -1
  167. package/front_end/panels/common/aiCodeCompletionDisclaimer.css +0 -1
  168. package/front_end/panels/console/ConsoleInsightTeaser.ts +1 -1
  169. package/front_end/panels/console/ConsolePinPane.ts +3 -3
  170. package/front_end/panels/console/ConsolePrompt.ts +6 -4
  171. package/front_end/panels/console/ConsoleSidebar.ts +8 -10
  172. package/front_end/panels/console_counters/WarningErrorCounter.ts +10 -11
  173. package/front_end/panels/coverage/CoverageView.ts +2 -2
  174. package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +3 -3
  175. package/front_end/panels/css_overview/CSSOverviewSidebarPanel.ts +1 -1
  176. package/front_end/panels/developer_resources/DeveloperResourcesView.ts +1 -1
  177. package/front_end/panels/elements/CSSRuleValidator.ts +1 -1
  178. package/front_end/panels/elements/ComputedStyleWidget.ts +3 -2
  179. package/front_end/panels/elements/ElementsTreeElement.ts +3 -3
  180. package/front_end/panels/elements/EventListenersWidget.ts +1 -3
  181. package/front_end/panels/elements/LayoutPane.ts +23 -13
  182. package/front_end/panels/elements/StandaloneStylesContainer.ts +7 -7
  183. package/front_end/panels/elements/StylePropertiesSection.ts +33 -5
  184. package/front_end/panels/elements/StylePropertyTreeElement.ts +5 -5
  185. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +6 -6
  186. package/front_end/panels/elements/StylesSidebarPane.ts +4 -3
  187. package/front_end/panels/elements/elements-meta.ts +18 -2
  188. package/front_end/panels/emulation/DeviceModeToolbar.ts +100 -40
  189. package/front_end/panels/emulation/DeviceModeView.ts +5 -4
  190. package/front_end/panels/emulation/MediaQueryInspector.ts +35 -19
  191. package/front_end/panels/event_listeners/EventListenersView.ts +4 -4
  192. package/front_end/panels/explain/components/ConsoleInsight.ts +8 -9
  193. package/front_end/panels/explain/explain-meta.ts +3 -3
  194. package/front_end/panels/layer_viewer/LayerTreeOutline.ts +135 -167
  195. package/front_end/panels/layer_viewer/Layers3DView.ts +10 -23
  196. package/front_end/panels/layer_viewer/layer_viewer-meta.ts +27 -0
  197. package/front_end/panels/lighthouse/LighthouseController.ts +44 -55
  198. package/front_end/panels/lighthouse/LighthousePanel.ts +9 -9
  199. package/front_end/panels/lighthouse/LighthouseReportSelector.ts +2 -2
  200. package/front_end/panels/lighthouse/LighthouseStartView.ts +9 -12
  201. package/front_end/panels/lighthouse/LighthouseStatusView.ts +33 -33
  202. package/front_end/panels/lighthouse/RadioSetting.ts +1 -1
  203. package/front_end/panels/lighthouse/lighthouse-meta.ts +131 -1
  204. package/front_end/panels/media/EventDisplayTable.ts +67 -94
  205. package/front_end/panels/media/PlayerListView.ts +1 -1
  206. package/front_end/panels/media/eventDisplayTable.css +9 -4
  207. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +5 -5
  208. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +1 -1
  209. package/front_end/panels/network/EventSourceMessagesView.ts +98 -107
  210. package/front_end/panels/network/NetworkLogViewColumns.ts +1 -1
  211. package/front_end/panels/network/NetworkWaterfallColumn.ts +1 -1
  212. package/front_end/panels/network/RequestConditionsDrawer.ts +2 -2
  213. package/front_end/panels/network/RequestCookiesView.ts +2 -2
  214. package/front_end/panels/network/RequestHeadersView.ts +5 -5
  215. package/front_end/panels/network/RequestPayloadView.ts +4 -4
  216. package/front_end/panels/network/RequestTimingView.ts +2 -2
  217. package/front_end/panels/network/components/DirectSocketConnectionView.ts +1 -1
  218. package/front_end/panels/network/eventSourceMessagesView.css +12 -3
  219. package/front_end/panels/network/networkTimingTable.css +2 -2
  220. package/front_end/panels/performance_monitor/PerformanceMonitor.ts +1 -1
  221. package/front_end/panels/profiler/BottomUpProfileDataGrid.ts +25 -29
  222. package/front_end/panels/profiler/HeapProfileView.ts +308 -247
  223. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +13 -3
  224. package/front_end/panels/profiler/HeapSnapshotView.ts +30 -10
  225. package/front_end/panels/profiler/HeapTimelineOverview.ts +5 -2
  226. package/front_end/panels/profiler/ProfileDataGrid.ts +128 -157
  227. package/front_end/panels/profiler/ProfileFlameChartDataProvider.ts +17 -5
  228. package/front_end/panels/profiler/ProfilesPanel.ts +2 -2
  229. package/front_end/panels/profiler/TopDownProfileDataGrid.ts +17 -21
  230. package/front_end/panels/profiler/profilesPanel.css +9 -13
  231. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +2 -2
  232. package/front_end/panels/recorder/CreateRecordingView.ts +4 -4
  233. package/front_end/panels/recorder/RecorderPanel.ts +6 -6
  234. package/front_end/panels/recorder/RecordingView.ts +1 -1
  235. package/front_end/panels/recorder/ReplaySection.ts +1 -1
  236. package/front_end/panels/recorder/StepView.ts +1 -1
  237. package/front_end/panels/recorder/injected/rollup.config.mjs +1 -1
  238. package/front_end/panels/search/SearchView.ts +1 -1
  239. package/front_end/panels/security/SecurityPanel.ts +54 -41
  240. package/front_end/panels/sensors/LocationsSettingsTab.ts +246 -233
  241. package/front_end/panels/sensors/SensorsView.ts +1 -1
  242. package/front_end/panels/settings/AISettingsTab.ts +11 -10
  243. package/front_end/panels/settings/SettingsScreen.ts +29 -24
  244. package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +2 -2
  245. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +5 -5
  246. package/front_end/panels/sources/BreakpointEditDialog.ts +2 -2
  247. package/front_end/panels/sources/BreakpointsView.ts +1 -1
  248. package/front_end/panels/sources/CallStackSidebarPane.ts +2 -2
  249. package/front_end/panels/sources/DebuggerPausedMessage.ts +2 -2
  250. package/front_end/panels/sources/DebuggerPlugin.ts +25 -22
  251. package/front_end/panels/sources/ScopeChainSidebarPane.ts +3 -1
  252. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +7 -5
  253. package/front_end/panels/sources/sources-meta.ts +1 -1
  254. package/front_end/panels/timeline/CountersGraph.ts +1 -2
  255. package/front_end/panels/timeline/ExtensionTrackAppender.ts +1 -1
  256. package/front_end/panels/timeline/TimelineDetailsView.ts +2 -2
  257. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +2 -2
  258. package/front_end/panels/timeline/TimelineFlameChartView.ts +4 -4
  259. package/front_end/panels/timeline/TimelinePaintProfilerView.ts +1 -1
  260. package/front_end/panels/timeline/TimelinePanel.ts +53 -81
  261. package/front_end/panels/timeline/TimelineSelectorStatsView.ts +10 -3
  262. package/front_end/panels/timeline/TimelineUIUtils.ts +18 -4
  263. package/front_end/panels/timeline/TrackConfigBanner.ts +1 -1
  264. package/front_end/panels/timeline/components/ExportTraceOptions.ts +1 -1
  265. package/front_end/panels/timeline/components/LayoutShiftDetails.ts +8 -9
  266. package/front_end/panels/timeline/components/NetworkRequestTooltip.ts +1 -1
  267. package/front_end/panels/timeline/components/TimelineRangeSummaryView.ts +1 -1
  268. package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +2 -2
  269. package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +1 -1
  270. package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +1 -1
  271. package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +2 -2
  272. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +5 -0
  273. package/front_end/panels/timeline/overlays/components/TimespanBreakdownOverlay.ts +13 -8
  274. package/front_end/panels/timeline/overlays/components/timespanBreakdownOverlay.css +1 -0
  275. package/front_end/panels/timeline/timeline-meta.ts +169 -0
  276. package/front_end/panels/timeline/timelineFlameChartView.css +5 -0
  277. package/front_end/panels/webauthn/WebauthnPane.ts +1 -1
  278. package/front_end/panels/whats_new/ReleaseNoteText.ts +9 -9
  279. package/front_end/panels/whats_new/resources/WNDT.md +7 -8
  280. package/front_end/third_party/chromium/README.chromium +1 -1
  281. package/front_end/third_party/web-vitals/README.chromium +2 -2
  282. package/front_end/third_party/web-vitals/package/README.md +120 -19
  283. package/front_end/third_party/web-vitals/package/attribution.d.ts +16 -0
  284. package/front_end/third_party/web-vitals/package/attribution.js +18 -0
  285. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onCLS.d.ts +1 -1
  286. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.d.ts +1 -7
  287. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.js +53 -32
  288. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.d.ts +2 -2
  289. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +43 -12
  290. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.d.ts +1 -1
  291. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.js +21 -3
  292. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.d.ts +1 -1
  293. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.js +30 -24
  294. package/front_end/third_party/web-vitals/package/dist/modules/lib/FCPEntryManager.d.ts +3 -0
  295. package/front_end/third_party/web-vitals/package/dist/modules/lib/FCPEntryManager.js +18 -0
  296. package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.d.ts +2 -1
  297. package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.js +18 -2
  298. package/front_end/third_party/web-vitals/package/dist/modules/lib/LCPEntryManager.d.ts +1 -0
  299. package/front_end/third_party/web-vitals/package/dist/modules/lib/LCPEntryManager.js +1 -0
  300. package/front_end/third_party/web-vitals/package/dist/modules/lib/bindReporter.d.ts +1 -1
  301. package/front_end/third_party/web-vitals/package/dist/modules/lib/generateUniqueID.js +1 -1
  302. package/front_end/third_party/web-vitals/package/dist/modules/lib/getLoadState.d.ts +1 -1
  303. package/front_end/third_party/web-vitals/package/dist/modules/lib/getLoadState.js +7 -7
  304. package/front_end/third_party/web-vitals/package/dist/modules/lib/getSelector.js +1 -1
  305. package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.d.ts +1 -1
  306. package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.js +4 -1
  307. package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.d.ts +7 -3
  308. package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.js +20 -11
  309. package/front_end/third_party/web-vitals/package/dist/modules/lib/initUnique.js +8 -3
  310. package/front_end/third_party/web-vitals/package/dist/modules/lib/observe.d.ts +3 -1
  311. package/front_end/third_party/web-vitals/package/dist/modules/lib/observe.js +19 -4
  312. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/interactionCountPolyfill.js +1 -1
  313. package/front_end/third_party/web-vitals/package/dist/modules/lib/softNavs.d.ts +3 -0
  314. package/front_end/third_party/web-vitals/package/dist/modules/lib/softNavs.js +38 -0
  315. package/front_end/third_party/web-vitals/package/dist/modules/lib/whenIdleOrHidden.js +5 -1
  316. package/front_end/third_party/web-vitals/package/dist/modules/onCLS.d.ts +1 -1
  317. package/front_end/third_party/web-vitals/package/dist/modules/onCLS.js +30 -11
  318. package/front_end/third_party/web-vitals/package/dist/modules/onFCP.d.ts +1 -1
  319. package/front_end/third_party/web-vitals/package/dist/modules/onFCP.js +36 -4
  320. package/front_end/third_party/web-vitals/package/dist/modules/onINP.d.ts +1 -1
  321. package/front_end/third_party/web-vitals/package/dist/modules/onINP.js +42 -22
  322. package/front_end/third_party/web-vitals/package/dist/modules/onLCP.d.ts +1 -1
  323. package/front_end/third_party/web-vitals/package/dist/modules/onLCP.js +109 -30
  324. package/front_end/third_party/web-vitals/package/dist/modules/onTTFB.d.ts +1 -1
  325. package/front_end/third_party/web-vitals/package/dist/modules/onTTFB.js +25 -7
  326. package/front_end/third_party/web-vitals/package/dist/modules/types/base.d.ts +24 -1
  327. package/front_end/third_party/web-vitals/package/dist/modules/types/fcp.d.ts +1 -1
  328. package/front_end/third_party/web-vitals/package/dist/modules/types/inp.d.ts +14 -6
  329. package/front_end/third_party/web-vitals/package/dist/modules/types/lcp.d.ts +1 -1
  330. package/front_end/third_party/web-vitals/package/dist/modules/types/ttfb.d.ts +2 -2
  331. package/front_end/third_party/web-vitals/package/dist/modules/types.d.ts +26 -4
  332. package/front_end/third_party/web-vitals/package/package.json +21 -22
  333. package/front_end/third_party/web-vitals/package/src/attribution/onCLS.ts +1 -1
  334. package/front_end/third_party/web-vitals/package/src/attribution/onFCP.ts +62 -39
  335. package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +52 -15
  336. package/front_end/third_party/web-vitals/package/src/attribution/onLCP.ts +25 -7
  337. package/front_end/third_party/web-vitals/package/src/attribution/onTTFB.ts +43 -37
  338. package/front_end/third_party/web-vitals/package/src/lib/{polyfills/getFirstHiddenTimePolyfill.ts → FCPEntryManager.ts} +4 -14
  339. package/front_end/third_party/web-vitals/package/src/lib/InteractionManager.ts +22 -2
  340. package/front_end/third_party/web-vitals/package/src/lib/LCPEntryManager.ts +1 -0
  341. package/front_end/third_party/web-vitals/package/src/lib/bindReporter.ts +1 -1
  342. package/front_end/third_party/web-vitals/package/src/lib/generateUniqueID.ts +1 -1
  343. package/front_end/third_party/web-vitals/package/src/lib/getLoadState.ts +11 -12
  344. package/front_end/third_party/web-vitals/package/src/lib/getSelector.ts +1 -1
  345. package/front_end/third_party/web-vitals/package/src/lib/getVisibilityWatcher.ts +4 -1
  346. package/front_end/third_party/web-vitals/package/src/lib/initMetric.ts +24 -11
  347. package/front_end/third_party/web-vitals/package/src/lib/initUnique.ts +12 -4
  348. package/front_end/third_party/web-vitals/package/src/lib/observe.ts +26 -5
  349. package/front_end/third_party/web-vitals/package/src/lib/polyfills/interactionCountPolyfill.ts +1 -1
  350. package/front_end/third_party/web-vitals/package/src/lib/softNavs.ts +48 -0
  351. package/front_end/third_party/web-vitals/package/src/lib/whenIdleOrHidden.ts +12 -4
  352. package/front_end/third_party/web-vitals/package/src/onCLS.ts +75 -18
  353. package/front_end/third_party/web-vitals/package/src/onFCP.ts +66 -7
  354. package/front_end/third_party/web-vitals/package/src/onINP.ts +100 -39
  355. package/front_end/third_party/web-vitals/package/src/onLCP.ts +169 -34
  356. package/front_end/third_party/web-vitals/package/src/onTTFB.ts +50 -13
  357. package/front_end/third_party/web-vitals/package/src/types/base.ts +31 -10
  358. package/front_end/third_party/web-vitals/package/src/types/fcp.ts +1 -1
  359. package/front_end/third_party/web-vitals/package/src/types/inp.ts +14 -6
  360. package/front_end/third_party/web-vitals/package/src/types/lcp.ts +1 -1
  361. package/front_end/third_party/web-vitals/package/src/types/ttfb.ts +2 -2
  362. package/front_end/third_party/web-vitals/package/src/types.ts +32 -9
  363. package/front_end/third_party/web-vitals/patches/0001-Add-onEachInteraction-to-onINP-options.patch +11 -11
  364. package/front_end/third_party/web-vitals/rebuild.sh +2 -2
  365. package/front_end/third_party/web-vitals/web-vitals-tsconfig.json +2 -0
  366. package/front_end/ui/components/buttons/Button.ts +16 -0
  367. package/front_end/ui/components/dialogs/Dialog.ts +1 -1
  368. package/front_end/ui/components/highlighting/HighlightManager.ts +6 -1
  369. package/front_end/ui/components/highlighting/highlighting.ts +1 -1
  370. package/front_end/ui/components/icon_button/FileSourceIcon.ts +1 -1
  371. package/front_end/ui/components/linkifier/LinkifierImpl.ts +1 -1
  372. package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +2 -2
  373. package/front_end/ui/components/settings/SettingCheckbox.ts +12 -7
  374. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +2 -2
  375. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +6 -6
  376. package/front_end/ui/components/text_editor/javascript.ts +3 -1
  377. package/front_end/ui/components/tooltips/Tooltip.ts +1 -1
  378. package/front_end/ui/legacy/ContextMenu.ts +12 -2
  379. package/front_end/ui/legacy/ListControl.ts +1 -1
  380. package/front_end/ui/legacy/SelectMenu.docs.ts +17 -19
  381. package/front_end/ui/legacy/Toolbar.ts +4 -1
  382. package/front_end/ui/legacy/Treeoutline.ts +1 -1
  383. package/front_end/ui/legacy/components/color_picker/spectrum.css +1 -2
  384. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +1 -1
  385. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +50 -4
  386. package/front_end/ui/legacy/components/object_ui/JavaScriptREPL.ts +3 -1
  387. package/front_end/ui/legacy/components/perf_ui/ChartViewport.ts +4 -4
  388. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +8 -7
  389. package/front_end/ui/legacy/components/quick_open/CommandMenu.ts +14 -11
  390. package/front_end/ui/legacy/components/quick_open/QuickOpen.ts +1 -1
  391. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +15 -5
  392. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +4 -4
  393. package/front_end/ui/legacy/components/utils/Linkifier.ts +5 -1
  394. package/front_end/ui/lit/render.ts +1 -1
  395. package/front_end/ui/settings/SettingUIRegistration.ts +8 -3
  396. package/front_end/ui/visual_logging/KnownContextValues.ts +8 -0
  397. package/front_end/ui/visual_logging/LoggingEvents.ts +1 -1
  398. package/inspector_overlay/main.ts +1 -1
  399. package/mcp/mcp.ts +5 -4
  400. package/package.json +13 -13
  401. package/front_end/models/ai_assistance/AgentProject.ts +0 -261
  402. package/front_end/models/ai_assistance/agents/PatchAgent.ts +0 -306
  403. package/front_end/models/issues_manager/CheckFormsIssuesTrigger.ts +0 -45
  404. package/front_end/models/text_utils/text_utils.ts +0 -5
  405. package/front_end/panels/ai_assistance/PatchWidget.ts +0 -867
  406. package/front_end/panels/ai_assistance/SelectWorkspaceDialog.ts +0 -368
  407. package/front_end/panels/ai_assistance/selectWorkspaceDialog.css +0 -92
@@ -1,12 +1,14 @@
1
1
  interface PerformanceEntryMap {
2
2
  'event': PerformanceEventTiming[];
3
3
  'first-input': PerformanceEventTiming[];
4
+ 'interaction-contentful-paint': InteractionContentfulPaint[];
4
5
  'layout-shift': LayoutShift[];
5
6
  'largest-contentful-paint': LargestContentfulPaint[];
6
7
  'long-animation-frame': PerformanceLongAnimationFrameTiming[];
7
8
  'paint': PerformancePaintTiming[];
8
9
  'navigation': PerformanceNavigationTiming[];
9
10
  'resource': PerformanceResourceTiming[];
11
+ 'soft-navigation': PerformanceSoftNavigation[];
10
12
  }
11
13
  /**
12
14
  * Takes a performance entry type and a callback function, and creates a
@@ -16,5 +18,5 @@ interface PerformanceEntryMap {
16
18
  * This function also feature-detects entry support and wraps the logic in a
17
19
  * try/catch to avoid errors in unsupporting browsers.
18
20
  */
19
- export declare const observe: <K extends keyof PerformanceEntryMap>(type: K, callback: (entries: PerformanceEntryMap[K]) => void, opts?: PerformanceObserverInit) => PerformanceObserver | undefined;
21
+ export declare const observe: <K extends keyof PerformanceEntryMap>(types: K[], callback: (entries: Array<PerformanceEntryMap[K][number]>) => void, opts?: PerformanceObserverInit) => PerformanceObserver | undefined;
20
22
  export {};
@@ -21,18 +21,33 @@
21
21
  * This function also feature-detects entry support and wraps the logic in a
22
22
  * try/catch to avoid errors in unsupporting browsers.
23
23
  */
24
- export const observe = (type, callback, opts = {}) => {
24
+ export const observe = (types, callback, opts = {}) => {
25
25
  try {
26
- if (PerformanceObserver.supportedEntryTypes.includes(type)) {
26
+ const supportedTypes = types.filter((t) => PerformanceObserver.supportedEntryTypes.includes(t));
27
+ if (supportedTypes.length > 0) {
27
28
  const po = new PerformanceObserver((list) => {
28
29
  // Delay by a microtask to workaround a bug in Safari where the
29
30
  // callback is invoked immediately, rather than in a separate task.
30
31
  // See: https://github.com/GoogleChrome/web-vitals/issues/277
31
32
  queueMicrotask(() => {
32
- callback(list.getEntries());
33
+ const entries = list.getEntries();
34
+ // When observing more than one entry type, entries from different
35
+ // types can be delivered out of order, so sort by end time
36
+ // (startTime + duration) to ensure they're in the right order.
37
+ // See: https://github.com/w3c/performance-timeline/issues/224
38
+ if (supportedTypes.length > 1) {
39
+ entries.sort((a, b) => {
40
+ const scoreA = a.startTime + a.duration;
41
+ const scoreB = b.startTime + b.duration;
42
+ return scoreA - scoreB;
43
+ });
44
+ }
45
+ callback(entries);
33
46
  });
34
47
  });
35
- po.observe({ type, buffered: true, ...opts });
48
+ for (const t of supportedTypes) {
49
+ po.observe({ type: t, buffered: true, ...opts });
50
+ }
36
51
  return po;
37
52
  }
38
53
  }
@@ -42,7 +42,7 @@ export const getInteractionCount = () => {
42
42
  export const initInteractionCountPolyfill = () => {
43
43
  if ('interactionCount' in performance || po)
44
44
  return;
45
- po = observe('event', updateEstimate, {
45
+ po = observe(['event'], updateEstimate, {
46
46
  durationThreshold: 0,
47
47
  });
48
48
  };
@@ -0,0 +1,3 @@
1
+ import type { ReportOpts } from '../types.js';
2
+ export declare const checkSoftNavsEnabled: (opts?: ReportOpts) => boolean | undefined;
3
+ export declare const storeSoftNavEntry: (map: Map<number, PerformanceSoftNavigation>, entry: PerformanceSoftNavigation) => void;
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Copyright 2023 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ export const checkSoftNavsEnabled = (opts) => {
17
+ return (PerformanceObserver.supportedEntryTypes.includes('soft-navigation') &&
18
+ // Older implementations expose the value as an attribute rather than the
19
+ // method. We only support the newer method as that was what was launched
20
+ // to stable unflagged.
21
+ typeof globalThis.PerformanceSoftNavigation?.prototype
22
+ ?.getLargestInteractionContentfulPaint === 'function' &&
23
+ opts &&
24
+ opts.reportSoftNavs);
25
+ };
26
+ // Stores a soft navigation entry keyed by its navigationId, keeping only
27
+ // the 2 most recent entries so the map cannot grow unbounded.
28
+ export const storeSoftNavEntry = (map, entry) => {
29
+ map.set(entry.navigationId, entry);
30
+ // Clean up older entries to prevent memory leaks, keeping only
31
+ // the 2 most recent entries.
32
+ if (map.size > 2) {
33
+ const firstKey = map.keys().next().value;
34
+ if (firstKey !== undefined) {
35
+ map.delete(firstKey);
36
+ }
37
+ }
38
+ };
@@ -19,6 +19,10 @@ import { runOnce } from './runOnce.js';
19
19
  * if the browser's visibility state is (or becomes) hidden.
20
20
  */
21
21
  export const whenIdleOrHidden = (cb) => {
22
+ // Cap the requestIdleCallback to 1 sec for very busy apps
23
+ // https://github.com/GoogleChrome/web-vitals/issues/754
24
+ // If not using rIC, then the setTimeout timeout should be 0
25
+ const timeout = 'requestIdleCallback' in globalThis ? 1000 : 0;
22
26
  const rIC = globalThis.requestIdleCallback || setTimeout;
23
27
  const cIC = globalThis.cancelIdleCallback || clearTimeout;
24
28
  // If the document is hidden, run the callback immediately, otherwise
@@ -37,6 +41,6 @@ export const whenIdleOrHidden = (cb) => {
37
41
  idleHandle = rIC(() => {
38
42
  removeEventListener('visibilitychange', onHidden, { capture: true });
39
43
  wrappedCb();
40
- });
44
+ }, { timeout: timeout });
41
45
  }
42
46
  };
@@ -1,4 +1,4 @@
1
- import { CLSMetric, MetricRatingThresholds, ReportOpts } from './types.js';
1
+ import type { CLSMetric, MetricRatingThresholds, ReportOpts } from './types.js';
2
2
  /** Thresholds for CLS. See https://web.dev/articles/cls#what_is_a_good_cls_score */
3
3
  export declare const CLSThresholds: MetricRatingThresholds;
4
4
  /**
@@ -13,16 +13,17 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { onBFCacheRestore } from './lib/bfcache.js';
16
+ import { getBFCacheRestoreTime, onBFCacheRestore } from './lib/bfcache.js';
17
17
  import { bindReporter } from './lib/bindReporter.js';
18
18
  import { doubleRAF } from './lib/doubleRAF.js';
19
+ import { getVisibilityWatcher } from './lib/getVisibilityWatcher.js';
19
20
  import { initMetric } from './lib/initMetric.js';
20
21
  import { initUnique } from './lib/initUnique.js';
21
22
  import { LayoutShiftManager } from './lib/LayoutShiftManager.js';
22
23
  import { observe } from './lib/observe.js';
24
+ import { checkSoftNavsEnabled } from './lib/softNavs.js';
23
25
  import { runOnce } from './lib/runOnce.js';
24
26
  import { onFCP } from './onFCP.js';
25
- import { getVisibilityWatcher } from './lib/getVisibilityWatcher.js';
26
27
  /** Thresholds for CLS. See https://web.dev/articles/cls#what_is_a_good_cls_score */
27
28
  export const CLSThresholds = [0.1, 0.25];
28
29
  /**
@@ -54,19 +55,39 @@ export const onCLS = (onReport, opts = {}) => {
54
55
  let metric = initMetric('CLS', 0);
55
56
  let report;
56
57
  const layoutShiftManager = initUnique(opts, LayoutShiftManager);
57
- const handleEntries = (entries) => {
58
- for (const entry of entries) {
59
- layoutShiftManager._processEntry(entry);
60
- }
58
+ const initNewCLSMetric = (navigationType, navigationId, navigationInteractionId, navigationURL, navigationStartTime) => {
59
+ metric = initMetric('CLS', 0, navigationType, navigationId, navigationInteractionId, navigationURL, navigationStartTime);
60
+ layoutShiftManager._sessionValue = 0;
61
+ report = bindReporter(onReport, metric, CLSThresholds, opts.reportAllChanges);
62
+ };
63
+ const updateAndReportMetric = (forceReport = false) => {
61
64
  // If the current session value is larger than the current CLS value,
62
65
  // update CLS and the entries contributing to it.
63
66
  if (layoutShiftManager._sessionValue > metric.value) {
64
67
  metric.value = layoutShiftManager._sessionValue;
65
68
  metric.entries = layoutShiftManager._sessionEntries;
66
- report();
67
69
  }
70
+ report(forceReport);
68
71
  };
69
- const po = observe('layout-shift', handleEntries);
72
+ const handleSoftNavEntry = (entry) => {
73
+ updateAndReportMetric(true);
74
+ initNewCLSMetric('soft-navigation', entry.navigationId, entry.interactionId, entry.name, entry.startTime);
75
+ };
76
+ const handleEntries = (entries) => {
77
+ for (const entry of entries) {
78
+ if (entry.entryType === 'soft-navigation') {
79
+ handleSoftNavEntry(entry);
80
+ continue;
81
+ }
82
+ layoutShiftManager._processEntry(entry);
83
+ }
84
+ updateAndReportMetric();
85
+ };
86
+ const types = ['layout-shift'];
87
+ if (checkSoftNavsEnabled(opts)) {
88
+ types.push('soft-navigation');
89
+ }
90
+ const po = observe(types, handleEntries);
70
91
  if (po) {
71
92
  report = bindReporter(onReport, metric, CLSThresholds, opts.reportAllChanges);
72
93
  visibilityWatcher.onHidden(() => {
@@ -76,9 +97,7 @@ export const onCLS = (onReport, opts = {}) => {
76
97
  // Only report after a bfcache restore if the `PerformanceObserver`
77
98
  // successfully registered.
78
99
  onBFCacheRestore(() => {
79
- layoutShiftManager._sessionValue = 0;
80
- metric = initMetric('CLS', 0);
81
- report = bindReporter(onReport, metric, CLSThresholds, opts.reportAllChanges);
100
+ initNewCLSMetric('back-forward-cache', metric.navigationId, metric.navigationInteractionId, metric.navigationURL, getBFCacheRestoreTime());
82
101
  doubleRAF(report);
83
102
  });
84
103
  // Queue a task to report (if nothing else triggers a report first).
@@ -1,4 +1,4 @@
1
- import { FCPMetric, MetricRatingThresholds, ReportOpts } from './types.js';
1
+ import type { FCPMetric, MetricRatingThresholds, ReportOpts } from './types.js';
2
2
  /** Thresholds for FCP. See https://web.dev/articles/fcp#what_is_a_good_fcp_score */
3
3
  export declare const FCPThresholds: MetricRatingThresholds;
4
4
  /**
@@ -13,13 +13,16 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { onBFCacheRestore } from './lib/bfcache.js';
17
16
  import { bindReporter } from './lib/bindReporter.js';
17
+ import { checkSoftNavsEnabled, storeSoftNavEntry } from './lib/softNavs.js';
18
18
  import { doubleRAF } from './lib/doubleRAF.js';
19
19
  import { getActivationStart } from './lib/getActivationStart.js';
20
20
  import { getVisibilityWatcher } from './lib/getVisibilityWatcher.js';
21
21
  import { initMetric } from './lib/initMetric.js';
22
+ import { initUnique } from './lib/initUnique.js';
23
+ import { FCPEntryManager } from './lib/FCPEntryManager.js';
22
24
  import { observe } from './lib/observe.js';
25
+ import { getBFCacheRestoreTime, onBFCacheRestore } from './lib/bfcache.js';
23
26
  import { whenActivated } from './lib/whenActivated.js';
24
27
  /** Thresholds for FCP. See https://web.dev/articles/fcp#what_is_a_good_fcp_score */
25
28
  export const FCPThresholds = [1800, 3000];
@@ -30,7 +33,12 @@ export const FCPThresholds = [1800, 3000];
30
33
  * value is a `DOMHighResTimeStamp`.
31
34
  */
32
35
  export const onFCP = (onReport, opts = {}) => {
36
+ const softNavsEnabled = checkSoftNavsEnabled(opts);
33
37
  whenActivated(() => {
38
+ // Create a new FCP entry manager for each page activation
39
+ // This allows us to track soft navigations separately
40
+ // needed when attribution is enabled.
41
+ const fcpEntryManager = initUnique(opts, FCPEntryManager);
34
42
  const visibilityWatcher = getVisibilityWatcher();
35
43
  let metric = initMetric('FCP');
36
44
  let report;
@@ -38,7 +46,7 @@ export const onFCP = (onReport, opts = {}) => {
38
46
  for (const entry of entries) {
39
47
  if (entry.name === 'first-contentful-paint') {
40
48
  po.disconnect();
41
- // Only report if the page wasn't hidden prior to the first paint.
49
+ // Only report if the page wasn't hidden prior to FCP.
42
50
  if (entry.startTime < visibilityWatcher.firstHiddenTime) {
43
51
  // The activationStart reference is used because FCP should be
44
52
  // relative to page activation rather than navigation start if the
@@ -46,18 +54,20 @@ export const onFCP = (onReport, opts = {}) => {
46
54
  // after the FCP, this time should be clamped at 0.
47
55
  metric.value = Math.max(entry.startTime - getActivationStart(), 0);
48
56
  metric.entries.push(entry);
57
+ metric.navigationId = entry.navigationId || metric.navigationId;
58
+ // FCP should only be reported once so can report right away
49
59
  report(true);
50
60
  }
51
61
  }
52
62
  }
53
63
  };
54
- const po = observe('paint', handleEntries);
64
+ const po = observe(['paint'], handleEntries);
55
65
  if (po) {
56
66
  report = bindReporter(onReport, metric, FCPThresholds, opts.reportAllChanges);
57
67
  // Only report after a bfcache restore if the `PerformanceObserver`
58
68
  // successfully registered or the `paint` entry exists.
59
69
  onBFCacheRestore((event) => {
60
- metric = initMetric('FCP');
70
+ metric = initMetric('FCP', -1, 'back-forward-cache', metric.navigationId, metric.navigationInteractionId, metric.navigationURL, getBFCacheRestoreTime());
61
71
  report = bindReporter(onReport, metric, FCPThresholds, opts.reportAllChanges);
62
72
  doubleRAF(() => {
63
73
  metric.value = performance.now() - event.timeStamp;
@@ -65,5 +75,27 @@ export const onFCP = (onReport, opts = {}) => {
65
75
  });
66
76
  });
67
77
  }
78
+ if (softNavsEnabled) {
79
+ // As first-contentful-paint is only reported once, we can handle soft
80
+ // navigations afterwards on their own for simplicity, as no need to
81
+ // observe both and sort the entries like for the other metrics
82
+ const handleSoftNavEntries = (entries) => {
83
+ entries.forEach((entry) => {
84
+ // Store the soft navigation entries in the entry manager so that
85
+ // they can be retrieved for attribution if necessary. This code
86
+ // is only used when attribution is enabled which sets the
87
+ // _softNavigationEntryMap.
88
+ if (fcpEntryManager._softNavigationEntryMap && entry.navigationId) {
89
+ storeSoftNavEntry(fcpEntryManager._softNavigationEntryMap, entry);
90
+ }
91
+ // Clamp FCP at 0. It should never be less, but better safe than sorry.
92
+ const FCPTime = Math.max((entry.presentationTime || entry.paintTime || 0) - entry.startTime, 0);
93
+ metric = initMetric('FCP', FCPTime, 'soft-navigation', entry.navigationId, entry.interactionId, entry.name, entry.startTime);
94
+ report = bindReporter(onReport, metric, FCPThresholds, opts.reportAllChanges);
95
+ report(true);
96
+ });
97
+ };
98
+ observe(['soft-navigation'], handleSoftNavEntries, opts);
99
+ }
68
100
  });
69
101
  };
@@ -1,4 +1,4 @@
1
- import { INPMetric, MetricRatingThresholds, INPReportOpts } from './types.js';
1
+ import type { INPMetric, MetricRatingThresholds, INPReportOpts } from './types.js';
2
2
  /** Thresholds for INP. See https://web.dev/articles/inp#what_is_a_good_inp_score */
3
3
  export declare const INPThresholds: MetricRatingThresholds;
4
4
  /**
@@ -13,12 +13,13 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { onBFCacheRestore } from './lib/bfcache.js';
16
+ import { getBFCacheRestoreTime, onBFCacheRestore } from './lib/bfcache.js';
17
17
  import { bindReporter } from './lib/bindReporter.js';
18
18
  import { initMetric } from './lib/initMetric.js';
19
19
  import { initUnique } from './lib/initUnique.js';
20
20
  import { InteractionManager } from './lib/InteractionManager.js';
21
21
  import { observe } from './lib/observe.js';
22
+ import { checkSoftNavsEnabled } from './lib/softNavs.js';
22
23
  import { initInteractionCountPolyfill } from './lib/polyfills/interactionCountPolyfill.js';
23
24
  import { whenActivated } from './lib/whenActivated.js';
24
25
  import { getVisibilityWatcher } from './lib/getVisibilityWatcher.js';
@@ -27,6 +28,12 @@ import { whenIdleOrHidden } from './lib/whenIdleOrHidden.js';
27
28
  export const INPThresholds = [200, 500];
28
29
  // The default `durationThreshold` used across this library for observing
29
30
  // `event` entries via PerformanceObserver.
31
+ // Event Timing entries have their durations rounded to the nearest 8ms,
32
+ // so a duration of 40ms would be any event that spans 2.5 or more frames
33
+ // at 60Hz. This threshold is chosen to strike a balance between usefulness
34
+ // and performance. Running this callback for any interaction that spans
35
+ // just one or two frames is likely not worth the insight that could be
36
+ // gained.
30
37
  const DEFAULT_DURATION_THRESHOLD = 40;
31
38
  /**
32
39
  * Calculates the [INP](https://web.dev/articles/inp) value for the current
@@ -70,7 +77,25 @@ export const onINP = (onReport, opts = {}) => {
70
77
  let metric = initMetric('INP');
71
78
  let report;
72
79
  const interactionManager = initUnique(opts, InteractionManager);
73
- const handleEntries = (entries) => {
80
+ const initNewINPMetric = (navigationType, navigationId, navigationInteractionId, navigationURL, navigationStartTime) => {
81
+ interactionManager._resetInteractions();
82
+ metric = initMetric('INP', -1, navigationType, navigationId, navigationInteractionId, navigationURL, navigationStartTime);
83
+ report = bindReporter(onReport, metric, INPThresholds, opts.reportAllChanges);
84
+ };
85
+ const updateINPMetric = () => {
86
+ const inp = interactionManager._estimateP98LongestInteraction(metric.navigationType);
87
+ if (inp && inp._latency !== metric.value) {
88
+ metric.value = inp._latency;
89
+ metric.entries = inp.entries;
90
+ report();
91
+ }
92
+ };
93
+ const handleSoftNavEntry = (entry) => {
94
+ updateINPMetric();
95
+ report(true);
96
+ initNewINPMetric('soft-navigation', entry.navigationId, entry.interactionId, entry.name, entry.startTime);
97
+ };
98
+ const handleEntries = (entries, forceReport = false) => {
74
99
  // Queue the `handleEntries()` callback in the next idle task.
75
100
  // This is needed to increase the chances that all event entries that
76
101
  // occurred between the user interaction and the next paint
@@ -79,40 +104,35 @@ export const onINP = (onReport, opts = {}) => {
79
104
  // 123+ that if rolled out fully may make this no longer necessary.
80
105
  whenIdleOrHidden(() => {
81
106
  for (const entry of entries) {
107
+ if (entry.entryType === 'soft-navigation') {
108
+ handleSoftNavEntry(entry);
109
+ continue;
110
+ }
82
111
  interactionManager._processEntry(entry);
83
112
  }
84
- const inp = interactionManager._estimateP98LongestInteraction();
85
- if (inp && inp._latency !== metric.value) {
86
- metric.value = inp._latency;
87
- metric.entries = inp.entries;
88
- report();
113
+ updateINPMetric();
114
+ if (forceReport) {
115
+ report(true);
89
116
  }
90
117
  });
91
118
  };
92
- const po = observe('event', handleEntries, {
93
- // Event Timing entries have their durations rounded to the nearest 8ms,
94
- // so a duration of 40ms would be any event that spans 2.5 or more frames
95
- // at 60Hz. This threshold is chosen to strike a balance between usefulness
96
- // and performance. Running this callback for any interaction that spans
97
- // just one or two frames is likely not worth the insight that could be
98
- // gained.
119
+ const types = ['event', 'first-input'];
120
+ if (checkSoftNavsEnabled(opts)) {
121
+ types.push('soft-navigation');
122
+ }
123
+ const po = observe(types, handleEntries, {
124
+ ...opts,
99
125
  durationThreshold: opts.durationThreshold ?? DEFAULT_DURATION_THRESHOLD,
100
126
  });
101
127
  report = bindReporter(onReport, metric, INPThresholds, opts.reportAllChanges);
102
128
  if (po) {
103
- // Also observe entries of type `first-input`. This is useful in cases
104
- // where the first interaction is less than the `durationThreshold`.
105
- po.observe({ type: 'first-input', buffered: true });
106
129
  visibilityWatcher.onHidden(() => {
107
- handleEntries(po.takeRecords());
108
- report(true);
130
+ handleEntries(po.takeRecords(), true);
109
131
  });
110
132
  // Only report after a bfcache restore if the `PerformanceObserver`
111
133
  // successfully registered.
112
134
  onBFCacheRestore(() => {
113
- interactionManager._resetInteractions();
114
- metric = initMetric('INP');
115
- report = bindReporter(onReport, metric, INPThresholds, opts.reportAllChanges);
135
+ initNewINPMetric('back-forward-cache', metric.navigationId, metric.navigationInteractionId, metric.navigationURL, getBFCacheRestoreTime());
116
136
  });
117
137
  }
118
138
  });
@@ -1,4 +1,4 @@
1
- import { LCPMetric, MetricRatingThresholds, ReportOpts } from './types.js';
1
+ import type { LCPMetric, MetricRatingThresholds, ReportOpts } from './types.js';
2
2
  /** Thresholds for LCP. See https://web.dev/articles/lcp#what_is_a_good_lcp_score */
3
3
  export declare const LCPThresholds: MetricRatingThresholds;
4
4
  /**
@@ -14,15 +14,15 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { LCPEntryManager } from './lib/LCPEntryManager.js';
17
- import { onBFCacheRestore } from './lib/bfcache.js';
17
+ import { getBFCacheRestoreTime, onBFCacheRestore } from './lib/bfcache.js';
18
18
  import { bindReporter } from './lib/bindReporter.js';
19
19
  import { doubleRAF } from './lib/doubleRAF.js';
20
20
  import { getActivationStart } from './lib/getActivationStart.js';
21
+ import { checkSoftNavsEnabled, storeSoftNavEntry } from './lib/softNavs.js';
21
22
  import { getVisibilityWatcher } from './lib/getVisibilityWatcher.js';
22
23
  import { initMetric } from './lib/initMetric.js';
23
24
  import { initUnique } from './lib/initUnique.js';
24
25
  import { observe } from './lib/observe.js';
25
- import { runOnce } from './lib/runOnce.js';
26
26
  import { whenActivated } from './lib/whenActivated.js';
27
27
  import { whenIdleOrHidden } from './lib/whenIdleOrHidden.js';
28
28
  /** Thresholds for LCP. See https://web.dev/articles/lcp#what_is_a_good_lcp_score */
@@ -39,72 +39,151 @@ export const LCPThresholds = [2500, 4000];
39
39
  * been determined.
40
40
  */
41
41
  export const onLCP = (onReport, opts = {}) => {
42
+ // As InteractionContentfulPaint entries used by soft navs can emit after
43
+ // LCP is finalized, we need a flag to know to ignore them.
44
+ let isFinalized = false;
45
+ const softNavsEnabled = checkSoftNavsEnabled(opts);
42
46
  whenActivated(() => {
43
- const visibilityWatcher = getVisibilityWatcher();
47
+ let visibilityWatcher = getVisibilityWatcher();
44
48
  let metric = initMetric('LCP');
45
49
  let report;
46
50
  const lcpEntryManager = initUnique(opts, LCPEntryManager);
51
+ const initNewLCPMetric = (navigation, navigationId, navigationInteractionId, navigationURL, navigationStartTime) => {
52
+ metric = initMetric('LCP', -1, navigation, navigationId, navigationInteractionId, navigationURL, navigationStartTime);
53
+ report = bindReporter(onReport, metric, LCPThresholds, opts.reportAllChanges);
54
+ // Reset the finalized flag
55
+ isFinalized = false;
56
+ // If it's a soft nav, then need to reset the visibilityWatcher
57
+ if (navigation === 'soft-navigation') {
58
+ visibilityWatcher = getVisibilityWatcher(true);
59
+ }
60
+ };
61
+ const handleSoftNavEntry = (entry) => {
62
+ if (lcpEntryManager._softNavigationEntryMap && entry.navigationId) {
63
+ storeSoftNavEntry(lcpEntryManager._softNavigationEntryMap, entry);
64
+ }
65
+ if (!isFinalized)
66
+ report(true);
67
+ initNewLCPMetric('soft-navigation', entry.navigationId, entry.interactionId, entry.name, entry.startTime);
68
+ // Soft Navs should contain the largest paint until now, so handle that
69
+ // as if it just happened, then listen for more.
70
+ // It can however be null in rare circumstances
71
+ // (see https://github.com/GoogleChrome/web-vitals/issues/725)
72
+ const largestInteractionContentfulPaint = entry.getLargestInteractionContentfulPaint?.();
73
+ if (largestInteractionContentfulPaint) {
74
+ handleEntries([largestInteractionContentfulPaint]);
75
+ }
76
+ };
47
77
  const handleEntries = (entries) => {
48
- // If reportAllChanges is set then call this function for each entry,
49
- // otherwise only consider the last one.
50
- if (!opts.reportAllChanges) {
78
+ // If reportAllChanges is set or soft navs is enabled then call this
79
+ // function for each entry, otherwise only consider the last one.
80
+ if (!opts.reportAllChanges && !softNavsEnabled) {
51
81
  entries = entries.slice(-1);
52
82
  }
53
83
  for (const entry of entries) {
54
- lcpEntryManager._processEntry(entry);
55
- // Only report if the page wasn't hidden prior to LCP.
56
- if (entry.startTime < visibilityWatcher.firstHiddenTime) {
84
+ if (!entry)
85
+ continue;
86
+ if (entry.entryType === 'soft-navigation') {
87
+ handleSoftNavEntry(entry);
88
+ continue;
89
+ }
90
+ let value = 0;
91
+ let metricEntries = [];
92
+ let renderTime = entry.startTime;
93
+ if (entry.entryType === 'largest-contentful-paint') {
57
94
  // The startTime attribute returns the value of the renderTime if it is
58
95
  // not 0, and the value of the loadTime otherwise. The activationStart
59
96
  // reference is used because LCP should be relative to page activation
60
97
  // rather than navigation start if the page was prerendered. But in cases
61
98
  // where `activationStart` occurs after the LCP, this time should be
62
99
  // clamped at 0.
63
- metric.value = Math.max(entry.startTime - getActivationStart(), 0);
64
- metric.entries = [entry];
100
+ value = Math.max(entry.startTime - getActivationStart(), 0);
101
+ lcpEntryManager._processEntry(entry);
102
+ metricEntries = [entry];
103
+ }
104
+ else if (entry.entryType === 'interaction-contentful-paint') {
105
+ const ICPEntry = entry;
106
+ // InteractionContentfulPaints should only happen after a
107
+ // PerformanceSoftNavigation so the metric should have been set
108
+ // with a non-zero navigationId mapping to a soft nav.
109
+ if (!metric.navigationId)
110
+ continue;
111
+ // Ignore interactions not for this soft nav
112
+ // (either paints that have bled into this interaction or paints when
113
+ // we should have already finalized)
114
+ if ('interactionId' in ICPEntry &&
115
+ ICPEntry.interactionId != metric.navigationInteractionId) {
116
+ continue;
117
+ }
118
+ renderTime = ICPEntry.largestContentfulPaint?.renderTime || 0;
119
+ // Paints should never be less than 0 but add cap just in case
120
+ value = Math.max(renderTime - entry.startTime, 0);
121
+ if (ICPEntry.largestContentfulPaint) {
122
+ lcpEntryManager._processEntry(ICPEntry.largestContentfulPaint);
123
+ metricEntries = [ICPEntry.largestContentfulPaint];
124
+ }
125
+ }
126
+ // Only report if the page wasn't hidden prior to LCP.
127
+ if (renderTime < visibilityWatcher.firstHiddenTime) {
128
+ metric.value = value;
129
+ metric.entries = metricEntries;
65
130
  report();
66
131
  }
67
132
  }
68
133
  };
69
- const po = observe('largest-contentful-paint', handleEntries);
134
+ const types = ['largest-contentful-paint'];
135
+ if (softNavsEnabled) {
136
+ types.push('interaction-contentful-paint', 'soft-navigation');
137
+ }
138
+ const po = observe(types, handleEntries);
70
139
  if (po) {
71
140
  report = bindReporter(onReport, metric, LCPThresholds, opts.reportAllChanges);
72
- // Ensure this logic only runs once, since it can be triggered from
73
- // any of three different event listeners below.
74
- const stopListening = runOnce(() => {
75
- handleEntries(po.takeRecords());
76
- po.disconnect();
77
- report(true);
78
- });
79
- // Need a separate wrapper to ensure the `runOnce` function above is
80
- // common for all three functions
81
- const stopListeningWrapper = (event) => {
82
- if (event.isTrusted) {
141
+ const finalizeEventTypes = ['keydown', 'click', 'visibilitychange'];
142
+ const finalizeLCP = (event) => {
143
+ if (event.isTrusted && !isFinalized) {
83
144
  // Wrap the listener in an idle callback so it's run in a separate
84
145
  // task to reduce potential INP impact.
85
146
  // https://github.com/GoogleChrome/web-vitals/issues/383
86
- whenIdleOrHidden(stopListening);
87
- removeEventListener(event.type, stopListeningWrapper, {
88
- capture: true,
147
+ const metricIdToFinalize = metric.id;
148
+ whenIdleOrHidden(() => {
149
+ if (!isFinalized) {
150
+ if (!softNavsEnabled) {
151
+ // Do some clean up since these won't be needed anymore.
152
+ po.disconnect();
153
+ for (const type of finalizeEventTypes) {
154
+ removeEventListener(type, finalizeLCP, { capture: true });
155
+ }
156
+ }
157
+ // As this is in a whenIdleOrHidden check, whether we're still
158
+ // on the metric you meant to finalize, and ignore if we've moved
159
+ // on in the meantime.
160
+ if (metricIdToFinalize === metric.id) {
161
+ isFinalized = true;
162
+ report(true);
163
+ }
164
+ }
89
165
  });
90
166
  }
91
167
  };
92
- // Stop listening after input or visibilitychange.
168
+ // Finalize the current LCP after input or visibilitychange.
169
+ // Although the browser will automatically stop emitting entries in these
170
+ // cases, we don't know it's finalized, so we track to allow early report.
93
171
  // Note: while scrolling is an input that stops LCP observation, it's
94
172
  // unreliable since it can be programmatically generated.
95
173
  // See: https://github.com/GoogleChrome/web-vitals/issues/75
96
- for (const type of ['keydown', 'click', 'visibilitychange']) {
97
- addEventListener(type, stopListeningWrapper, {
174
+ for (const type of finalizeEventTypes) {
175
+ addEventListener(type, finalizeLCP, {
98
176
  capture: true,
99
177
  });
100
178
  }
101
179
  // Only report after a bfcache restore if the `PerformanceObserver`
102
180
  // successfully registered.
103
181
  onBFCacheRestore((event) => {
104
- metric = initMetric('LCP');
182
+ initNewLCPMetric('back-forward-cache', metric.navigationId, metric.navigationInteractionId, metric.navigationURL, getBFCacheRestoreTime());
105
183
  report = bindReporter(onReport, metric, LCPThresholds, opts.reportAllChanges);
106
184
  doubleRAF(() => {
107
185
  metric.value = performance.now() - event.timeStamp;
186
+ isFinalized = true;
108
187
  report(true);
109
188
  });
110
189
  });