chrome-devtools-frontend 1.0.1526630 → 1.0.1528866

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 (319) hide show
  1. package/docs/ui_engineering.md +159 -0
  2. package/eslint.config.mjs +6 -1
  3. package/front_end/core/i18n/i18nImpl.ts +6 -1
  4. package/front_end/core/protocol_client/protocol_client.ts +1 -1
  5. package/front_end/core/root/Runtime.ts +28 -4
  6. package/front_end/core/sdk/CSSMatchedStyles.ts +50 -7
  7. package/front_end/core/sdk/CSSRule.ts +35 -6
  8. package/front_end/core/sdk/Connections.ts +2 -1
  9. package/front_end/core/sdk/DOMModel.ts +4 -0
  10. package/front_end/core/sdk/DebuggerModel.ts +5 -1
  11. package/front_end/core/sdk/NetworkManager.ts +214 -31
  12. package/front_end/core/sdk/PreloadingModel.ts +82 -17
  13. package/front_end/core/sdk/RehydratingConnection.snapshot.txt +1 -1
  14. package/front_end/core/sdk/RehydratingConnection.ts +29 -4
  15. package/front_end/core/sdk/ScopeTreeCache.ts +8 -3
  16. package/front_end/core/sdk/SourceMap.ts +37 -11
  17. package/front_end/core/sdk/SourceMapManager.ts +13 -2
  18. package/front_end/core/sdk/SourceMapScopesInfo.ts +17 -0
  19. package/front_end/core/sdk/TargetManager.ts +0 -22
  20. package/front_end/core/sdk/TraceObject.ts +8 -7
  21. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +81 -0
  22. package/front_end/entrypoints/inspector_main/InspectorMain.ts +3 -1
  23. package/front_end/entrypoints/main/GlobalAiButton.ts +1 -0
  24. package/front_end/entrypoints/main/MainImpl.ts +20 -25
  25. package/front_end/generated/InspectorBackendCommands.js +3 -2
  26. package/front_end/generated/protocol.ts +17 -3
  27. package/front_end/models/ai_assistance/BuiltInAi.ts +111 -0
  28. package/front_end/models/ai_assistance/ai_assistance.ts +53 -24
  29. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +105 -0
  30. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +6 -1
  31. package/front_end/models/extensions/ExtensionView.ts +3 -0
  32. package/front_end/models/javascript_metadata/NativeFunctions.js +23 -27
  33. package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +31 -29
  34. package/front_end/models/persistence/EditFileSystemView.ts +1 -0
  35. package/front_end/models/source_map_scopes/NamesResolver.ts +5 -11
  36. package/front_end/models/stack_trace/Trie.ts +9 -0
  37. package/front_end/models/trace/lantern/types/Lantern.ts +1 -1
  38. package/front_end/panels/accessibility/AXBreadcrumbsPane.ts +1 -0
  39. package/front_end/panels/accessibility/AccessibilitySidebarView.ts +1 -0
  40. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +120 -113
  41. package/front_end/panels/ai_assistance/PatchWidget.ts +9 -8
  42. package/front_end/panels/ai_assistance/SelectWorkspaceDialog.ts +2 -0
  43. package/front_end/panels/ai_assistance/components/ChatView.ts +29 -29
  44. package/front_end/panels/ai_assistance/components/UserActionRow.ts +1 -0
  45. package/front_end/panels/animation/AnimationTimeline.ts +1 -0
  46. package/front_end/panels/application/CookieItemsView.ts +1 -0
  47. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  48. package/front_end/panels/application/ServiceWorkerCacheViews.ts +2 -0
  49. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +11 -5
  50. package/front_end/panels/application/preloading/components/PreloadingMismatchedHeadersGrid.ts +2 -2
  51. package/front_end/panels/application/preloading/components/PreloadingString.ts +7 -5
  52. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +22 -10
  53. package/front_end/panels/changes/CombinedDiffView.ts +1 -0
  54. package/front_end/panels/console/ConsoleInsightTeaser.ts +106 -0
  55. package/front_end/panels/console/ConsolePanel.ts +2 -0
  56. package/front_end/panels/console/ConsolePrompt.ts +12 -2
  57. package/front_end/panels/console/ConsoleSidebar.ts +1 -1
  58. package/front_end/panels/console/ConsoleView.ts +12 -0
  59. package/front_end/panels/console/ConsoleViewMessage.ts +27 -0
  60. package/front_end/panels/{explain → console}/PromptBuilder.ts +12 -7
  61. package/front_end/panels/console/console.ts +6 -0
  62. package/front_end/panels/console/consoleInsightTeaser.css +55 -0
  63. package/front_end/panels/coverage/CoverageListView.ts +29 -11
  64. package/front_end/panels/coverage/CoverageView.ts +292 -284
  65. package/front_end/panels/coverage/coverageView.css +17 -0
  66. package/front_end/panels/elements/ComputedStyleWidget.ts +1 -0
  67. package/front_end/panels/elements/LayoutPane.ts +1 -0
  68. package/front_end/panels/elements/NodeStackTraceWidget.ts +1 -0
  69. package/front_end/panels/elements/StylePropertyTreeElement.ts +5 -1
  70. package/front_end/panels/elements/stylePropertiesTreeOutline.css +17 -0
  71. package/front_end/panels/emulation/DeviceModeView.ts +2 -0
  72. package/front_end/panels/explain/ActionDelegate.ts +1 -2
  73. package/front_end/panels/explain/components/ConsoleInsight.ts +14 -12
  74. package/front_end/panels/explain/explain.ts +0 -1
  75. package/front_end/panels/js_timeline/js_timeline-meta.ts +1 -1
  76. package/front_end/panels/layer_viewer/Layers3DView.ts +2 -0
  77. package/front_end/panels/lighthouse/LighthouseReportSelector.ts +1 -0
  78. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +1 -0
  79. package/front_end/panels/media/MainView.ts +1 -0
  80. package/front_end/panels/media/TickingFlameChart.ts +2 -0
  81. package/front_end/panels/network/BlockedURLsPane.ts +111 -85
  82. package/front_end/panels/network/EventSourceMessagesView.ts +1 -0
  83. package/front_end/panels/network/NetworkItemView.ts +1 -0
  84. package/front_end/panels/network/NetworkLogView.ts +9 -7
  85. package/front_end/panels/network/NetworkOverview.ts +1 -0
  86. package/front_end/panels/network/RequestCookiesView.ts +1 -0
  87. package/front_end/panels/network/RequestHTMLView.ts +1 -0
  88. package/front_end/panels/network/RequestInitiatorView.ts +1 -0
  89. package/front_end/panels/network/RequestPayloadView.ts +1 -0
  90. package/front_end/panels/network/RequestPreviewView.ts +1 -0
  91. package/front_end/panels/network/RequestResponseView.ts +1 -0
  92. package/front_end/panels/network/RequestTimingView.ts +2 -0
  93. package/front_end/panels/network/ResourceDirectSocketChunkView.ts +1 -0
  94. package/front_end/panels/network/ResourceWebSocketFrameView.ts +1 -0
  95. package/front_end/panels/network/components/RequestHeadersView.ts +2 -0
  96. package/front_end/panels/network/components/RequestTrustTokensView.ts +2 -0
  97. package/front_end/panels/performance_monitor/PerformanceMonitor.ts +2 -0
  98. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +2 -0
  99. package/front_end/panels/profiler/HeapSnapshotView.ts +7 -0
  100. package/front_end/panels/profiler/IsolateSelector.ts +1 -0
  101. package/front_end/panels/profiler/LiveHeapProfileView.ts +1 -0
  102. package/front_end/panels/profiler/ProfileView.ts +1 -0
  103. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -0
  104. package/front_end/panels/recorder/RecorderPanel.ts +2 -0
  105. package/front_end/panels/screencast/ScreencastView.ts +1 -0
  106. package/front_end/panels/search/SearchView.ts +1 -0
  107. package/front_end/panels/settings/AISettingsTab.ts +3 -3
  108. package/front_end/panels/settings/WorkspaceSettingsTab.ts +2 -0
  109. package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +2 -2
  110. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +12 -0
  111. package/front_end/panels/sources/BreakpointsView.ts +1 -0
  112. package/front_end/panels/sources/DebuggerPlugin.ts +1 -0
  113. package/front_end/panels/sources/UISourceCodeFrame.ts +17 -2
  114. package/front_end/panels/timeline/README.md +2 -2
  115. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +1 -1
  116. package/front_end/panels/timeline/TimelineFlameChartView.ts +4 -3
  117. package/front_end/panels/timeline/TimelineLayersView.ts +1 -0
  118. package/front_end/panels/timeline/TimelinePaintProfilerView.ts +114 -37
  119. package/front_end/panels/timeline/TimelinePanel.ts +43 -62
  120. package/front_end/panels/timeline/TimelineTreeView.ts +1 -0
  121. package/front_end/panels/timeline/components/LiveMetricsView.ts +4 -8
  122. package/front_end/panels/timeline/components/Sidebar.ts +2 -0
  123. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
  124. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +7 -7
  125. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +1 -1
  126. package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +4 -4
  127. package/front_end/panels/web_audio/WebAudioView.ts +1 -0
  128. package/front_end/third_party/chromium/README.chromium +1 -1
  129. package/front_end/third_party/lighthouse/README.chromium +2 -2
  130. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1530 -2426
  131. package/front_end/third_party/lighthouse/locales/ar-XB.json +107 -455
  132. package/front_end/third_party/lighthouse/locales/ar.json +107 -455
  133. package/front_end/third_party/lighthouse/locales/bg.json +96 -444
  134. package/front_end/third_party/lighthouse/locales/ca.json +96 -444
  135. package/front_end/third_party/lighthouse/locales/cs.json +96 -444
  136. package/front_end/third_party/lighthouse/locales/da.json +96 -444
  137. package/front_end/third_party/lighthouse/locales/de.json +96 -444
  138. package/front_end/third_party/lighthouse/locales/el.json +96 -444
  139. package/front_end/third_party/lighthouse/locales/en-GB.json +96 -444
  140. package/front_end/third_party/lighthouse/locales/en-US.json +116 -467
  141. package/front_end/third_party/lighthouse/locales/en-XA.json +93 -441
  142. package/front_end/third_party/lighthouse/locales/en-XL.json +116 -467
  143. package/front_end/third_party/lighthouse/locales/es-419.json +96 -444
  144. package/front_end/third_party/lighthouse/locales/es.json +96 -444
  145. package/front_end/third_party/lighthouse/locales/fi.json +96 -444
  146. package/front_end/third_party/lighthouse/locales/fil.json +96 -444
  147. package/front_end/third_party/lighthouse/locales/fr.json +96 -444
  148. package/front_end/third_party/lighthouse/locales/he.json +118 -466
  149. package/front_end/third_party/lighthouse/locales/hi.json +96 -444
  150. package/front_end/third_party/lighthouse/locales/hr.json +100 -448
  151. package/front_end/third_party/lighthouse/locales/hu.json +96 -444
  152. package/front_end/third_party/lighthouse/locales/id.json +96 -444
  153. package/front_end/third_party/lighthouse/locales/it.json +96 -444
  154. package/front_end/third_party/lighthouse/locales/ja.json +96 -444
  155. package/front_end/third_party/lighthouse/locales/ko.json +97 -445
  156. package/front_end/third_party/lighthouse/locales/lt.json +96 -444
  157. package/front_end/third_party/lighthouse/locales/lv.json +97 -445
  158. package/front_end/third_party/lighthouse/locales/nl.json +96 -444
  159. package/front_end/third_party/lighthouse/locales/no.json +96 -444
  160. package/front_end/third_party/lighthouse/locales/pl.json +96 -444
  161. package/front_end/third_party/lighthouse/locales/pt-PT.json +96 -444
  162. package/front_end/third_party/lighthouse/locales/pt.json +97 -445
  163. package/front_end/third_party/lighthouse/locales/ro.json +97 -445
  164. package/front_end/third_party/lighthouse/locales/ru.json +96 -444
  165. package/front_end/third_party/lighthouse/locales/sk.json +96 -444
  166. package/front_end/third_party/lighthouse/locales/sl.json +96 -444
  167. package/front_end/third_party/lighthouse/locales/sr-Latn.json +96 -444
  168. package/front_end/third_party/lighthouse/locales/sr.json +96 -444
  169. package/front_end/third_party/lighthouse/locales/sv.json +96 -444
  170. package/front_end/third_party/lighthouse/locales/ta.json +96 -444
  171. package/front_end/third_party/lighthouse/locales/te.json +97 -445
  172. package/front_end/third_party/lighthouse/locales/th.json +96 -444
  173. package/front_end/third_party/lighthouse/locales/tr.json +96 -444
  174. package/front_end/third_party/lighthouse/locales/uk.json +96 -444
  175. package/front_end/third_party/lighthouse/locales/vi.json +96 -444
  176. package/front_end/third_party/lighthouse/locales/zh-HK.json +96 -444
  177. package/front_end/third_party/lighthouse/locales/zh-TW.json +97 -445
  178. package/front_end/third_party/lighthouse/locales/zh.json +96 -444
  179. package/front_end/third_party/lighthouse/report/bundle.d.ts +8 -14
  180. package/front_end/third_party/lighthouse/report/bundle.js +10 -49
  181. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
  182. package/front_end/third_party/web-vitals/README.chromium +5 -8
  183. package/front_end/third_party/web-vitals/package/README.md +191 -152
  184. package/front_end/third_party/web-vitals/package/dist/modules/attribution/index.d.ts +0 -1
  185. package/front_end/third_party/web-vitals/package/dist/modules/attribution/index.js +0 -1
  186. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onCLS.d.ts +2 -2
  187. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onCLS.js +45 -26
  188. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.d.ts +2 -2
  189. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.js +3 -3
  190. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.d.ts +10 -10
  191. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +307 -206
  192. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.d.ts +2 -2
  193. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.js +69 -49
  194. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.d.ts +2 -2
  195. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.js +2 -2
  196. package/front_end/third_party/web-vitals/package/dist/modules/index.d.ts +0 -1
  197. package/front_end/third_party/web-vitals/package/dist/modules/index.js +0 -1
  198. package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.d.ts +33 -0
  199. package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.js +111 -0
  200. package/front_end/third_party/web-vitals/package/dist/modules/lib/LCPEntryManager.d.ts +4 -0
  201. package/front_end/third_party/web-vitals/package/dist/modules/{attribution/deprecated.js → lib/LCPEntryManager.js} +6 -7
  202. package/front_end/third_party/web-vitals/package/dist/modules/lib/LayoutShiftManager.d.ts +6 -0
  203. package/front_end/third_party/web-vitals/package/dist/modules/lib/LayoutShiftManager.js +44 -0
  204. package/front_end/third_party/web-vitals/package/dist/modules/lib/bindReporter.js +1 -1
  205. package/front_end/third_party/web-vitals/package/dist/modules/lib/generateUniqueID.js +1 -1
  206. package/front_end/third_party/web-vitals/package/dist/modules/lib/getActivationStart.js +1 -1
  207. package/front_end/third_party/web-vitals/package/dist/modules/lib/getNavigationEntry.js +5 -7
  208. package/front_end/third_party/web-vitals/package/dist/modules/lib/getSelector.d.ts +1 -1
  209. package/front_end/third_party/web-vitals/package/dist/modules/lib/getSelector.js +9 -12
  210. package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.d.ts +1 -0
  211. package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.js +52 -33
  212. package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.d.ts +0 -2
  213. package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.js +2 -2
  214. package/front_end/third_party/web-vitals/package/dist/modules/lib/initUnique.d.ts +6 -0
  215. package/front_end/third_party/web-vitals/package/dist/modules/{deprecated.js → lib/initUnique.js} +11 -4
  216. package/front_end/third_party/web-vitals/package/dist/modules/lib/observe.js +3 -6
  217. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/interactionCountPolyfill.js +6 -6
  218. package/front_end/third_party/web-vitals/package/dist/modules/lib/{whenIdle.d.ts → whenIdleOrHidden.d.ts} +1 -1
  219. package/front_end/third_party/web-vitals/package/dist/modules/lib/{whenIdle.js → whenIdleOrHidden.js} +10 -8
  220. package/front_end/third_party/web-vitals/package/dist/modules/onCLS.js +17 -35
  221. package/front_end/third_party/web-vitals/package/dist/modules/onFCP.js +3 -5
  222. package/front_end/third_party/web-vitals/package/dist/modules/onINP.d.ts +9 -7
  223. package/front_end/third_party/web-vitals/package/dist/modules/onINP.js +27 -19
  224. package/front_end/third_party/web-vitals/package/dist/modules/onLCP.js +33 -26
  225. package/front_end/third_party/web-vitals/package/dist/modules/onTTFB.js +2 -4
  226. package/front_end/third_party/web-vitals/package/dist/modules/types/base.d.ts +6 -5
  227. package/front_end/third_party/web-vitals/package/dist/modules/types/cls.d.ts +5 -3
  228. package/front_end/third_party/web-vitals/package/dist/modules/types/inp.d.ts +80 -33
  229. package/front_end/third_party/web-vitals/package/dist/modules/types/lcp.d.ts +6 -2
  230. package/front_end/third_party/web-vitals/package/dist/modules/types.d.ts +28 -4
  231. package/front_end/third_party/web-vitals/package/dist/modules/types.js +0 -1
  232. package/front_end/third_party/web-vitals/package/package.json +4 -10
  233. package/front_end/third_party/web-vitals/package/src/attribution/index.ts +0 -1
  234. package/front_end/third_party/web-vitals/package/src/attribution/onCLS.ts +58 -33
  235. package/front_end/third_party/web-vitals/package/src/attribution/onFCP.ts +4 -4
  236. package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +382 -258
  237. package/front_end/third_party/web-vitals/package/src/attribution/onLCP.ts +96 -69
  238. package/front_end/third_party/web-vitals/package/src/attribution/onTTFB.ts +3 -3
  239. package/front_end/third_party/web-vitals/package/src/index.ts +0 -1
  240. package/front_end/third_party/web-vitals/package/src/lib/InteractionManager.ts +146 -0
  241. package/front_end/third_party/web-vitals/package/src/{attribution/deprecated.ts → lib/LCPEntryManager.ts} +6 -9
  242. package/front_end/third_party/web-vitals/package/src/lib/LayoutShiftManager.ts +50 -0
  243. package/front_end/third_party/web-vitals/package/src/lib/bindReporter.ts +1 -1
  244. package/front_end/third_party/web-vitals/package/src/lib/generateUniqueID.ts +1 -1
  245. package/front_end/third_party/web-vitals/package/src/lib/getActivationStart.ts +1 -1
  246. package/front_end/third_party/web-vitals/package/src/lib/getNavigationEntry.ts +5 -8
  247. package/front_end/third_party/web-vitals/package/src/lib/getSelector.ts +12 -12
  248. package/front_end/third_party/web-vitals/package/src/lib/getVisibilityWatcher.ts +57 -35
  249. package/front_end/third_party/web-vitals/package/src/lib/initMetric.ts +2 -2
  250. package/front_end/third_party/web-vitals/package/src/{deprecated.ts → lib/initUnique.ts} +14 -8
  251. package/front_end/third_party/web-vitals/package/src/lib/observe.ts +3 -11
  252. package/front_end/third_party/web-vitals/package/src/lib/polyfills/interactionCountPolyfill.ts +12 -6
  253. package/front_end/third_party/web-vitals/package/src/lib/{whenIdle.ts → whenIdleOrHidden.ts} +10 -8
  254. package/front_end/third_party/web-vitals/package/src/onCLS.ts +17 -38
  255. package/front_end/third_party/web-vitals/package/src/onFCP.ts +3 -6
  256. package/front_end/third_party/web-vitals/package/src/onINP.ts +33 -28
  257. package/front_end/third_party/web-vitals/package/src/onLCP.ts +36 -29
  258. package/front_end/third_party/web-vitals/package/src/onTTFB.ts +2 -5
  259. package/front_end/third_party/web-vitals/package/src/types/base.ts +5 -5
  260. package/front_end/third_party/web-vitals/package/src/types/cls.ts +5 -3
  261. package/front_end/third_party/web-vitals/package/src/types/inp.ts +88 -33
  262. package/front_end/third_party/web-vitals/package/src/types/lcp.ts +6 -2
  263. package/front_end/third_party/web-vitals/package/src/types.ts +47 -4
  264. package/front_end/third_party/web-vitals/patches/0001-Add-onEachInteraction-to-onINP-options.patch +75 -0
  265. package/front_end/third_party/web-vitals/rebuild.sh +32 -18
  266. package/front_end/third_party/web-vitals/web-vitals-tsconfig.json +5 -10
  267. package/front_end/third_party/web-vitals/web-vitals.ts +0 -2
  268. package/front_end/ui/components/docs/console_insight/basic.ts +3 -2
  269. package/front_end/ui/components/legacy_wrapper/LegacyWrapper.ts +2 -0
  270. package/front_end/ui/components/text_editor/TextEditor.ts +0 -2
  271. package/front_end/ui/legacy/InspectorView.ts +2 -0
  272. package/front_end/ui/legacy/SplitWidget.ts +2 -0
  273. package/front_end/ui/legacy/TabbedPane.ts +1 -0
  274. package/front_end/ui/legacy/TargetCrashedScreen.ts +1 -0
  275. package/front_end/ui/legacy/UIUtils.ts +8 -19
  276. package/front_end/ui/legacy/ViewManager.ts +1 -0
  277. package/front_end/ui/legacy/components/color_picker/FormatPickerContextMenu.ts +7 -20
  278. package/front_end/ui/legacy/components/color_picker/Spectrum.ts +2 -0
  279. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +1 -0
  280. package/front_end/ui/legacy/components/inline_editor/BezierEditor.ts +1 -0
  281. package/front_end/ui/legacy/components/perf_ui/ChartViewport.ts +1 -0
  282. package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +1 -0
  283. package/front_end/ui/legacy/components/source_frame/FontView.ts +1 -0
  284. package/front_end/ui/legacy/components/source_frame/ImageView.ts +1 -0
  285. package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -0
  286. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +1 -0
  287. package/front_end/ui/legacy/components/source_frame/StreamingContentHexView.ts +2 -0
  288. package/front_end/ui/visual_logging/KnownContextValues.ts +17 -0
  289. package/mcp/README.md +7 -0
  290. package/mcp/mcp.ts +8 -0
  291. package/package.json +1 -1
  292. package/front_end/models/live-metrics/web-vitals-injected/OnEachInteraction.ts +0 -34
  293. package/front_end/third_party/web-vitals/package/attribution.d.ts +0 -16
  294. package/front_end/third_party/web-vitals/package/attribution.js +0 -18
  295. package/front_end/third_party/web-vitals/package/dist/modules/attribution/deprecated.d.ts +0 -7
  296. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFID.d.ts +0 -11
  297. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFID.js +0 -46
  298. package/front_end/third_party/web-vitals/package/dist/modules/deprecated.d.ts +0 -5
  299. package/front_end/third_party/web-vitals/package/dist/modules/lib/interactions.d.ts +0 -31
  300. package/front_end/third_party/web-vitals/package/dist/modules/lib/interactions.js +0 -107
  301. package/front_end/third_party/web-vitals/package/dist/modules/lib/onHidden.d.ts +0 -1
  302. package/front_end/third_party/web-vitals/package/dist/modules/lib/onHidden.js +0 -22
  303. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/firstInputPolyfill.d.ts +0 -7
  304. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/firstInputPolyfill.js +0 -147
  305. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/getFirstHiddenTimePolyfill.d.ts +0 -1
  306. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/getFirstHiddenTimePolyfill.js +0 -25
  307. package/front_end/third_party/web-vitals/package/dist/modules/onFID.d.ts +0 -13
  308. package/front_end/third_party/web-vitals/package/dist/modules/onFID.js +0 -70
  309. package/front_end/third_party/web-vitals/package/dist/modules/types/fid.d.ts +0 -46
  310. package/front_end/third_party/web-vitals/package/dist/modules/types/fid.js +0 -16
  311. package/front_end/third_party/web-vitals/package/src/attribution/onFID.ts +0 -62
  312. package/front_end/third_party/web-vitals/package/src/lib/interactions.ts +0 -139
  313. package/front_end/third_party/web-vitals/package/src/lib/onHidden.ts +0 -23
  314. package/front_end/third_party/web-vitals/package/src/lib/polyfills/firstInputPolyfill.ts +0 -174
  315. package/front_end/third_party/web-vitals/package/src/onFID.ts +0 -105
  316. package/front_end/third_party/web-vitals/package/src/types/fid.ts +0 -65
  317. package/front_end/ui/components/text_editor/textEditor.css +0 -18
  318. package/front_end/ui/legacy/inlineButton.css +0 -22
  319. /package/front_end/entrypoints/{rehydrated_devtools_app/rehydrated_devtools_app.ts → trace_app/trace_app.ts} +0 -0
@@ -22,7 +22,7 @@ import {MetricType} from '../types.js';
22
22
 
23
23
  export const initMetric = <MetricName extends MetricType['name']>(
24
24
  name: MetricName,
25
- value?: number,
25
+ value: number = -1,
26
26
  ) => {
27
27
  const navEntry = getNavigationEntry();
28
28
  let navigationType: MetricType['navigationType'] = 'navigate';
@@ -47,7 +47,7 @@ export const initMetric = <MetricName extends MetricType['name']>(
47
47
 
48
48
  return {
49
49
  name,
50
- value: typeof value === 'undefined' ? -1 : value,
50
+ value,
51
51
  rating: 'good' as const, // If needed, will be updated when reported. `const` to keep the type from widening to `string`.
52
52
  delta: 0,
53
53
  entries,
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2022 Google LLC
2
+ * Copyright 2024 Google LLC
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -14,10 +14,16 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- export {
18
- /**
19
- * @deprecated Use `onINP()` instead.
20
- */
21
- onFID,
22
- FIDThresholds,
23
- } from './onFID.js';
17
+ const instanceMap: WeakMap<object, unknown> = new WeakMap();
18
+
19
+ /**
20
+ * A function that accepts and identity object and a class object and returns
21
+ * either a new instance of that class or an existing instance, if the
22
+ * identity object was previously used.
23
+ */
24
+ export function initUnique<T>(identityObj: object, ClassObj: new () => T): T {
25
+ if (!instanceMap.get(identityObj)) {
26
+ instanceMap.set(identityObj, new ClassObj());
27
+ }
28
+ return instanceMap.get(identityObj)! as T;
29
+ }
@@ -36,7 +36,7 @@ interface PerformanceEntryMap {
36
36
  export const observe = <K extends keyof PerformanceEntryMap>(
37
37
  type: K,
38
38
  callback: (entries: PerformanceEntryMap[K]) => void,
39
- opts?: PerformanceObserverInit,
39
+ opts: PerformanceObserverInit = {},
40
40
  ): PerformanceObserver | undefined => {
41
41
  try {
42
42
  if (PerformanceObserver.supportedEntryTypes.includes(type)) {
@@ -48,18 +48,10 @@ export const observe = <K extends keyof PerformanceEntryMap>(
48
48
  callback(list.getEntries() as PerformanceEntryMap[K]);
49
49
  });
50
50
  });
51
- po.observe(
52
- Object.assign(
53
- {
54
- type,
55
- buffered: true,
56
- },
57
- opts || {},
58
- ) as PerformanceObserverInit,
59
- );
51
+ po.observe({type, buffered: true, ...opts});
60
52
  return po;
61
53
  }
62
- } catch (e) {
54
+ } catch {
63
55
  // Do nothing.
64
56
  }
65
57
  return;
@@ -27,16 +27,22 @@ let minKnownInteractionId = Infinity;
27
27
  let maxKnownInteractionId = 0;
28
28
 
29
29
  const updateEstimate = (entries: PerformanceEventTiming[]) => {
30
- entries.forEach((e) => {
31
- if (e.interactionId) {
32
- minKnownInteractionId = Math.min(minKnownInteractionId, e.interactionId);
33
- maxKnownInteractionId = Math.max(maxKnownInteractionId, e.interactionId);
30
+ for (const entry of entries) {
31
+ if (entry.interactionId) {
32
+ minKnownInteractionId = Math.min(
33
+ minKnownInteractionId,
34
+ entry.interactionId,
35
+ );
36
+ maxKnownInteractionId = Math.max(
37
+ maxKnownInteractionId,
38
+ entry.interactionId,
39
+ );
34
40
 
35
41
  interactionCountEstimate = maxKnownInteractionId
36
42
  ? (maxKnownInteractionId - minKnownInteractionId) / 7 + 1
37
43
  : 0;
38
44
  }
39
- });
45
+ }
40
46
  };
41
47
 
42
48
  let po: PerformanceObserver | undefined;
@@ -46,7 +52,7 @@ let po: PerformanceObserver | undefined;
46
52
  * or the polyfill estimate in this module.
47
53
  */
48
54
  export const getInteractionCount = () => {
49
- return po ? interactionCountEstimate : performance.interactionCount || 0;
55
+ return po ? interactionCountEstimate : performance.interactionCount ?? 0;
50
56
  };
51
57
 
52
58
  /**
@@ -14,25 +14,27 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import {onHidden} from './onHidden.js';
18
17
  import {runOnce} from './runOnce.js';
19
18
 
20
19
  /**
21
20
  * Runs the passed callback during the next idle period, or immediately
22
21
  * if the browser's visibility state is (or becomes) hidden.
23
22
  */
24
- export const whenIdle = (cb: () => void): number => {
25
- const rIC = self.requestIdleCallback || self.setTimeout;
23
+ export const whenIdleOrHidden = (cb: () => void) => {
24
+ const rIC = globalThis.requestIdleCallback || setTimeout;
26
25
 
27
- let handle = -1;
28
- cb = runOnce(cb);
29
26
  // If the document is hidden, run the callback immediately, otherwise
30
27
  // race an idle callback with the next `visibilitychange` event.
31
28
  if (document.visibilityState === 'hidden') {
32
29
  cb();
33
30
  } else {
34
- handle = rIC(cb);
35
- onHidden(cb);
31
+ cb = runOnce(cb);
32
+ addEventListener('visibilitychange', cb, {once: true, capture: true});
33
+ rIC(() => {
34
+ cb();
35
+ // Remove the above event listener since no longer required.
36
+ // See: https://github.com/GoogleChrome/web-vitals/issues/622
37
+ removeEventListener('visibilitychange', cb, {capture: true});
38
+ });
36
39
  }
37
- return handle;
38
40
  };
@@ -15,13 +15,15 @@
15
15
  */
16
16
 
17
17
  import {onBFCacheRestore} from './lib/bfcache.js';
18
- import {initMetric} from './lib/initMetric.js';
19
- import {observe} from './lib/observe.js';
20
18
  import {bindReporter} from './lib/bindReporter.js';
21
19
  import {doubleRAF} from './lib/doubleRAF.js';
22
- import {onHidden} from './lib/onHidden.js';
20
+ import {initMetric} from './lib/initMetric.js';
21
+ import {initUnique} from './lib/initUnique.js';
22
+ import {LayoutShiftManager} from './lib/LayoutShiftManager.js';
23
+ import {observe} from './lib/observe.js';
23
24
  import {runOnce} from './lib/runOnce.js';
24
25
  import {onFCP} from './onFCP.js';
26
+ import {getVisibilityWatcher} from './lib/getVisibilityWatcher.js';
25
27
  import {CLSMetric, MetricRatingThresholds, ReportOpts} from './types.js';
26
28
 
27
29
  /** Thresholds for CLS. See https://web.dev/articles/cls#what_is_a_good_cls_score */
@@ -50,11 +52,9 @@ export const CLSThresholds: MetricRatingThresholds = [0.1, 0.25];
50
52
  */
51
53
  export const onCLS = (
52
54
  onReport: (metric: CLSMetric) => void,
53
- opts?: ReportOpts,
55
+ opts: ReportOpts = {},
54
56
  ) => {
55
- // Set defaults
56
- opts = opts || {};
57
-
57
+ const visibilityWatcher = getVisibilityWatcher();
58
58
  // Start monitoring FCP so we can only report CLS if FCP is also reported.
59
59
  // Note: this is done to match the current behavior of CrUX.
60
60
  onFCP(
@@ -62,39 +62,18 @@ export const onCLS = (
62
62
  let metric = initMetric('CLS', 0);
63
63
  let report: ReturnType<typeof bindReporter>;
64
64
 
65
- let sessionValue = 0;
66
- let sessionEntries: LayoutShift[] = [];
65
+ const layoutShiftManager = initUnique(opts, LayoutShiftManager);
67
66
 
68
67
  const handleEntries = (entries: LayoutShift[]) => {
69
- entries.forEach((entry) => {
70
- // Only count layout shifts without recent user input.
71
- if (!entry.hadRecentInput) {
72
- const firstSessionEntry = sessionEntries[0];
73
- const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
74
-
75
- // If the entry occurred less than 1 second after the previous entry
76
- // and less than 5 seconds after the first entry in the session,
77
- // include the entry in the current session. Otherwise, start a new
78
- // session.
79
- if (
80
- sessionValue &&
81
- entry.startTime - lastSessionEntry.startTime < 1000 &&
82
- entry.startTime - firstSessionEntry.startTime < 5000
83
- ) {
84
- sessionValue += entry.value;
85
- sessionEntries.push(entry);
86
- } else {
87
- sessionValue = entry.value;
88
- sessionEntries = [entry];
89
- }
90
- }
91
- });
68
+ for (const entry of entries) {
69
+ layoutShiftManager._processEntry(entry);
70
+ }
92
71
 
93
72
  // If the current session value is larger than the current CLS value,
94
73
  // update CLS and the entries contributing to it.
95
- if (sessionValue > metric.value) {
96
- metric.value = sessionValue;
97
- metric.entries = sessionEntries;
74
+ if (layoutShiftManager._sessionValue > metric.value) {
75
+ metric.value = layoutShiftManager._sessionValue;
76
+ metric.entries = layoutShiftManager._sessionEntries;
98
77
  report();
99
78
  }
100
79
  };
@@ -108,7 +87,7 @@ export const onCLS = (
108
87
  opts!.reportAllChanges,
109
88
  );
110
89
 
111
- onHidden(() => {
90
+ visibilityWatcher.onHidden(() => {
112
91
  handleEntries(po.takeRecords() as CLSMetric['entries']);
113
92
  report(true);
114
93
  });
@@ -116,7 +95,7 @@ export const onCLS = (
116
95
  // Only report after a bfcache restore if the `PerformanceObserver`
117
96
  // successfully registered.
118
97
  onBFCacheRestore(() => {
119
- sessionValue = 0;
98
+ layoutShiftManager._sessionValue = 0;
120
99
  metric = initMetric('CLS', 0);
121
100
  report = bindReporter(
122
101
  onReport,
@@ -131,7 +110,7 @@ export const onCLS = (
131
110
  // Queue a task to report (if nothing else triggers a report first).
132
111
  // This allows CLS to be reported as soon as FCP fires when
133
112
  // `reportAllChanges` is true.
134
- setTimeout(report, 0);
113
+ setTimeout(report);
135
114
  }
136
115
  }),
137
116
  );
@@ -35,18 +35,15 @@ export const FCPThresholds: MetricRatingThresholds = [1800, 3000];
35
35
  */
36
36
  export const onFCP = (
37
37
  onReport: (metric: FCPMetric) => void,
38
- opts?: ReportOpts,
38
+ opts: ReportOpts = {},
39
39
  ) => {
40
- // Set defaults
41
- opts = opts || {};
42
-
43
40
  whenActivated(() => {
44
41
  const visibilityWatcher = getVisibilityWatcher();
45
42
  let metric = initMetric('FCP');
46
43
  let report: ReturnType<typeof bindReporter>;
47
44
 
48
45
  const handleEntries = (entries: FCPMetric['entries']) => {
49
- entries.forEach((entry) => {
46
+ for (const entry of entries) {
50
47
  if (entry.name === 'first-contentful-paint') {
51
48
  po!.disconnect();
52
49
 
@@ -61,7 +58,7 @@ export const onFCP = (
61
58
  report(true);
62
59
  }
63
60
  }
64
- });
61
+ }
65
62
  };
66
63
 
67
64
  const po = observe('paint', handleEntries);
@@ -17,34 +17,36 @@
17
17
  import {onBFCacheRestore} from './lib/bfcache.js';
18
18
  import {bindReporter} from './lib/bindReporter.js';
19
19
  import {initMetric} from './lib/initMetric.js';
20
- import {
21
- DEFAULT_DURATION_THRESHOLD,
22
- processInteractionEntry,
23
- estimateP98LongestInteraction,
24
- resetInteractions,
25
- } from './lib/interactions.js';
20
+ import {initUnique} from './lib/initUnique.js';
21
+ import {InteractionManager} from './lib/InteractionManager.js';
26
22
  import {observe} from './lib/observe.js';
27
- import {onHidden} from './lib/onHidden.js';
28
23
  import {initInteractionCountPolyfill} from './lib/polyfills/interactionCountPolyfill.js';
29
24
  import {whenActivated} from './lib/whenActivated.js';
30
- import {whenIdle} from './lib/whenIdle.js';
25
+ import {getVisibilityWatcher} from './lib/getVisibilityWatcher.js';
26
+ import {whenIdleOrHidden} from './lib/whenIdleOrHidden.js';
31
27
 
32
- import {INPMetric, MetricRatingThresholds, ReportOpts} from './types.js';
28
+ import {INPMetric, MetricRatingThresholds, INPReportOpts} from './types.js';
33
29
 
34
30
  /** Thresholds for INP. See https://web.dev/articles/inp#what_is_a_good_inp_score */
35
31
  export const INPThresholds: MetricRatingThresholds = [200, 500];
36
32
 
33
+ // The default `durationThreshold` used across this library for observing
34
+ // `event` entries via PerformanceObserver.
35
+ const DEFAULT_DURATION_THRESHOLD = 40;
36
+
37
37
  /**
38
38
  * Calculates the [INP](https://web.dev/articles/inp) value for the current
39
39
  * page and calls the `callback` function once the value is ready, along with
40
40
  * the `event` performance entries reported for that interaction. The reported
41
41
  * value is a `DOMHighResTimeStamp`.
42
42
  *
43
- * A custom `durationThreshold` configuration option can optionally be passed to
44
- * control what `event-timing` entries are considered for INP reporting. The
45
- * default threshold is `40`, which means INP scores of less than 40 are
46
- * reported as 0. Note that this will not affect your 75th percentile INP value
47
- * unless that value is also less than 40 (well below the recommended
43
+ * A custom `durationThreshold` configuration option can optionally be passed
44
+ * to control what `event-timing` entries are considered for INP reporting. The
45
+ * default threshold is `40`, which means INP scores of less than 40 will not
46
+ * be reported. To avoid reporting no interactions in these cases, the library
47
+ * will fall back to the input delay of the first interaction. Note that this
48
+ * will not affect your 75th percentile INP value unless that value is also
49
+ * less than 40 (well below the recommended
48
50
  * [good](https://web.dev/articles/inp#what_is_a_good_inp_score) threshold).
49
51
  *
50
52
  * If the `reportAllChanges` configuration option is set to `true`, the
@@ -63,20 +65,19 @@ export const INPThresholds: MetricRatingThresholds = [200, 500];
63
65
  */
64
66
  export const onINP = (
65
67
  onReport: (metric: INPMetric) => void,
66
- opts?: ReportOpts,
68
+ opts: INPReportOpts = {},
67
69
  ) => {
68
70
  // Return if the browser doesn't support all APIs needed to measure INP.
69
71
  if (
70
72
  !(
71
- 'PerformanceEventTiming' in self &&
73
+ globalThis.PerformanceEventTiming &&
72
74
  'interactionId' in PerformanceEventTiming.prototype
73
75
  )
74
76
  ) {
75
77
  return;
76
78
  }
77
79
 
78
- // Set defaults
79
- opts = opts || {};
80
+ const visibilityWatcher = getVisibilityWatcher();
80
81
 
81
82
  whenActivated(() => {
82
83
  // TODO(philipwalton): remove once the polyfill is no longer needed.
@@ -85,6 +86,8 @@ export const onINP = (
85
86
  let metric = initMetric('INP');
86
87
  let report: ReturnType<typeof bindReporter>;
87
88
 
89
+ const interactionManager = initUnique(opts, InteractionManager);
90
+
88
91
  const handleEntries = (entries: INPMetric['entries']) => {
89
92
  // Queue the `handleEntries()` callback in the next idle task.
90
93
  // This is needed to increase the chances that all event entries that
@@ -92,13 +95,15 @@ export const onINP = (
92
95
  // have been dispatched. Note: there is currently an experiment
93
96
  // running in Chrome (EventTimingKeypressAndCompositionInteractionId)
94
97
  // 123+ that if rolled out fully may make this no longer necessary.
95
- whenIdle(() => {
96
- entries.forEach(processInteractionEntry);
98
+ whenIdleOrHidden(() => {
99
+ for (const entry of entries) {
100
+ interactionManager._processEntry(entry);
101
+ }
97
102
 
98
- const inp = estimateP98LongestInteraction();
103
+ const inp = interactionManager._estimateP98LongestInteraction();
99
104
 
100
- if (inp && inp.latency !== metric.value) {
101
- metric.value = inp.latency;
105
+ if (inp && inp._latency !== metric.value) {
106
+ metric.value = inp._latency;
102
107
  metric.entries = inp.entries;
103
108
  report();
104
109
  }
@@ -112,14 +117,14 @@ export const onINP = (
112
117
  // and performance. Running this callback for any interaction that spans
113
118
  // just one or two frames is likely not worth the insight that could be
114
119
  // gained.
115
- durationThreshold: opts!.durationThreshold ?? DEFAULT_DURATION_THRESHOLD,
120
+ durationThreshold: opts.durationThreshold ?? DEFAULT_DURATION_THRESHOLD,
116
121
  });
117
122
 
118
123
  report = bindReporter(
119
124
  onReport,
120
125
  metric,
121
126
  INPThresholds,
122
- opts!.reportAllChanges,
127
+ opts.reportAllChanges,
123
128
  );
124
129
 
125
130
  if (po) {
@@ -127,7 +132,7 @@ export const onINP = (
127
132
  // where the first interaction is less than the `durationThreshold`.
128
133
  po.observe({type: 'first-input', buffered: true});
129
134
 
130
- onHidden(() => {
135
+ visibilityWatcher.onHidden(() => {
131
136
  handleEntries(po.takeRecords() as INPMetric['entries']);
132
137
  report(true);
133
138
  });
@@ -135,14 +140,14 @@ export const onINP = (
135
140
  // Only report after a bfcache restore if the `PerformanceObserver`
136
141
  // successfully registered.
137
142
  onBFCacheRestore(() => {
138
- resetInteractions();
143
+ interactionManager._resetInteractions();
139
144
 
140
145
  metric = initMetric('INP');
141
146
  report = bindReporter(
142
147
  onReport,
143
148
  metric,
144
149
  INPThresholds,
145
- opts!.reportAllChanges,
150
+ opts.reportAllChanges,
146
151
  );
147
152
  });
148
153
  }
@@ -14,24 +14,23 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ import {LCPEntryManager} from './lib/LCPEntryManager.js';
17
18
  import {onBFCacheRestore} from './lib/bfcache.js';
18
19
  import {bindReporter} from './lib/bindReporter.js';
19
20
  import {doubleRAF} from './lib/doubleRAF.js';
20
21
  import {getActivationStart} from './lib/getActivationStart.js';
21
22
  import {getVisibilityWatcher} from './lib/getVisibilityWatcher.js';
22
23
  import {initMetric} from './lib/initMetric.js';
24
+ import {initUnique} from './lib/initUnique.js';
23
25
  import {observe} from './lib/observe.js';
24
- import {onHidden} from './lib/onHidden.js';
25
26
  import {runOnce} from './lib/runOnce.js';
26
27
  import {whenActivated} from './lib/whenActivated.js';
27
- import {whenIdle} from './lib/whenIdle.js';
28
+ import {whenIdleOrHidden} from './lib/whenIdleOrHidden.js';
28
29
  import {LCPMetric, MetricRatingThresholds, ReportOpts} from './types.js';
29
30
 
30
31
  /** Thresholds for LCP. See https://web.dev/articles/lcp#what_is_a_good_lcp_score */
31
32
  export const LCPThresholds: MetricRatingThresholds = [2500, 4000];
32
33
 
33
- const reportedMetricIDs: Record<string, boolean> = {};
34
-
35
34
  /**
36
35
  * Calculates the [LCP](https://web.dev/articles/lcp) value for the current page and
37
36
  * calls the `callback` function once the value is ready (along with the
@@ -45,16 +44,15 @@ const reportedMetricIDs: Record<string, boolean> = {};
45
44
  */
46
45
  export const onLCP = (
47
46
  onReport: (metric: LCPMetric) => void,
48
- opts?: ReportOpts,
47
+ opts: ReportOpts = {},
49
48
  ) => {
50
- // Set defaults
51
- opts = opts || {};
52
-
53
49
  whenActivated(() => {
54
50
  const visibilityWatcher = getVisibilityWatcher();
55
51
  let metric = initMetric('LCP');
56
52
  let report: ReturnType<typeof bindReporter>;
57
53
 
54
+ const lcpEntryManager = initUnique(opts, LCPEntryManager);
55
+
58
56
  const handleEntries = (entries: LCPMetric['entries']) => {
59
57
  // If reportAllChanges is set then call this function for each entry,
60
58
  // otherwise only consider the last one.
@@ -62,7 +60,9 @@ export const onLCP = (
62
60
  entries = entries.slice(-1);
63
61
  }
64
62
 
65
- entries.forEach((entry) => {
63
+ for (const entry of entries) {
64
+ lcpEntryManager._processEntry(entry);
65
+
66
66
  // Only report if the page wasn't hidden prior to LCP.
67
67
  if (entry.startTime < visibilityWatcher.firstHiddenTime) {
68
68
  // The startTime attribute returns the value of the renderTime if it is
@@ -75,7 +75,7 @@ export const onLCP = (
75
75
  metric.entries = [entry];
76
76
  report();
77
77
  }
78
- });
78
+ }
79
79
  };
80
80
 
81
81
  const po = observe('largest-contentful-paint', handleEntries);
@@ -88,29 +88,37 @@ export const onLCP = (
88
88
  opts!.reportAllChanges,
89
89
  );
90
90
 
91
+ // Ensure this logic only runs once, since it can be triggered from
92
+ // any of three different event listeners below.
91
93
  const stopListening = runOnce(() => {
92
- if (!reportedMetricIDs[metric.id]) {
93
- handleEntries(po!.takeRecords() as LCPMetric['entries']);
94
- po!.disconnect();
95
- reportedMetricIDs[metric.id] = true;
96
- report(true);
97
- }
94
+ handleEntries(po!.takeRecords() as LCPMetric['entries']);
95
+ po!.disconnect();
96
+ report(true);
98
97
  });
99
98
 
100
- // Stop listening after input. Note: while scrolling is an input that
101
- // stops LCP observation, it's unreliable since it can be programmatically
102
- // generated. See: https://github.com/GoogleChrome/web-vitals/issues/75
103
- ['keydown', 'click'].forEach((type) => {
104
- // Wrap in a setTimeout so the callback is run in a separate task
105
- // to avoid extending the keyboard/click handler to reduce INP impact
106
- // https://github.com/GoogleChrome/web-vitals/issues/383
107
- addEventListener(type, () => whenIdle(stopListening), {
108
- once: true,
99
+ // Need a separate wrapper to ensure the `runOnce` function above is
100
+ // common for all three functions
101
+ const stopListeningWrapper = (event: Event) => {
102
+ if (event.isTrusted) {
103
+ // Wrap the listener in an idle callback so it's run in a separate
104
+ // task to reduce potential INP impact.
105
+ // https://github.com/GoogleChrome/web-vitals/issues/383
106
+ whenIdleOrHidden(stopListening);
107
+ removeEventListener(event.type, stopListeningWrapper, {
108
+ capture: true,
109
+ });
110
+ }
111
+ };
112
+
113
+ // Stop listening after input or visibilitychange.
114
+ // Note: while scrolling is an input that stops LCP observation, it's
115
+ // unreliable since it can be programmatically generated.
116
+ // See: https://github.com/GoogleChrome/web-vitals/issues/75
117
+ for (const type of ['keydown', 'click', 'visibilitychange']) {
118
+ addEventListener(type, stopListeningWrapper, {
109
119
  capture: true,
110
120
  });
111
- });
112
-
113
- onHidden(stopListening);
121
+ }
114
122
 
115
123
  // Only report after a bfcache restore if the `PerformanceObserver`
116
124
  // successfully registered.
@@ -125,7 +133,6 @@ export const onLCP = (
125
133
 
126
134
  doubleRAF(() => {
127
135
  metric.value = performance.now() - event.timeStamp;
128
- reportedMetricIDs[metric.id] = true;
129
136
  report(true);
130
137
  });
131
138
  });
@@ -36,7 +36,7 @@ const whenReady = (callback: () => void) => {
36
36
  addEventListener('load', () => whenReady(callback), true);
37
37
  } else {
38
38
  // Queue a task so the callback runs after `loadEventEnd`.
39
- setTimeout(callback, 0);
39
+ setTimeout(callback);
40
40
  }
41
41
  };
42
42
 
@@ -57,11 +57,8 @@ const whenReady = (callback: () => void) => {
57
57
  */
58
58
  export const onTTFB = (
59
59
  onReport: (metric: TTFBMetric) => void,
60
- opts?: ReportOpts,
60
+ opts: ReportOpts = {},
61
61
  ) => {
62
- // Set defaults
63
- opts = opts || {};
64
-
65
62
  let metric = initMetric('TTFB');
66
63
  let report = bindReporter(
67
64
  onReport,
@@ -16,7 +16,6 @@
16
16
 
17
17
  import type {CLSMetric, CLSMetricWithAttribution} from './cls.js';
18
18
  import type {FCPMetric, FCPMetricWithAttribution} from './fcp.js';
19
- import type {FIDMetric, FIDMetricWithAttribution} from './fid.js';
20
19
  import type {INPMetric, INPMetricWithAttribution} from './inp.js';
21
20
  import type {LCPMetric, LCPMetricWithAttribution} from './lcp.js';
22
21
  import type {TTFBMetric, TTFBMetricWithAttribution} from './ttfb.js';
@@ -25,7 +24,7 @@ export interface Metric {
25
24
  /**
26
25
  * The name of the metric (in acronym form).
27
26
  */
28
- name: 'CLS' | 'FCP' | 'FID' | 'INP' | 'LCP' | 'TTFB';
27
+ name: 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB';
29
28
 
30
29
  /**
31
30
  * The current value of the metric.
@@ -87,7 +86,6 @@ export interface Metric {
87
86
  export type MetricType =
88
87
  | CLSMetric
89
88
  | FCPMetric
90
- | FIDMetric
91
89
  | INPMetric
92
90
  | LCPMetric
93
91
  | TTFBMetric;
@@ -96,7 +94,6 @@ export type MetricType =
96
94
  export type MetricWithAttribution =
97
95
  | CLSMetricWithAttribution
98
96
  | FCPMetricWithAttribution
99
- | FIDMetricWithAttribution
100
97
  | INPMetricWithAttribution
101
98
  | LCPMetricWithAttribution
102
99
  | TTFBMetricWithAttribution;
@@ -127,7 +124,10 @@ export interface ReportCallback {
127
124
 
128
125
  export interface ReportOpts {
129
126
  reportAllChanges?: boolean;
130
- durationThreshold?: number;
127
+ }
128
+
129
+ export interface AttributionReportOpts extends ReportOpts {
130
+ generateTarget?: (el: Node | null) => string | undefined;
131
131
  }
132
132
 
133
133
  /**
@@ -31,9 +31,11 @@ export interface CLSMetric extends Metric {
31
31
  */
32
32
  export interface CLSAttribution {
33
33
  /**
34
- * A selector identifying the first element (in document order) that
35
- * shifted when the single largest layout shift contributing to the page's
36
- * CLS score occurred.
34
+ * By default, a selector identifying the first element (in document order)
35
+ * that shifted when the single largest layout shift that contributed to the
36
+ * page's CLS score occurred. If the `generateTarget` configuration option
37
+ * was passed, then this will instead be the return value of that function,
38
+ * falling back to the default if that returns null or undefined.
37
39
  */
38
40
  largestShiftTarget?: string;
39
41
  /**