@sentry/browser-utils 10.58.0

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 (312) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/build/cjs/debug-build.js +6 -0
  4. package/build/cjs/debug-build.js.map +1 -0
  5. package/build/cjs/getNativeImplementation.js +51 -0
  6. package/build/cjs/getNativeImplementation.js.map +1 -0
  7. package/build/cjs/htmlTreeAsString.js +110 -0
  8. package/build/cjs/htmlTreeAsString.js.map +1 -0
  9. package/build/cjs/index.js +54 -0
  10. package/build/cjs/index.js.map +1 -0
  11. package/build/cjs/instrument/dom.js +137 -0
  12. package/build/cjs/instrument/dom.js.map +1 -0
  13. package/build/cjs/instrument/history.js +56 -0
  14. package/build/cjs/instrument/history.js.map +1 -0
  15. package/build/cjs/instrument/xhr.js +108 -0
  16. package/build/cjs/instrument/xhr.js.map +1 -0
  17. package/build/cjs/is.js +15 -0
  18. package/build/cjs/is.js.map +1 -0
  19. package/build/cjs/metrics/browserMetrics.js +535 -0
  20. package/build/cjs/metrics/browserMetrics.js.map +1 -0
  21. package/build/cjs/metrics/cls.js +64 -0
  22. package/build/cjs/metrics/cls.js.map +1 -0
  23. package/build/cjs/metrics/elementTiming.js +72 -0
  24. package/build/cjs/metrics/elementTiming.js.map +1 -0
  25. package/build/cjs/metrics/inp.js +170 -0
  26. package/build/cjs/metrics/inp.js.map +1 -0
  27. package/build/cjs/metrics/instrument.js +152 -0
  28. package/build/cjs/metrics/instrument.js.map +1 -0
  29. package/build/cjs/metrics/lcp.js +77 -0
  30. package/build/cjs/metrics/lcp.js.map +1 -0
  31. package/build/cjs/metrics/resourceTiming.js +44 -0
  32. package/build/cjs/metrics/resourceTiming.js.map +1 -0
  33. package/build/cjs/metrics/utils.js +137 -0
  34. package/build/cjs/metrics/utils.js.map +1 -0
  35. package/build/cjs/metrics/web-vitals/getCLS.js +46 -0
  36. package/build/cjs/metrics/web-vitals/getCLS.js.map +1 -0
  37. package/build/cjs/metrics/web-vitals/getINP.js +60 -0
  38. package/build/cjs/metrics/web-vitals/getINP.js.map +1 -0
  39. package/build/cjs/metrics/web-vitals/getLCP.js +62 -0
  40. package/build/cjs/metrics/web-vitals/getLCP.js.map +1 -0
  41. package/build/cjs/metrics/web-vitals/lib/InteractionManager.js +87 -0
  42. package/build/cjs/metrics/web-vitals/lib/InteractionManager.js.map +1 -0
  43. package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js +11 -0
  44. package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js.map +1 -0
  45. package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js +27 -0
  46. package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js.map +1 -0
  47. package/build/cjs/metrics/web-vitals/lib/bindReporter.js +31 -0
  48. package/build/cjs/metrics/web-vitals/lib/bindReporter.js.map +1 -0
  49. package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js +8 -0
  50. package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js.map +1 -0
  51. package/build/cjs/metrics/web-vitals/lib/getActivationStart.js +11 -0
  52. package/build/cjs/metrics/web-vitals/lib/getActivationStart.js.map +1 -0
  53. package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js +17 -0
  54. package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js.map +1 -0
  55. package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js +48 -0
  56. package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js.map +1 -0
  57. package/build/cjs/metrics/web-vitals/lib/globalListeners.js +18 -0
  58. package/build/cjs/metrics/web-vitals/lib/globalListeners.js.map +1 -0
  59. package/build/cjs/metrics/web-vitals/lib/initMetric.js +34 -0
  60. package/build/cjs/metrics/web-vitals/lib/initMetric.js.map +1 -0
  61. package/build/cjs/metrics/web-vitals/lib/initUnique.js +16 -0
  62. package/build/cjs/metrics/web-vitals/lib/initUnique.js.map +1 -0
  63. package/build/cjs/metrics/web-vitals/lib/observe.js +20 -0
  64. package/build/cjs/metrics/web-vitals/lib/observe.js.map +1 -0
  65. package/build/cjs/metrics/web-vitals/lib/onHidden.js +17 -0
  66. package/build/cjs/metrics/web-vitals/lib/onHidden.js.map +1 -0
  67. package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +32 -0
  68. package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +1 -0
  69. package/build/cjs/metrics/web-vitals/lib/runOnce.js +14 -0
  70. package/build/cjs/metrics/web-vitals/lib/runOnce.js.map +1 -0
  71. package/build/cjs/metrics/web-vitals/lib/whenActivated.js +14 -0
  72. package/build/cjs/metrics/web-vitals/lib/whenActivated.js.map +1 -0
  73. package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js +24 -0
  74. package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js.map +1 -0
  75. package/build/cjs/metrics/web-vitals/onFCP.js +37 -0
  76. package/build/cjs/metrics/web-vitals/onFCP.js.map +1 -0
  77. package/build/cjs/metrics/web-vitals/onTTFB.js +35 -0
  78. package/build/cjs/metrics/web-vitals/onTTFB.js.map +1 -0
  79. package/build/cjs/metrics/webVitalSpans.js +199 -0
  80. package/build/cjs/metrics/webVitalSpans.js.map +1 -0
  81. package/build/cjs/networkUtils.js +70 -0
  82. package/build/cjs/networkUtils.js.map +1 -0
  83. package/build/cjs/types.js +8 -0
  84. package/build/cjs/types.js.map +1 -0
  85. package/build/esm/debug-build.js +4 -0
  86. package/build/esm/debug-build.js.map +1 -0
  87. package/build/esm/getNativeImplementation.js +46 -0
  88. package/build/esm/getNativeImplementation.js.map +1 -0
  89. package/build/esm/htmlTreeAsString.js +108 -0
  90. package/build/esm/htmlTreeAsString.js.map +1 -0
  91. package/build/esm/index.js +15 -0
  92. package/build/esm/index.js.map +1 -0
  93. package/build/esm/instrument/dom.js +134 -0
  94. package/build/esm/instrument/dom.js.map +1 -0
  95. package/build/esm/instrument/history.js +53 -0
  96. package/build/esm/instrument/history.js.map +1 -0
  97. package/build/esm/instrument/xhr.js +104 -0
  98. package/build/esm/instrument/xhr.js.map +1 -0
  99. package/build/esm/is.js +13 -0
  100. package/build/esm/is.js.map +1 -0
  101. package/build/esm/metrics/browserMetrics.js +524 -0
  102. package/build/esm/metrics/browserMetrics.js.map +1 -0
  103. package/build/esm/metrics/cls.js +61 -0
  104. package/build/esm/metrics/cls.js.map +1 -0
  105. package/build/esm/metrics/elementTiming.js +69 -0
  106. package/build/esm/metrics/elementTiming.js.map +1 -0
  107. package/build/esm/metrics/inp.js +162 -0
  108. package/build/esm/metrics/inp.js.map +1 -0
  109. package/build/esm/metrics/instrument.js +145 -0
  110. package/build/esm/metrics/instrument.js.map +1 -0
  111. package/build/esm/metrics/lcp.js +72 -0
  112. package/build/esm/metrics/lcp.js.map +1 -0
  113. package/build/esm/metrics/resourceTiming.js +42 -0
  114. package/build/esm/metrics/resourceTiming.js.map +1 -0
  115. package/build/esm/metrics/utils.js +128 -0
  116. package/build/esm/metrics/utils.js.map +1 -0
  117. package/build/esm/metrics/web-vitals/getCLS.js +43 -0
  118. package/build/esm/metrics/web-vitals/getCLS.js.map +1 -0
  119. package/build/esm/metrics/web-vitals/getINP.js +57 -0
  120. package/build/esm/metrics/web-vitals/getINP.js.map +1 -0
  121. package/build/esm/metrics/web-vitals/getLCP.js +59 -0
  122. package/build/esm/metrics/web-vitals/getLCP.js.map +1 -0
  123. package/build/esm/metrics/web-vitals/lib/InteractionManager.js +85 -0
  124. package/build/esm/metrics/web-vitals/lib/InteractionManager.js.map +1 -0
  125. package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js +9 -0
  126. package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js.map +1 -0
  127. package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js +25 -0
  128. package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js.map +1 -0
  129. package/build/esm/metrics/web-vitals/lib/bindReporter.js +29 -0
  130. package/build/esm/metrics/web-vitals/lib/bindReporter.js.map +1 -0
  131. package/build/esm/metrics/web-vitals/lib/generateUniqueID.js +6 -0
  132. package/build/esm/metrics/web-vitals/lib/generateUniqueID.js.map +1 -0
  133. package/build/esm/metrics/web-vitals/lib/getActivationStart.js +9 -0
  134. package/build/esm/metrics/web-vitals/lib/getActivationStart.js.map +1 -0
  135. package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js +15 -0
  136. package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js.map +1 -0
  137. package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js +46 -0
  138. package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js.map +1 -0
  139. package/build/esm/metrics/web-vitals/lib/globalListeners.js +15 -0
  140. package/build/esm/metrics/web-vitals/lib/globalListeners.js.map +1 -0
  141. package/build/esm/metrics/web-vitals/lib/initMetric.js +32 -0
  142. package/build/esm/metrics/web-vitals/lib/initMetric.js.map +1 -0
  143. package/build/esm/metrics/web-vitals/lib/initUnique.js +14 -0
  144. package/build/esm/metrics/web-vitals/lib/initUnique.js.map +1 -0
  145. package/build/esm/metrics/web-vitals/lib/observe.js +18 -0
  146. package/build/esm/metrics/web-vitals/lib/observe.js.map +1 -0
  147. package/build/esm/metrics/web-vitals/lib/onHidden.js +15 -0
  148. package/build/esm/metrics/web-vitals/lib/onHidden.js.map +1 -0
  149. package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +29 -0
  150. package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +1 -0
  151. package/build/esm/metrics/web-vitals/lib/runOnce.js +12 -0
  152. package/build/esm/metrics/web-vitals/lib/runOnce.js.map +1 -0
  153. package/build/esm/metrics/web-vitals/lib/whenActivated.js +12 -0
  154. package/build/esm/metrics/web-vitals/lib/whenActivated.js.map +1 -0
  155. package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js +22 -0
  156. package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js.map +1 -0
  157. package/build/esm/metrics/web-vitals/onFCP.js +34 -0
  158. package/build/esm/metrics/web-vitals/onFCP.js.map +1 -0
  159. package/build/esm/metrics/web-vitals/onTTFB.js +32 -0
  160. package/build/esm/metrics/web-vitals/onTTFB.js.map +1 -0
  161. package/build/esm/metrics/webVitalSpans.js +191 -0
  162. package/build/esm/metrics/webVitalSpans.js.map +1 -0
  163. package/build/esm/networkUtils.js +64 -0
  164. package/build/esm/networkUtils.js.map +1 -0
  165. package/build/esm/package.json +1 -0
  166. package/build/esm/types.js +6 -0
  167. package/build/esm/types.js.map +1 -0
  168. package/build/types/debug-build.d.ts +7 -0
  169. package/build/types/debug-build.d.ts.map +1 -0
  170. package/build/types/getNativeImplementation.d.ts +69 -0
  171. package/build/types/getNativeImplementation.d.ts.map +1 -0
  172. package/build/types/htmlTreeAsString.d.ts +11 -0
  173. package/build/types/htmlTreeAsString.d.ts.map +1 -0
  174. package/build/types/index.d.ts +15 -0
  175. package/build/types/index.d.ts.map +1 -0
  176. package/build/types/instrument/dom.d.ts +11 -0
  177. package/build/types/instrument/dom.d.ts.map +1 -0
  178. package/build/types/instrument/history.d.ts +15 -0
  179. package/build/types/instrument/history.d.ts.map +1 -0
  180. package/build/types/instrument/xhr.d.ts +14 -0
  181. package/build/types/instrument/xhr.d.ts.map +1 -0
  182. package/build/types/is.d.ts +7 -0
  183. package/build/types/is.d.ts.map +1 -0
  184. package/build/types/metrics/browserMetrics.d.ts +116 -0
  185. package/build/types/metrics/browserMetrics.d.ts.map +1 -0
  186. package/build/types/metrics/cls.d.ts +17 -0
  187. package/build/types/metrics/cls.d.ts.map +1 -0
  188. package/build/types/metrics/elementTiming.d.ts +19 -0
  189. package/build/types/metrics/elementTiming.d.ts.map +1 -0
  190. package/build/types/metrics/inp.d.ts +35 -0
  191. package/build/types/metrics/inp.d.ts.map +1 -0
  192. package/build/types/metrics/instrument.d.ts +121 -0
  193. package/build/types/metrics/instrument.d.ts.map +1 -0
  194. package/build/types/metrics/lcp.d.ts +22 -0
  195. package/build/types/metrics/lcp.d.ts.map +1 -0
  196. package/build/types/metrics/resourceTiming.d.ts +13 -0
  197. package/build/types/metrics/resourceTiming.d.ts.map +1 -0
  198. package/build/types/metrics/utils.d.ts +73 -0
  199. package/build/types/metrics/utils.d.ts.map +1 -0
  200. package/build/types/metrics/web-vitals/getCLS.d.ts +26 -0
  201. package/build/types/metrics/web-vitals/getCLS.d.ts.map +1 -0
  202. package/build/types/metrics/web-vitals/getINP.d.ts +34 -0
  203. package/build/types/metrics/web-vitals/getINP.d.ts.map +1 -0
  204. package/build/types/metrics/web-vitals/getLCP.d.ts +16 -0
  205. package/build/types/metrics/web-vitals/getLCP.d.ts.map +1 -0
  206. package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts +37 -0
  207. package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts.map +1 -0
  208. package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts +5 -0
  209. package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts.map +1 -0
  210. package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts +7 -0
  211. package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts.map +1 -0
  212. package/build/types/metrics/web-vitals/lib/bindReporter.d.ts +7 -0
  213. package/build/types/metrics/web-vitals/lib/bindReporter.d.ts.map +1 -0
  214. package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts +7 -0
  215. package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts.map +1 -0
  216. package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts +2 -0
  217. package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts.map +1 -0
  218. package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts +2 -0
  219. package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts.map +1 -0
  220. package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts +5 -0
  221. package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts.map +1 -0
  222. package/build/types/metrics/web-vitals/lib/globalListeners.d.ts +11 -0
  223. package/build/types/metrics/web-vitals/lib/globalListeners.d.ts.map +1 -0
  224. package/build/types/metrics/web-vitals/lib/initMetric.d.ts +21 -0
  225. package/build/types/metrics/web-vitals/lib/initMetric.d.ts.map +1 -0
  226. package/build/types/metrics/web-vitals/lib/initUnique.d.ts +7 -0
  227. package/build/types/metrics/web-vitals/lib/initUnique.d.ts.map +1 -0
  228. package/build/types/metrics/web-vitals/lib/observe.d.ts +23 -0
  229. package/build/types/metrics/web-vitals/lib/observe.d.ts.map +1 -0
  230. package/build/types/metrics/web-vitals/lib/onHidden.d.ts +27 -0
  231. package/build/types/metrics/web-vitals/lib/onHidden.d.ts.map +1 -0
  232. package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +15 -0
  233. package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts.map +1 -0
  234. package/build/types/metrics/web-vitals/lib/runOnce.d.ts +2 -0
  235. package/build/types/metrics/web-vitals/lib/runOnce.d.ts.map +1 -0
  236. package/build/types/metrics/web-vitals/lib/whenActivated.d.ts +2 -0
  237. package/build/types/metrics/web-vitals/lib/whenActivated.d.ts.map +1 -0
  238. package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts +6 -0
  239. package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts.map +1 -0
  240. package/build/types/metrics/web-vitals/onFCP.d.ts +11 -0
  241. package/build/types/metrics/web-vitals/onFCP.d.ts.map +1 -0
  242. package/build/types/metrics/web-vitals/onTTFB.d.ts +20 -0
  243. package/build/types/metrics/web-vitals/onTTFB.d.ts.map +1 -0
  244. package/build/types/metrics/web-vitals/types/base.d.ts +103 -0
  245. package/build/types/metrics/web-vitals/types/base.d.ts.map +1 -0
  246. package/build/types/metrics/web-vitals/types/cls.d.ts +58 -0
  247. package/build/types/metrics/web-vitals/types/cls.d.ts.map +1 -0
  248. package/build/types/metrics/web-vitals/types/fcp.d.ts +47 -0
  249. package/build/types/metrics/web-vitals/types/fcp.d.ts.map +1 -0
  250. package/build/types/metrics/web-vitals/types/inp.d.ts +150 -0
  251. package/build/types/metrics/web-vitals/types/inp.d.ts.map +1 -0
  252. package/build/types/metrics/web-vitals/types/lcp.d.ts +74 -0
  253. package/build/types/metrics/web-vitals/types/lcp.d.ts.map +1 -0
  254. package/build/types/metrics/web-vitals/types/ttfb.d.ts +60 -0
  255. package/build/types/metrics/web-vitals/types/ttfb.d.ts.map +1 -0
  256. package/build/types/metrics/web-vitals/types.d.ts +78 -0
  257. package/build/types/metrics/web-vitals/types.d.ts.map +1 -0
  258. package/build/types/metrics/webVitalSpans.d.ts +65 -0
  259. package/build/types/metrics/webVitalSpans.d.ts.map +1 -0
  260. package/build/types/networkUtils.d.ts +25 -0
  261. package/build/types/networkUtils.d.ts.map +1 -0
  262. package/build/types/types.d.ts +15 -0
  263. package/build/types/types.d.ts.map +1 -0
  264. package/build/types-ts3.8/debug-build.d.ts +7 -0
  265. package/build/types-ts3.8/getNativeImplementation.d.ts +69 -0
  266. package/build/types-ts3.8/htmlTreeAsString.d.ts +11 -0
  267. package/build/types-ts3.8/index.d.ts +15 -0
  268. package/build/types-ts3.8/instrument/dom.d.ts +11 -0
  269. package/build/types-ts3.8/instrument/history.d.ts +15 -0
  270. package/build/types-ts3.8/instrument/xhr.d.ts +14 -0
  271. package/build/types-ts3.8/is.d.ts +7 -0
  272. package/build/types-ts3.8/metrics/browserMetrics.d.ts +119 -0
  273. package/build/types-ts3.8/metrics/cls.d.ts +17 -0
  274. package/build/types-ts3.8/metrics/elementTiming.d.ts +19 -0
  275. package/build/types-ts3.8/metrics/inp.d.ts +35 -0
  276. package/build/types-ts3.8/metrics/instrument.d.ts +121 -0
  277. package/build/types-ts3.8/metrics/lcp.d.ts +22 -0
  278. package/build/types-ts3.8/metrics/resourceTiming.d.ts +13 -0
  279. package/build/types-ts3.8/metrics/utils.d.ts +73 -0
  280. package/build/types-ts3.8/metrics/web-vitals/getCLS.d.ts +26 -0
  281. package/build/types-ts3.8/metrics/web-vitals/getINP.d.ts +34 -0
  282. package/build/types-ts3.8/metrics/web-vitals/getLCP.d.ts +16 -0
  283. package/build/types-ts3.8/metrics/web-vitals/lib/InteractionManager.d.ts +37 -0
  284. package/build/types-ts3.8/metrics/web-vitals/lib/LCPEntryManager.d.ts +5 -0
  285. package/build/types-ts3.8/metrics/web-vitals/lib/LayoutShiftManager.d.ts +7 -0
  286. package/build/types-ts3.8/metrics/web-vitals/lib/bindReporter.d.ts +7 -0
  287. package/build/types-ts3.8/metrics/web-vitals/lib/generateUniqueID.d.ts +7 -0
  288. package/build/types-ts3.8/metrics/web-vitals/lib/getActivationStart.d.ts +2 -0
  289. package/build/types-ts3.8/metrics/web-vitals/lib/getNavigationEntry.d.ts +2 -0
  290. package/build/types-ts3.8/metrics/web-vitals/lib/getVisibilityWatcher.d.ts +5 -0
  291. package/build/types-ts3.8/metrics/web-vitals/lib/globalListeners.d.ts +11 -0
  292. package/build/types-ts3.8/metrics/web-vitals/lib/initMetric.d.ts +21 -0
  293. package/build/types-ts3.8/metrics/web-vitals/lib/initUnique.d.ts +7 -0
  294. package/build/types-ts3.8/metrics/web-vitals/lib/observe.d.ts +23 -0
  295. package/build/types-ts3.8/metrics/web-vitals/lib/onHidden.d.ts +27 -0
  296. package/build/types-ts3.8/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +15 -0
  297. package/build/types-ts3.8/metrics/web-vitals/lib/runOnce.d.ts +2 -0
  298. package/build/types-ts3.8/metrics/web-vitals/lib/whenActivated.d.ts +2 -0
  299. package/build/types-ts3.8/metrics/web-vitals/lib/whenIdleOrHidden.d.ts +6 -0
  300. package/build/types-ts3.8/metrics/web-vitals/onFCP.d.ts +11 -0
  301. package/build/types-ts3.8/metrics/web-vitals/onTTFB.d.ts +20 -0
  302. package/build/types-ts3.8/metrics/web-vitals/types/base.d.ts +106 -0
  303. package/build/types-ts3.8/metrics/web-vitals/types/cls.d.ts +58 -0
  304. package/build/types-ts3.8/metrics/web-vitals/types/fcp.d.ts +47 -0
  305. package/build/types-ts3.8/metrics/web-vitals/types/inp.d.ts +150 -0
  306. package/build/types-ts3.8/metrics/web-vitals/types/lcp.d.ts +74 -0
  307. package/build/types-ts3.8/metrics/web-vitals/types/ttfb.d.ts +60 -0
  308. package/build/types-ts3.8/metrics/web-vitals/types.d.ts +78 -0
  309. package/build/types-ts3.8/metrics/webVitalSpans.d.ts +65 -0
  310. package/build/types-ts3.8/networkUtils.d.ts +28 -0
  311. package/build/types-ts3.8/types.d.ts +15 -0
  312. package/package.json +69 -0
@@ -0,0 +1,61 @@
1
+ import { debug, browserPerformanceTimeOrigin, timestampInSeconds, getCurrentScope, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT, SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
2
+ import { DEBUG_BUILD } from '../debug-build.js';
3
+ import { htmlTreeAsString } from '../htmlTreeAsString.js';
4
+ import { addClsInstrumentationHandler } from './instrument.js';
5
+ import { supportsWebVital, listenForWebVitalReportEvents, msToSec, startStandaloneWebVitalSpan } from './utils.js';
6
+
7
+ function trackClsAsStandaloneSpan(client) {
8
+ let standaloneCLsValue = 0;
9
+ let standaloneClsEntry;
10
+ if (!supportsWebVital("layout-shift")) {
11
+ return;
12
+ }
13
+ const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {
14
+ const entry = metric.entries[metric.entries.length - 1];
15
+ if (!entry) {
16
+ return;
17
+ }
18
+ standaloneCLsValue = metric.value;
19
+ standaloneClsEntry = entry;
20
+ }, true);
21
+ listenForWebVitalReportEvents(client, (reportEvent, pageloadSpanId) => {
22
+ _sendStandaloneClsSpan(standaloneCLsValue, standaloneClsEntry, pageloadSpanId, reportEvent);
23
+ cleanupClsHandler();
24
+ });
25
+ }
26
+ function _sendStandaloneClsSpan(clsValue, entry, pageloadSpanId, reportEvent) {
27
+ DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);
28
+ const startTime = entry ? msToSec((browserPerformanceTimeOrigin() || 0) + entry.startTime) : timestampInSeconds();
29
+ const routeName = getCurrentScope().getScopeData().transactionName;
30
+ const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : "Layout shift";
31
+ const attributes = {
32
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.browser.cls",
33
+ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "ui.webvital.cls",
34
+ [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,
35
+ // attach the pageload span id to the CLS span so that we can link them in the UI
36
+ "sentry.pageload.span_id": pageloadSpanId,
37
+ // describes what triggered the web vital to be reported
38
+ "sentry.report_event": reportEvent
39
+ };
40
+ if (entry?.sources) {
41
+ entry.sources.forEach((source, index) => {
42
+ attributes[`cls.source.${index + 1}`] = htmlTreeAsString(source.node);
43
+ });
44
+ }
45
+ const span = startStandaloneWebVitalSpan({
46
+ name,
47
+ transaction: routeName,
48
+ attributes,
49
+ startTime
50
+ });
51
+ if (span) {
52
+ span.addEvent("cls", {
53
+ [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: "",
54
+ [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: clsValue
55
+ });
56
+ span.end(startTime);
57
+ }
58
+ }
59
+
60
+ export { _sendStandaloneClsSpan, trackClsAsStandaloneSpan };
61
+ //# sourceMappingURL=cls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cls.js","sources":["../../../src/metrics/cls.ts"],"sourcesContent":["import type { Client, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n timestampInSeconds,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { addClsInstrumentationHandler } from './instrument';\nimport type { WebVitalReportEvent } from './utils';\nimport { listenForWebVitalReportEvents, msToSec, startStandaloneWebVitalSpan, supportsWebVital } from './utils';\n\n/**\n * Starts tracking the Cumulative Layout Shift on the current page and collects the value once\n *\n * - the page visibility is hidden\n * - a navigation span is started (to stop CLS measurement for SPA soft navigations)\n *\n * Once either of these events triggers, the CLS value is sent as a standalone span and we stop\n * measuring CLS.\n */\nexport function trackClsAsStandaloneSpan(client: Client): void {\n let standaloneCLsValue = 0;\n let standaloneClsEntry: LayoutShift | undefined;\n\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n standaloneCLsValue = metric.value;\n standaloneClsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, pageloadSpanId) => {\n _sendStandaloneClsSpan(standaloneCLsValue, standaloneClsEntry, pageloadSpanId, reportEvent);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing!\n */\nexport function _sendStandaloneClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpanId: string,\n reportEvent: WebVitalReportEvent,\n) {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const startTime = entry ? msToSec((browserPerformanceTimeOrigin() || 0) + entry.startTime) : timestampInSeconds();\n const routeName = getCurrentScope().getScopeData().transactionName;\n\n const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.cls',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'ui.webvital.cls',\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,\n // attach the pageload span id to the CLS span so that we can link them in the UI\n 'sentry.pageload.span_id': pageloadSpanId,\n // describes what triggered the web vital to be reported\n 'sentry.report_event': reportEvent,\n };\n\n // Add CLS sources as span attributes to help with debugging layout shifts\n // See: https://developer.mozilla.org/en-US/docs/Web/API/LayoutShift/sources\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n const span = startStandaloneWebVitalSpan({\n name,\n transaction: routeName,\n attributes,\n startTime,\n });\n\n if (span) {\n span.addEvent('cls', {\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: '',\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: clsValue,\n });\n\n // LayoutShift performance entries always have a duration of 0, so we don't need to add `entry.duration` here\n // see: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry/duration\n span.end(startTime);\n }\n}\n"],"names":[],"mappings":";;;;;;AA2BO,SAAS,yBAAyB,MAAA,EAAsB;AAC7D,EAAA,IAAI,kBAAA,GAAqB,CAAA;AACzB,EAAA,IAAI,kBAAA;AAEJ,EAAA,IAAI,CAAC,gBAAA,CAAiB,cAAc,CAAA,EAAG;AACrC,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,iBAAA,GAAoB,4BAAA,CAA6B,CAAC,EAAE,QAAO,KAAM;AACrE,IAAA,MAAM,QAAQ,MAAA,CAAO,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAC,CAAA;AACtD,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA;AAAA,IACF;AACA,IAAA,kBAAA,GAAqB,MAAA,CAAO,KAAA;AAC5B,IAAA,kBAAA,GAAqB,KAAA;AAAA,EACvB,GAAG,IAAI,CAAA;AAEP,EAAA,6BAAA,CAA8B,MAAA,EAAQ,CAAC,WAAA,EAAa,cAAA,KAAmB;AACrE,IAAA,sBAAA,CAAuB,kBAAA,EAAoB,kBAAA,EAAoB,cAAA,EAAgB,WAAW,CAAA;AAC1F,IAAA,iBAAA,EAAkB;AAAA,EACpB,CAAC,CAAA;AACH;AAKO,SAAS,sBAAA,CACd,QAAA,EACA,KAAA,EACA,cAAA,EACA,WAAA,EACA;AACA,EAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,CAAA,kBAAA,EAAqB,QAAQ,CAAA,CAAA,CAAG,CAAA;AAEzD,EAAA,MAAM,SAAA,GAAY,QAAQ,OAAA,CAAA,CAAS,4BAAA,MAAkC,CAAA,IAAK,KAAA,CAAM,SAAS,CAAA,GAAI,kBAAA,EAAmB;AAChH,EAAA,MAAM,SAAA,GAAY,eAAA,EAAgB,CAAE,YAAA,EAAa,CAAE,eAAA;AAEnD,EAAA,MAAM,IAAA,GAAO,QAAQ,gBAAA,CAAiB,KAAA,CAAM,QAAQ,CAAC,CAAA,EAAG,IAAI,CAAA,GAAI,cAAA;AAEhE,EAAA,MAAM,UAAA,GAA6B;AAAA,IACjC,CAAC,gCAAgC,GAAG,uBAAA;AAAA,IACpC,CAAC,4BAA4B,GAAG,iBAAA;AAAA,IAChC,CAAC,iCAAiC,GAAG,CAAA;AAAA;AAAA,IAErC,yBAAA,EAA2B,cAAA;AAAA;AAAA,IAE3B,qBAAA,EAAuB;AAAA,GACzB;AAIA,EAAA,IAAI,OAAO,OAAA,EAAS;AAClB,IAAA,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,CAAC,MAAA,EAAQ,KAAA,KAAU;AACvC,MAAA,UAAA,CAAW,cAAc,KAAA,GAAQ,CAAC,EAAE,CAAA,GAAI,gBAAA,CAAiB,OAAO,IAAI,CAAA;AAAA,IACtE,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,OAAO,2BAAA,CAA4B;AAAA,IACvC,IAAA;AAAA,IACA,WAAA,EAAa,SAAA;AAAA,IACb,UAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,IAAA,CAAK,SAAS,KAAA,EAAO;AAAA,MACnB,CAAC,0CAA0C,GAAG,EAAA;AAAA,MAC9C,CAAC,2CAA2C,GAAG;AAAA,KAChD,CAAA;AAID,IAAA,IAAA,CAAK,IAAI,SAAS,CAAA;AAAA,EACpB;AACF;;;;"}
@@ -0,0 +1,69 @@
1
+ import { defineIntegration, browserPerformanceTimeOrigin, metrics } from '@sentry/core';
2
+ import { addPerformanceInstrumentationHandler } from './instrument.js';
3
+ import { getBrowserPerformanceAPI } from './utils.js';
4
+
5
+ const INTEGRATION_NAME = "ElementTiming";
6
+ const _elementTimingIntegration = (() => {
7
+ return {
8
+ name: INTEGRATION_NAME,
9
+ setup() {
10
+ const performance = getBrowserPerformanceAPI();
11
+ if (!performance || !browserPerformanceTimeOrigin()) {
12
+ return;
13
+ }
14
+ addPerformanceInstrumentationHandler("element", ({ entries }) => {
15
+ for (const entry of entries) {
16
+ const elementEntry = entry;
17
+ if (!elementEntry.identifier) {
18
+ continue;
19
+ }
20
+ const identifier = elementEntry.identifier;
21
+ const paintType = elementEntry.name;
22
+ const renderTime = elementEntry.renderTime;
23
+ const loadTime = elementEntry.loadTime;
24
+ const metricAttributes = {
25
+ "sentry.origin": "auto.ui.browser.element_timing",
26
+ "ui.element.identifier": identifier
27
+ };
28
+ if (paintType) {
29
+ metricAttributes["ui.element.paint_type"] = paintType;
30
+ }
31
+ if (elementEntry.id) {
32
+ metricAttributes["ui.element.id"] = elementEntry.id;
33
+ }
34
+ if (elementEntry.element) {
35
+ metricAttributes["ui.element.type"] = elementEntry.element.tagName.toLowerCase();
36
+ }
37
+ if (elementEntry.url) {
38
+ metricAttributes["ui.element.url"] = elementEntry.url;
39
+ }
40
+ if (elementEntry.naturalWidth) {
41
+ metricAttributes["ui.element.width"] = elementEntry.naturalWidth;
42
+ }
43
+ if (elementEntry.naturalHeight) {
44
+ metricAttributes["ui.element.height"] = elementEntry.naturalHeight;
45
+ }
46
+ if (renderTime > 0) {
47
+ metrics.distribution(`ui.element.render_time`, renderTime, {
48
+ unit: "millisecond",
49
+ attributes: metricAttributes
50
+ });
51
+ }
52
+ if (loadTime > 0) {
53
+ metrics.distribution(`ui.element.load_time`, loadTime, {
54
+ unit: "millisecond",
55
+ attributes: metricAttributes
56
+ });
57
+ }
58
+ }
59
+ });
60
+ }
61
+ };
62
+ });
63
+ const elementTimingIntegration = defineIntegration(_elementTimingIntegration);
64
+ function startTrackingElementTiming() {
65
+ return () => void 0;
66
+ }
67
+
68
+ export { elementTimingIntegration, startTrackingElementTiming };
69
+ //# sourceMappingURL=elementTiming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elementTiming.js","sources":["../../../src/metrics/elementTiming.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { browserPerformanceTimeOrigin, defineIntegration, metrics } from '@sentry/core';\nimport { addPerformanceInstrumentationHandler } from './instrument';\nimport { getBrowserPerformanceAPI } from './utils';\n\n// ElementTiming interface based on the W3C spec\ninterface PerformanceElementTiming extends PerformanceEntry {\n renderTime: number;\n loadTime: number;\n intersectionRect: DOMRectReadOnly;\n identifier: string;\n naturalWidth: number;\n naturalHeight: number;\n id: string;\n element: Element | null;\n url?: string;\n}\n\nconst INTEGRATION_NAME = 'ElementTiming';\n\nconst _elementTimingIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setup() {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n addPerformanceInstrumentationHandler('element', ({ entries }) => {\n for (const entry of entries) {\n const elementEntry = entry as PerformanceElementTiming;\n\n if (!elementEntry.identifier) {\n continue;\n }\n\n const identifier = elementEntry.identifier;\n const paintType = elementEntry.name as 'image-paint' | 'text-paint' | undefined;\n const renderTime = elementEntry.renderTime;\n const loadTime = elementEntry.loadTime;\n\n const metricAttributes: Record<string, string | number> = {\n 'sentry.origin': 'auto.ui.browser.element_timing',\n 'ui.element.identifier': identifier,\n };\n\n if (paintType) {\n metricAttributes['ui.element.paint_type'] = paintType;\n }\n\n if (elementEntry.id) {\n metricAttributes['ui.element.id'] = elementEntry.id;\n }\n\n if (elementEntry.element) {\n metricAttributes['ui.element.type'] = elementEntry.element.tagName.toLowerCase();\n }\n\n if (elementEntry.url) {\n metricAttributes['ui.element.url'] = elementEntry.url;\n }\n\n if (elementEntry.naturalWidth) {\n metricAttributes['ui.element.width'] = elementEntry.naturalWidth;\n }\n\n if (elementEntry.naturalHeight) {\n metricAttributes['ui.element.height'] = elementEntry.naturalHeight;\n }\n\n if (renderTime > 0) {\n metrics.distribution(`ui.element.render_time`, renderTime, {\n unit: 'millisecond',\n attributes: metricAttributes,\n });\n }\n\n if (loadTime > 0) {\n metrics.distribution(`ui.element.load_time`, loadTime, {\n unit: 'millisecond',\n attributes: metricAttributes,\n });\n }\n }\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Captures [Element Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceElementTiming)\n * data as Sentry metrics.\n *\n * To mark an element for tracking, add the `elementtiming` HTML attribute:\n * ```html\n * <img src=\"hero.jpg\" elementtiming=\"hero-image\" />\n * <p elementtiming=\"hero-text\">Welcome!</p>\n * ```\n *\n * This emits `ui.element.render_time` and `ui.element.load_time` (for images)\n * as distribution metrics, tagged with the element's identifier and paint type.\n */\nexport const elementTimingIntegration = defineIntegration(_elementTimingIntegration);\n\n/**\n * @deprecated Use `elementTimingIntegration` instead. This function is a no-op and will be removed in a future version.\n */\nexport function startTrackingElementTiming(): () => void {\n return () => undefined;\n}\n"],"names":[],"mappings":";;;;AAkBA,MAAM,gBAAA,GAAmB,eAAA;AAEzB,MAAM,6BAA6B,MAAM;AACvC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,KAAA,GAAQ;AACN,MAAA,MAAM,cAAc,wBAAA,EAAyB;AAC7C,MAAA,IAAI,CAAC,WAAA,IAAe,CAAC,4BAAA,EAA6B,EAAG;AACnD,QAAA;AAAA,MACF;AAEA,MAAA,oCAAA,CAAqC,SAAA,EAAW,CAAC,EAAE,OAAA,EAAQ,KAAM;AAC/D,QAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,UAAA,MAAM,YAAA,GAAe,KAAA;AAErB,UAAA,IAAI,CAAC,aAAa,UAAA,EAAY;AAC5B,YAAA;AAAA,UACF;AAEA,UAAA,MAAM,aAAa,YAAA,CAAa,UAAA;AAChC,UAAA,MAAM,YAAY,YAAA,CAAa,IAAA;AAC/B,UAAA,MAAM,aAAa,YAAA,CAAa,UAAA;AAChC,UAAA,MAAM,WAAW,YAAA,CAAa,QAAA;AAE9B,UAAA,MAAM,gBAAA,GAAoD;AAAA,YACxD,eAAA,EAAiB,gCAAA;AAAA,YACjB,uBAAA,EAAyB;AAAA,WAC3B;AAEA,UAAA,IAAI,SAAA,EAAW;AACb,YAAA,gBAAA,CAAiB,uBAAuB,CAAA,GAAI,SAAA;AAAA,UAC9C;AAEA,UAAA,IAAI,aAAa,EAAA,EAAI;AACnB,YAAA,gBAAA,CAAiB,eAAe,IAAI,YAAA,CAAa,EAAA;AAAA,UACnD;AAEA,UAAA,IAAI,aAAa,OAAA,EAAS;AACxB,YAAA,gBAAA,CAAiB,iBAAiB,CAAA,GAAI,YAAA,CAAa,OAAA,CAAQ,QAAQ,WAAA,EAAY;AAAA,UACjF;AAEA,UAAA,IAAI,aAAa,GAAA,EAAK;AACpB,YAAA,gBAAA,CAAiB,gBAAgB,IAAI,YAAA,CAAa,GAAA;AAAA,UACpD;AAEA,UAAA,IAAI,aAAa,YAAA,EAAc;AAC7B,YAAA,gBAAA,CAAiB,kBAAkB,IAAI,YAAA,CAAa,YAAA;AAAA,UACtD;AAEA,UAAA,IAAI,aAAa,aAAA,EAAe;AAC9B,YAAA,gBAAA,CAAiB,mBAAmB,IAAI,YAAA,CAAa,aAAA;AAAA,UACvD;AAEA,UAAA,IAAI,aAAa,CAAA,EAAG;AAClB,YAAA,OAAA,CAAQ,YAAA,CAAa,0BAA0B,UAAA,EAAY;AAAA,cACzD,IAAA,EAAM,aAAA;AAAA,cACN,UAAA,EAAY;AAAA,aACb,CAAA;AAAA,UACH;AAEA,UAAA,IAAI,WAAW,CAAA,EAAG;AAChB,YAAA,OAAA,CAAQ,YAAA,CAAa,wBAAwB,QAAA,EAAU;AAAA,cACrD,IAAA,EAAM,aAAA;AAAA,cACN,UAAA,EAAY;AAAA,aACb,CAAA;AAAA,UACH;AAAA,QACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAeO,MAAM,wBAAA,GAA2B,kBAAkB,yBAAyB;AAK5E,SAAS,0BAAA,GAAyC;AACvD,EAAA,OAAO,MAAM,MAAA;AACf;;;;"}
@@ -0,0 +1,162 @@
1
+ import { isBrowser, browserPerformanceTimeOrigin, getActiveSpan, getRootSpan, spanToJSON, getCurrentScope, SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
2
+ import { htmlTreeAsString } from '../htmlTreeAsString.js';
3
+ import { WINDOW } from '../types.js';
4
+ import { addPerformanceInstrumentationHandler, addInpInstrumentationHandler, isPerformanceEventTiming } from './instrument.js';
5
+ import { getBrowserPerformanceAPI, msToSec, startStandaloneWebVitalSpan } from './utils.js';
6
+
7
+ const LAST_INTERACTIONS = [];
8
+ const INTERACTIONS_SPAN_MAP = /* @__PURE__ */ new Map();
9
+ const ELEMENT_NAME_TIMESTAMP_MAP = /* @__PURE__ */ new Map();
10
+ const MAX_PLAUSIBLE_INP_DURATION = 60;
11
+ function startTrackingINP() {
12
+ const performance = getBrowserPerformanceAPI();
13
+ if (performance && browserPerformanceTimeOrigin()) {
14
+ const inpCallback = _trackINP();
15
+ return () => {
16
+ inpCallback();
17
+ };
18
+ }
19
+ return () => void 0;
20
+ }
21
+ const INP_ENTRY_MAP = {
22
+ click: "click",
23
+ pointerdown: "click",
24
+ pointerup: "click",
25
+ mousedown: "click",
26
+ mouseup: "click",
27
+ touchstart: "click",
28
+ touchend: "click",
29
+ mouseover: "hover",
30
+ mouseout: "hover",
31
+ mouseenter: "hover",
32
+ mouseleave: "hover",
33
+ pointerover: "hover",
34
+ pointerout: "hover",
35
+ pointerenter: "hover",
36
+ pointerleave: "hover",
37
+ dragstart: "drag",
38
+ dragend: "drag",
39
+ drag: "drag",
40
+ dragenter: "drag",
41
+ dragleave: "drag",
42
+ dragover: "drag",
43
+ drop: "drag",
44
+ keydown: "press",
45
+ keyup: "press",
46
+ keypress: "press",
47
+ input: "press"
48
+ };
49
+ function _trackINP() {
50
+ return addInpInstrumentationHandler(_onInp);
51
+ }
52
+ const _onInp = ({ metric }) => {
53
+ if (metric.value == void 0) {
54
+ return;
55
+ }
56
+ const duration = msToSec(metric.value);
57
+ if (duration > MAX_PLAUSIBLE_INP_DURATION) {
58
+ return;
59
+ }
60
+ const entry = metric.entries.find((entry2) => entry2.duration === metric.value && INP_ENTRY_MAP[entry2.name]);
61
+ if (!entry) {
62
+ return;
63
+ }
64
+ const { interactionId } = entry;
65
+ const interactionType = INP_ENTRY_MAP[entry.name];
66
+ const startTime = msToSec(browserPerformanceTimeOrigin() + entry.startTime);
67
+ const activeSpan = getActiveSpan();
68
+ const rootSpan = activeSpan ? getRootSpan(activeSpan) : void 0;
69
+ const cachedInteractionContext = interactionId != null ? INTERACTIONS_SPAN_MAP.get(interactionId) : void 0;
70
+ const spanToUse = cachedInteractionContext?.span || rootSpan;
71
+ const routeName = spanToUse ? spanToJSON(spanToUse).description : getCurrentScope().getScopeData().transactionName;
72
+ const name = cachedInteractionContext?.elementName || htmlTreeAsString(entry.target);
73
+ const attributes = {
74
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.browser.inp",
75
+ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `ui.interaction.${interactionType}`,
76
+ [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry.duration
77
+ };
78
+ const span = startStandaloneWebVitalSpan({
79
+ name,
80
+ transaction: routeName,
81
+ attributes,
82
+ startTime
83
+ });
84
+ if (span) {
85
+ span.addEvent("inp", {
86
+ [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: "millisecond",
87
+ [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: metric.value
88
+ });
89
+ span.end(startTime + duration);
90
+ }
91
+ };
92
+ function getCachedInteractionContext(interactionId) {
93
+ return interactionId != null ? INTERACTIONS_SPAN_MAP.get(interactionId) : void 0;
94
+ }
95
+ function registerInpInteractionListener() {
96
+ const interactionEvents = Object.keys(INP_ENTRY_MAP);
97
+ if (isBrowser()) {
98
+ interactionEvents.forEach((eventType) => {
99
+ WINDOW.addEventListener(eventType, captureElementFromEvent, { capture: true, passive: true });
100
+ });
101
+ }
102
+ function captureElementFromEvent(event) {
103
+ const target = event.target;
104
+ if (!target) {
105
+ return;
106
+ }
107
+ const elementName = htmlTreeAsString(target);
108
+ const timestamp = Math.round(event.timeStamp);
109
+ ELEMENT_NAME_TIMESTAMP_MAP.set(timestamp, elementName);
110
+ if (ELEMENT_NAME_TIMESTAMP_MAP.size > 50) {
111
+ const firstKey = ELEMENT_NAME_TIMESTAMP_MAP.keys().next().value;
112
+ if (firstKey !== void 0) {
113
+ ELEMENT_NAME_TIMESTAMP_MAP.delete(firstKey);
114
+ }
115
+ }
116
+ }
117
+ function resolveElementNameFromEntry(entry) {
118
+ const timestamp = Math.round(entry.startTime);
119
+ let elementName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp);
120
+ if (!elementName) {
121
+ for (let offset = -5; offset <= 5; offset++) {
122
+ const nearbyName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp + offset);
123
+ if (nearbyName) {
124
+ elementName = nearbyName;
125
+ break;
126
+ }
127
+ }
128
+ }
129
+ return elementName || "<unknown>";
130
+ }
131
+ const handleEntries = ({ entries }) => {
132
+ const activeSpan = getActiveSpan();
133
+ const activeRootSpan = activeSpan && getRootSpan(activeSpan);
134
+ entries.forEach((entry) => {
135
+ if (!isPerformanceEventTiming(entry)) {
136
+ return;
137
+ }
138
+ const interactionId = entry.interactionId;
139
+ if (interactionId == null) {
140
+ return;
141
+ }
142
+ if (INTERACTIONS_SPAN_MAP.has(interactionId)) {
143
+ return;
144
+ }
145
+ const elementName = entry.target ? htmlTreeAsString(entry.target) : resolveElementNameFromEntry(entry);
146
+ if (LAST_INTERACTIONS.length > 10) {
147
+ const last = LAST_INTERACTIONS.shift();
148
+ INTERACTIONS_SPAN_MAP.delete(last);
149
+ }
150
+ LAST_INTERACTIONS.push(interactionId);
151
+ INTERACTIONS_SPAN_MAP.set(interactionId, {
152
+ span: activeRootSpan,
153
+ elementName
154
+ });
155
+ });
156
+ };
157
+ addPerformanceInstrumentationHandler("event", handleEntries);
158
+ addPerformanceInstrumentationHandler("first-input", handleEntries);
159
+ }
160
+
161
+ export { INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION, _onInp, _trackINP, getCachedInteractionContext, registerInpInteractionListener, startTrackingINP };
162
+ //# sourceMappingURL=inp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inp.js","sources":["../../../src/metrics/inp.ts"],"sourcesContent":["import type { Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n isBrowser,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport type { InstrumentationHandlerCallback } from './instrument';\nimport {\n addInpInstrumentationHandler,\n addPerformanceInstrumentationHandler,\n isPerformanceEventTiming,\n} from './instrument';\nimport { getBrowserPerformanceAPI, msToSec, startStandaloneWebVitalSpan } from './utils';\n\ninterface InteractionContext {\n span: Span | undefined;\n elementName: string;\n}\n\nconst LAST_INTERACTIONS: number[] = [];\nconst INTERACTIONS_SPAN_MAP = new Map<number, InteractionContext>();\n\n// Map to store element names by timestamp, since we get the DOM event before the PerformanceObserver entry\nconst ELEMENT_NAME_TIMESTAMP_MAP = new Map<number, string>();\n\n/**\n * 60 seconds is the maximum for a plausible INP value\n * (source: Me)\n */\nexport const MAX_PLAUSIBLE_INP_DURATION = 60;\n/**\n * Start tracking INP webvital events.\n */\nexport function startTrackingINP(): () => void {\n const performance = getBrowserPerformanceAPI();\n if (performance && browserPerformanceTimeOrigin()) {\n const inpCallback = _trackINP();\n\n return (): void => {\n inpCallback();\n };\n }\n\n return () => undefined;\n}\n\nexport const INP_ENTRY_MAP: Record<string, 'click' | 'hover' | 'drag' | 'press'> = {\n click: 'click',\n pointerdown: 'click',\n pointerup: 'click',\n mousedown: 'click',\n mouseup: 'click',\n touchstart: 'click',\n touchend: 'click',\n mouseover: 'hover',\n mouseout: 'hover',\n mouseenter: 'hover',\n mouseleave: 'hover',\n pointerover: 'hover',\n pointerout: 'hover',\n pointerenter: 'hover',\n pointerleave: 'hover',\n dragstart: 'drag',\n dragend: 'drag',\n drag: 'drag',\n dragenter: 'drag',\n dragleave: 'drag',\n dragover: 'drag',\n drop: 'drag',\n keydown: 'press',\n keyup: 'press',\n keypress: 'press',\n input: 'press',\n};\n\n/** Starts tracking the Interaction to Next Paint on the current page. #\n * exported only for testing\n */\nexport function _trackINP(): () => void {\n return addInpInstrumentationHandler(_onInp);\n}\n\n/**\n * exported only for testing\n */\nexport const _onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (metric.value == undefined) {\n return;\n }\n\n const duration = msToSec(metric.value);\n\n // We received occasional reports of hour-long INP values.\n // Therefore, we add a sanity check to avoid creating spans for\n // unrealistically long INP durations.\n if (duration > MAX_PLAUSIBLE_INP_DURATION) {\n return;\n }\n\n const entry = metric.entries.find(entry => entry.duration === metric.value && INP_ENTRY_MAP[entry.name]);\n\n if (!entry) {\n return;\n }\n\n const { interactionId } = entry;\n const interactionType = INP_ENTRY_MAP[entry.name];\n\n /** Build the INP span, create an envelope from the span, and then send the envelope */\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // We first try to lookup the interaction context from our INTERACTIONS_SPAN_MAP,\n // where we cache the route and element name per interactionId\n const cachedInteractionContext = interactionId != null ? INTERACTIONS_SPAN_MAP.get(interactionId) : undefined;\n\n const spanToUse = cachedInteractionContext?.span || rootSpan;\n\n // Else, we try to use the active span.\n // Finally, we fall back to look at the transactionName on the scope\n const routeName = spanToUse ? spanToJSON(spanToUse).description : getCurrentScope().getScopeData().transactionName;\n\n const name = cachedInteractionContext?.elementName || htmlTreeAsString(entry.target);\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.inp',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `ui.interaction.${interactionType}`,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry.duration,\n };\n\n const span = startStandaloneWebVitalSpan({\n name,\n transaction: routeName,\n attributes,\n startTime,\n });\n\n if (span) {\n span.addEvent('inp', {\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: 'millisecond',\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: metric.value,\n });\n\n span.end(startTime + duration);\n }\n};\n\n/**\n * Look up a cached interaction context (element name + root span) by interactionId.\n * Returns undefined if no context was cached for this interaction.\n */\nexport function getCachedInteractionContext(interactionId: number | undefined): InteractionContext | undefined {\n return interactionId != null ? INTERACTIONS_SPAN_MAP.get(interactionId) : undefined;\n}\n\n/**\n * Register a listener to cache route information for INP interactions.\n */\nexport function registerInpInteractionListener(): void {\n // Listen for all interaction events that could contribute to INP\n const interactionEvents = Object.keys(INP_ENTRY_MAP);\n if (isBrowser()) {\n interactionEvents.forEach(eventType => {\n WINDOW.addEventListener(eventType, captureElementFromEvent, { capture: true, passive: true });\n });\n }\n\n /**\n * Captures the element name from a DOM event and stores it in the ELEMENT_NAME_TIMESTAMP_MAP.\n */\n function captureElementFromEvent(event: Event): void {\n const target = event.target as HTMLElement | null;\n if (!target) {\n return;\n }\n\n const elementName = htmlTreeAsString(target);\n const timestamp = Math.round(event.timeStamp);\n\n // Store the element name by timestamp so we can match it with the PerformanceEntry\n ELEMENT_NAME_TIMESTAMP_MAP.set(timestamp, elementName);\n\n // Clean up old\n if (ELEMENT_NAME_TIMESTAMP_MAP.size > 50) {\n const firstKey = ELEMENT_NAME_TIMESTAMP_MAP.keys().next().value;\n if (firstKey !== undefined) {\n ELEMENT_NAME_TIMESTAMP_MAP.delete(firstKey);\n }\n }\n }\n\n /**\n * Tries to get the element name from the timestamp map.\n */\n function resolveElementNameFromEntry(entry: PerformanceEntry): string {\n const timestamp = Math.round(entry.startTime);\n let elementName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp);\n\n // try nearby timestamps (±5ms)\n if (!elementName) {\n for (let offset = -5; offset <= 5; offset++) {\n const nearbyName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp + offset);\n if (nearbyName) {\n elementName = nearbyName;\n break;\n }\n }\n }\n\n return elementName || '<unknown>';\n }\n\n const handleEntries = ({ entries }: { entries: PerformanceEntry[] }): void => {\n const activeSpan = getActiveSpan();\n const activeRootSpan = activeSpan && getRootSpan(activeSpan);\n\n entries.forEach(entry => {\n if (!isPerformanceEventTiming(entry)) {\n return;\n }\n\n const interactionId = entry.interactionId;\n if (interactionId == null) {\n return;\n }\n\n // If the interaction was already recorded before, nothing more to do\n if (INTERACTIONS_SPAN_MAP.has(interactionId)) {\n return;\n }\n\n const elementName = entry.target ? htmlTreeAsString(entry.target) : resolveElementNameFromEntry(entry);\n\n // We keep max. 10 interactions in the list, then remove the oldest one & clean up\n if (LAST_INTERACTIONS.length > 10) {\n const last = LAST_INTERACTIONS.shift() as number;\n INTERACTIONS_SPAN_MAP.delete(last);\n }\n\n // We add the interaction to the list of recorded interactions\n // and store both the span and element name for this interaction\n LAST_INTERACTIONS.push(interactionId);\n INTERACTIONS_SPAN_MAP.set(interactionId, {\n span: activeRootSpan,\n elementName,\n });\n });\n };\n\n addPerformanceInstrumentationHandler('event', handleEntries);\n addPerformanceInstrumentationHandler('first-input', handleEntries);\n}\n"],"names":["entry"],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ import { debug, getFunctionName } from '@sentry/core';
2
+ import { DEBUG_BUILD } from '../debug-build.js';
3
+ import { onCLS } from './web-vitals/getCLS.js';
4
+ import { onINP } from './web-vitals/getINP.js';
5
+ import { onLCP } from './web-vitals/getLCP.js';
6
+ import { observe } from './web-vitals/lib/observe.js';
7
+ import { onTTFB } from './web-vitals/onTTFB.js';
8
+
9
+ const handlers = {};
10
+ const instrumented = {};
11
+ let _previousCls;
12
+ let _previousLcp;
13
+ let _previousTtfb;
14
+ let _previousInp;
15
+ function addClsInstrumentationHandler(callback, stopOnCallback = false) {
16
+ return addMetricObserver("cls", callback, instrumentCls, _previousCls, stopOnCallback);
17
+ }
18
+ function addLcpInstrumentationHandler(callback, stopOnCallback = false) {
19
+ return addMetricObserver("lcp", callback, instrumentLcp, _previousLcp, stopOnCallback);
20
+ }
21
+ function addTtfbInstrumentationHandler(callback) {
22
+ return addMetricObserver("ttfb", callback, instrumentTtfb, _previousTtfb);
23
+ }
24
+ function addInpInstrumentationHandler(callback) {
25
+ return addMetricObserver("inp", callback, instrumentInp, _previousInp);
26
+ }
27
+ function addPerformanceInstrumentationHandler(type, callback) {
28
+ addHandler(type, callback);
29
+ if (!instrumented[type]) {
30
+ instrumentPerformanceObserver(type);
31
+ instrumented[type] = true;
32
+ }
33
+ return getCleanupCallback(type, callback);
34
+ }
35
+ function triggerHandlers(type, data) {
36
+ const typeHandlers = handlers[type];
37
+ if (!typeHandlers?.length) {
38
+ return;
39
+ }
40
+ for (const handler of typeHandlers) {
41
+ try {
42
+ handler(data);
43
+ } catch (e) {
44
+ DEBUG_BUILD && debug.error(
45
+ `Error while triggering instrumentation handler.
46
+ Type: ${type}
47
+ Name: ${getFunctionName(handler)}
48
+ Error:`,
49
+ e
50
+ );
51
+ }
52
+ }
53
+ }
54
+ function instrumentCls() {
55
+ return onCLS(
56
+ (metric) => {
57
+ triggerHandlers("cls", {
58
+ metric
59
+ });
60
+ _previousCls = metric;
61
+ },
62
+ // We want the callback to be called whenever the CLS value updates.
63
+ // By default, the callback is only called when the tab goes to the background.
64
+ { reportAllChanges: true }
65
+ );
66
+ }
67
+ function instrumentLcp() {
68
+ return onLCP(
69
+ (metric) => {
70
+ triggerHandlers("lcp", {
71
+ metric
72
+ });
73
+ _previousLcp = metric;
74
+ },
75
+ // We want the callback to be called whenever the LCP value updates.
76
+ // By default, the callback is only called when the tab goes to the background.
77
+ { reportAllChanges: true }
78
+ );
79
+ }
80
+ function instrumentTtfb() {
81
+ return onTTFB((metric) => {
82
+ triggerHandlers("ttfb", {
83
+ metric
84
+ });
85
+ _previousTtfb = metric;
86
+ });
87
+ }
88
+ function instrumentInp() {
89
+ return onINP((metric) => {
90
+ triggerHandlers("inp", {
91
+ metric
92
+ });
93
+ _previousInp = metric;
94
+ });
95
+ }
96
+ function addMetricObserver(type, callback, instrumentFn, previousValue, stopOnCallback = false) {
97
+ addHandler(type, callback);
98
+ let stopListening;
99
+ if (!instrumented[type]) {
100
+ stopListening = instrumentFn();
101
+ instrumented[type] = true;
102
+ }
103
+ if (previousValue) {
104
+ callback({ metric: previousValue });
105
+ }
106
+ return getCleanupCallback(type, callback, stopOnCallback ? stopListening : void 0);
107
+ }
108
+ function instrumentPerformanceObserver(type) {
109
+ const options = {};
110
+ if (type === "event") {
111
+ options.durationThreshold = 0;
112
+ }
113
+ observe(
114
+ type,
115
+ (entries) => {
116
+ triggerHandlers(type, { entries });
117
+ },
118
+ options
119
+ );
120
+ }
121
+ function addHandler(type, handler) {
122
+ handlers[type] = handlers[type] || [];
123
+ handlers[type].push(handler);
124
+ }
125
+ function getCleanupCallback(type, callback, stopListening) {
126
+ return () => {
127
+ if (stopListening) {
128
+ stopListening();
129
+ }
130
+ const typeHandlers = handlers[type];
131
+ if (!typeHandlers) {
132
+ return;
133
+ }
134
+ const index = typeHandlers.indexOf(callback);
135
+ if (index !== -1) {
136
+ typeHandlers.splice(index, 1);
137
+ }
138
+ };
139
+ }
140
+ function isPerformanceEventTiming(entry) {
141
+ return "duration" in entry;
142
+ }
143
+
144
+ export { addClsInstrumentationHandler, addInpInstrumentationHandler, addLcpInstrumentationHandler, addPerformanceInstrumentationHandler, addTtfbInstrumentationHandler, isPerformanceEventTiming };
145
+ //# sourceMappingURL=instrument.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrument.js","sources":["../../../src/metrics/instrument.ts"],"sourcesContent":["import { debug, getFunctionName } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { onCLS } from './web-vitals/getCLS';\nimport { onINP } from './web-vitals/getINP';\nimport { onLCP } from './web-vitals/getLCP';\nimport { observe } from './web-vitals/lib/observe';\nimport { onTTFB } from './web-vitals/onTTFB';\n\ntype InstrumentHandlerTypePerformanceObserver =\n | 'longtask'\n | 'event'\n | 'navigation'\n | 'paint'\n | 'resource'\n | 'element'\n // fist-input is still needed for INP\n | 'first-input';\n\ntype InstrumentHandlerTypeMetric = 'cls' | 'lcp' | 'ttfb' | 'inp';\n\n// We provide this here manually instead of relying on a global, as this is not available in non-browser environements\n// And we do not want to expose such types\ninterface PerformanceEntry {\n readonly duration: number;\n readonly entryType: string;\n readonly name: string;\n readonly startTime: number;\n toJSON(): Record<string, unknown>;\n}\nexport interface PerformanceEventTiming extends PerformanceEntry {\n processingStart: number;\n processingEnd: number;\n duration: number;\n cancelable?: boolean;\n target?: unknown | null;\n interactionId?: number;\n}\n\ninterface PerformanceScriptTiming extends PerformanceEntry {\n sourceURL: string;\n sourceFunctionName: string;\n sourceCharPosition: number;\n invoker: string;\n invokerType: string;\n}\nexport interface PerformanceLongAnimationFrameTiming extends PerformanceEntry {\n scripts: PerformanceScriptTiming[];\n}\n\ninterface Metric {\n /**\n * The name of the metric (in acronym form).\n */\n name: 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB';\n\n /**\n * The current value of the metric.\n */\n value: number;\n\n /**\n * The rating as to whether the metric value is within the \"good\",\n * \"needs improvement\", or \"poor\" thresholds of the metric.\n */\n rating: 'good' | 'needs-improvement' | 'poor';\n\n /**\n * The delta between the current value and the last-reported value.\n * On the first report, `delta` and `value` will always be the same.\n */\n delta: number;\n\n /**\n * A unique ID representing this particular metric instance. This ID can\n * be used by an analytics tool to dedupe multiple values sent for the same\n * metric instance, or to group multiple deltas together and calculate a\n * total. It can also be used to differentiate multiple different metric\n * instances sent from the same page, which can happen if the page is\n * restored from the back/forward cache (in that case new metrics object\n * get created).\n */\n id: string;\n\n /**\n * Any performance entries relevant to the metric value calculation.\n * The array may also be empty if the metric value was not based on any\n * entries (e.g. a CLS value of 0 given no layout shifts).\n */\n entries: PerformanceEntry[];\n\n /**\n * The type of navigation\n *\n * Navigation Timing API (or `undefined` if the browser doesn't\n * support that API). For pages that are restored from the bfcache, this\n * value will be 'back-forward-cache'.\n */\n navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'restore';\n}\n\ntype InstrumentHandlerType = InstrumentHandlerTypeMetric | InstrumentHandlerTypePerformanceObserver;\n\ntype StopListening = undefined | void | (() => void);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InstrumentHandlerCallback = (data: any) => void;\n\ntype CleanupHandlerCallback = () => void;\n\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\nlet _previousCls: Metric | undefined;\nlet _previousLcp: Metric | undefined;\nlet _previousTtfb: Metric | undefined;\nlet _previousInp: Metric | undefined;\n\n/**\n * Add a callback that will be triggered when a CLS metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called.\n * This will lead to the CLS being finalized and frozen.\n */\nexport function addClsInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a LCP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called.\n * This will lead to the LCP being finalized and frozen.\n */\nexport function addLcpInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a TTFD metric is available.\n */\nexport function addTtfbInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('ttfb', callback, instrumentTtfb, _previousTtfb);\n}\n\nexport type InstrumentationHandlerCallback = (data: {\n metric: Omit<Metric, 'entries'> & {\n entries: PerformanceEventTiming[];\n };\n}) => void;\n\n/**\n * Add a callback that will be triggered when a INP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addInpInstrumentationHandler(callback: InstrumentationHandlerCallback): CleanupHandlerCallback {\n return addMetricObserver('inp', callback, instrumentInp, _previousInp);\n}\n\nexport function addPerformanceInstrumentationHandler(\n type: 'event',\n callback: (data: { entries: ((PerformanceEntry & { target?: unknown | null }) | PerformanceEventTiming)[] }) => void,\n): CleanupHandlerCallback;\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback;\n\n/**\n * Add a callback that will be triggered when a performance observer is triggered,\n * and receives the entries of the observer.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumentPerformanceObserver(type);\n instrumented[type] = true;\n }\n\n return getCleanupCallback(type, callback);\n}\n\n/** Trigger all handlers of a given type. */\nfunction triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = handlers[type];\n\n if (!typeHandlers?.length) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n debug.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n\nfunction instrumentCls(): StopListening {\n return onCLS(\n metric => {\n triggerHandlers('cls', {\n metric,\n });\n _previousCls = metric;\n },\n // We want the callback to be called whenever the CLS value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: true },\n );\n}\n\nfunction instrumentLcp(): StopListening {\n return onLCP(\n metric => {\n triggerHandlers('lcp', {\n metric,\n });\n _previousLcp = metric;\n },\n // We want the callback to be called whenever the LCP value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: true },\n );\n}\n\nfunction instrumentTtfb(): StopListening {\n return onTTFB(metric => {\n triggerHandlers('ttfb', {\n metric,\n });\n _previousTtfb = metric;\n });\n}\n\nfunction instrumentInp(): void {\n return onINP(metric => {\n triggerHandlers('inp', {\n metric,\n });\n _previousInp = metric;\n });\n}\n\nfunction addMetricObserver(\n type: InstrumentHandlerTypeMetric,\n callback: InstrumentHandlerCallback,\n instrumentFn: () => StopListening,\n previousValue: Metric | undefined,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n let stopListening: StopListening | undefined;\n\n if (!instrumented[type]) {\n stopListening = instrumentFn();\n instrumented[type] = true;\n }\n\n if (previousValue) {\n callback({ metric: previousValue });\n }\n\n return getCleanupCallback(type, callback, stopOnCallback ? stopListening : undefined);\n}\n\nfunction instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObserver): void {\n const options: PerformanceObserverInit = {};\n\n // Special per-type options we want to use\n if (type === 'event') {\n options.durationThreshold = 0;\n }\n\n observe(\n type,\n entries => {\n triggerHandlers(type, { entries });\n },\n options,\n );\n}\n\nfunction addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n handlers[type].push(handler);\n}\n\n// Get a callback which can be called to remove the instrumentation handler\nfunction getCleanupCallback(\n type: InstrumentHandlerType,\n callback: InstrumentHandlerCallback,\n stopListening: StopListening,\n): CleanupHandlerCallback {\n return () => {\n if (stopListening) {\n stopListening();\n }\n\n const typeHandlers = handlers[type];\n\n if (!typeHandlers) {\n return;\n }\n\n const index = typeHandlers.indexOf(callback);\n if (index !== -1) {\n typeHandlers.splice(index, 1);\n }\n };\n}\n\n/**\n * Check if a PerformanceEntry is a PerformanceEventTiming by checking for the `duration` property.\n */\nexport function isPerformanceEventTiming(entry: PerformanceEntry): entry is PerformanceEventTiming {\n return 'duration' in entry;\n}\n"],"names":[],"mappings":";;;;;;;;AA6GA,MAAM,WAA6E,EAAC;AACpF,MAAM,eAA6D,EAAC;AAEpE,IAAI,YAAA;AACJ,IAAI,YAAA;AACJ,IAAI,aAAA;AACJ,IAAI,YAAA;AASG,SAAS,4BAAA,CACd,QAAA,EACA,cAAA,GAAiB,KAAA,EACO;AACxB,EAAA,OAAO,iBAAA,CAAkB,KAAA,EAAO,QAAA,EAAU,aAAA,EAAe,cAAc,cAAc,CAAA;AACvF;AASO,SAAS,4BAAA,CACd,QAAA,EACA,cAAA,GAAiB,KAAA,EACO;AACxB,EAAA,OAAO,iBAAA,CAAkB,KAAA,EAAO,QAAA,EAAU,aAAA,EAAe,cAAc,cAAc,CAAA;AACvF;AAKO,SAAS,8BAA8B,QAAA,EAAsE;AAClH,EAAA,OAAO,iBAAA,CAAkB,MAAA,EAAQ,QAAA,EAAU,cAAA,EAAgB,aAAa,CAAA;AAC1E;AAYO,SAAS,6BAA6B,QAAA,EAAkE;AAC7G,EAAA,OAAO,iBAAA,CAAkB,KAAA,EAAO,QAAA,EAAU,aAAA,EAAe,YAAY,CAAA;AACvE;AAgBO,SAAS,oCAAA,CACd,MACA,QAAA,EACwB;AACxB,EAAA,UAAA,CAAW,MAAM,QAAQ,CAAA;AAEzB,EAAA,IAAI,CAAC,YAAA,CAAa,IAAI,CAAA,EAAG;AACvB,IAAA,6BAAA,CAA8B,IAAI,CAAA;AAClC,IAAA,YAAA,CAAa,IAAI,CAAA,GAAI,IAAA;AAAA,EACvB;AAEA,EAAA,OAAO,kBAAA,CAAmB,MAAM,QAAQ,CAAA;AAC1C;AAGA,SAAS,eAAA,CAAgB,MAA6B,IAAA,EAAqB;AACzE,EAAA,MAAM,YAAA,GAAe,SAAS,IAAI,CAAA;AAElC,EAAA,IAAI,CAAC,cAAc,MAAA,EAAQ;AACzB,IAAA;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,WAAW,YAAA,EAAc;AAClC,IAAA,IAAI;AACF,MAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,IACd,SAAS,CAAA,EAAG;AACV,MAAA,WAAA,IACE,KAAA,CAAM,KAAA;AAAA,QACJ,CAAA;AAAA,MAAA,EAA0D,IAAI;AAAA,MAAA,EAAW,eAAA,CAAgB,OAAO,CAAC;AAAA,MAAA,CAAA;AAAA,QACjG;AAAA,OACF;AAAA,IACJ;AAAA,EACF;AACF;AAEA,SAAS,aAAA,GAA+B;AACtC,EAAA,OAAO,KAAA;AAAA,IACL,CAAA,MAAA,KAAU;AACR,MAAA,eAAA,CAAgB,KAAA,EAAO;AAAA,QACrB;AAAA,OACD,CAAA;AACD,MAAA,YAAA,GAAe,MAAA;AAAA,IACjB,CAAA;AAAA;AAAA;AAAA,IAGA,EAAE,kBAAkB,IAAA;AAAK,GAC3B;AACF;AAEA,SAAS,aAAA,GAA+B;AACtC,EAAA,OAAO,KAAA;AAAA,IACL,CAAA,MAAA,KAAU;AACR,MAAA,eAAA,CAAgB,KAAA,EAAO;AAAA,QACrB;AAAA,OACD,CAAA;AACD,MAAA,YAAA,GAAe,MAAA;AAAA,IACjB,CAAA;AAAA;AAAA;AAAA,IAGA,EAAE,kBAAkB,IAAA;AAAK,GAC3B;AACF;AAEA,SAAS,cAAA,GAAgC;AACvC,EAAA,OAAO,OAAO,CAAA,MAAA,KAAU;AACtB,IAAA,eAAA,CAAgB,MAAA,EAAQ;AAAA,MACtB;AAAA,KACD,CAAA;AACD,IAAA,aAAA,GAAgB,MAAA;AAAA,EAClB,CAAC,CAAA;AACH;AAEA,SAAS,aAAA,GAAsB;AAC7B,EAAA,OAAO,MAAM,CAAA,MAAA,KAAU;AACrB,IAAA,eAAA,CAAgB,KAAA,EAAO;AAAA,MACrB;AAAA,KACD,CAAA;AACD,IAAA,YAAA,GAAe,MAAA;AAAA,EACjB,CAAC,CAAA;AACH;AAEA,SAAS,kBACP,IAAA,EACA,QAAA,EACA,YAAA,EACA,aAAA,EACA,iBAAiB,KAAA,EACO;AACxB,EAAA,UAAA,CAAW,MAAM,QAAQ,CAAA;AAEzB,EAAA,IAAI,aAAA;AAEJ,EAAA,IAAI,CAAC,YAAA,CAAa,IAAI,CAAA,EAAG;AACvB,IAAA,aAAA,GAAgB,YAAA,EAAa;AAC7B,IAAA,YAAA,CAAa,IAAI,CAAA,GAAI,IAAA;AAAA,EACvB;AAEA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,QAAA,CAAS,EAAE,MAAA,EAAQ,aAAA,EAAe,CAAA;AAAA,EACpC;AAEA,EAAA,OAAO,kBAAA,CAAmB,IAAA,EAAM,QAAA,EAAU,cAAA,GAAiB,gBAAgB,MAAS,CAAA;AACtF;AAEA,SAAS,8BAA8B,IAAA,EAAsD;AAC3F,EAAA,MAAM,UAAmC,EAAC;AAG1C,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAA,OAAA,CAAQ,iBAAA,GAAoB,CAAA;AAAA,EAC9B;AAEA,EAAA,OAAA;AAAA,IACE,IAAA;AAAA,IACA,CAAA,OAAA,KAAW;AACT,MAAA,eAAA,CAAgB,IAAA,EAAM,EAAE,OAAA,EAAS,CAAA;AAAA,IACnC,CAAA;AAAA,IACA;AAAA,GACF;AACF;AAEA,SAAS,UAAA,CAAW,MAA6B,OAAA,EAA0C;AACzF,EAAA,QAAA,CAAS,IAAI,CAAA,GAAI,QAAA,CAAS,IAAI,KAAK,EAAC;AACpC,EAAA,QAAA,CAAS,IAAI,CAAA,CAAE,IAAA,CAAK,OAAO,CAAA;AAC7B;AAGA,SAAS,kBAAA,CACP,IAAA,EACA,QAAA,EACA,aAAA,EACwB;AACxB,EAAA,OAAO,MAAM;AACX,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,aAAA,EAAc;AAAA,IAChB;AAEA,IAAA,MAAM,YAAA,GAAe,SAAS,IAAI,CAAA;AAElC,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA;AAC3C,IAAA,IAAI,UAAU,EAAA,EAAI;AAChB,MAAA,YAAA,CAAa,MAAA,CAAO,OAAO,CAAC,CAAA;AAAA,IAC9B;AAAA,EACF,CAAA;AACF;AAKO,SAAS,yBAAyB,KAAA,EAA0D;AACjG,EAAA,OAAO,UAAA,IAAc,KAAA;AACvB;;;;"}
@@ -0,0 +1,72 @@
1
+ import { debug, browserPerformanceTimeOrigin, getCurrentScope, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT, SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
2
+ import { DEBUG_BUILD } from '../debug-build.js';
3
+ import { htmlTreeAsString } from '../htmlTreeAsString.js';
4
+ import { addLcpInstrumentationHandler } from './instrument.js';
5
+ import { supportsWebVital, listenForWebVitalReportEvents, msToSec, startStandaloneWebVitalSpan } from './utils.js';
6
+
7
+ const MAX_PLAUSIBLE_LCP_DURATION = 6e4;
8
+ function isValidLcpMetric(lcpValue) {
9
+ return lcpValue != null && lcpValue > 0 && lcpValue <= MAX_PLAUSIBLE_LCP_DURATION;
10
+ }
11
+ function trackLcpAsStandaloneSpan(client) {
12
+ let standaloneLcpValue = 0;
13
+ let standaloneLcpEntry;
14
+ if (!supportsWebVital("largest-contentful-paint")) {
15
+ return;
16
+ }
17
+ const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {
18
+ const entry = metric.entries[metric.entries.length - 1];
19
+ if (!entry || !isValidLcpMetric(metric.value)) {
20
+ return;
21
+ }
22
+ standaloneLcpValue = metric.value;
23
+ standaloneLcpEntry = entry;
24
+ }, true);
25
+ listenForWebVitalReportEvents(client, (reportEvent, pageloadSpanId) => {
26
+ _sendStandaloneLcpSpan(standaloneLcpValue, standaloneLcpEntry, pageloadSpanId, reportEvent);
27
+ cleanupLcpHandler();
28
+ });
29
+ }
30
+ function _sendStandaloneLcpSpan(lcpValue, entry, pageloadSpanId, reportEvent) {
31
+ if (!isValidLcpMetric(lcpValue)) {
32
+ return;
33
+ }
34
+ DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);
35
+ const startTime = msToSec((browserPerformanceTimeOrigin() || 0) + (entry?.startTime || 0));
36
+ const routeName = getCurrentScope().getScopeData().transactionName;
37
+ const name = entry ? htmlTreeAsString(entry.element) : "Largest contentful paint";
38
+ const attributes = {
39
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.browser.lcp",
40
+ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "ui.webvital.lcp",
41
+ [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,
42
+ // LCP is a point-in-time metric
43
+ // attach the pageload span id to the LCP span so that we can link them in the UI
44
+ "sentry.pageload.span_id": pageloadSpanId,
45
+ // describes what triggered the web vital to be reported
46
+ "sentry.report_event": reportEvent
47
+ };
48
+ if (entry) {
49
+ entry.element && (attributes["lcp.element"] = htmlTreeAsString(entry.element));
50
+ entry.id && (attributes["lcp.id"] = entry.id);
51
+ entry.url && (attributes["lcp.url"] = entry.url);
52
+ entry.loadTime != null && (attributes["lcp.loadTime"] = entry.loadTime);
53
+ entry.renderTime != null && (attributes["lcp.renderTime"] = entry.renderTime);
54
+ entry.size != null && (attributes["lcp.size"] = entry.size);
55
+ }
56
+ const span = startStandaloneWebVitalSpan({
57
+ name,
58
+ transaction: routeName,
59
+ attributes,
60
+ startTime
61
+ });
62
+ if (span) {
63
+ span.addEvent("lcp", {
64
+ [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: "millisecond",
65
+ [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: lcpValue
66
+ });
67
+ span.end(startTime);
68
+ }
69
+ }
70
+
71
+ export { MAX_PLAUSIBLE_LCP_DURATION, _sendStandaloneLcpSpan, isValidLcpMetric, trackLcpAsStandaloneSpan };
72
+ //# sourceMappingURL=lcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lcp.js","sources":["../../../src/metrics/lcp.ts"],"sourcesContent":["import type { Client, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { addLcpInstrumentationHandler } from './instrument';\nimport type { WebVitalReportEvent } from './utils';\nimport { listenForWebVitalReportEvents, msToSec, startStandaloneWebVitalSpan, supportsWebVital } from './utils';\n\n/**\n * 60 seconds is the maximum for a plausible LCP value.\n */\nexport const MAX_PLAUSIBLE_LCP_DURATION = 60_000;\n\nexport function isValidLcpMetric(lcpValue: number | undefined): lcpValue is number {\n return lcpValue != null && lcpValue > 0 && lcpValue <= MAX_PLAUSIBLE_LCP_DURATION;\n}\n\n/**\n * Starts tracking the Largest Contentful Paint on the current page and collects the value once\n *\n * - the page visibility is hidden\n * - a navigation span is started (to stop LCP measurement for SPA soft navigations)\n *\n * Once either of these events triggers, the LCP value is sent as a standalone span and we stop\n * measuring LCP for subsequent routes.\n */\nexport function trackLcpAsStandaloneSpan(client: Client): void {\n let standaloneLcpValue = 0;\n let standaloneLcpEntry: LargestContentfulPaint | undefined;\n\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n standaloneLcpValue = metric.value;\n standaloneLcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, pageloadSpanId) => {\n _sendStandaloneLcpSpan(standaloneLcpValue, standaloneLcpEntry, pageloadSpanId, reportEvent);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing!\n */\nexport function _sendStandaloneLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpanId: string,\n reportEvent: WebVitalReportEvent,\n) {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const startTime = msToSec((browserPerformanceTimeOrigin() || 0) + (entry?.startTime || 0));\n const routeName = getCurrentScope().getScopeData().transactionName;\n\n const name = entry ? htmlTreeAsString(entry.element) : 'Largest contentful paint';\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.lcp',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'ui.webvital.lcp',\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0, // LCP is a point-in-time metric\n // attach the pageload span id to the LCP span so that we can link them in the UI\n 'sentry.pageload.span_id': pageloadSpanId,\n // describes what triggered the web vital to be reported\n 'sentry.report_event': reportEvent,\n };\n\n if (entry) {\n entry.element && (attributes['lcp.element'] = htmlTreeAsString(entry.element));\n entry.id && (attributes['lcp.id'] = entry.id);\n\n entry.url && (attributes['lcp.url'] = entry.url);\n\n // loadTime is the time of LCP that's related to receiving the LCP element response..\n entry.loadTime != null && (attributes['lcp.loadTime'] = entry.loadTime);\n\n // renderTime is loadTime + rendering time\n // it's 0 if the LCP element is loaded from a 3rd party origin that doesn't send the\n // `Timing-Allow-Origin` header.\n entry.renderTime != null && (attributes['lcp.renderTime'] = entry.renderTime);\n\n entry.size != null && (attributes['lcp.size'] = entry.size);\n }\n\n const span = startStandaloneWebVitalSpan({\n name,\n transaction: routeName,\n attributes,\n startTime,\n });\n\n if (span) {\n span.addEvent('lcp', {\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: 'millisecond',\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: lcpValue,\n });\n\n // LCP is a point-in-time metric, so we end the span immediately\n span.end(startTime);\n }\n}\n"],"names":[],"mappings":"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"}