@paulirish/trace_engine 0.0.32 → 0.0.34

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 (309) hide show
  1. package/.tmp/tsbuildinfo/analyze-trace.d.mts +18 -0
  2. package/.tmp/tsbuildinfo/analyze-trace.d.mts.map +1 -0
  3. package/.tmp/tsbuildinfo/models/trace/LanternComputationData.d.ts +46 -0
  4. package/.tmp/tsbuildinfo/models/trace/LanternComputationData.d.ts.map +1 -0
  5. package/.tmp/tsbuildinfo/models/trace/LegacyTracingModel.d.ts +2 -0
  6. package/.tmp/tsbuildinfo/models/trace/LegacyTracingModel.d.ts.map +1 -0
  7. package/.tmp/tsbuildinfo/models/trace/ModelImpl.d.ts +72 -0
  8. package/.tmp/tsbuildinfo/models/trace/ModelImpl.d.ts.map +1 -0
  9. package/.tmp/tsbuildinfo/models/trace/Processor.d.ts +25 -0
  10. package/.tmp/tsbuildinfo/models/trace/Processor.d.ts.map +1 -0
  11. package/.tmp/tsbuildinfo/models/trace/TracingManager.d.ts +2 -0
  12. package/.tmp/tsbuildinfo/models/trace/TracingManager.d.ts.map +1 -0
  13. package/.tmp/tsbuildinfo/models/trace/trace.d.ts +13 -0
  14. package/.tmp/tsbuildinfo/models/trace/trace.d.ts.map +1 -0
  15. package/.tmp/tsbuildinfo/test/test-trace-engine.d.mts +2 -0
  16. package/.tmp/tsbuildinfo/test/test-trace-engine.d.mts.map +1 -0
  17. package/.tmp/tsbuildinfo/third_party/third-party-web/third-party-web.d.ts +3 -0
  18. package/.tmp/tsbuildinfo/third_party/third-party-web/third-party-web.d.ts.map +1 -0
  19. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -0
  20. package/README.md +6 -10
  21. package/analyze-trace.mjs +51 -16
  22. package/core/platform/ArrayUtilities.js +1 -0
  23. package/core/platform/ArrayUtilities.js.map +1 -1
  24. package/core/platform/DevToolsPath.d.ts +1 -1
  25. package/core/platform/DevToolsPath.js.map +1 -1
  26. package/core/platform/MimeType.js +4 -2
  27. package/core/platform/MimeType.js.map +1 -1
  28. package/core/platform/NumberUtilities.js +8 -0
  29. package/core/platform/NumberUtilities.js.map +1 -1
  30. package/core/platform/ServerTiming.d.ts +31 -0
  31. package/core/platform/ServerTiming.js +212 -0
  32. package/core/platform/ServerTiming.js.map +1 -0
  33. package/core/platform/Timing.d.ts +1 -1
  34. package/core/platform/Timing.js.map +1 -1
  35. package/core/platform/TypescriptUtilities.d.ts +3 -0
  36. package/core/platform/TypescriptUtilities.js.map +1 -1
  37. package/core/platform/UIString.d.ts +1 -1
  38. package/core/platform/UIString.js.map +1 -1
  39. package/core/platform/UserVisibleError.d.ts +1 -1
  40. package/core/platform/UserVisibleError.js.map +1 -1
  41. package/core/platform/platform-tsconfig.json +1 -1
  42. package/core/platform/platform.d.ts +2 -2
  43. package/core/platform/platform.js +2 -2
  44. package/core/platform/platform.js.map +1 -1
  45. package/generated/protocol.d.ts +289 -16
  46. package/models/trace/LanternComputationData.d.ts +4 -4
  47. package/models/trace/LanternComputationData.js +22 -23
  48. package/models/trace/LanternComputationData.js.map +1 -1
  49. package/models/trace/ModelImpl.d.ts +11 -12
  50. package/models/trace/ModelImpl.js +22 -33
  51. package/models/trace/ModelImpl.js.map +1 -1
  52. package/models/trace/Processor.d.ts +21 -12
  53. package/models/trace/Processor.js +151 -67
  54. package/models/trace/Processor.js.map +1 -1
  55. package/models/trace/TracingManager.js.map +1 -1
  56. package/models/trace/extras/FetchNodes.d.ts +8 -8
  57. package/models/trace/extras/FetchNodes.js +16 -11
  58. package/models/trace/extras/FetchNodes.js.map +1 -1
  59. package/models/trace/extras/FilmStrip.d.ts +2 -2
  60. package/models/trace/extras/FilmStrip.js +8 -8
  61. package/models/trace/extras/FilmStrip.js.map +1 -1
  62. package/models/trace/extras/MainThreadActivity.d.ts +1 -1
  63. package/models/trace/extras/MainThreadActivity.js +1 -1
  64. package/models/trace/extras/MainThreadActivity.js.map +1 -1
  65. package/models/trace/extras/Metadata.js +2 -2
  66. package/models/trace/extras/Metadata.js.map +1 -1
  67. package/models/trace/extras/ThirdParties.d.ts +23 -0
  68. package/models/trace/extras/ThirdParties.js +152 -0
  69. package/models/trace/extras/ThirdParties.js.map +1 -0
  70. package/models/trace/extras/URLForEntry.d.ts +9 -1
  71. package/models/trace/extras/URLForEntry.js +18 -10
  72. package/models/trace/extras/URLForEntry.js.map +1 -1
  73. package/models/trace/extras/extras-tsconfig.json +1 -0
  74. package/models/trace/extras/extras.d.ts +4 -1
  75. package/models/trace/extras/extras.js +4 -1
  76. package/models/trace/extras/extras.js.map +1 -1
  77. package/models/trace/handlers/AnimationHandler.d.ts +2 -2
  78. package/models/trace/handlers/AnimationHandler.js +1 -1
  79. package/models/trace/handlers/AnimationHandler.js.map +1 -1
  80. package/models/trace/handlers/AuctionWorkletsHandler.d.ts +2 -2
  81. package/models/trace/handlers/AuctionWorkletsHandler.js +11 -11
  82. package/models/trace/handlers/AuctionWorkletsHandler.js.map +1 -1
  83. package/models/trace/handlers/ExtensionTraceDataHandler.d.ts +6 -6
  84. package/models/trace/handlers/ExtensionTraceDataHandler.js +12 -8
  85. package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
  86. package/models/trace/handlers/FramesHandler.d.ts +34 -22
  87. package/models/trace/handlers/FramesHandler.js +54 -26
  88. package/models/trace/handlers/FramesHandler.js.map +1 -1
  89. package/models/trace/handlers/GPUHandler.d.ts +4 -4
  90. package/models/trace/handlers/GPUHandler.js +3 -3
  91. package/models/trace/handlers/GPUHandler.js.map +1 -1
  92. package/models/trace/handlers/ImagePaintingHandler.d.ts +3 -3
  93. package/models/trace/handlers/ImagePaintingHandler.js +6 -8
  94. package/models/trace/handlers/ImagePaintingHandler.js.map +1 -1
  95. package/models/trace/handlers/InitiatorsHandler.d.ts +3 -3
  96. package/models/trace/handlers/InitiatorsHandler.js +25 -14
  97. package/models/trace/handlers/InitiatorsHandler.js.map +1 -1
  98. package/models/trace/handlers/InvalidationsHandler.d.ts +4 -2
  99. package/models/trace/handlers/InvalidationsHandler.js +29 -11
  100. package/models/trace/handlers/InvalidationsHandler.js.map +1 -1
  101. package/models/trace/handlers/LargestImagePaintHandler.d.ts +2 -2
  102. package/models/trace/handlers/LargestImagePaintHandler.js +1 -1
  103. package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
  104. package/models/trace/handlers/LargestTextPaintHandler.d.ts +2 -2
  105. package/models/trace/handlers/LargestTextPaintHandler.js +1 -1
  106. package/models/trace/handlers/LargestTextPaintHandler.js.map +1 -1
  107. package/models/trace/handlers/LayerTreeHandler.d.ts +6 -6
  108. package/models/trace/handlers/LayerTreeHandler.js +6 -6
  109. package/models/trace/handlers/LayerTreeHandler.js.map +1 -1
  110. package/models/trace/handlers/LayoutShiftsHandler.d.ts +14 -20
  111. package/models/trace/handlers/LayoutShiftsHandler.js +87 -12
  112. package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
  113. package/models/trace/handlers/MemoryHandler.d.ts +2 -2
  114. package/models/trace/handlers/MemoryHandler.js +1 -1
  115. package/models/trace/handlers/MemoryHandler.js.map +1 -1
  116. package/models/trace/handlers/MetaHandler.d.ts +15 -14
  117. package/models/trace/handlers/MetaHandler.js +32 -30
  118. package/models/trace/handlers/MetaHandler.js.map +1 -1
  119. package/models/trace/handlers/ModelHandlers.d.ts +1 -1
  120. package/models/trace/handlers/ModelHandlers.js +1 -1
  121. package/models/trace/handlers/ModelHandlers.js.map +1 -1
  122. package/models/trace/handlers/NetworkRequestsHandler.d.ts +13 -12
  123. package/models/trace/handlers/NetworkRequestsHandler.js +68 -66
  124. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  125. package/models/trace/handlers/PageFramesHandler.d.ts +2 -2
  126. package/models/trace/handlers/PageFramesHandler.js +2 -2
  127. package/models/trace/handlers/PageFramesHandler.js.map +1 -1
  128. package/models/trace/handlers/PageLoadMetricsHandler.d.ts +7 -7
  129. package/models/trace/handlers/PageLoadMetricsHandler.js +21 -24
  130. package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
  131. package/models/trace/handlers/RendererHandler.d.ts +19 -19
  132. package/models/trace/handlers/RendererHandler.js +5 -5
  133. package/models/trace/handlers/RendererHandler.js.map +1 -1
  134. package/models/trace/handlers/SamplesHandler.d.ts +6 -6
  135. package/models/trace/handlers/SamplesHandler.js +3 -3
  136. package/models/trace/handlers/SamplesHandler.js.map +1 -1
  137. package/models/trace/handlers/ScreenshotsHandler.d.ts +6 -4
  138. package/models/trace/handlers/ScreenshotsHandler.js +11 -9
  139. package/models/trace/handlers/ScreenshotsHandler.js.map +1 -1
  140. package/models/trace/handlers/SelectorStatsHandler.d.ts +3 -3
  141. package/models/trace/handlers/SelectorStatsHandler.js +2 -2
  142. package/models/trace/handlers/SelectorStatsHandler.js.map +1 -1
  143. package/models/trace/handlers/ServerTimingsHandler.d.ts +10 -0
  144. package/models/trace/handlers/ServerTimingsHandler.js +118 -0
  145. package/models/trace/handlers/ServerTimingsHandler.js.map +1 -0
  146. package/models/trace/handlers/Threads.d.ts +7 -7
  147. package/models/trace/handlers/Threads.js +5 -5
  148. package/models/trace/handlers/Threads.js.map +1 -1
  149. package/models/trace/handlers/UserInteractionsHandler.d.ts +13 -11
  150. package/models/trace/handlers/UserInteractionsHandler.js +13 -7
  151. package/models/trace/handlers/UserInteractionsHandler.js.map +1 -1
  152. package/models/trace/handlers/UserTimingsHandler.d.ts +5 -5
  153. package/models/trace/handlers/UserTimingsHandler.js +52 -9
  154. package/models/trace/handlers/UserTimingsHandler.js.map +1 -1
  155. package/models/trace/handlers/WarningsHandler.d.ts +5 -5
  156. package/models/trace/handlers/WarningsHandler.js +4 -5
  157. package/models/trace/handlers/WarningsHandler.js.map +1 -1
  158. package/models/trace/handlers/WorkersHandler.d.ts +4 -4
  159. package/models/trace/handlers/WorkersHandler.js +1 -1
  160. package/models/trace/handlers/WorkersHandler.js.map +1 -1
  161. package/models/trace/handlers/handlers-tsconfig.json +1 -1
  162. package/models/trace/handlers/types.d.ts +7 -7
  163. package/models/trace/handlers/types.js.map +1 -1
  164. package/models/trace/helpers/Extensions.d.ts +2 -2
  165. package/models/trace/helpers/Extensions.js.map +1 -1
  166. package/models/trace/helpers/Network.d.ts +2 -2
  167. package/models/trace/helpers/Network.js +19 -2
  168. package/models/trace/helpers/Network.js.map +1 -1
  169. package/models/trace/helpers/SamplesIntegrator.d.ts +5 -5
  170. package/models/trace/helpers/SamplesIntegrator.js +10 -11
  171. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  172. package/models/trace/helpers/SyntheticEvents.d.ts +8 -14
  173. package/models/trace/helpers/SyntheticEvents.js +20 -31
  174. package/models/trace/helpers/SyntheticEvents.js.map +1 -1
  175. package/models/trace/helpers/Timing.d.ts +18 -4
  176. package/models/trace/helpers/Timing.js +43 -1
  177. package/models/trace/helpers/Timing.js.map +1 -1
  178. package/models/trace/helpers/Trace.d.ts +46 -32
  179. package/models/trace/helpers/Trace.js +53 -24
  180. package/models/trace/helpers/Trace.js.map +1 -1
  181. package/models/trace/helpers/TreeHelpers.d.ts +40 -8
  182. package/models/trace/helpers/TreeHelpers.js +147 -19
  183. package/models/trace/helpers/TreeHelpers.js.map +1 -1
  184. package/models/trace/helpers/helpers-tsconfig.json +3 -0
  185. package/models/trace/insights/Common.d.ts +4 -3
  186. package/models/trace/insights/Common.js +22 -7
  187. package/models/trace/insights/Common.js.map +1 -1
  188. package/models/trace/insights/CumulativeLayoutShift.d.ts +36 -13
  189. package/models/trace/insights/CumulativeLayoutShift.js +199 -73
  190. package/models/trace/insights/CumulativeLayoutShift.js.map +1 -1
  191. package/models/trace/insights/DocumentLatency.d.ts +9 -4
  192. package/models/trace/insights/DocumentLatency.js +82 -7
  193. package/models/trace/insights/DocumentLatency.js.map +1 -1
  194. package/models/trace/insights/FontDisplay.d.ts +11 -0
  195. package/models/trace/insights/FontDisplay.js +44 -0
  196. package/models/trace/insights/FontDisplay.js.map +1 -0
  197. package/models/trace/insights/InsightRunners.d.ts +3 -0
  198. package/models/trace/insights/InsightRunners.js +3 -0
  199. package/models/trace/insights/InsightRunners.js.map +1 -1
  200. package/models/trace/insights/InteractionToNextPaint.d.ts +4 -5
  201. package/models/trace/insights/InteractionToNextPaint.js +5 -3
  202. package/models/trace/insights/InteractionToNextPaint.js.map +1 -1
  203. package/models/trace/insights/LargestContentfulPaint.d.ts +20 -7
  204. package/models/trace/insights/LargestContentfulPaint.js +57 -37
  205. package/models/trace/insights/LargestContentfulPaint.js.map +1 -1
  206. package/models/trace/insights/RenderBlocking.d.ts +3 -3
  207. package/models/trace/insights/RenderBlocking.js +29 -24
  208. package/models/trace/insights/RenderBlocking.js.map +1 -1
  209. package/models/trace/insights/SlowCSSSelector.d.ts +11 -0
  210. package/models/trace/insights/SlowCSSSelector.js +67 -0
  211. package/models/trace/insights/SlowCSSSelector.js.map +1 -0
  212. package/models/trace/insights/ThirdPartyWeb.d.ts +13 -0
  213. package/models/trace/insights/ThirdPartyWeb.js +42 -0
  214. package/models/trace/insights/ThirdPartyWeb.js.map +1 -0
  215. package/models/trace/insights/Viewport.d.ts +5 -2
  216. package/models/trace/insights/Viewport.js +14 -9
  217. package/models/trace/insights/Viewport.js.map +1 -1
  218. package/models/trace/insights/insights-tsconfig.json +9 -0
  219. package/models/trace/insights/insights.d.ts +1 -0
  220. package/models/trace/insights/insights.js +1 -0
  221. package/models/trace/insights/insights.js.map +1 -1
  222. package/models/trace/insights/types.d.ts +43 -25
  223. package/models/trace/insights/types.js.map +1 -1
  224. package/models/trace/lantern/core/NetworkAnalyzer.d.ts +9 -9
  225. package/models/trace/lantern/core/NetworkAnalyzer.js +18 -15
  226. package/models/trace/lantern/core/NetworkAnalyzer.js.map +1 -1
  227. package/models/trace/lantern/graph/BaseNode.d.ts +4 -4
  228. package/models/trace/lantern/graph/BaseNode.js +21 -21
  229. package/models/trace/lantern/graph/BaseNode.js.map +1 -1
  230. package/models/trace/lantern/graph/CPUNode.d.ts +1 -1
  231. package/models/trace/lantern/graph/CPUNode.js +5 -5
  232. package/models/trace/lantern/graph/CPUNode.js.map +1 -1
  233. package/models/trace/lantern/graph/PageDependencyGraph.d.ts +4 -4
  234. package/models/trace/lantern/graph/PageDependencyGraph.js +5 -5
  235. package/models/trace/lantern/graph/PageDependencyGraph.js.map +1 -1
  236. package/models/trace/lantern/simulation/ConnectionPool.d.ts +7 -7
  237. package/models/trace/lantern/simulation/ConnectionPool.js +26 -26
  238. package/models/trace/lantern/simulation/ConnectionPool.js.map +1 -1
  239. package/models/trace/lantern/simulation/DNSCache.d.ts +3 -3
  240. package/models/trace/lantern/simulation/DNSCache.js +11 -11
  241. package/models/trace/lantern/simulation/DNSCache.js.map +1 -1
  242. package/models/trace/lantern/simulation/SimulationTimingMap.d.ts +1 -1
  243. package/models/trace/lantern/simulation/SimulationTimingMap.js +15 -15
  244. package/models/trace/lantern/simulation/SimulationTimingMap.js.map +1 -1
  245. package/models/trace/lantern/simulation/Simulator.d.ts +28 -28
  246. package/models/trace/lantern/simulation/Simulator.js +113 -113
  247. package/models/trace/lantern/simulation/Simulator.js.map +1 -1
  248. package/models/trace/lantern/simulation/TCPConnection.d.ts +9 -9
  249. package/models/trace/lantern/simulation/TCPConnection.js +36 -36
  250. package/models/trace/lantern/simulation/TCPConnection.js.map +1 -1
  251. package/models/trace/root-causes/LayoutShift.d.ts +13 -13
  252. package/models/trace/root-causes/LayoutShift.js +7 -25
  253. package/models/trace/root-causes/LayoutShift.js.map +1 -1
  254. package/models/trace/types/Configuration.d.ts +16 -0
  255. package/models/trace/types/Configuration.js +1 -0
  256. package/models/trace/types/Configuration.js.map +1 -1
  257. package/models/trace/types/Extensions.d.ts +9 -12
  258. package/models/trace/types/Extensions.js +2 -1
  259. package/models/trace/types/Extensions.js.map +1 -1
  260. package/models/trace/types/File.d.ts +55 -23
  261. package/models/trace/types/File.js +15 -3
  262. package/models/trace/types/File.js.map +1 -1
  263. package/models/trace/types/TraceEvents.d.ts +868 -713
  264. package/models/trace/types/TraceEvents.js +281 -276
  265. package/models/trace/types/TraceEvents.js.map +1 -1
  266. package/models/trace/types/types.d.ts +1 -1
  267. package/models/trace/types/types.js +1 -1
  268. package/models/trace/types/types.js.map +1 -1
  269. package/package.json +10 -4
  270. package/test/test-trace-engine.mjs +56 -3
  271. package/third_party/third-party-web/third-party-web.js +1 -0
  272. package/tsconfig.json +29 -0
  273. package/core/platform/PromiseUtilities.d.ts +0 -10
  274. package/core/platform/PromiseUtilities.js +0 -18
  275. package/core/platform/PromiseUtilities.js.map +0 -1
  276. package/core/platform/SetUtilities.d.ts +0 -2
  277. package/core/platform/SetUtilities.js +0 -23
  278. package/core/platform/SetUtilities.js.map +0 -1
  279. package/models/trace/EntriesFilter.d.ts +0 -72
  280. package/models/trace/EntriesFilter.js +0 -296
  281. package/models/trace/EntriesFilter.js.map +0 -1
  282. package/models/trace/LegacyTracingModel.js.map +0 -1
  283. package/models/trace/handlers/EnhancedTracesHandler.d.ts +0 -48
  284. package/models/trace/handlers/EnhancedTracesHandler.js +0 -165
  285. package/models/trace/handlers/EnhancedTracesHandler.js.map +0 -1
  286. package/models/trace/lantern/BaseNode.d.ts +0 -91
  287. package/models/trace/lantern/BaseNode.js +0 -268
  288. package/models/trace/lantern/BaseNode.js.map +0 -1
  289. package/models/trace/lantern/CPUNode.d.ts +0 -24
  290. package/models/trace/lantern/CPUNode.js +0 -64
  291. package/models/trace/lantern/CPUNode.js.map +0 -1
  292. package/models/trace/lantern/LanternError.d.ts +0 -3
  293. package/models/trace/lantern/LanternError.js +0 -7
  294. package/models/trace/lantern/LanternError.js.map +0 -1
  295. package/models/trace/lantern/MetricsModule.d.ts +0 -11
  296. package/models/trace/lantern/MetricsModule.js +0 -14
  297. package/models/trace/lantern/MetricsModule.js.map +0 -1
  298. package/models/trace/lantern/NetworkNode.d.ts +0 -22
  299. package/models/trace/lantern/NetworkNode.js +0 -83
  300. package/models/trace/lantern/NetworkNode.js.map +0 -1
  301. package/models/trace/lantern/PageDependencyGraph.d.ts +0 -43
  302. package/models/trace/lantern/PageDependencyGraph.js +0 -509
  303. package/models/trace/lantern/PageDependencyGraph.js.map +0 -1
  304. package/models/trace/lantern/SimulationModule.d.ts +0 -17
  305. package/models/trace/lantern/SimulationModule.js +0 -13
  306. package/models/trace/lantern/SimulationModule.js.map +0 -1
  307. package/models/trace/lantern/simulation/NetworkAnalyzer.d.ts +0 -112
  308. package/models/trace/lantern/simulation/NetworkAnalyzer.js +0 -486
  309. package/models/trace/lantern/simulation/NetworkAnalyzer.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Viewport.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Viewport.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAAqB,cAAc,EAAmD,MAAM,YAAY,CAAC;AAEhH,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,eAA0C,EAAE,OAAiC;IAE3G,MAAM,MAAM,GAAG,eAAe,CAAC,gBAAgB,CAAC,gCAAgC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QAC9F,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,UAAU,GACZ,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAChH,IAAI,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC;YACjE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,uCAAuC;QACvC,OAAO;YACL,eAAe,EAAE,IAAI;YACrB,QAAQ,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC;SACrC,CAAC;IACJ,CAAC;IAED,wDAAwD;IACxD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACpC,OAAO;gBACL,eAAe,EAAE,KAAK;aACvB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,eAAe,EAAE,IAAI;KACtB,CAAC;AACJ,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\n\nimport {type InsightResult, InsightWarning, type NavigationInsightContext, type RequiredData} from './types.js';\n\nexport function deps(): ['Meta', 'UserInteractions'] {\n return ['Meta', 'UserInteractions'];\n}\n\nexport function generateInsight(traceParsedData: RequiredData<typeof deps>, context: NavigationInsightContext):\n InsightResult<{mobileOptimized: boolean | null}> {\n const events = traceParsedData.UserInteractions.beginCommitCompositorFrameEvents.filter(event => {\n if (event.args.frame !== context.frameId) {\n return false;\n }\n\n const navigation =\n Helpers.Trace.getNavigationForTraceEvent(event, context.frameId, traceParsedData.Meta.navigationsByFrameId);\n if (navigation?.args.data?.navigationId !== context.navigationId) {\n return false;\n }\n\n return true;\n });\n\n if (!events.length) {\n // Trace doesn't have the data we need.\n return {\n mobileOptimized: null,\n warnings: [InsightWarning.NO_LAYOUT],\n };\n }\n\n // Returns true only if all events are mobile optimized.\n for (const event of events) {\n if (!event.args.is_mobile_optimized) {\n return {\n mobileOptimized: false,\n };\n }\n }\n\n return {\n mobileOptimized: true,\n };\n}\n"]}
1
+ {"version":3,"file":"Viewport.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Viewport.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAGjD,OAAO,EAA6C,cAAc,EAAoB,MAAM,YAAY,CAAC;AAEzG,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AACtC,CAAC;AAOD,MAAM,UAAU,eAAe,CAC3B,WAAsC,EAAE,OAA0B;IACpE,MAAM,gBAAgB,GAAG,WAAW,CAAC,gBAAgB,CAAC,gCAAgC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QACpG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC;QAC7B,uCAAuC;QACvC,OAAO;YACL,eAAe,EAAE,IAAI;YACrB,QAAQ,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC;SACrC,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QACtF,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAC9C,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,wDAAwD;IACxD,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACpC,OAAO;gBACL,eAAe,EAAE,KAAK;gBACtB,aAAa;gBACb,aAAa,EAAE,EAAC,GAAG,EAAE,GAAgC,EAAC;aACvD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,eAAe,EAAE,IAAI;QACrB,aAAa;KACd,CAAC;AACJ,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {type InsightResult, type InsightSetContext, InsightWarning, type RequiredData} from './types.js';\n\nexport function deps(): ['Meta', 'UserInteractions'] {\n return ['Meta', 'UserInteractions'];\n}\n\nexport type ViewportInsightResult = InsightResult<{\n mobileOptimized: boolean | null,\n viewportEvent?: Types.Events.ParseMetaViewport,\n}>;\n\nexport function generateInsight(\n parsedTrace: RequiredData<typeof deps>, context: InsightSetContext): ViewportInsightResult {\n const compositorEvents = parsedTrace.UserInteractions.beginCommitCompositorFrameEvents.filter(event => {\n if (event.args.frame !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n if (!compositorEvents.length) {\n // Trace doesn't have the data we need.\n return {\n mobileOptimized: null,\n warnings: [InsightWarning.NO_LAYOUT],\n };\n }\n\n const viewportEvent = parsedTrace.UserInteractions.parseMetaViewportEvents.find(event => {\n if (event.args.data.frame !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n // Returns true only if all events are mobile optimized.\n for (const event of compositorEvents) {\n if (!event.args.is_mobile_optimized) {\n return {\n mobileOptimized: false,\n viewportEvent,\n metricSavings: {INP: 300 as Types.Timing.MilliSeconds},\n };\n }\n }\n\n return {\n mobileOptimized: true,\n viewportEvent,\n };\n}\n"]}
@@ -32,10 +32,13 @@
32
32
  "../../../../../../../front_end/models/trace/insights/Common.ts",
33
33
  "../../../../../../../front_end/models/trace/insights/CumulativeLayoutShift.ts",
34
34
  "../../../../../../../front_end/models/trace/insights/DocumentLatency.ts",
35
+ "../../../../../../../front_end/models/trace/insights/FontDisplay.ts",
35
36
  "../../../../../../../front_end/models/trace/insights/InsightRunners.ts",
36
37
  "../../../../../../../front_end/models/trace/insights/InteractionToNextPaint.ts",
37
38
  "../../../../../../../front_end/models/trace/insights/LargestContentfulPaint.ts",
38
39
  "../../../../../../../front_end/models/trace/insights/RenderBlocking.ts",
40
+ "../../../../../../../front_end/models/trace/insights/SlowCSSSelector.ts",
41
+ "../../../../../../../front_end/models/trace/insights/ThirdPartyWeb.ts",
39
42
  "../../../../../../../front_end/models/trace/insights/Viewport.ts",
40
43
  "../../../../../../../front_end/models/trace/insights/types.ts",
41
44
  "../../../../../../../front_end/legacy/legacy-defs.d.ts",
@@ -43,6 +46,12 @@
43
46
  "../../../../../../../node_modules/@types/filesystem/index.d.ts"
44
47
  ],
45
48
  "references": [
49
+ {
50
+ "path": "../../../third_party/third-party-web/bundle-tsconfig.json"
51
+ },
52
+ {
53
+ "path": "../extras/bundle-tsconfig.json"
54
+ },
46
55
  {
47
56
  "path": "../handlers/bundle-tsconfig.json"
48
57
  },
@@ -1,2 +1,3 @@
1
+ export * as Common from './Common.js';
1
2
  export * as InsightRunners from './InsightRunners.js';
2
3
  export * as Types from './types.js';
@@ -1,6 +1,7 @@
1
1
  // Copyright 2024 The Chromium Authors. All rights reserved.
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
+ export * as Common from './Common.js';
4
5
  export * as InsightRunners from './InsightRunners.js';
5
6
  export * as Types from './types.js';
6
7
  //# sourceMappingURL=insights.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"insights.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/insights.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as InsightRunners from './InsightRunners.js';\nexport * as Types from './types.js';\n"]}
1
+ {"version":3,"file":"insights.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/insights.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as Common from './Common.js';\nexport * as InsightRunners from './InsightRunners.js';\nexport * as Types from './types.js';\n"]}
@@ -3,16 +3,24 @@ import type * as Lantern from '../lantern/lantern.js';
3
3
  import type * as Types from '../types/types.js';
4
4
  import type * as InsightsRunners from './InsightRunners.js';
5
5
  /**
6
- * Context for which navigation an insight should look at.
6
+ * Context for the portion of the trace an insight should look at.
7
7
  */
8
- export interface NavigationInsightContext {
8
+ export type InsightSetContext = InsightSetContextWithoutNavigation | InsightSetContextWithNavigation;
9
+ export interface InsightSetContextWithoutNavigation {
10
+ bounds: Types.Timing.TraceWindowMicroSeconds;
9
11
  frameId: string;
12
+ navigation?: never;
13
+ }
14
+ export interface InsightSetContextWithNavigation {
15
+ bounds: Types.Timing.TraceWindowMicroSeconds;
16
+ frameId: string;
17
+ navigation: Types.Events.NavigationStart;
10
18
  navigationId: string;
11
19
  lantern?: LanternContext;
12
20
  }
13
21
  export interface LanternContext {
14
- graph: Lantern.Graph.Node<Types.TraceEvents.SyntheticNetworkRequest>;
15
- simulator: Lantern.Simulation.Simulator<Types.TraceEvents.SyntheticNetworkRequest>;
22
+ graph: Lantern.Graph.Node<Types.Events.SyntheticNetworkRequest>;
23
+ simulator: Lantern.Simulation.Simulator<Types.Events.SyntheticNetworkRequest>;
16
24
  metrics: Record<string, Lantern.Metrics.MetricResult>;
17
25
  }
18
26
  export type InsightRunnersType = typeof InsightsRunners;
@@ -22,36 +30,46 @@ export declare enum InsightWarning {
22
30
  NO_DOCUMENT_REQUEST = "NO_DOCUMENT_REQUEST",
23
31
  NO_LAYOUT = "NO_LAYOUT"
24
32
  }
33
+ export interface MetricSavings {
34
+ FCP?: Types.Timing.MilliSeconds;
35
+ LCP?: Types.Timing.MilliSeconds;
36
+ TBT?: Types.Timing.MilliSeconds;
37
+ CLS?: number;
38
+ INP?: Types.Timing.MilliSeconds;
39
+ }
25
40
  export type InsightResult<R extends Record<string, unknown>> = R & {
41
+ relatedEvents?: Types.Events.Event[];
26
42
  warnings?: InsightWarning[];
27
- metricSavings?: {
28
- FCP?: number;
29
- LCP?: number;
30
- TBT?: number;
31
- CLS?: number;
32
- INP?: number;
33
- };
43
+ metricSavings?: MetricSavings;
44
+ };
45
+ /**
46
+ * Contains insights for a specific navigation. If a trace began after a navigation already started,
47
+ * this could instead represent the duration from the beginning of the trace up to the first recorded
48
+ * navigation (or the end of the trace).
49
+ */
50
+ export type InsightSets = {
51
+ /** If for a navigation, this is the navigationId. Else it is Trace.Types.Events.NO_NAVIGATION. */
52
+ id: Types.Events.NavigationId;
53
+ /** The URL to show in the accordion list. */
54
+ url: URL;
55
+ frameId: string;
56
+ bounds: Types.Timing.TraceWindowMicroSeconds;
57
+ data: InsightResults;
58
+ navigation?: Types.Events.NavigationStart;
34
59
  };
35
- export type LCPInsightResult = InsightResult<{
36
- lcpMs?: Types.Timing.MilliSeconds;
37
- lcpTs?: Types.Timing.MilliSeconds;
38
- phases?: InsightsRunners.LargestContentfulPaint.LCPPhases;
39
- shouldRemoveLazyLoading?: boolean;
40
- shouldIncreasePriorityHint?: boolean;
41
- shouldPreloadImage?: boolean;
42
- lcpResource?: Types.TraceEvents.SyntheticNetworkRequest;
43
- earliestDiscoveryTimeTs?: Types.Timing.MicroSeconds;
44
- }>;
45
60
  /**
46
61
  * Contains insights for a specific navigation.
47
62
  */
48
- export type NavigationInsightData = {
49
- [I in keyof InsightRunnersType]: ReturnType<InsightRunnersType[I]['generateInsight']> | Error;
63
+ export type InsightResults = {
64
+ [I in keyof InsightRunnersType]: ReturnType<InsightRunnersType[I]['generateInsight']>;
50
65
  };
51
66
  /**
52
- * Contains insights for the entire trace. Insights are grouped by `navigationId`.
67
+ * Contains insights for the entire trace. Insights are mostly grouped by `navigationId`, with one exception:
68
+ *
69
+ * If the analyzed trace started after the navigation, and has meaningful work with that span, there is no
70
+ * navigation to map it to. In this case `Types.Events.NO_NAVIGATION` is used for the key.
53
71
  */
54
- export type TraceInsightData = Map<string, NavigationInsightData>;
72
+ export type TraceInsightSets = Map<Types.Events.NavigationId, InsightSets>;
55
73
  /**
56
74
  * Represents the narrow set of dependencies defined by an insight's `deps()` function. `Meta` is always included regardless of `deps()`.
57
75
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/types.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAyB7B,MAAM,CAAN,IAAY,cAMX;AAND,WAAY,cAAc;IACxB,iCAAe,CAAA;IACf,mCAAiB,CAAA;IACjB,uEAAuE;IACvE,6DAA2C,CAAA;IAC3C,yCAAuB,CAAA;AACzB,CAAC,EANW,cAAc,KAAd,cAAc,QAMzB","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport type * as InsightsRunners from './InsightRunners.js';\n\n/**\n * Context for which navigation an insight should look at.\n */\nexport interface NavigationInsightContext {\n frameId: string;\n navigationId: string;\n lantern?: LanternContext;\n}\n\nexport interface LanternContext {\n graph: Lantern.Graph.Node<Types.TraceEvents.SyntheticNetworkRequest>;\n simulator: Lantern.Simulation.Simulator<Types.TraceEvents.SyntheticNetworkRequest>;\n metrics: Record<string, Lantern.Metrics.MetricResult>;\n}\n\nexport type InsightRunnersType = typeof InsightsRunners;\n\nexport enum InsightWarning {\n NO_FP = 'NO_FP',\n NO_LCP = 'NO_LCP',\n // No network request could be identified as the primary HTML document.\n NO_DOCUMENT_REQUEST = 'NO_DOCUMENT_REQUEST',\n NO_LAYOUT = 'NO_LAYOUT',\n}\n\nexport type InsightResult<R extends Record<string, unknown>> = R&{\n warnings?: InsightWarning[],\n metricSavings?: {\n /* eslint-disable @typescript-eslint/naming-convention */\n FCP?: number,\n LCP?: number,\n TBT?: number,\n CLS?: number,\n INP?: number,\n /* eslint-enable @typescript-eslint/naming-convention */\n },\n};\n\nexport type LCPInsightResult = InsightResult<{\n lcpMs?: Types.Timing.MilliSeconds,\n lcpTs?: Types.Timing.MilliSeconds,\n phases?: InsightsRunners.LargestContentfulPaint.LCPPhases,\n shouldRemoveLazyLoading?: boolean,\n shouldIncreasePriorityHint?: boolean,\n shouldPreloadImage?: boolean,\n lcpResource?: Types.TraceEvents.SyntheticNetworkRequest,\n earliestDiscoveryTimeTs?: Types.Timing.MicroSeconds,\n}>;\n\n/**\n * Contains insights for a specific navigation.\n */\nexport type NavigationInsightData = {\n [I in keyof InsightRunnersType]: ReturnType<InsightRunnersType[I]['generateInsight']>|Error;\n};\n\n/**\n * Contains insights for the entire trace. Insights are grouped by `navigationId`.\n */\nexport type TraceInsightData = Map<string, NavigationInsightData>;\n\n/**\n * Represents the narrow set of dependencies defined by an insight's `deps()` function. `Meta` is always included regardless of `deps()`.\n */\nexport type RequiredData<D extends() => Array<keyof typeof Handlers.ModelHandlers>> =\n Handlers.Types.EnabledHandlerDataWithMeta<Pick<typeof Handlers.ModelHandlers, ReturnType<D>[number]>>;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/types.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAmC7B,MAAM,CAAN,IAAY,cAMX;AAND,WAAY,cAAc;IACxB,iCAAe,CAAA;IACf,mCAAiB,CAAA;IACjB,uEAAuE;IACvE,6DAA2C,CAAA;IAC3C,yCAAuB,CAAA;AACzB,CAAC,EANW,cAAc,KAAd,cAAc,QAMzB","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport type * as InsightsRunners from './InsightRunners.js';\n\n/**\n * Context for the portion of the trace an insight should look at.\n */\nexport type InsightSetContext = InsightSetContextWithoutNavigation|InsightSetContextWithNavigation;\n\nexport interface InsightSetContextWithoutNavigation {\n bounds: Types.Timing.TraceWindowMicroSeconds;\n frameId: string;\n navigation?: never;\n}\n\nexport interface InsightSetContextWithNavigation {\n bounds: Types.Timing.TraceWindowMicroSeconds;\n frameId: string;\n navigation: Types.Events.NavigationStart;\n navigationId: string;\n lantern?: LanternContext;\n}\n\nexport interface LanternContext {\n graph: Lantern.Graph.Node<Types.Events.SyntheticNetworkRequest>;\n simulator: Lantern.Simulation.Simulator<Types.Events.SyntheticNetworkRequest>;\n metrics: Record<string, Lantern.Metrics.MetricResult>;\n}\n\nexport type InsightRunnersType = typeof InsightsRunners;\n\nexport enum InsightWarning {\n NO_FP = 'NO_FP',\n NO_LCP = 'NO_LCP',\n // No network request could be identified as the primary HTML document.\n NO_DOCUMENT_REQUEST = 'NO_DOCUMENT_REQUEST',\n NO_LAYOUT = 'NO_LAYOUT',\n}\n\nexport interface MetricSavings {\n /* eslint-disable @typescript-eslint/naming-convention */\n FCP?: Types.Timing.MilliSeconds;\n LCP?: Types.Timing.MilliSeconds;\n TBT?: Types.Timing.MilliSeconds;\n CLS?: number;\n INP?: Types.Timing.MilliSeconds;\n /* eslint-enable @typescript-eslint/naming-convention */\n}\n\nexport type InsightResult<R extends Record<string, unknown>> = R&{\n relatedEvents?: Types.Events.Event[],\n warnings?: InsightWarning[],\n metricSavings?: MetricSavings,\n};\n\n/**\n * Contains insights for a specific navigation. If a trace began after a navigation already started,\n * this could instead represent the duration from the beginning of the trace up to the first recorded\n * navigation (or the end of the trace).\n */\nexport type InsightSets = {\n /** If for a navigation, this is the navigationId. Else it is Trace.Types.Events.NO_NAVIGATION. */\n id: Types.Events.NavigationId,\n /** The URL to show in the accordion list. */\n url: URL,\n frameId: string,\n bounds: Types.Timing.TraceWindowMicroSeconds,\n data: InsightResults,\n navigation?: Types.Events.NavigationStart,\n};\n\n/**\n * Contains insights for a specific navigation.\n */\nexport type InsightResults = {\n [I in keyof InsightRunnersType]: ReturnType<InsightRunnersType[I]['generateInsight']>;\n};\n\n/**\n * Contains insights for the entire trace. Insights are mostly grouped by `navigationId`, with one exception:\n *\n * If the analyzed trace started after the navigation, and has meaningful work with that span, there is no\n * navigation to map it to. In this case `Types.Events.NO_NAVIGATION` is used for the key.\n */\nexport type TraceInsightSets = Map<Types.Events.NavigationId, InsightSets>;\n\n/**\n * Represents the narrow set of dependencies defined by an insight's `deps()` function. `Meta` is always included regardless of `deps()`.\n */\nexport type RequiredData<D extends() => Array<keyof typeof Handlers.ModelHandlers>> =\n Handlers.Types.EnabledHandlerDataWithMeta<Pick<typeof Handlers.ModelHandlers, ReturnType<D>[number]>>;\n"]}
@@ -34,7 +34,7 @@ declare class NetworkAnalyzer {
34
34
  static groupByOrigin(records: Lantern.NetworkRequest[]): Map<string, Lantern.NetworkRequest[]>;
35
35
  static getSummary(values: number[]): Summary;
36
36
  static summarize(values: Map<string, number[]>): Map<string, Summary>;
37
- static _estimateValueByOrigin(requests: Lantern.NetworkRequest[], iteratee: (e: RequestInfo) => number | number[] | undefined): Map<string, number[]>;
37
+ static estimateValueByOrigin(requests: Lantern.NetworkRequest[], iteratee: (e: RequestInfo) => number | number[] | undefined): Map<string, number[]>;
38
38
  /**
39
39
  * Estimates the observed RTT to each origin based on how long the connection setup.
40
40
  * For h1 and h2, this could includes two estimates - one for the TCP handshake, another for
@@ -43,31 +43,31 @@ declare class NetworkAnalyzer {
43
43
  * single handshake.
44
44
  * This is the most accurate and preferred method of measurement when the data is available.
45
45
  */
46
- static _estimateRTTViaConnectionTiming(info: RequestInfo): number[] | number | undefined;
46
+ static estimateRTTViaConnectionTiming(info: RequestInfo): number[] | number | undefined;
47
47
  /**
48
48
  * Estimates the observed RTT to each origin based on how long a download took on a fresh connection.
49
49
  * NOTE: this will tend to overestimate the actual RTT quite significantly as the download can be
50
50
  * slow for other reasons as well such as bandwidth constraints.
51
51
  */
52
- static _estimateRTTViaDownloadTiming(info: RequestInfo): number | undefined;
52
+ static estimateRTTViaDownloadTiming(info: RequestInfo): number | undefined;
53
53
  /**
54
54
  * Estimates the observed RTT to each origin based on how long it took until Chrome could
55
55
  * start sending the actual request when a new connection was required.
56
56
  * NOTE: this will tend to overestimate the actual RTT as the request can be delayed for other
57
57
  * reasons as well such as more SSL handshakes if TLS False Start is not enabled.
58
58
  */
59
- static _estimateRTTViaSendStartTiming(info: RequestInfo): number | undefined;
59
+ static estimateRTTViaSendStartTiming(info: RequestInfo): number | undefined;
60
60
  /**
61
61
  * Estimates the observed RTT to each origin based on how long it took until Chrome received the
62
62
  * headers of the response (~TTFB).
63
63
  * NOTE: this is the most inaccurate way to estimate the RTT, but in some environments it's all
64
64
  * we have access to :(
65
65
  */
66
- static _estimateRTTViaHeadersEndTiming(info: RequestInfo): number | undefined;
66
+ static estimateRTTViaHeadersEndTiming(info: RequestInfo): number | undefined;
67
67
  /**
68
68
  * Given the RTT to each origin, estimates the observed server response times.
69
69
  */
70
- static _estimateResponseTimeByOrigin(records: Lantern.NetworkRequest[], rttByOrigin: Map<string, number>): Map<string, number[]>;
70
+ static estimateResponseTimeByOrigin(records: Lantern.NetworkRequest[], rttByOrigin: Map<string, number>): Map<string, number[]>;
71
71
  static canTrustConnectionInformation(requests: Lantern.NetworkRequest[]): boolean;
72
72
  /**
73
73
  * Returns a map of requestId -> connectionReused, estimating the information if the information
@@ -92,15 +92,15 @@ declare class NetworkAnalyzer {
92
92
  /**
93
93
  * Computes the average throughput for the given requests in bits/second.
94
94
  * Excludes data URI, failed or otherwise incomplete, and cached requests.
95
- * Returns Infinity if there were no analyzable network requests.
95
+ * Returns null if there were no analyzable network requests.
96
96
  */
97
- static estimateThroughput(records: Lantern.NetworkRequest[]): number;
97
+ static estimateThroughput(records: Lantern.NetworkRequest[]): number | null;
98
98
  static computeRTTAndServerResponseTime(records: Lantern.NetworkRequest[]): {
99
99
  rtt: number;
100
100
  additionalRttByOrigin: Map<string, number>;
101
101
  serverResponseTimeByOrigin: Map<string, number>;
102
102
  };
103
- static analyze(records: Lantern.NetworkRequest[]): Lantern.Simulation.Settings['networkAnalysis'];
103
+ static analyze(records: Lantern.NetworkRequest[]): Lantern.Simulation.Settings['networkAnalysis'] | null;
104
104
  static findResourceForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T | undefined;
105
105
  static findLastDocumentForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T | undefined;
106
106
  /**
@@ -93,7 +93,7 @@ class NetworkAnalyzer {
93
93
  summaryByKey.set(NetworkAnalyzer.summary, NetworkAnalyzer.getSummary(allEstimates));
94
94
  return summaryByKey;
95
95
  }
96
- static _estimateValueByOrigin(requests, iteratee) {
96
+ static estimateValueByOrigin(requests, iteratee) {
97
97
  const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(requests);
98
98
  const groupedByOrigin = NetworkAnalyzer.groupByOrigin(requests);
99
99
  const estimates = new Map();
@@ -128,7 +128,7 @@ class NetworkAnalyzer {
128
128
  * single handshake.
129
129
  * This is the most accurate and preferred method of measurement when the data is available.
130
130
  */
131
- static _estimateRTTViaConnectionTiming(info) {
131
+ static estimateRTTViaConnectionTiming(info) {
132
132
  const { timing, connectionReused, request } = info;
133
133
  if (connectionReused) {
134
134
  return;
@@ -152,7 +152,7 @@ class NetworkAnalyzer {
152
152
  * NOTE: this will tend to overestimate the actual RTT quite significantly as the download can be
153
153
  * slow for other reasons as well such as bandwidth constraints.
154
154
  */
155
- static _estimateRTTViaDownloadTiming(info) {
155
+ static estimateRTTViaDownloadTiming(info) {
156
156
  const { timing, connectionReused, request } = info;
157
157
  if (connectionReused) {
158
158
  return;
@@ -181,7 +181,7 @@ class NetworkAnalyzer {
181
181
  * NOTE: this will tend to overestimate the actual RTT as the request can be delayed for other
182
182
  * reasons as well such as more SSL handshakes if TLS False Start is not enabled.
183
183
  */
184
- static _estimateRTTViaSendStartTiming(info) {
184
+ static estimateRTTViaSendStartTiming(info) {
185
185
  const { timing, connectionReused, request } = info;
186
186
  if (connectionReused) {
187
187
  return;
@@ -207,7 +207,7 @@ class NetworkAnalyzer {
207
207
  * NOTE: this is the most inaccurate way to estimate the RTT, but in some environments it's all
208
208
  * we have access to :(
209
209
  */
210
- static _estimateRTTViaHeadersEndTiming(info) {
210
+ static estimateRTTViaHeadersEndTiming(info) {
211
211
  const { timing, connectionReused, request } = info;
212
212
  if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {
213
213
  return;
@@ -237,8 +237,8 @@ class NetworkAnalyzer {
237
237
  /**
238
238
  * Given the RTT to each origin, estimates the observed server response times.
239
239
  */
240
- static _estimateResponseTimeByOrigin(records, rttByOrigin) {
241
- return NetworkAnalyzer._estimateValueByOrigin(records, ({ request, timing }) => {
240
+ static estimateResponseTimeByOrigin(records, rttByOrigin) {
241
+ return NetworkAnalyzer.estimateValueByOrigin(records, ({ request, timing }) => {
242
242
  if (request.serverResponseTime !== undefined) {
243
243
  return request.serverResponseTime;
244
244
  }
@@ -314,7 +314,7 @@ class NetworkAnalyzer {
314
314
  function collectEstimates(estimator, multiplier = 1) {
315
315
  for (const request of originRequests) {
316
316
  const timing = request.timing;
317
- if (!timing) {
317
+ if (!timing || !request.transferSize) {
318
318
  continue;
319
319
  }
320
320
  const estimates = estimator({
@@ -334,7 +334,7 @@ class NetworkAnalyzer {
334
334
  }
335
335
  }
336
336
  if (!forceCoarseEstimates) {
337
- collectEstimates(this._estimateRTTViaConnectionTiming);
337
+ collectEstimates(this.estimateRTTViaConnectionTiming);
338
338
  }
339
339
  // Connection timing can be missing for a few reasons:
340
340
  // - Origin was preconnected, which we don't have instrumentation for.
@@ -343,13 +343,13 @@ class NetworkAnalyzer {
343
343
  // - Not provided in LR netstack.
344
344
  if (!originEstimates.length) {
345
345
  if (useDownloadEstimates) {
346
- collectEstimates(this._estimateRTTViaDownloadTiming, coarseEstimateMultiplier);
346
+ collectEstimates(this.estimateRTTViaDownloadTiming, coarseEstimateMultiplier);
347
347
  }
348
348
  if (useSendStartEstimates) {
349
- collectEstimates(this._estimateRTTViaSendStartTiming, coarseEstimateMultiplier);
349
+ collectEstimates(this.estimateRTTViaSendStartTiming, coarseEstimateMultiplier);
350
350
  }
351
351
  if (useHeadersEndEstimates) {
352
- collectEstimates(this._estimateRTTViaHeadersEndTiming, coarseEstimateMultiplier);
352
+ collectEstimates(this.estimateRTTViaHeadersEndTiming, coarseEstimateMultiplier);
353
353
  }
354
354
  }
355
355
  if (originEstimates.length) {
@@ -374,13 +374,13 @@ class NetworkAnalyzer {
374
374
  rttByOrigin.set(origin, summary.min);
375
375
  }
376
376
  }
377
- const estimatesByOrigin = NetworkAnalyzer._estimateResponseTimeByOrigin(records, rttByOrigin);
377
+ const estimatesByOrigin = NetworkAnalyzer.estimateResponseTimeByOrigin(records, rttByOrigin);
378
378
  return NetworkAnalyzer.summarize(estimatesByOrigin);
379
379
  }
380
380
  /**
381
381
  * Computes the average throughput for the given requests in bits/second.
382
382
  * Excludes data URI, failed or otherwise incomplete, and cached requests.
383
- * Returns Infinity if there were no analyzable network requests.
383
+ * Returns null if there were no analyzable network requests.
384
384
  */
385
385
  static estimateThroughput(records) {
386
386
  let totalBytes = 0;
@@ -404,7 +404,7 @@ class NetworkAnalyzer {
404
404
  }, [])
405
405
  .sort((a, b) => a.time - b.time);
406
406
  if (!timeBoundaries.length) {
407
- return Infinity;
407
+ return null;
408
408
  }
409
409
  let inflight = 0;
410
410
  let currentStart = 0;
@@ -456,6 +456,9 @@ class NetworkAnalyzer {
456
456
  }
457
457
  static analyze(records) {
458
458
  const throughput = NetworkAnalyzer.estimateThroughput(records);
459
+ if (throughput === null) {
460
+ return null;
461
+ }
459
462
  return {
460
463
  throughput,
461
464
  ...NetworkAnalyzer.computeRTTAndServerResponseTime(records),
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkAnalyzer.js","sourceRoot":"","sources":["../../../../../../../../front_end/models/trace/lantern/core/NetworkAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Lantern from '../types/types.js';\n\nimport {LanternError} from './LanternError.js';\n\nclass UrlUtils {\n /**\n * There is fancy URL rewriting logic for the chrome://settings page that we need to work around.\n * Why? Special handling was added by Chrome team to allow a pushState transition between chrome:// pages.\n * As a result, the network URL (chrome://chrome/settings/) doesn't match the final document URL (chrome://settings/).\n */\n static rewriteChromeInternalUrl(url: string): string {\n if (!url || !url.startsWith('chrome://')) {\n return url;\n }\n // Chrome adds a trailing slash to `chrome://` URLs, but the spec does not.\n // https://github.com/GoogleChrome/lighthouse/pull/3941#discussion_r154026009\n if (url.endsWith('/')) {\n url = url.replace(/\\/$/, '');\n }\n return url.replace(/^chrome:\\/\\/chrome\\//, 'chrome://');\n }\n\n /**\n * Determine if url1 equals url2, ignoring URL fragments.\n */\n static equalWithExcludedFragments(url1: string, url2: string): boolean {\n [url1, url2] = [url1, url2].map(this.rewriteChromeInternalUrl);\n try {\n const urla = new URL(url1);\n urla.hash = '';\n\n const urlb = new URL(url2);\n urlb.hash = '';\n\n return urla.href === urlb.href;\n } catch (e) {\n return false;\n }\n }\n}\n\ninterface Summary {\n min: number;\n max: number;\n avg: number;\n median: number;\n}\n\ninterface RTTEstimateOptions {\n /**\n * TCP connection handshake information will be used when available, but in\n * some circumstances this data can be unreliable. This flag exposes an\n * option to ignore the handshake data and use the coarse download/TTFB timing data.\n */\n forceCoarseEstimates?: boolean;\n /**\n * Coarse estimates include lots of extra time and noise multiply by some factor\n * to deflate the estimates a bit.\n */\n coarseEstimateMultiplier?: number;\n /** Useful for testing to isolate the different methods of estimation. */\n useDownloadEstimates?: boolean;\n /** Useful for testing to isolate the different methods of estimation. */\n useSendStartEstimates?: boolean;\n /** Useful for testing to isolate the different methods of estimation. */\n useHeadersEndEstimates?: boolean;\n}\n\ntype RequestInfo = {\n request: Lantern.NetworkRequest,\n timing: Lantern.ResourceTiming,\n connectionReused?: boolean,\n};\n\nconst INITIAL_CWD = 14 * 1024;\n\n// Assume that 40% of TTFB was server response time by default for static assets\nconst DEFAULT_SERVER_RESPONSE_PERCENTAGE = 0.4;\n\n/**\n * For certain resource types, server response time takes up a greater percentage of TTFB (dynamic\n * assets like HTML documents, XHR/API calls, etc)\n */\nconst SERVER_RESPONSE_PERCENTAGE_OF_TTFB: Partial<Record<Lantern.ResourceType, number>> = {\n Document: 0.9,\n XHR: 0.9,\n Fetch: 0.9,\n};\n\nclass NetworkAnalyzer {\n static get summary(): string {\n return '__SUMMARY__';\n }\n\n static groupByOrigin(records: Lantern.NetworkRequest[]): Map<string, Lantern.NetworkRequest[]> {\n const grouped = new Map();\n records.forEach(item => {\n const key = item.parsedURL.securityOrigin;\n const group = grouped.get(key) || [];\n group.push(item);\n grouped.set(key, group);\n });\n return grouped;\n }\n\n static getSummary(values: number[]): Summary {\n values.sort((a, b) => a - b);\n\n let median;\n if (values.length === 0) {\n median = values[0];\n } else if (values.length % 2 === 0) {\n const a = values[Math.floor((values.length - 1) / 2)];\n const b = values[Math.floor((values.length - 1) / 2) + 1];\n median = (a + b) / 2;\n } else {\n median = values[Math.floor((values.length - 1) / 2)];\n }\n\n return {\n min: values[0],\n max: values[values.length - 1],\n avg: values.reduce((a, b) => a + b, 0) / values.length,\n median,\n };\n }\n\n static summarize(values: Map<string, number[]>): Map<string, Summary> {\n const summaryByKey = new Map();\n const allEstimates = [];\n for (const [key, estimates] of values) {\n summaryByKey.set(key, NetworkAnalyzer.getSummary(estimates));\n allEstimates.push(...estimates);\n }\n\n summaryByKey.set(NetworkAnalyzer.summary, NetworkAnalyzer.getSummary(allEstimates));\n return summaryByKey;\n }\n\n static _estimateValueByOrigin(\n requests: Lantern.NetworkRequest[],\n iteratee: (e: RequestInfo) => number | number[] | undefined): Map<string, number[]> {\n const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(requests);\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(requests);\n\n const estimates = new Map();\n for (const [origin, originRequests] of groupedByOrigin.entries()) {\n let originEstimates: number[] = [];\n\n for (const request of originRequests) {\n const timing = request.timing;\n if (!timing) {\n continue;\n }\n\n const value = iteratee({\n request,\n timing,\n connectionReused: connectionWasReused.get(request.requestId),\n });\n if (typeof value !== 'undefined') {\n originEstimates = originEstimates.concat(value);\n }\n }\n\n if (!originEstimates.length) {\n continue;\n }\n estimates.set(origin, originEstimates);\n }\n\n return estimates;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long the connection setup.\n * For h1 and h2, this could includes two estimates - one for the TCP handshake, another for\n * SSL negotiation.\n * For h3, we get only one estimate since QUIC establishes a secure connection in a\n * single handshake.\n * This is the most accurate and preferred method of measurement when the data is available.\n */\n static _estimateRTTViaConnectionTiming(info: RequestInfo): number[]|number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n const {connectStart, sslStart, sslEnd, connectEnd} = timing;\n if (connectEnd >= 0 && connectStart >= 0 && request.protocol.startsWith('h3')) {\n // These values are equal to sslStart and sslEnd for h3.\n return connectEnd - connectStart;\n }\n if (sslStart >= 0 && sslEnd >= 0 && sslStart !== connectStart) {\n // SSL can also be more than 1 RT but assume False Start was used.\n return [connectEnd - sslStart, sslStart - connectStart];\n }\n if (connectStart >= 0 && connectEnd >= 0) {\n return connectEnd - connectStart;\n }\n\n return;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long a download took on a fresh connection.\n * NOTE: this will tend to overestimate the actual RTT quite significantly as the download can be\n * slow for other reasons as well such as bandwidth constraints.\n */\n static _estimateRTTViaDownloadTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n // Only look at downloads that went past the initial congestion window\n if (request.transferSize <= INITIAL_CWD) {\n return;\n }\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n\n // Compute the amount of time downloading everything after the first congestion window took\n const totalTime = request.networkEndTime - request.networkRequestTime;\n const downloadTimeAfterFirstByte = totalTime - timing.receiveHeadersEnd;\n const numberOfRoundTrips = Math.log2(request.transferSize / INITIAL_CWD);\n\n // Ignore requests that required a high number of round trips since bandwidth starts to play\n // a larger role than latency\n if (numberOfRoundTrips > 5) {\n return;\n }\n\n return downloadTimeAfterFirstByte / numberOfRoundTrips;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long it took until Chrome could\n * start sending the actual request when a new connection was required.\n * NOTE: this will tend to overestimate the actual RTT as the request can be delayed for other\n * reasons as well such as more SSL handshakes if TLS False Start is not enabled.\n */\n static _estimateRTTViaSendStartTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n if (!Number.isFinite(timing.sendStart) || timing.sendStart < 0) {\n return;\n }\n\n // Assume everything before sendStart was just DNS + (SSL)? + TCP handshake\n // 1 RT for DNS, 1 RT (maybe) for SSL, 1 RT for TCP\n let roundTrips = 1;\n // TCP\n if (!request.protocol.startsWith('h3')) {\n roundTrips += 1;\n }\n if (request.parsedURL.scheme === 'https') {\n roundTrips += 1;\n }\n return timing.sendStart / roundTrips;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long it took until Chrome received the\n * headers of the response (~TTFB).\n * NOTE: this is the most inaccurate way to estimate the RTT, but in some environments it's all\n * we have access to :(\n */\n static _estimateRTTViaHeadersEndTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n if (!request.resourceType) {\n return;\n }\n\n const serverResponseTimePercentage =\n SERVER_RESPONSE_PERCENTAGE_OF_TTFB[request.resourceType] || DEFAULT_SERVER_RESPONSE_PERCENTAGE;\n const estimatedServerResponseTime = timing.receiveHeadersEnd * serverResponseTimePercentage;\n\n // When connection was reused...\n // TTFB = 1 RT for request + server response time\n let roundTrips = 1;\n\n // When connection was fresh...\n // TTFB = DNS + (SSL)? + TCP handshake + 1 RT for request + server response time\n if (!connectionReused) {\n roundTrips += 1; // DNS\n if (!request.protocol.startsWith('h3')) {\n roundTrips += 1; // TCP\n }\n if (request.parsedURL.scheme === 'https') {\n roundTrips += 1; // SSL\n }\n }\n\n // subtract out our estimated server response time\n return Math.max((timing.receiveHeadersEnd - estimatedServerResponseTime) / roundTrips, 3);\n }\n\n /**\n * Given the RTT to each origin, estimates the observed server response times.\n */\n static _estimateResponseTimeByOrigin(records: Lantern.NetworkRequest[], rttByOrigin: Map<string, number>):\n Map<string, number[]> {\n return NetworkAnalyzer._estimateValueByOrigin(records, ({request, timing}) => {\n if (request.serverResponseTime !== undefined) {\n return request.serverResponseTime;\n }\n\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n if (!Number.isFinite(timing.sendEnd) || timing.sendEnd < 0) {\n return;\n }\n\n const ttfb = timing.receiveHeadersEnd - timing.sendEnd;\n const origin = request.parsedURL.securityOrigin;\n const rtt = rttByOrigin.get(origin) || rttByOrigin.get(NetworkAnalyzer.summary) || 0;\n return Math.max(ttfb - rtt, 0);\n });\n }\n\n static canTrustConnectionInformation(requests: Lantern.NetworkRequest[]): boolean {\n const connectionIdWasStarted = new Map();\n for (const request of requests) {\n const started = connectionIdWasStarted.get(request.connectionId) || !request.connectionReused;\n connectionIdWasStarted.set(request.connectionId, started);\n }\n\n // We probably can't trust the network information if all the connection IDs were the same\n if (connectionIdWasStarted.size <= 1) {\n return false;\n }\n // Or if there were connections that were always reused (a connection had to have started at some point)\n return Array.from(connectionIdWasStarted.values()).every(started => started);\n }\n\n /**\n * Returns a map of requestId -> connectionReused, estimating the information if the information\n * available in the records themselves appears untrustworthy.\n */\n static estimateIfConnectionWasReused(records: Lantern.NetworkRequest[], options?: {forceCoarseEstimates: boolean}):\n Map<string, boolean> {\n const {forceCoarseEstimates = false} = options || {};\n\n // Check if we can trust the connection information coming from the protocol\n if (!forceCoarseEstimates && NetworkAnalyzer.canTrustConnectionInformation(records)) {\n return new Map(records.map(request => [request.requestId, Boolean(request.connectionReused)]));\n }\n\n // Otherwise we're on our own, a request may not have needed a fresh connection if...\n // - It was not the first request to the domain\n // - It was H2\n // - It was after the first request to the domain ended\n const connectionWasReused = new Map();\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n for (const originRecords of groupedByOrigin.values()) {\n const earliestReusePossible =\n originRecords.map(request => request.networkEndTime).reduce((a, b) => Math.min(a, b), Infinity);\n\n for (const request of originRecords) {\n connectionWasReused.set(\n request.requestId,\n request.networkRequestTime >= earliestReusePossible || request.protocol === 'h2',\n );\n }\n\n const firstRecord = originRecords.reduce((a, b) => {\n return a.networkRequestTime > b.networkRequestTime ? b : a;\n });\n connectionWasReused.set(firstRecord.requestId, false);\n }\n\n return connectionWasReused;\n }\n\n /**\n * Estimates the RTT to each origin by examining observed network timing information.\n * Attempts to use the most accurate information first and falls back to coarser estimates when it\n * is unavailable.\n */\n static estimateRTTByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions): Map<string, Summary> {\n const {\n forceCoarseEstimates = false,\n // coarse estimates include lots of extra time and noise\n // multiply by some factor to deflate the estimates a bit.\n coarseEstimateMultiplier = 0.3,\n useDownloadEstimates = true,\n useSendStartEstimates = true,\n useHeadersEndEstimates = true,\n } = options || {};\n\n const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(records);\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n\n const estimatesByOrigin = new Map();\n for (const [origin, originRequests] of groupedByOrigin.entries()) {\n const originEstimates: number[] = [];\n\n // eslint-disable-next-line no-inner-declarations\n function collectEstimates(estimator: (e: RequestInfo) => number[] | number | undefined, multiplier = 1): void {\n for (const request of originRequests) {\n const timing = request.timing;\n if (!timing) {\n continue;\n }\n\n const estimates = estimator({\n request,\n timing,\n connectionReused: connectionWasReused.get(request.requestId),\n });\n if (estimates === undefined) {\n continue;\n }\n\n if (!Array.isArray(estimates)) {\n originEstimates.push(estimates * multiplier);\n } else {\n originEstimates.push(...estimates.map(e => e * multiplier));\n }\n }\n }\n\n if (!forceCoarseEstimates) {\n collectEstimates(this._estimateRTTViaConnectionTiming);\n }\n\n // Connection timing can be missing for a few reasons:\n // - Origin was preconnected, which we don't have instrumentation for.\n // - Trace began recording after a connection has already been established (for example, in timespan mode)\n // - Perhaps Chrome established a connection already in the background (service worker? Just guessing here)\n // - Not provided in LR netstack.\n if (!originEstimates.length) {\n if (useDownloadEstimates) {\n collectEstimates(this._estimateRTTViaDownloadTiming, coarseEstimateMultiplier);\n }\n if (useSendStartEstimates) {\n collectEstimates(this._estimateRTTViaSendStartTiming, coarseEstimateMultiplier);\n }\n if (useHeadersEndEstimates) {\n collectEstimates(this._estimateRTTViaHeadersEndTiming, coarseEstimateMultiplier);\n }\n }\n\n if (originEstimates.length) {\n estimatesByOrigin.set(origin, originEstimates);\n }\n }\n\n if (!estimatesByOrigin.size) {\n throw new LanternError('No timing information available');\n }\n return NetworkAnalyzer.summarize(estimatesByOrigin);\n }\n\n /**\n * Estimates the server response time of each origin. RTT times can be passed in or will be\n * estimated automatically if not provided.\n */\n static estimateServerResponseTimeByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions&{\n rttByOrigin?: Map<string, number>,\n }): Map<string, Summary> {\n let rttByOrigin = (options || {}).rttByOrigin;\n if (!rttByOrigin) {\n rttByOrigin = new Map();\n\n const rttSummaryByOrigin = NetworkAnalyzer.estimateRTTByOrigin(records, options);\n for (const [origin, summary] of rttSummaryByOrigin.entries()) {\n rttByOrigin.set(origin, summary.min);\n }\n }\n\n const estimatesByOrigin = NetworkAnalyzer._estimateResponseTimeByOrigin(records, rttByOrigin);\n return NetworkAnalyzer.summarize(estimatesByOrigin);\n }\n\n /**\n * Computes the average throughput for the given requests in bits/second.\n * Excludes data URI, failed or otherwise incomplete, and cached requests.\n * Returns Infinity if there were no analyzable network requests.\n */\n static estimateThroughput(records: Lantern.NetworkRequest[]): number {\n let totalBytes = 0;\n\n // We will measure throughput by summing the total bytes downloaded by the total time spent\n // downloading those bytes. We slice up all the network requests into start/end boundaries, so\n // it's easier to deal with the gaps in downloading.\n const timeBoundaries = records\n .reduce(\n (boundaries, request) => {\n const scheme = request.parsedURL?.scheme;\n // Requests whose bodies didn't come over the network or didn't completely finish will mess\n // with the computation, just skip over them.\n if (scheme === 'data' || request.failed || !request.finished ||\n request.statusCode > 300 || !request.transferSize) {\n return boundaries;\n }\n\n // If we've made it this far, all the times we need should be valid (i.e. not undefined/-1).\n totalBytes += request.transferSize;\n boundaries.push({time: request.responseHeadersEndTime / 1000, isStart: true});\n boundaries.push({time: request.networkEndTime / 1000, isStart: false});\n return boundaries;\n },\n [] as Array<{time: number, isStart: boolean}>)\n .sort((a, b) => a.time - b.time);\n\n if (!timeBoundaries.length) {\n return Infinity;\n }\n\n let inflight = 0;\n let currentStart = 0;\n let totalDuration = 0;\n\n timeBoundaries.forEach(boundary => {\n if (boundary.isStart) {\n if (inflight === 0) {\n // We just ended a quiet period, keep track of when the download period started\n currentStart = boundary.time;\n }\n inflight++;\n } else {\n inflight--;\n if (inflight === 0) {\n // We just entered a quiet period, update our duration with the time we spent downloading\n totalDuration += boundary.time - currentStart;\n }\n }\n });\n\n return totalBytes * 8 / totalDuration;\n }\n\n static computeRTTAndServerResponseTime(records: Lantern.NetworkRequest[]):\n {rtt: number, additionalRttByOrigin: Map<string, number>, serverResponseTimeByOrigin: Map<string, number>} {\n // First pass compute the estimated observed RTT to each origin's servers.\n const rttByOrigin = new Map<string, number>();\n for (const [origin, summary] of NetworkAnalyzer.estimateRTTByOrigin(records).entries()) {\n rttByOrigin.set(origin, summary.min);\n }\n\n // We'll use the minimum RTT as the assumed connection latency since we care about how much addt'l\n // latency each origin introduces as Lantern will be simulating with its own connection latency.\n const minimumRtt = Math.min(...Array.from(rttByOrigin.values()));\n // We'll use the observed RTT information to help estimate the server response time\n const responseTimeSummaries = NetworkAnalyzer.estimateServerResponseTimeByOrigin(records, {\n rttByOrigin,\n });\n\n const additionalRttByOrigin = new Map<string, number>();\n const serverResponseTimeByOrigin = new Map<string, number>();\n for (const [origin, summary] of responseTimeSummaries.entries()) {\n // Not all origins have usable timing data, we'll default to using no additional latency.\n const rttForOrigin = rttByOrigin.get(origin) || minimumRtt;\n additionalRttByOrigin.set(origin, rttForOrigin - minimumRtt);\n serverResponseTimeByOrigin.set(origin, summary.median);\n }\n\n return {\n rtt: minimumRtt,\n additionalRttByOrigin,\n serverResponseTimeByOrigin,\n };\n }\n\n static analyze(records: Lantern.NetworkRequest[]): Lantern.Simulation.Settings['networkAnalysis'] {\n const throughput = NetworkAnalyzer.estimateThroughput(records);\n return {\n throughput,\n ...NetworkAnalyzer.computeRTTAndServerResponseTime(records),\n };\n }\n\n static findResourceForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T|undefined {\n // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n return records.find(\n request => resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n );\n }\n\n static findLastDocumentForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T|undefined {\n // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n const matchingRequests = records.filter(\n request => request.resourceType === 'Document' &&\n // Note: `request.url` should never have a fragment, else this optimization gives wrong results.\n resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n );\n return matchingRequests[matchingRequests.length - 1];\n }\n\n /**\n * Resolves redirect chain given a main document.\n * See: {@link NetworkAnalyzer.findLastDocumentForUrl} for how to retrieve main document.\n */\n static resolveRedirects<T extends Lantern.NetworkRequest>(request: T): T {\n while (request.redirectDestination) {\n request = request.redirectDestination as T;\n }\n return request;\n }\n}\n\nexport {NetworkAnalyzer};\n"]}
1
+ {"version":3,"file":"NetworkAnalyzer.js","sourceRoot":"","sources":["../../../../../../../../front_end/models/trace/lantern/core/NetworkAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Lantern from '../types/types.js';\n\nimport {LanternError} from './LanternError.js';\n\nclass UrlUtils {\n /**\n * There is fancy URL rewriting logic for the chrome://settings page that we need to work around.\n * Why? Special handling was added by Chrome team to allow a pushState transition between chrome:// pages.\n * As a result, the network URL (chrome://chrome/settings/) doesn't match the final document URL (chrome://settings/).\n */\n static rewriteChromeInternalUrl(url: string): string {\n if (!url || !url.startsWith('chrome://')) {\n return url;\n }\n // Chrome adds a trailing slash to `chrome://` URLs, but the spec does not.\n // https://github.com/GoogleChrome/lighthouse/pull/3941#discussion_r154026009\n if (url.endsWith('/')) {\n url = url.replace(/\\/$/, '');\n }\n return url.replace(/^chrome:\\/\\/chrome\\//, 'chrome://');\n }\n\n /**\n * Determine if url1 equals url2, ignoring URL fragments.\n */\n static equalWithExcludedFragments(url1: string, url2: string): boolean {\n [url1, url2] = [url1, url2].map(this.rewriteChromeInternalUrl);\n try {\n const urla = new URL(url1);\n urla.hash = '';\n\n const urlb = new URL(url2);\n urlb.hash = '';\n\n return urla.href === urlb.href;\n } catch (e) {\n return false;\n }\n }\n}\n\ninterface Summary {\n min: number;\n max: number;\n avg: number;\n median: number;\n}\n\ninterface RTTEstimateOptions {\n /**\n * TCP connection handshake information will be used when available, but in\n * some circumstances this data can be unreliable. This flag exposes an\n * option to ignore the handshake data and use the coarse download/TTFB timing data.\n */\n forceCoarseEstimates?: boolean;\n /**\n * Coarse estimates include lots of extra time and noise multiply by some factor\n * to deflate the estimates a bit.\n */\n coarseEstimateMultiplier?: number;\n /** Useful for testing to isolate the different methods of estimation. */\n useDownloadEstimates?: boolean;\n /** Useful for testing to isolate the different methods of estimation. */\n useSendStartEstimates?: boolean;\n /** Useful for testing to isolate the different methods of estimation. */\n useHeadersEndEstimates?: boolean;\n}\n\ntype RequestInfo = {\n request: Lantern.NetworkRequest,\n timing: Lantern.ResourceTiming,\n connectionReused?: boolean,\n};\n\nconst INITIAL_CWD = 14 * 1024;\n\n// Assume that 40% of TTFB was server response time by default for static assets\nconst DEFAULT_SERVER_RESPONSE_PERCENTAGE = 0.4;\n\n/**\n * For certain resource types, server response time takes up a greater percentage of TTFB (dynamic\n * assets like HTML documents, XHR/API calls, etc)\n */\nconst SERVER_RESPONSE_PERCENTAGE_OF_TTFB: Partial<Record<Lantern.ResourceType, number>> = {\n Document: 0.9,\n XHR: 0.9,\n Fetch: 0.9,\n};\n\nclass NetworkAnalyzer {\n static get summary(): string {\n return '__SUMMARY__';\n }\n\n static groupByOrigin(records: Lantern.NetworkRequest[]): Map<string, Lantern.NetworkRequest[]> {\n const grouped = new Map();\n records.forEach(item => {\n const key = item.parsedURL.securityOrigin;\n const group = grouped.get(key) || [];\n group.push(item);\n grouped.set(key, group);\n });\n return grouped;\n }\n\n static getSummary(values: number[]): Summary {\n values.sort((a, b) => a - b);\n\n let median;\n if (values.length === 0) {\n median = values[0];\n } else if (values.length % 2 === 0) {\n const a = values[Math.floor((values.length - 1) / 2)];\n const b = values[Math.floor((values.length - 1) / 2) + 1];\n median = (a + b) / 2;\n } else {\n median = values[Math.floor((values.length - 1) / 2)];\n }\n\n return {\n min: values[0],\n max: values[values.length - 1],\n avg: values.reduce((a, b) => a + b, 0) / values.length,\n median,\n };\n }\n\n static summarize(values: Map<string, number[]>): Map<string, Summary> {\n const summaryByKey = new Map();\n const allEstimates = [];\n for (const [key, estimates] of values) {\n summaryByKey.set(key, NetworkAnalyzer.getSummary(estimates));\n allEstimates.push(...estimates);\n }\n\n summaryByKey.set(NetworkAnalyzer.summary, NetworkAnalyzer.getSummary(allEstimates));\n return summaryByKey;\n }\n\n static estimateValueByOrigin(\n requests: Lantern.NetworkRequest[],\n iteratee: (e: RequestInfo) => number | number[] | undefined): Map<string, number[]> {\n const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(requests);\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(requests);\n\n const estimates = new Map();\n for (const [origin, originRequests] of groupedByOrigin.entries()) {\n let originEstimates: number[] = [];\n\n for (const request of originRequests) {\n const timing = request.timing;\n if (!timing) {\n continue;\n }\n\n const value = iteratee({\n request,\n timing,\n connectionReused: connectionWasReused.get(request.requestId),\n });\n if (typeof value !== 'undefined') {\n originEstimates = originEstimates.concat(value);\n }\n }\n\n if (!originEstimates.length) {\n continue;\n }\n estimates.set(origin, originEstimates);\n }\n\n return estimates;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long the connection setup.\n * For h1 and h2, this could includes two estimates - one for the TCP handshake, another for\n * SSL negotiation.\n * For h3, we get only one estimate since QUIC establishes a secure connection in a\n * single handshake.\n * This is the most accurate and preferred method of measurement when the data is available.\n */\n static estimateRTTViaConnectionTiming(info: RequestInfo): number[]|number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n const {connectStart, sslStart, sslEnd, connectEnd} = timing;\n if (connectEnd >= 0 && connectStart >= 0 && request.protocol.startsWith('h3')) {\n // These values are equal to sslStart and sslEnd for h3.\n return connectEnd - connectStart;\n }\n if (sslStart >= 0 && sslEnd >= 0 && sslStart !== connectStart) {\n // SSL can also be more than 1 RT but assume False Start was used.\n return [connectEnd - sslStart, sslStart - connectStart];\n }\n if (connectStart >= 0 && connectEnd >= 0) {\n return connectEnd - connectStart;\n }\n\n return;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long a download took on a fresh connection.\n * NOTE: this will tend to overestimate the actual RTT quite significantly as the download can be\n * slow for other reasons as well such as bandwidth constraints.\n */\n static estimateRTTViaDownloadTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n // Only look at downloads that went past the initial congestion window\n if (request.transferSize <= INITIAL_CWD) {\n return;\n }\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n\n // Compute the amount of time downloading everything after the first congestion window took\n const totalTime = request.networkEndTime - request.networkRequestTime;\n const downloadTimeAfterFirstByte = totalTime - timing.receiveHeadersEnd;\n const numberOfRoundTrips = Math.log2(request.transferSize / INITIAL_CWD);\n\n // Ignore requests that required a high number of round trips since bandwidth starts to play\n // a larger role than latency\n if (numberOfRoundTrips > 5) {\n return;\n }\n\n return downloadTimeAfterFirstByte / numberOfRoundTrips;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long it took until Chrome could\n * start sending the actual request when a new connection was required.\n * NOTE: this will tend to overestimate the actual RTT as the request can be delayed for other\n * reasons as well such as more SSL handshakes if TLS False Start is not enabled.\n */\n static estimateRTTViaSendStartTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n if (!Number.isFinite(timing.sendStart) || timing.sendStart < 0) {\n return;\n }\n\n // Assume everything before sendStart was just DNS + (SSL)? + TCP handshake\n // 1 RT for DNS, 1 RT (maybe) for SSL, 1 RT for TCP\n let roundTrips = 1;\n // TCP\n if (!request.protocol.startsWith('h3')) {\n roundTrips += 1;\n }\n if (request.parsedURL.scheme === 'https') {\n roundTrips += 1;\n }\n return timing.sendStart / roundTrips;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long it took until Chrome received the\n * headers of the response (~TTFB).\n * NOTE: this is the most inaccurate way to estimate the RTT, but in some environments it's all\n * we have access to :(\n */\n static estimateRTTViaHeadersEndTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n if (!request.resourceType) {\n return;\n }\n\n const serverResponseTimePercentage =\n SERVER_RESPONSE_PERCENTAGE_OF_TTFB[request.resourceType] || DEFAULT_SERVER_RESPONSE_PERCENTAGE;\n const estimatedServerResponseTime = timing.receiveHeadersEnd * serverResponseTimePercentage;\n\n // When connection was reused...\n // TTFB = 1 RT for request + server response time\n let roundTrips = 1;\n\n // When connection was fresh...\n // TTFB = DNS + (SSL)? + TCP handshake + 1 RT for request + server response time\n if (!connectionReused) {\n roundTrips += 1; // DNS\n if (!request.protocol.startsWith('h3')) {\n roundTrips += 1; // TCP\n }\n if (request.parsedURL.scheme === 'https') {\n roundTrips += 1; // SSL\n }\n }\n\n // subtract out our estimated server response time\n return Math.max((timing.receiveHeadersEnd - estimatedServerResponseTime) / roundTrips, 3);\n }\n\n /**\n * Given the RTT to each origin, estimates the observed server response times.\n */\n static estimateResponseTimeByOrigin(records: Lantern.NetworkRequest[], rttByOrigin: Map<string, number>):\n Map<string, number[]> {\n return NetworkAnalyzer.estimateValueByOrigin(records, ({request, timing}) => {\n if (request.serverResponseTime !== undefined) {\n return request.serverResponseTime;\n }\n\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n if (!Number.isFinite(timing.sendEnd) || timing.sendEnd < 0) {\n return;\n }\n\n const ttfb = timing.receiveHeadersEnd - timing.sendEnd;\n const origin = request.parsedURL.securityOrigin;\n const rtt = rttByOrigin.get(origin) || rttByOrigin.get(NetworkAnalyzer.summary) || 0;\n return Math.max(ttfb - rtt, 0);\n });\n }\n\n static canTrustConnectionInformation(requests: Lantern.NetworkRequest[]): boolean {\n const connectionIdWasStarted = new Map();\n for (const request of requests) {\n const started = connectionIdWasStarted.get(request.connectionId) || !request.connectionReused;\n connectionIdWasStarted.set(request.connectionId, started);\n }\n\n // We probably can't trust the network information if all the connection IDs were the same\n if (connectionIdWasStarted.size <= 1) {\n return false;\n }\n // Or if there were connections that were always reused (a connection had to have started at some point)\n return Array.from(connectionIdWasStarted.values()).every(started => started);\n }\n\n /**\n * Returns a map of requestId -> connectionReused, estimating the information if the information\n * available in the records themselves appears untrustworthy.\n */\n static estimateIfConnectionWasReused(records: Lantern.NetworkRequest[], options?: {forceCoarseEstimates: boolean}):\n Map<string, boolean> {\n const {forceCoarseEstimates = false} = options || {};\n\n // Check if we can trust the connection information coming from the protocol\n if (!forceCoarseEstimates && NetworkAnalyzer.canTrustConnectionInformation(records)) {\n return new Map(records.map(request => [request.requestId, Boolean(request.connectionReused)]));\n }\n\n // Otherwise we're on our own, a request may not have needed a fresh connection if...\n // - It was not the first request to the domain\n // - It was H2\n // - It was after the first request to the domain ended\n const connectionWasReused = new Map();\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n for (const originRecords of groupedByOrigin.values()) {\n const earliestReusePossible =\n originRecords.map(request => request.networkEndTime).reduce((a, b) => Math.min(a, b), Infinity);\n\n for (const request of originRecords) {\n connectionWasReused.set(\n request.requestId,\n request.networkRequestTime >= earliestReusePossible || request.protocol === 'h2',\n );\n }\n\n const firstRecord = originRecords.reduce((a, b) => {\n return a.networkRequestTime > b.networkRequestTime ? b : a;\n });\n connectionWasReused.set(firstRecord.requestId, false);\n }\n\n return connectionWasReused;\n }\n\n /**\n * Estimates the RTT to each origin by examining observed network timing information.\n * Attempts to use the most accurate information first and falls back to coarser estimates when it\n * is unavailable.\n */\n static estimateRTTByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions): Map<string, Summary> {\n const {\n forceCoarseEstimates = false,\n // coarse estimates include lots of extra time and noise\n // multiply by some factor to deflate the estimates a bit.\n coarseEstimateMultiplier = 0.3,\n useDownloadEstimates = true,\n useSendStartEstimates = true,\n useHeadersEndEstimates = true,\n } = options || {};\n\n const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(records);\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n\n const estimatesByOrigin = new Map();\n for (const [origin, originRequests] of groupedByOrigin.entries()) {\n const originEstimates: number[] = [];\n\n // eslint-disable-next-line no-inner-declarations\n function collectEstimates(estimator: (e: RequestInfo) => number[] | number | undefined, multiplier = 1): void {\n for (const request of originRequests) {\n const timing = request.timing;\n if (!timing || !request.transferSize) {\n continue;\n }\n\n const estimates = estimator({\n request,\n timing,\n connectionReused: connectionWasReused.get(request.requestId),\n });\n if (estimates === undefined) {\n continue;\n }\n\n if (!Array.isArray(estimates)) {\n originEstimates.push(estimates * multiplier);\n } else {\n originEstimates.push(...estimates.map(e => e * multiplier));\n }\n }\n }\n\n if (!forceCoarseEstimates) {\n collectEstimates(this.estimateRTTViaConnectionTiming);\n }\n\n // Connection timing can be missing for a few reasons:\n // - Origin was preconnected, which we don't have instrumentation for.\n // - Trace began recording after a connection has already been established (for example, in timespan mode)\n // - Perhaps Chrome established a connection already in the background (service worker? Just guessing here)\n // - Not provided in LR netstack.\n if (!originEstimates.length) {\n if (useDownloadEstimates) {\n collectEstimates(this.estimateRTTViaDownloadTiming, coarseEstimateMultiplier);\n }\n if (useSendStartEstimates) {\n collectEstimates(this.estimateRTTViaSendStartTiming, coarseEstimateMultiplier);\n }\n if (useHeadersEndEstimates) {\n collectEstimates(this.estimateRTTViaHeadersEndTiming, coarseEstimateMultiplier);\n }\n }\n\n if (originEstimates.length) {\n estimatesByOrigin.set(origin, originEstimates);\n }\n }\n\n if (!estimatesByOrigin.size) {\n throw new LanternError('No timing information available');\n }\n return NetworkAnalyzer.summarize(estimatesByOrigin);\n }\n\n /**\n * Estimates the server response time of each origin. RTT times can be passed in or will be\n * estimated automatically if not provided.\n */\n static estimateServerResponseTimeByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions&{\n rttByOrigin?: Map<string, number>,\n }): Map<string, Summary> {\n let rttByOrigin = (options || {}).rttByOrigin;\n if (!rttByOrigin) {\n rttByOrigin = new Map();\n\n const rttSummaryByOrigin = NetworkAnalyzer.estimateRTTByOrigin(records, options);\n for (const [origin, summary] of rttSummaryByOrigin.entries()) {\n rttByOrigin.set(origin, summary.min);\n }\n }\n\n const estimatesByOrigin = NetworkAnalyzer.estimateResponseTimeByOrigin(records, rttByOrigin);\n return NetworkAnalyzer.summarize(estimatesByOrigin);\n }\n\n /**\n * Computes the average throughput for the given requests in bits/second.\n * Excludes data URI, failed or otherwise incomplete, and cached requests.\n * Returns null if there were no analyzable network requests.\n */\n static estimateThroughput(records: Lantern.NetworkRequest[]): number|null {\n let totalBytes = 0;\n\n // We will measure throughput by summing the total bytes downloaded by the total time spent\n // downloading those bytes. We slice up all the network requests into start/end boundaries, so\n // it's easier to deal with the gaps in downloading.\n const timeBoundaries = records\n .reduce(\n (boundaries, request) => {\n const scheme = request.parsedURL?.scheme;\n // Requests whose bodies didn't come over the network or didn't completely finish will mess\n // with the computation, just skip over them.\n if (scheme === 'data' || request.failed || !request.finished ||\n request.statusCode > 300 || !request.transferSize) {\n return boundaries;\n }\n\n // If we've made it this far, all the times we need should be valid (i.e. not undefined/-1).\n totalBytes += request.transferSize;\n boundaries.push({time: request.responseHeadersEndTime / 1000, isStart: true});\n boundaries.push({time: request.networkEndTime / 1000, isStart: false});\n return boundaries;\n },\n [] as Array<{time: number, isStart: boolean}>)\n .sort((a, b) => a.time - b.time);\n\n if (!timeBoundaries.length) {\n return null;\n }\n\n let inflight = 0;\n let currentStart = 0;\n let totalDuration = 0;\n\n timeBoundaries.forEach(boundary => {\n if (boundary.isStart) {\n if (inflight === 0) {\n // We just ended a quiet period, keep track of when the download period started\n currentStart = boundary.time;\n }\n inflight++;\n } else {\n inflight--;\n if (inflight === 0) {\n // We just entered a quiet period, update our duration with the time we spent downloading\n totalDuration += boundary.time - currentStart;\n }\n }\n });\n\n return totalBytes * 8 / totalDuration;\n }\n\n static computeRTTAndServerResponseTime(records: Lantern.NetworkRequest[]):\n {rtt: number, additionalRttByOrigin: Map<string, number>, serverResponseTimeByOrigin: Map<string, number>} {\n // First pass compute the estimated observed RTT to each origin's servers.\n const rttByOrigin = new Map<string, number>();\n for (const [origin, summary] of NetworkAnalyzer.estimateRTTByOrigin(records).entries()) {\n rttByOrigin.set(origin, summary.min);\n }\n\n // We'll use the minimum RTT as the assumed connection latency since we care about how much addt'l\n // latency each origin introduces as Lantern will be simulating with its own connection latency.\n const minimumRtt = Math.min(...Array.from(rttByOrigin.values()));\n // We'll use the observed RTT information to help estimate the server response time\n const responseTimeSummaries = NetworkAnalyzer.estimateServerResponseTimeByOrigin(records, {\n rttByOrigin,\n });\n\n const additionalRttByOrigin = new Map<string, number>();\n const serverResponseTimeByOrigin = new Map<string, number>();\n for (const [origin, summary] of responseTimeSummaries.entries()) {\n // Not all origins have usable timing data, we'll default to using no additional latency.\n const rttForOrigin = rttByOrigin.get(origin) || minimumRtt;\n additionalRttByOrigin.set(origin, rttForOrigin - minimumRtt);\n serverResponseTimeByOrigin.set(origin, summary.median);\n }\n\n return {\n rtt: minimumRtt,\n additionalRttByOrigin,\n serverResponseTimeByOrigin,\n };\n }\n\n static analyze(records: Lantern.NetworkRequest[]): Lantern.Simulation.Settings['networkAnalysis']|null {\n const throughput = NetworkAnalyzer.estimateThroughput(records);\n if (throughput === null) {\n return null;\n }\n\n return {\n throughput,\n ...NetworkAnalyzer.computeRTTAndServerResponseTime(records),\n };\n }\n\n static findResourceForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T|undefined {\n // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n return records.find(\n request => resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n );\n }\n\n static findLastDocumentForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T|undefined {\n // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n const matchingRequests = records.filter(\n request => request.resourceType === 'Document' &&\n // Note: `request.url` should never have a fragment, else this optimization gives wrong results.\n resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n );\n return matchingRequests[matchingRequests.length - 1];\n }\n\n /**\n * Resolves redirect chain given a main document.\n * See: {@link NetworkAnalyzer.findLastDocumentForUrl} for how to retrieve main document.\n */\n static resolveRedirects<T extends Lantern.NetworkRequest>(request: T): T {\n while (request.redirectDestination) {\n request = request.redirectDestination as T;\n }\n return request;\n }\n}\n\nexport {NetworkAnalyzer};\n"]}
@@ -1,6 +1,6 @@
1
1
  import type * as Lantern from '../types/types.js';
2
- import { type CPUNode } from './CPUNode.js';
3
- import { type NetworkNode } from './NetworkNode.js';
2
+ import type { CPUNode } from './CPUNode.js';
3
+ import type { NetworkNode } from './NetworkNode.js';
4
4
  /**
5
5
  * A union of all types derived from BaseNode, allowing type check discrimination
6
6
  * based on `node.type`. If a new node type is created, it should be added here.
@@ -25,8 +25,8 @@ declare class BaseNode<T = Lantern.AnyNetworkObject> {
25
25
  };
26
26
  _id: string;
27
27
  _isMainDocument: boolean;
28
- _dependents: Node[];
29
- _dependencies: Node[];
28
+ dependents: Node[];
29
+ dependencies: Node[];
30
30
  constructor(id: string);
31
31
  get id(): string;
32
32
  get type(): 'network' | 'cpu';