chrome-devtools-frontend 1.0.1526630 → 1.0.1529186

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 (339) hide show
  1. package/docs/ui_engineering.md +159 -0
  2. package/eslint.config.mjs +6 -1
  3. package/front_end/core/host/UserMetrics.ts +2 -1
  4. package/front_end/core/i18n/i18nImpl.ts +6 -1
  5. package/front_end/core/protocol_client/protocol_client.ts +1 -1
  6. package/front_end/core/root/Runtime.ts +38 -4
  7. package/front_end/core/sdk/CSSMatchedStyles.ts +50 -7
  8. package/front_end/core/sdk/CSSRule.ts +35 -6
  9. package/front_end/core/sdk/Connections.ts +2 -1
  10. package/front_end/core/sdk/DOMModel.ts +4 -0
  11. package/front_end/core/sdk/DebuggerModel.ts +5 -1
  12. package/front_end/core/sdk/NetworkManager.ts +267 -34
  13. package/front_end/core/sdk/PreloadingModel.ts +82 -17
  14. package/front_end/core/sdk/RehydratingConnection.snapshot.txt +1 -1
  15. package/front_end/core/sdk/RehydratingConnection.ts +29 -4
  16. package/front_end/core/sdk/ScopeTreeCache.ts +8 -3
  17. package/front_end/core/sdk/SourceMap.ts +41 -11
  18. package/front_end/core/sdk/SourceMapManager.ts +13 -2
  19. package/front_end/core/sdk/SourceMapScopesInfo.ts +49 -2
  20. package/front_end/core/sdk/TargetManager.ts +0 -22
  21. package/front_end/core/sdk/TraceObject.ts +8 -7
  22. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +81 -0
  23. package/front_end/entrypoints/inspector_main/InspectorMain.ts +3 -1
  24. package/front_end/entrypoints/main/GlobalAiButton.ts +1 -0
  25. package/front_end/entrypoints/main/MainImpl.ts +42 -28
  26. package/front_end/generated/InspectorBackendCommands.js +3 -2
  27. package/front_end/generated/SupportedCSSProperties.js +2 -0
  28. package/front_end/generated/protocol.ts +17 -3
  29. package/front_end/models/ai_assistance/BuiltInAi.ts +111 -0
  30. package/front_end/models/ai_assistance/ConversationHandler.ts +15 -14
  31. package/front_end/models/ai_assistance/ai_assistance.ts +53 -24
  32. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +105 -0
  33. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +6 -1
  34. package/front_end/models/extensions/ExtensionView.ts +3 -0
  35. package/front_end/models/javascript_metadata/NativeFunctions.js +31 -27
  36. package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +31 -29
  37. package/front_end/models/persistence/NetworkPersistenceManager.ts +3 -5
  38. package/front_end/models/persistence/PersistenceImpl.ts +0 -5
  39. package/front_end/models/persistence/persistence-meta.ts +0 -31
  40. package/front_end/models/persistence/persistence.ts +0 -6
  41. package/front_end/models/source_map_scopes/NamesResolver.ts +5 -11
  42. package/front_end/models/stack_trace/Trie.ts +9 -0
  43. package/front_end/models/trace/lantern/types/Lantern.ts +1 -1
  44. package/front_end/panels/accessibility/AXBreadcrumbsPane.ts +1 -0
  45. package/front_end/panels/accessibility/AccessibilitySidebarView.ts +1 -0
  46. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +120 -113
  47. package/front_end/panels/ai_assistance/PatchWidget.ts +9 -8
  48. package/front_end/panels/ai_assistance/SelectWorkspaceDialog.ts +2 -0
  49. package/front_end/panels/ai_assistance/components/ChatView.ts +29 -29
  50. package/front_end/panels/ai_assistance/components/UserActionRow.ts +1 -0
  51. package/front_end/panels/animation/AnimationTimeline.ts +1 -0
  52. package/front_end/panels/application/CookieItemsView.ts +1 -0
  53. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  54. package/front_end/panels/application/ServiceWorkerCacheViews.ts +2 -0
  55. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +11 -5
  56. package/front_end/panels/application/preloading/components/PreloadingMismatchedHeadersGrid.ts +2 -2
  57. package/front_end/panels/application/preloading/components/PreloadingString.ts +7 -5
  58. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +22 -10
  59. package/front_end/panels/changes/CombinedDiffView.ts +1 -0
  60. package/front_end/{models/persistence → panels/common}/PersistenceUtils.ts +15 -17
  61. package/front_end/panels/common/common.ts +1 -0
  62. package/front_end/panels/console/ConsoleInsightTeaser.ts +369 -0
  63. package/front_end/panels/console/ConsolePanel.ts +2 -0
  64. package/front_end/panels/console/ConsolePrompt.ts +12 -2
  65. package/front_end/panels/console/ConsoleSidebar.ts +1 -1
  66. package/front_end/panels/console/ConsoleView.ts +12 -0
  67. package/front_end/panels/console/ConsoleViewMessage.ts +44 -0
  68. package/front_end/panels/{explain → console}/PromptBuilder.ts +12 -7
  69. package/front_end/panels/console/console-meta.ts +14 -0
  70. package/front_end/panels/console/console.ts +6 -0
  71. package/front_end/panels/console/consoleInsightTeaser.css +83 -0
  72. package/front_end/panels/coverage/CoverageListView.ts +29 -11
  73. package/front_end/panels/coverage/CoverageView.ts +292 -284
  74. package/front_end/panels/coverage/coverageView.css +17 -0
  75. package/front_end/panels/elements/ComputedStyleWidget.ts +1 -0
  76. package/front_end/panels/elements/LayoutPane.ts +1 -0
  77. package/front_end/panels/elements/NodeStackTraceWidget.ts +1 -0
  78. package/front_end/panels/elements/StylePropertyTreeElement.ts +5 -1
  79. package/front_end/panels/elements/stylePropertiesTreeOutline.css +17 -0
  80. package/front_end/panels/emulation/DeviceModeView.ts +2 -0
  81. package/front_end/panels/explain/ActionDelegate.ts +4 -2
  82. package/front_end/panels/explain/components/ConsoleInsight.ts +14 -12
  83. package/front_end/panels/explain/explain-meta.ts +7 -0
  84. package/front_end/panels/explain/explain.ts +0 -1
  85. package/front_end/panels/js_timeline/js_timeline-meta.ts +1 -1
  86. package/front_end/panels/layer_viewer/Layers3DView.ts +2 -0
  87. package/front_end/panels/lighthouse/LighthouseReportSelector.ts +1 -0
  88. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +1 -0
  89. package/front_end/panels/media/MainView.ts +1 -0
  90. package/front_end/panels/media/TickingFlameChart.ts +2 -0
  91. package/front_end/panels/network/BlockedURLsPane.ts +237 -108
  92. package/front_end/panels/network/EventSourceMessagesView.ts +1 -0
  93. package/front_end/panels/network/NetworkItemView.ts +1 -0
  94. package/front_end/panels/network/NetworkLogView.ts +9 -7
  95. package/front_end/panels/network/NetworkOverview.ts +1 -0
  96. package/front_end/panels/network/RequestCookiesView.ts +1 -0
  97. package/front_end/panels/network/RequestHTMLView.ts +1 -0
  98. package/front_end/panels/network/RequestInitiatorView.ts +1 -0
  99. package/front_end/panels/network/RequestPayloadView.ts +1 -0
  100. package/front_end/panels/network/RequestPreviewView.ts +1 -0
  101. package/front_end/panels/network/RequestResponseView.ts +1 -0
  102. package/front_end/panels/network/RequestTimingView.ts +2 -0
  103. package/front_end/panels/network/ResourceDirectSocketChunkView.ts +1 -0
  104. package/front_end/panels/network/ResourceWebSocketFrameView.ts +1 -0
  105. package/front_end/panels/network/components/RequestHeadersView.ts +2 -0
  106. package/front_end/panels/network/components/RequestTrustTokensView.ts +2 -0
  107. package/front_end/panels/performance_monitor/PerformanceMonitor.ts +2 -0
  108. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +2 -0
  109. package/front_end/panels/profiler/HeapSnapshotView.ts +7 -0
  110. package/front_end/panels/profiler/IsolateSelector.ts +1 -0
  111. package/front_end/panels/profiler/LiveHeapProfileView.ts +1 -0
  112. package/front_end/panels/profiler/ProfileView.ts +1 -0
  113. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -0
  114. package/front_end/panels/recorder/RecorderPanel.ts +2 -0
  115. package/front_end/panels/screencast/ScreencastView.ts +1 -0
  116. package/front_end/panels/search/SearchView.ts +1 -0
  117. package/front_end/panels/settings/AISettingsTab.ts +3 -3
  118. package/front_end/{models/persistence → panels/settings}/EditFileSystemView.ts +3 -6
  119. package/front_end/panels/settings/WorkspaceSettingsTab.ts +4 -1
  120. package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +2 -2
  121. package/front_end/panels/settings/settings.ts +2 -0
  122. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +12 -0
  123. package/front_end/panels/sources/BreakpointsView.ts +1 -0
  124. package/front_end/panels/sources/DebuggerPlugin.ts +1 -0
  125. package/front_end/{models/persistence → panels/sources}/PersistenceActions.ts +8 -12
  126. package/front_end/panels/sources/TabbedEditorContainer.ts +2 -1
  127. package/front_end/panels/sources/UISourceCodeFrame.ts +17 -2
  128. package/front_end/panels/sources/sources-meta.ts +15 -0
  129. package/front_end/panels/sources/sources.ts +2 -0
  130. package/front_end/panels/timeline/README.md +2 -2
  131. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +1 -1
  132. package/front_end/panels/timeline/TimelineFlameChartView.ts +4 -3
  133. package/front_end/panels/timeline/TimelineLayersView.ts +1 -0
  134. package/front_end/panels/timeline/TimelinePaintProfilerView.ts +114 -37
  135. package/front_end/panels/timeline/TimelinePanel.ts +43 -62
  136. package/front_end/panels/timeline/TimelineTreeView.ts +1 -0
  137. package/front_end/panels/timeline/components/LiveMetricsView.ts +4 -8
  138. package/front_end/panels/timeline/components/Sidebar.ts +2 -0
  139. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
  140. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +7 -7
  141. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +1 -1
  142. package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +4 -4
  143. package/front_end/panels/utils/utils.ts +2 -1
  144. package/front_end/panels/web_audio/WebAudioView.ts +1 -0
  145. package/front_end/third_party/chromium/README.chromium +1 -1
  146. package/front_end/third_party/diff/diff_match_patch.js +1 -1
  147. package/front_end/third_party/lighthouse/README.chromium +2 -2
  148. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1530 -2426
  149. package/front_end/third_party/lighthouse/locales/ar-XB.json +107 -455
  150. package/front_end/third_party/lighthouse/locales/ar.json +107 -455
  151. package/front_end/third_party/lighthouse/locales/bg.json +96 -444
  152. package/front_end/third_party/lighthouse/locales/ca.json +96 -444
  153. package/front_end/third_party/lighthouse/locales/cs.json +96 -444
  154. package/front_end/third_party/lighthouse/locales/da.json +96 -444
  155. package/front_end/third_party/lighthouse/locales/de.json +96 -444
  156. package/front_end/third_party/lighthouse/locales/el.json +96 -444
  157. package/front_end/third_party/lighthouse/locales/en-GB.json +96 -444
  158. package/front_end/third_party/lighthouse/locales/en-US.json +116 -467
  159. package/front_end/third_party/lighthouse/locales/en-XA.json +93 -441
  160. package/front_end/third_party/lighthouse/locales/en-XL.json +116 -467
  161. package/front_end/third_party/lighthouse/locales/es-419.json +96 -444
  162. package/front_end/third_party/lighthouse/locales/es.json +96 -444
  163. package/front_end/third_party/lighthouse/locales/fi.json +96 -444
  164. package/front_end/third_party/lighthouse/locales/fil.json +96 -444
  165. package/front_end/third_party/lighthouse/locales/fr.json +96 -444
  166. package/front_end/third_party/lighthouse/locales/he.json +118 -466
  167. package/front_end/third_party/lighthouse/locales/hi.json +96 -444
  168. package/front_end/third_party/lighthouse/locales/hr.json +100 -448
  169. package/front_end/third_party/lighthouse/locales/hu.json +96 -444
  170. package/front_end/third_party/lighthouse/locales/id.json +96 -444
  171. package/front_end/third_party/lighthouse/locales/it.json +96 -444
  172. package/front_end/third_party/lighthouse/locales/ja.json +96 -444
  173. package/front_end/third_party/lighthouse/locales/ko.json +97 -445
  174. package/front_end/third_party/lighthouse/locales/lt.json +96 -444
  175. package/front_end/third_party/lighthouse/locales/lv.json +97 -445
  176. package/front_end/third_party/lighthouse/locales/nl.json +96 -444
  177. package/front_end/third_party/lighthouse/locales/no.json +96 -444
  178. package/front_end/third_party/lighthouse/locales/pl.json +96 -444
  179. package/front_end/third_party/lighthouse/locales/pt-PT.json +96 -444
  180. package/front_end/third_party/lighthouse/locales/pt.json +97 -445
  181. package/front_end/third_party/lighthouse/locales/ro.json +97 -445
  182. package/front_end/third_party/lighthouse/locales/ru.json +96 -444
  183. package/front_end/third_party/lighthouse/locales/sk.json +96 -444
  184. package/front_end/third_party/lighthouse/locales/sl.json +96 -444
  185. package/front_end/third_party/lighthouse/locales/sr-Latn.json +96 -444
  186. package/front_end/third_party/lighthouse/locales/sr.json +96 -444
  187. package/front_end/third_party/lighthouse/locales/sv.json +96 -444
  188. package/front_end/third_party/lighthouse/locales/ta.json +96 -444
  189. package/front_end/third_party/lighthouse/locales/te.json +97 -445
  190. package/front_end/third_party/lighthouse/locales/th.json +96 -444
  191. package/front_end/third_party/lighthouse/locales/tr.json +96 -444
  192. package/front_end/third_party/lighthouse/locales/uk.json +96 -444
  193. package/front_end/third_party/lighthouse/locales/vi.json +96 -444
  194. package/front_end/third_party/lighthouse/locales/zh-HK.json +96 -444
  195. package/front_end/third_party/lighthouse/locales/zh-TW.json +97 -445
  196. package/front_end/third_party/lighthouse/locales/zh.json +96 -444
  197. package/front_end/third_party/lighthouse/report/bundle.d.ts +8 -14
  198. package/front_end/third_party/lighthouse/report/bundle.js +10 -49
  199. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
  200. package/front_end/third_party/web-vitals/README.chromium +5 -8
  201. package/front_end/third_party/web-vitals/package/README.md +191 -152
  202. package/front_end/third_party/web-vitals/package/dist/modules/attribution/index.d.ts +0 -1
  203. package/front_end/third_party/web-vitals/package/dist/modules/attribution/index.js +0 -1
  204. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onCLS.d.ts +2 -2
  205. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onCLS.js +45 -26
  206. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.d.ts +2 -2
  207. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.js +3 -3
  208. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.d.ts +10 -10
  209. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +307 -206
  210. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.d.ts +2 -2
  211. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.js +69 -49
  212. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.d.ts +2 -2
  213. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.js +2 -2
  214. package/front_end/third_party/web-vitals/package/dist/modules/index.d.ts +0 -1
  215. package/front_end/third_party/web-vitals/package/dist/modules/index.js +0 -1
  216. package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.d.ts +33 -0
  217. package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.js +111 -0
  218. package/front_end/third_party/web-vitals/package/dist/modules/lib/LCPEntryManager.d.ts +4 -0
  219. package/front_end/third_party/web-vitals/package/dist/modules/{attribution/deprecated.js → lib/LCPEntryManager.js} +6 -7
  220. package/front_end/third_party/web-vitals/package/dist/modules/lib/LayoutShiftManager.d.ts +6 -0
  221. package/front_end/third_party/web-vitals/package/dist/modules/lib/LayoutShiftManager.js +44 -0
  222. package/front_end/third_party/web-vitals/package/dist/modules/lib/bindReporter.js +1 -1
  223. package/front_end/third_party/web-vitals/package/dist/modules/lib/generateUniqueID.js +1 -1
  224. package/front_end/third_party/web-vitals/package/dist/modules/lib/getActivationStart.js +1 -1
  225. package/front_end/third_party/web-vitals/package/dist/modules/lib/getNavigationEntry.js +5 -7
  226. package/front_end/third_party/web-vitals/package/dist/modules/lib/getSelector.d.ts +1 -1
  227. package/front_end/third_party/web-vitals/package/dist/modules/lib/getSelector.js +9 -12
  228. package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.d.ts +1 -0
  229. package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.js +52 -33
  230. package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.d.ts +0 -2
  231. package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.js +2 -2
  232. package/front_end/third_party/web-vitals/package/dist/modules/lib/initUnique.d.ts +6 -0
  233. package/front_end/third_party/web-vitals/package/dist/modules/{deprecated.js → lib/initUnique.js} +11 -4
  234. package/front_end/third_party/web-vitals/package/dist/modules/lib/observe.js +3 -6
  235. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/interactionCountPolyfill.js +6 -6
  236. package/front_end/third_party/web-vitals/package/dist/modules/lib/{whenIdle.d.ts → whenIdleOrHidden.d.ts} +1 -1
  237. package/front_end/third_party/web-vitals/package/dist/modules/lib/{whenIdle.js → whenIdleOrHidden.js} +10 -8
  238. package/front_end/third_party/web-vitals/package/dist/modules/onCLS.js +17 -35
  239. package/front_end/third_party/web-vitals/package/dist/modules/onFCP.js +3 -5
  240. package/front_end/third_party/web-vitals/package/dist/modules/onINP.d.ts +9 -7
  241. package/front_end/third_party/web-vitals/package/dist/modules/onINP.js +27 -19
  242. package/front_end/third_party/web-vitals/package/dist/modules/onLCP.js +33 -26
  243. package/front_end/third_party/web-vitals/package/dist/modules/onTTFB.js +2 -4
  244. package/front_end/third_party/web-vitals/package/dist/modules/types/base.d.ts +6 -5
  245. package/front_end/third_party/web-vitals/package/dist/modules/types/cls.d.ts +5 -3
  246. package/front_end/third_party/web-vitals/package/dist/modules/types/inp.d.ts +80 -33
  247. package/front_end/third_party/web-vitals/package/dist/modules/types/lcp.d.ts +6 -2
  248. package/front_end/third_party/web-vitals/package/dist/modules/types.d.ts +28 -4
  249. package/front_end/third_party/web-vitals/package/dist/modules/types.js +0 -1
  250. package/front_end/third_party/web-vitals/package/package.json +4 -10
  251. package/front_end/third_party/web-vitals/package/src/attribution/index.ts +0 -1
  252. package/front_end/third_party/web-vitals/package/src/attribution/onCLS.ts +58 -33
  253. package/front_end/third_party/web-vitals/package/src/attribution/onFCP.ts +4 -4
  254. package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +382 -258
  255. package/front_end/third_party/web-vitals/package/src/attribution/onLCP.ts +96 -69
  256. package/front_end/third_party/web-vitals/package/src/attribution/onTTFB.ts +3 -3
  257. package/front_end/third_party/web-vitals/package/src/index.ts +0 -1
  258. package/front_end/third_party/web-vitals/package/src/lib/InteractionManager.ts +146 -0
  259. package/front_end/third_party/web-vitals/package/src/{attribution/deprecated.ts → lib/LCPEntryManager.ts} +6 -9
  260. package/front_end/third_party/web-vitals/package/src/lib/LayoutShiftManager.ts +50 -0
  261. package/front_end/third_party/web-vitals/package/src/lib/bindReporter.ts +1 -1
  262. package/front_end/third_party/web-vitals/package/src/lib/generateUniqueID.ts +1 -1
  263. package/front_end/third_party/web-vitals/package/src/lib/getActivationStart.ts +1 -1
  264. package/front_end/third_party/web-vitals/package/src/lib/getNavigationEntry.ts +5 -8
  265. package/front_end/third_party/web-vitals/package/src/lib/getSelector.ts +12 -12
  266. package/front_end/third_party/web-vitals/package/src/lib/getVisibilityWatcher.ts +57 -35
  267. package/front_end/third_party/web-vitals/package/src/lib/initMetric.ts +2 -2
  268. package/front_end/third_party/web-vitals/package/src/{deprecated.ts → lib/initUnique.ts} +14 -8
  269. package/front_end/third_party/web-vitals/package/src/lib/observe.ts +3 -11
  270. package/front_end/third_party/web-vitals/package/src/lib/polyfills/interactionCountPolyfill.ts +12 -6
  271. package/front_end/third_party/web-vitals/package/src/lib/{whenIdle.ts → whenIdleOrHidden.ts} +10 -8
  272. package/front_end/third_party/web-vitals/package/src/onCLS.ts +17 -38
  273. package/front_end/third_party/web-vitals/package/src/onFCP.ts +3 -6
  274. package/front_end/third_party/web-vitals/package/src/onINP.ts +33 -28
  275. package/front_end/third_party/web-vitals/package/src/onLCP.ts +36 -29
  276. package/front_end/third_party/web-vitals/package/src/onTTFB.ts +2 -5
  277. package/front_end/third_party/web-vitals/package/src/types/base.ts +5 -5
  278. package/front_end/third_party/web-vitals/package/src/types/cls.ts +5 -3
  279. package/front_end/third_party/web-vitals/package/src/types/inp.ts +88 -33
  280. package/front_end/third_party/web-vitals/package/src/types/lcp.ts +6 -2
  281. package/front_end/third_party/web-vitals/package/src/types.ts +47 -4
  282. package/front_end/third_party/web-vitals/patches/0001-Add-onEachInteraction-to-onINP-options.patch +75 -0
  283. package/front_end/third_party/web-vitals/rebuild.sh +32 -18
  284. package/front_end/third_party/web-vitals/web-vitals-tsconfig.json +5 -10
  285. package/front_end/third_party/web-vitals/web-vitals.ts +0 -2
  286. package/front_end/ui/components/docs/console_insight/basic.ts +3 -2
  287. package/front_end/ui/components/legacy_wrapper/LegacyWrapper.ts +2 -0
  288. package/front_end/ui/components/text_editor/TextEditor.ts +0 -2
  289. package/front_end/ui/legacy/InspectorView.ts +2 -0
  290. package/front_end/ui/legacy/ListWidget.ts +2 -2
  291. package/front_end/ui/legacy/SplitWidget.ts +2 -0
  292. package/front_end/ui/legacy/TabbedPane.ts +1 -0
  293. package/front_end/ui/legacy/TargetCrashedScreen.ts +1 -0
  294. package/front_end/ui/legacy/UIUtils.ts +8 -19
  295. package/front_end/ui/legacy/ViewManager.ts +1 -0
  296. package/front_end/ui/legacy/components/color_picker/FormatPickerContextMenu.ts +7 -20
  297. package/front_end/ui/legacy/components/color_picker/Spectrum.ts +2 -0
  298. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +1 -0
  299. package/front_end/ui/legacy/components/inline_editor/BezierEditor.ts +1 -0
  300. package/front_end/ui/legacy/components/perf_ui/ChartViewport.ts +1 -0
  301. package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +1 -0
  302. package/front_end/ui/legacy/components/source_frame/FontView.ts +1 -0
  303. package/front_end/ui/legacy/components/source_frame/ImageView.ts +1 -0
  304. package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -0
  305. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +1 -0
  306. package/front_end/ui/legacy/components/source_frame/StreamingContentHexView.ts +2 -0
  307. package/front_end/ui/visual_logging/KnownContextValues.ts +25 -0
  308. package/mcp/README.md +7 -0
  309. package/mcp/mcp.ts +8 -0
  310. package/package.json +1 -1
  311. package/front_end/models/live-metrics/web-vitals-injected/OnEachInteraction.ts +0 -34
  312. package/front_end/third_party/web-vitals/package/attribution.d.ts +0 -16
  313. package/front_end/third_party/web-vitals/package/attribution.js +0 -18
  314. package/front_end/third_party/web-vitals/package/dist/modules/attribution/deprecated.d.ts +0 -7
  315. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFID.d.ts +0 -11
  316. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFID.js +0 -46
  317. package/front_end/third_party/web-vitals/package/dist/modules/deprecated.d.ts +0 -5
  318. package/front_end/third_party/web-vitals/package/dist/modules/lib/interactions.d.ts +0 -31
  319. package/front_end/third_party/web-vitals/package/dist/modules/lib/interactions.js +0 -107
  320. package/front_end/third_party/web-vitals/package/dist/modules/lib/onHidden.d.ts +0 -1
  321. package/front_end/third_party/web-vitals/package/dist/modules/lib/onHidden.js +0 -22
  322. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/firstInputPolyfill.d.ts +0 -7
  323. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/firstInputPolyfill.js +0 -147
  324. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/getFirstHiddenTimePolyfill.d.ts +0 -1
  325. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/getFirstHiddenTimePolyfill.js +0 -25
  326. package/front_end/third_party/web-vitals/package/dist/modules/onFID.d.ts +0 -13
  327. package/front_end/third_party/web-vitals/package/dist/modules/onFID.js +0 -70
  328. package/front_end/third_party/web-vitals/package/dist/modules/types/fid.d.ts +0 -46
  329. package/front_end/third_party/web-vitals/package/dist/modules/types/fid.js +0 -16
  330. package/front_end/third_party/web-vitals/package/src/attribution/onFID.ts +0 -62
  331. package/front_end/third_party/web-vitals/package/src/lib/interactions.ts +0 -139
  332. package/front_end/third_party/web-vitals/package/src/lib/onHidden.ts +0 -23
  333. package/front_end/third_party/web-vitals/package/src/lib/polyfills/firstInputPolyfill.ts +0 -174
  334. package/front_end/third_party/web-vitals/package/src/onFID.ts +0 -105
  335. package/front_end/third_party/web-vitals/package/src/types/fid.ts +0 -65
  336. package/front_end/ui/components/text_editor/textEditor.css +0 -18
  337. package/front_end/ui/legacy/inlineButton.css +0 -22
  338. /package/front_end/entrypoints/{rehydrated_devtools_app/rehydrated_devtools_app.ts → trace_app/trace_app.ts} +0 -0
  339. /package/front_end/{models/persistence → panels/settings}/editFileSystemView.css +0 -0
@@ -15,9 +15,10 @@
15
15
  */
16
16
  import { getLoadState } from '../lib/getLoadState.js';
17
17
  import { getSelector } from '../lib/getSelector.js';
18
- import { longestInteractionList, entryPreProcessingCallbacks, longestInteractionMap, } from '../lib/interactions.js';
18
+ import { initUnique } from '../lib/initUnique.js';
19
+ import { InteractionManager } from '../lib/InteractionManager.js';
19
20
  import { observe } from '../lib/observe.js';
20
- import { whenIdle } from '../lib/whenIdle.js';
21
+ import { whenIdleOrHidden } from '../lib/whenIdleOrHidden.js';
21
22
  import { onINP as unattributedOnINP } from '../onINP.js';
22
23
  // The maximum number of previous frames for which data is kept.
23
24
  // Storing data about previous frames is necessary to handle cases where event
@@ -27,212 +28,19 @@ import { onINP as unattributedOnINP } from '../onINP.js';
27
28
  // In most cases this out-of-order data is only off by a frame or two, so
28
29
  // keeping the most recent 50 should be more than sufficient.
29
30
  const MAX_PREVIOUS_FRAMES = 50;
30
- // A PerformanceObserver, observing new `long-animation-frame` entries.
31
- // If this variable is defined it means the browser supports LoAF.
32
- let loafObserver;
33
- // A list of LoAF entries that have been dispatched and could potentially
34
- // intersect with the INP candidate interaction. Note that periodically this
35
- // list is cleaned up and entries that are known to not match INP are removed.
36
- let pendingLoAFs = [];
37
- // An array of groups of all the event timing entries that occurred within a
38
- // particular frame. Note that periodically this array is cleaned up and entries
39
- // that are known to not match INP are removed.
40
- let pendingEntriesGroups = [];
41
- // The `processingEnd` time of most recently-processed event, chronologically.
42
- let latestProcessingEnd = 0;
43
- // A WeakMap to look up the event-timing-entries group of a given entry.
44
- // Note that this only maps from "important" entries: either the first input or
45
- // those with an `interactionId`.
46
- const entryToEntriesGroupMap = new WeakMap();
47
- // A mapping of interactionIds to the target Node.
48
- export const interactionTargetMap = new Map();
49
- // A reference to the idle task used to clean up entries from the above
50
- // variables. If the value is -1 it means no task is queue, and if it's
51
- // greater than -1 the value corresponds to the idle callback handle.
52
- let idleHandle = -1;
53
- /**
54
- * Adds new LoAF entries to the `pendingLoAFs` list.
55
- */
56
- const handleLoAFEntries = (entries) => {
57
- pendingLoAFs = pendingLoAFs.concat(entries);
58
- queueCleanup();
59
- };
60
- // Get a reference to the interaction target element in case it's removed
61
- // from the DOM later.
62
- const saveInteractionTarget = (entry) => {
63
- // TODO(b/376777343): Remove this modification when web-vitals.js doesn't retain DOM nodes anymore
64
- // Although it is useful for DevTools to retain nodes for diagnostic purposes, it is not preferable
65
- // to retaining Nodes in memory when the user does not expect them to.
66
- //
67
- // if (entry.interactionId &&
68
- // entry.target &&
69
- // !interactionTargetMap.has(entry.interactionId)) {
70
- // interactionTargetMap.set(entry.interactionId, entry.target);
71
- // }
72
- };
73
- /**
74
- * Groups entries that were presented within the same animation frame by
75
- * a common `renderTime`. This function works by referencing
76
- * `pendingEntriesGroups` and using an existing render time if one is found
77
- * (otherwise creating a new one). This function also adds all interaction
78
- * entries to an `entryToRenderTimeMap` WeakMap so that the "grouped" entries
79
- * can be looked up later.
80
- */
81
- const groupEntriesByRenderTime = (entry) => {
82
- const renderTime = entry.startTime + entry.duration;
83
- let group;
84
- latestProcessingEnd = Math.max(latestProcessingEnd, entry.processingEnd);
85
- // Iterate over all previous render times in reverse order to find a match.
86
- // Go in reverse since the most likely match will be at the end.
87
- for (let i = pendingEntriesGroups.length - 1; i >= 0; i--) {
88
- const potentialGroup = pendingEntriesGroups[i];
89
- // If a group's render time is within 8ms of the entry's render time,
90
- // assume they were part of the same frame and add it to the group.
91
- if (Math.abs(renderTime - potentialGroup.renderTime) <= 8) {
92
- group = potentialGroup;
93
- group.startTime = Math.min(entry.startTime, group.startTime);
94
- group.processingStart = Math.min(entry.processingStart, group.processingStart);
95
- group.processingEnd = Math.max(entry.processingEnd, group.processingEnd);
96
- group.entries.push(entry);
97
- break;
98
- }
99
- }
100
- // If there was no matching group, assume this is a new frame.
101
- if (!group) {
102
- group = {
103
- startTime: entry.startTime,
104
- processingStart: entry.processingStart,
105
- processingEnd: entry.processingEnd,
106
- renderTime,
107
- entries: [entry],
108
- };
109
- pendingEntriesGroups.push(group);
110
- }
111
- // Store the grouped render time for this entry for reference later.
112
- if (entry.interactionId || entry.entryType === 'first-input') {
113
- entryToEntriesGroupMap.set(entry, group);
114
- }
115
- queueCleanup();
116
- };
117
- const queueCleanup = () => {
118
- // Queue cleanup of entries that are not part of any INP candidates.
119
- if (idleHandle < 0) {
120
- idleHandle = whenIdle(cleanupEntries);
121
- }
122
- };
123
- const cleanupEntries = () => {
124
- // Delete any stored interaction target elements if they're not part of one
125
- // of the 10 longest interactions.
126
- if (interactionTargetMap.size > 10) {
127
- interactionTargetMap.forEach((_, key) => {
128
- if (!longestInteractionMap.has(key)) {
129
- interactionTargetMap.delete(key);
130
- }
131
- });
132
- }
133
- // Keep all render times that are part of a pending INP candidate or
134
- // that occurred within the 50 most recently-dispatched groups of events.
135
- const longestInteractionGroups = longestInteractionList.map((i) => {
136
- return entryToEntriesGroupMap.get(i.entries[0]);
137
- });
138
- const minIndex = pendingEntriesGroups.length - MAX_PREVIOUS_FRAMES;
139
- pendingEntriesGroups = pendingEntriesGroups.filter((group, index) => {
140
- if (index >= minIndex)
141
- return true;
142
- return longestInteractionGroups.includes(group);
143
- });
144
- // Keep all pending LoAF entries that either:
145
- // 1) intersect with entries in the newly cleaned up `pendingEntriesGroups`
146
- // 2) occur after the most recently-processed event entry (for up to MAX_PREVIOUS_FRAMES)
147
- const loafsToKeep = new Set();
148
- for (let i = 0; i < pendingEntriesGroups.length; i++) {
149
- const group = pendingEntriesGroups[i];
150
- getIntersectingLoAFs(group.startTime, group.processingEnd).forEach((loaf) => {
151
- loafsToKeep.add(loaf);
152
- });
153
- }
154
- const prevFrameIndexCutoff = pendingLoAFs.length - 1 - MAX_PREVIOUS_FRAMES;
155
- // Filter `pendingLoAFs` to preserve LoAF order.
156
- pendingLoAFs = pendingLoAFs.filter((loaf, index) => {
157
- if (loaf.startTime > latestProcessingEnd && index > prevFrameIndexCutoff) {
158
- return true;
159
- }
160
- return loafsToKeep.has(loaf);
161
- });
162
- // Reset the idle callback handle so it can be queued again.
163
- idleHandle = -1;
164
- };
165
- entryPreProcessingCallbacks.push(saveInteractionTarget, groupEntriesByRenderTime);
166
- const getIntersectingLoAFs = (start, end) => {
167
- const intersectingLoAFs = [];
168
- for (let i = 0, loaf; (loaf = pendingLoAFs[i]); i++) {
169
- // If the LoAF ends before the given start time, ignore it.
170
- if (loaf.startTime + loaf.duration < start)
171
- continue;
172
- // If the LoAF starts after the given end time, ignore it and all
173
- // subsequent pending LoAFs (because they're in time order).
174
- if (loaf.startTime > end)
175
- break;
176
- // Still here? If so this LoAF intersects with the interaction.
177
- intersectingLoAFs.push(loaf);
178
- }
179
- return intersectingLoAFs;
180
- };
181
- export const attributeINP = (metric) => {
182
- const firstEntry = metric.entries[0];
183
- const group = entryToEntriesGroupMap.get(firstEntry);
184
- const processingStart = firstEntry.processingStart;
185
- const processingEnd = group.processingEnd;
186
- // Sort the entries in processing time order.
187
- const processedEventEntries = group.entries.sort((a, b) => {
188
- return a.processingStart - b.processingStart;
189
- });
190
- const longAnimationFrameEntries = getIntersectingLoAFs(firstEntry.startTime, processingEnd);
191
- // The first interaction entry may not have a target defined, so use the
192
- // first one found in the entry list.
193
- // TODO: when the following bug is fixed just use `firstInteractionEntry`.
194
- // https://bugs.chromium.org/p/chromium/issues/detail?id=1367329
195
- // As a fallback, also check the interactionTargetMap (to account for
196
- // cases where the element is removed from the DOM before reporting happens).
197
- const firstEntryWithTarget = metric.entries.find((entry) => entry.target);
198
- const interactionTargetElement = (firstEntryWithTarget && firstEntryWithTarget.target) ||
199
- interactionTargetMap.get(firstEntry.interactionId);
200
- // Since entry durations are rounded to the nearest 8ms, we need to clamp
201
- // the `nextPaintTime` value to be higher than the `processingEnd` or
202
- // end time of any LoAF entry.
203
- const nextPaintTimeCandidates = [
204
- firstEntry.startTime + firstEntry.duration,
205
- processingEnd,
206
- ].concat(longAnimationFrameEntries.map((loaf) => loaf.startTime + loaf.duration));
207
- const nextPaintTime = Math.max.apply(Math, nextPaintTimeCandidates);
208
- const attribution = {
209
- interactionTarget: getSelector(interactionTargetElement),
210
- interactionTargetElement: interactionTargetElement,
211
- interactionType: firstEntry.name.startsWith('key') ? 'keyboard' : 'pointer',
212
- interactionTime: firstEntry.startTime,
213
- nextPaintTime: nextPaintTime,
214
- processedEventEntries: processedEventEntries,
215
- longAnimationFrameEntries: longAnimationFrameEntries,
216
- inputDelay: processingStart - firstEntry.startTime,
217
- processingDuration: processingEnd - processingStart,
218
- presentationDelay: Math.max(nextPaintTime - processingEnd, 0),
219
- loadState: getLoadState(firstEntry.startTime),
220
- };
221
- // Use Object.assign to set property to keep tsc happy.
222
- const metricWithAttribution = Object.assign(metric, { attribution });
223
- return metricWithAttribution;
224
- };
225
31
  /**
226
32
  * Calculates the [INP](https://web.dev/articles/inp) value for the current
227
33
  * page and calls the `callback` function once the value is ready, along with
228
34
  * the `event` performance entries reported for that interaction. The reported
229
35
  * value is a `DOMHighResTimeStamp`.
230
36
  *
231
- * A custom `durationThreshold` configuration option can optionally be passed to
232
- * control what `event-timing` entries are considered for INP reporting. The
233
- * default threshold is `40`, which means INP scores of less than 40 are
234
- * reported as 0. Note that this will not affect your 75th percentile INP value
235
- * unless that value is also less than 40 (well below the recommended
37
+ * A custom `durationThreshold` configuration option can optionally be passed
38
+ * to control what `event-timing` entries are considered for INP reporting. The
39
+ * default threshold is `40`, which means INP scores of less than 40 will not
40
+ * be reported. To avoid reporting no interactions in these cases, the library
41
+ * will fall back to the input delay of the first interaction. Note that this
42
+ * will not affect your 75th percentile INP value unless that value is also
43
+ * less than 40 (well below the recommended
236
44
  * [good](https://web.dev/articles/inp#what_is_a_good_inp_score) threshold).
237
45
  *
238
46
  * If the `reportAllChanges` configuration option is set to `true`, the
@@ -242,17 +50,310 @@ export const attributeINP = (metric) => {
242
50
  *
243
51
  * _**Important:** INP should be continually monitored for changes throughout
244
52
  * the entire lifespan of a page—including if the user returns to the page after
245
- * it's been hidden/backgrounded. However, since browsers often [will not fire
53
+ * it has been hidden/backgrounded. However, since browsers often [will not fire
246
54
  * additional callbacks once the user has backgrounded a
247
55
  * page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden),
248
56
  * `callback` is always called when the page's visibility state changes to
249
57
  * hidden. As a result, the `callback` function might be called multiple times
250
58
  * during the same page load._
251
59
  */
252
- export const onINP = (onReport, opts) => {
253
- if (!loafObserver) {
254
- loafObserver = observe('long-animation-frame', handleLoAFEntries);
60
+ export const onINP = (onReport, opts = {}) => {
61
+ // Clone the opts object to ensure it's unique, so we can initialize a
62
+ // single instance of the `InteractionManager` class that's shared only with
63
+ // this function invocation and the `unattributedOnINP()` invocation below
64
+ // (which is passed the same `opts` object).
65
+ opts = Object.assign({}, opts);
66
+ const interactionManager = initUnique(opts, InteractionManager);
67
+ // A list of LoAF entries that have been dispatched and could potentially
68
+ // intersect with the INP candidate interaction. Note that periodically this
69
+ // list is cleaned up and entries that are known to not match INP are removed.
70
+ let pendingLoAFs = [];
71
+ // An array of groups of all the event timing entries that occurred within a
72
+ // particular frame. Note that periodically this array is cleaned up and entries
73
+ // that are known to not match INP are removed.
74
+ let pendingEntriesGroups = [];
75
+ // The `processingEnd` time of most recently-processed event, chronologically.
76
+ let latestProcessingEnd = 0;
77
+ // A WeakMap to look up the event-timing-entries group of a given entry.
78
+ // Note that this only maps from "important" entries: either the first input or
79
+ // those with an `interactionId`.
80
+ const entryToEntriesGroupMap = new WeakMap();
81
+ // A mapping of interactionIds to the target Node.
82
+ const interactionTargetMap = new WeakMap();
83
+ // A boolean flag indicating whether or not a cleanup task has been queued.
84
+ let cleanupPending = false;
85
+ /**
86
+ * Adds new LoAF entries to the `pendingLoAFs` list.
87
+ */
88
+ const handleLoAFEntries = (entries) => {
89
+ pendingLoAFs = pendingLoAFs.concat(entries);
90
+ queueCleanup();
91
+ };
92
+ const saveInteractionTarget = (interaction) => {
93
+ if (!interactionTargetMap.get(interaction)) {
94
+ const node = interaction.entries[0].target;
95
+ if (node) {
96
+ const customTarget = opts.generateTarget?.(node) ?? getSelector(node);
97
+ interactionTargetMap.set(interaction, customTarget);
98
+ }
99
+ }
100
+ };
101
+ /**
102
+ * Groups entries that were presented within the same animation frame by
103
+ * a common `renderTime`. This function works by referencing
104
+ * `pendingEntriesGroups` and using an existing render time if one is found
105
+ * (otherwise creating a new one). This function also adds all interaction
106
+ * entries to an `entryToRenderTimeMap` WeakMap so that the "grouped" entries
107
+ * can be looked up later.
108
+ */
109
+ const groupEntriesByRenderTime = (entry) => {
110
+ const renderTime = entry.startTime + entry.duration;
111
+ let group;
112
+ latestProcessingEnd = Math.max(latestProcessingEnd, entry.processingEnd);
113
+ // Iterate over all previous render times in reverse order to find a match.
114
+ // Go in reverse since the most likely match will be at the end.
115
+ for (let i = pendingEntriesGroups.length - 1; i >= 0; i--) {
116
+ const potentialGroup = pendingEntriesGroups[i];
117
+ // If a group's render time is within 8ms of the entry's render time,
118
+ // assume they were part of the same frame and add it to the group.
119
+ if (Math.abs(renderTime - potentialGroup.renderTime) <= 8) {
120
+ group = potentialGroup;
121
+ group.startTime = Math.min(entry.startTime, group.startTime);
122
+ group.processingStart = Math.min(entry.processingStart, group.processingStart);
123
+ group.processingEnd = Math.max(entry.processingEnd, group.processingEnd);
124
+ group.entries.push(entry);
125
+ break;
126
+ }
127
+ }
128
+ // If there was no matching group, assume this is a new frame.
129
+ if (!group) {
130
+ group = {
131
+ startTime: entry.startTime,
132
+ processingStart: entry.processingStart,
133
+ processingEnd: entry.processingEnd,
134
+ renderTime,
135
+ entries: [entry],
136
+ };
137
+ pendingEntriesGroups.push(group);
138
+ }
139
+ // Store the grouped render time for this entry for reference later.
140
+ if (entry.interactionId || entry.entryType === 'first-input') {
141
+ entryToEntriesGroupMap.set(entry, group);
142
+ }
143
+ queueCleanup();
144
+ };
145
+ const queueCleanup = () => {
146
+ // Queue cleanup of entries that are not part of any INP candidates.
147
+ if (!cleanupPending) {
148
+ whenIdleOrHidden(cleanupEntries);
149
+ cleanupPending = true;
150
+ }
151
+ };
152
+ const cleanupEntries = () => {
153
+ // Keep all render times that are part of a pending INP candidate or
154
+ // that occurred within the 50 most recently-dispatched groups of events.
155
+ const longestInteractionGroups = interactionManager._longestInteractionList.map((i) => {
156
+ return entryToEntriesGroupMap.get(i.entries[0]);
157
+ });
158
+ const minIndex = pendingEntriesGroups.length - MAX_PREVIOUS_FRAMES;
159
+ pendingEntriesGroups = pendingEntriesGroups.filter((group, index) => {
160
+ if (index >= minIndex)
161
+ return true;
162
+ return longestInteractionGroups.includes(group);
163
+ });
164
+ // Keep all pending LoAF entries that either:
165
+ // 1) intersect with entries in the newly cleaned up `pendingEntriesGroups`
166
+ // 2) occur after the most recently-processed event entry (for up to MAX_PREVIOUS_FRAMES)
167
+ const loafsToKeep = new Set();
168
+ for (const group of pendingEntriesGroups) {
169
+ const loafs = getIntersectingLoAFs(group.startTime, group.processingEnd);
170
+ for (const loaf of loafs) {
171
+ loafsToKeep.add(loaf);
172
+ }
173
+ }
174
+ const prevFrameIndexCutoff = pendingLoAFs.length - 1 - MAX_PREVIOUS_FRAMES;
175
+ // Filter `pendingLoAFs` to preserve LoAF order.
176
+ pendingLoAFs = pendingLoAFs.filter((loaf, index) => {
177
+ if (loaf.startTime > latestProcessingEnd &&
178
+ index > prevFrameIndexCutoff) {
179
+ return true;
180
+ }
181
+ return loafsToKeep.has(loaf);
182
+ });
183
+ cleanupPending = false;
184
+ };
185
+ async function handleOnEachInteractionCallback(entry) {
186
+ if (!opts.onEachInteraction) {
187
+ return;
188
+ }
189
+ // Wait a microtask so this "pre" processing callback actually
190
+ // becomes a "post" processing callback.
191
+ void (await Promise.resolve());
192
+ if (!entry.interactionId) {
193
+ return;
194
+ }
195
+ const interaction = attributeINP({
196
+ entries: [entry],
197
+ // The only value we really need for `attributeINP` is `entries`
198
+ // Everything else is included to fill out the type.
199
+ name: 'INP',
200
+ rating: 'good',
201
+ value: entry.duration,
202
+ delta: entry.duration,
203
+ navigationType: 'navigate',
204
+ id: 'N/A',
205
+ });
206
+ opts.onEachInteraction(interaction);
255
207
  }
208
+ interactionManager._onBeforeProcessingEntry = (entry) => {
209
+ void handleOnEachInteractionCallback(entry);
210
+ groupEntriesByRenderTime(entry);
211
+ };
212
+ interactionManager._onAfterProcessingINPCandidate = saveInteractionTarget;
213
+ const getIntersectingLoAFs = (start, end) => {
214
+ const intersectingLoAFs = [];
215
+ for (const loaf of pendingLoAFs) {
216
+ // If the LoAF ends before the given start time, ignore it.
217
+ if (loaf.startTime + loaf.duration < start)
218
+ continue;
219
+ // If the LoAF starts after the given end time, ignore it and all
220
+ // subsequent pending LoAFs (because they're in time order).
221
+ if (loaf.startTime > end)
222
+ break;
223
+ // Still here? If so this LoAF intersects with the interaction.
224
+ intersectingLoAFs.push(loaf);
225
+ }
226
+ return intersectingLoAFs;
227
+ };
228
+ const attributeLoAFDetails = (attribution) => {
229
+ // If there is no LoAF data then nothing further to attribute
230
+ if (!attribution.longAnimationFrameEntries?.length) {
231
+ return;
232
+ }
233
+ const interactionTime = attribution.interactionTime;
234
+ const inputDelay = attribution.inputDelay;
235
+ const processingDuration = attribution.processingDuration;
236
+ // Stats across all LoAF entries and scripts.
237
+ let totalScriptDuration = 0;
238
+ let totalStyleAndLayoutDuration = 0;
239
+ let totalPaintDuration = 0;
240
+ let longestScriptDuration = 0;
241
+ let longestScriptEntry;
242
+ let longestScriptSubpart;
243
+ for (const loafEntry of attribution.longAnimationFrameEntries) {
244
+ totalStyleAndLayoutDuration =
245
+ totalStyleAndLayoutDuration +
246
+ loafEntry.startTime +
247
+ loafEntry.duration -
248
+ loafEntry.styleAndLayoutStart;
249
+ for (const script of loafEntry.scripts) {
250
+ const scriptEndTime = script.startTime + script.duration;
251
+ if (scriptEndTime < interactionTime) {
252
+ continue;
253
+ }
254
+ const intersectingScriptDuration = scriptEndTime - Math.max(interactionTime, script.startTime);
255
+ // Since forcedStyleAndLayoutDuration doesn't provide timestamps, we
256
+ // apportion the total based on the intersectingScriptDuration. Not
257
+ // correct depending on when it occurred, but the best we can do.
258
+ const intersectingForceStyleAndLayoutDuration = script.duration
259
+ ? (intersectingScriptDuration / script.duration) *
260
+ script.forcedStyleAndLayoutDuration
261
+ : 0;
262
+ // For scripts we exclude forcedStyleAndLayout (same as DevTools does
263
+ // in its summary totals) and instead include that in
264
+ // totalStyleAndLayoutDuration
265
+ totalScriptDuration +=
266
+ intersectingScriptDuration - intersectingForceStyleAndLayoutDuration;
267
+ totalStyleAndLayoutDuration += intersectingForceStyleAndLayoutDuration;
268
+ if (intersectingScriptDuration > longestScriptDuration) {
269
+ // Set the subpart this occurred in.
270
+ longestScriptSubpart =
271
+ script.startTime < interactionTime + inputDelay
272
+ ? 'input-delay'
273
+ : script.startTime >=
274
+ interactionTime + inputDelay + processingDuration
275
+ ? 'presentation-delay'
276
+ : 'processing-duration';
277
+ longestScriptEntry = script;
278
+ longestScriptDuration = intersectingScriptDuration;
279
+ }
280
+ }
281
+ }
282
+ // Calculate the totalPaintDuration from the last LoAF after
283
+ // presentationDelay starts (where available)
284
+ const lastLoAF = attribution.longAnimationFrameEntries.at(-1);
285
+ const lastLoAFEndTime = lastLoAF
286
+ ? lastLoAF.startTime + lastLoAF.duration
287
+ : 0;
288
+ if (lastLoAFEndTime >= interactionTime + inputDelay + processingDuration) {
289
+ totalPaintDuration = attribution.nextPaintTime - lastLoAFEndTime;
290
+ }
291
+ if (longestScriptEntry && longestScriptSubpart) {
292
+ attribution.longestScript = {
293
+ entry: longestScriptEntry,
294
+ subpart: longestScriptSubpart,
295
+ intersectingDuration: longestScriptDuration,
296
+ };
297
+ }
298
+ attribution.totalScriptDuration = totalScriptDuration;
299
+ attribution.totalStyleAndLayoutDuration = totalStyleAndLayoutDuration;
300
+ attribution.totalPaintDuration = totalPaintDuration;
301
+ attribution.totalUnattributedDuration =
302
+ attribution.nextPaintTime -
303
+ interactionTime -
304
+ totalScriptDuration -
305
+ totalStyleAndLayoutDuration -
306
+ totalPaintDuration;
307
+ };
308
+ const attributeINP = (metric) => {
309
+ const firstEntry = metric.entries[0];
310
+ const group = entryToEntriesGroupMap.get(firstEntry);
311
+ const processingStart = firstEntry.processingStart;
312
+ // Due to the fact that durations can be rounded down to the nearest 8ms,
313
+ // we have to clamp `nextPaintTime` so it doesn't appear to occur before
314
+ // processing starts. Note: we can't use `processingEnd` since processing
315
+ // can extend beyond the event duration in some cases (see next comment).
316
+ const nextPaintTime = Math.max(firstEntry.startTime + firstEntry.duration, processingStart);
317
+ // For the purposes of attribution, clamp `processingEnd` to `nextPaintTime`,
318
+ // so processing is never reported as taking longer than INP (which can
319
+ // happen via the web APIs in the case of sync modals, e.g. `alert()`).
320
+ // See: https://github.com/GoogleChrome/web-vitals/issues/492
321
+ const processingEnd = Math.min(group.processingEnd, nextPaintTime);
322
+ // Sort the entries in processing time order.
323
+ const processedEventEntries = group.entries.sort((a, b) => {
324
+ return a.processingStart - b.processingStart;
325
+ });
326
+ const longAnimationFrameEntries = getIntersectingLoAFs(firstEntry.startTime, processingEnd);
327
+ const interaction = interactionManager._longestInteractionMap.get(firstEntry.interactionId);
328
+ const attribution = {
329
+ // TS flags the next line because `interactionTargetMap.get()` might
330
+ // return `undefined`, but we ignore this assuming the user knows what
331
+ // they are doing.
332
+ interactionTarget: interactionTargetMap.get(interaction),
333
+ interactionType: firstEntry.name.startsWith('key')
334
+ ? 'keyboard'
335
+ : 'pointer',
336
+ interactionTime: firstEntry.startTime,
337
+ nextPaintTime: nextPaintTime,
338
+ processedEventEntries: processedEventEntries,
339
+ longAnimationFrameEntries: longAnimationFrameEntries,
340
+ inputDelay: processingStart - firstEntry.startTime,
341
+ processingDuration: processingEnd - processingStart,
342
+ presentationDelay: nextPaintTime - processingEnd,
343
+ loadState: getLoadState(firstEntry.startTime),
344
+ longestScript: undefined,
345
+ totalScriptDuration: undefined,
346
+ totalStyleAndLayoutDuration: undefined,
347
+ totalPaintDuration: undefined,
348
+ totalUnattributedDuration: undefined,
349
+ };
350
+ attributeLoAFDetails(attribution);
351
+ // Use `Object.assign()` to ensure the original metric object is returned.
352
+ const metricWithAttribution = Object.assign(metric, { attribution });
353
+ return metricWithAttribution;
354
+ };
355
+ // Start observing LoAF entries for attribution.
356
+ observe('long-animation-frame', handleLoAFEntries);
256
357
  unattributedOnINP((metric) => {
257
358
  const metricWithAttribution = attributeINP(metric);
258
359
  onReport(metricWithAttribution);
@@ -1,4 +1,4 @@
1
- import { LCPMetricWithAttribution, ReportOpts } from '../types.js';
1
+ import { LCPMetricWithAttribution, AttributionReportOpts } from '../types.js';
2
2
  /**
3
3
  * Calculates the [LCP](https://web.dev/articles/lcp) value for the current page and
4
4
  * calls the `callback` function once the value is ready (along with the
@@ -10,4 +10,4 @@ import { LCPMetricWithAttribution, ReportOpts } from '../types.js';
10
10
  * performance entry is dispatched, or once the final value of the metric has
11
11
  * been determined.
12
12
  */
13
- export declare const onLCP: (onReport: (metric: LCPMetricWithAttribution) => void, opts?: ReportOpts) => void;
13
+ export declare const onLCP: (onReport: (metric: LCPMetricWithAttribution) => void, opts?: AttributionReportOpts) => void;