@sentry/browser-utils 11.0.0-alpha.0 → 11.0.0-alpha.1

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 (288) hide show
  1. package/build/cjs/index.js +29 -28
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/cjs/instrumentation/dom.js.map +1 -0
  4. package/build/cjs/instrumentation/history.js.map +1 -0
  5. package/build/cjs/instrumentation/location.js.map +1 -0
  6. package/build/cjs/{metrics/instrument.js → instrumentation/performanceObserver.js} +44 -32
  7. package/build/cjs/instrumentation/performanceObserver.js.map +1 -0
  8. package/build/cjs/instrumentation/xhr.js.map +1 -0
  9. package/build/cjs/{metrics → performance}/elementTiming.js +2 -2
  10. package/build/cjs/performance/elementTiming.js.map +1 -0
  11. package/build/cjs/{metrics/browserMetrics.js → performance/entries.js} +22 -175
  12. package/build/cjs/performance/entries.js.map +1 -0
  13. package/build/cjs/performance/resourceTiming.js.map +1 -0
  14. package/build/cjs/{metrics → performance}/userTiming.js +4 -3
  15. package/build/cjs/performance/userTiming.js.map +1 -0
  16. package/build/cjs/{metrics → performance}/utils.js +1 -27
  17. package/build/cjs/performance/utils.js.map +1 -0
  18. package/build/cjs/{metrics → web-vitals}/inp.js +4 -4
  19. package/build/cjs/web-vitals/inp.js.map +1 -0
  20. package/build/cjs/web-vitals/lcp.js.map +1 -0
  21. package/build/cjs/web-vitals/reportEvents.js +31 -0
  22. package/build/cjs/web-vitals/reportEvents.js.map +1 -0
  23. package/build/cjs/{metrics/webVitalSpans.js → web-vitals/spans.js} +11 -10
  24. package/build/cjs/web-vitals/spans.js.map +1 -0
  25. package/build/cjs/web-vitals/tracking.js +164 -0
  26. package/build/cjs/web-vitals/tracking.js.map +1 -0
  27. package/build/cjs/web-vitals/utils.js +99 -0
  28. package/build/cjs/web-vitals/utils.js.map +1 -0
  29. package/build/esm/index.js +14 -13
  30. package/build/esm/index.js.map +1 -1
  31. package/build/esm/instrumentation/dom.js.map +1 -0
  32. package/build/esm/instrumentation/history.js.map +1 -0
  33. package/build/esm/instrumentation/location.js.map +1 -0
  34. package/build/esm/{metrics/instrument.js → instrumentation/performanceObserver.js} +42 -30
  35. package/build/esm/instrumentation/performanceObserver.js.map +1 -0
  36. package/build/esm/instrumentation/xhr.js.map +1 -0
  37. package/build/esm/package.json +1 -1
  38. package/build/esm/{metrics → performance}/elementTiming.js +1 -1
  39. package/build/esm/performance/elementTiming.js.map +1 -0
  40. package/build/esm/{metrics/browserMetrics.js → performance/entries.js} +15 -166
  41. package/build/esm/performance/entries.js.map +1 -0
  42. package/build/esm/performance/resourceTiming.js.map +1 -0
  43. package/build/esm/{metrics → performance}/userTiming.js +4 -3
  44. package/build/esm/performance/userTiming.js.map +1 -0
  45. package/build/esm/{metrics → performance}/utils.js +3 -28
  46. package/build/esm/performance/utils.js.map +1 -0
  47. package/build/esm/{metrics → web-vitals}/inp.js +1 -1
  48. package/build/esm/web-vitals/inp.js.map +1 -0
  49. package/build/esm/web-vitals/lcp.js.map +1 -0
  50. package/build/esm/web-vitals/reportEvents.js +29 -0
  51. package/build/esm/web-vitals/reportEvents.js.map +1 -0
  52. package/build/esm/{metrics/webVitalSpans.js → web-vitals/spans.js} +7 -6
  53. package/build/esm/web-vitals/spans.js.map +1 -0
  54. package/build/esm/web-vitals/tracking.js +161 -0
  55. package/build/esm/web-vitals/tracking.js.map +1 -0
  56. package/build/esm/web-vitals/utils.js +91 -0
  57. package/build/esm/web-vitals/utils.js.map +1 -0
  58. package/build/types/index.d.ts +13 -12
  59. package/build/types/index.d.ts.map +1 -1
  60. package/build/types/instrumentation/dom.d.ts.map +1 -0
  61. package/build/types/instrumentation/history.d.ts.map +1 -0
  62. package/build/types/instrumentation/location.d.ts.map +1 -0
  63. package/build/types/{metrics/instrument.d.ts → instrumentation/performanceObserver.d.ts} +3 -3
  64. package/build/types/instrumentation/performanceObserver.d.ts.map +1 -0
  65. package/build/types/instrumentation/xhr.d.ts.map +1 -0
  66. package/build/types/performance/elementTiming.d.ts.map +1 -0
  67. package/build/types/{metrics/browserMetrics.d.ts → performance/entries.d.ts} +3 -46
  68. package/build/types/performance/entries.d.ts.map +1 -0
  69. package/build/types/performance/resourceTiming.d.ts.map +1 -0
  70. package/build/types/performance/userTiming.d.ts.map +1 -0
  71. package/build/types/{metrics → performance}/utils.d.ts +1 -17
  72. package/build/types/performance/utils.d.ts.map +1 -0
  73. package/build/types/web-vitals/inp.d.ts.map +1 -0
  74. package/build/types/web-vitals/lcp.d.ts.map +1 -0
  75. package/build/types/web-vitals/reportEvents.d.ts +18 -0
  76. package/build/types/web-vitals/reportEvents.d.ts.map +1 -0
  77. package/build/types/{metrics/webVitalSpans.d.ts → web-vitals/spans.d.ts} +3 -3
  78. package/build/types/web-vitals/spans.d.ts.map +1 -0
  79. package/build/types/web-vitals/tracking.d.ts +46 -0
  80. package/build/types/web-vitals/tracking.d.ts.map +1 -0
  81. package/build/types/{metrics/web-vitals/lib/globalListeners.d.ts → web-vitals/utils.d.ts} +16 -1
  82. package/build/types/web-vitals/utils.d.ts.map +1 -0
  83. package/package.json +4 -3
  84. package/build/cjs/instrument/dom.js.map +0 -1
  85. package/build/cjs/instrument/history.js.map +0 -1
  86. package/build/cjs/instrument/location.js.map +0 -1
  87. package/build/cjs/instrument/xhr.js.map +0 -1
  88. package/build/cjs/metrics/browserMetrics.js.map +0 -1
  89. package/build/cjs/metrics/elementTiming.js.map +0 -1
  90. package/build/cjs/metrics/inp.js.map +0 -1
  91. package/build/cjs/metrics/instrument.js.map +0 -1
  92. package/build/cjs/metrics/lcp.js.map +0 -1
  93. package/build/cjs/metrics/resourceTiming.js.map +0 -1
  94. package/build/cjs/metrics/userTiming.js.map +0 -1
  95. package/build/cjs/metrics/utils.js.map +0 -1
  96. package/build/cjs/metrics/web-vitals/getCLS.js +0 -46
  97. package/build/cjs/metrics/web-vitals/getCLS.js.map +0 -1
  98. package/build/cjs/metrics/web-vitals/getINP.js +0 -60
  99. package/build/cjs/metrics/web-vitals/getINP.js.map +0 -1
  100. package/build/cjs/metrics/web-vitals/getLCP.js +0 -62
  101. package/build/cjs/metrics/web-vitals/getLCP.js.map +0 -1
  102. package/build/cjs/metrics/web-vitals/lib/InteractionManager.js +0 -87
  103. package/build/cjs/metrics/web-vitals/lib/InteractionManager.js.map +0 -1
  104. package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js +0 -11
  105. package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js.map +0 -1
  106. package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js +0 -27
  107. package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js.map +0 -1
  108. package/build/cjs/metrics/web-vitals/lib/bindReporter.js +0 -31
  109. package/build/cjs/metrics/web-vitals/lib/bindReporter.js.map +0 -1
  110. package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js +0 -8
  111. package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js.map +0 -1
  112. package/build/cjs/metrics/web-vitals/lib/getActivationStart.js +0 -11
  113. package/build/cjs/metrics/web-vitals/lib/getActivationStart.js.map +0 -1
  114. package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js +0 -17
  115. package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js.map +0 -1
  116. package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js +0 -44
  117. package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js.map +0 -1
  118. package/build/cjs/metrics/web-vitals/lib/globalListeners.js +0 -18
  119. package/build/cjs/metrics/web-vitals/lib/globalListeners.js.map +0 -1
  120. package/build/cjs/metrics/web-vitals/lib/initMetric.js +0 -34
  121. package/build/cjs/metrics/web-vitals/lib/initMetric.js.map +0 -1
  122. package/build/cjs/metrics/web-vitals/lib/initUnique.js +0 -16
  123. package/build/cjs/metrics/web-vitals/lib/initUnique.js.map +0 -1
  124. package/build/cjs/metrics/web-vitals/lib/observe.js +0 -20
  125. package/build/cjs/metrics/web-vitals/lib/observe.js.map +0 -1
  126. package/build/cjs/metrics/web-vitals/lib/onHidden.js +0 -16
  127. package/build/cjs/metrics/web-vitals/lib/onHidden.js.map +0 -1
  128. package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +0 -32
  129. package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +0 -1
  130. package/build/cjs/metrics/web-vitals/lib/runOnce.js +0 -14
  131. package/build/cjs/metrics/web-vitals/lib/runOnce.js.map +0 -1
  132. package/build/cjs/metrics/web-vitals/lib/whenActivated.js +0 -14
  133. package/build/cjs/metrics/web-vitals/lib/whenActivated.js.map +0 -1
  134. package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -22
  135. package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js.map +0 -1
  136. package/build/cjs/metrics/web-vitals/onFCP.js +0 -37
  137. package/build/cjs/metrics/web-vitals/onFCP.js.map +0 -1
  138. package/build/cjs/metrics/web-vitals/onTTFB.js +0 -35
  139. package/build/cjs/metrics/web-vitals/onTTFB.js.map +0 -1
  140. package/build/cjs/metrics/webVitalSpans.js.map +0 -1
  141. package/build/esm/instrument/dom.js.map +0 -1
  142. package/build/esm/instrument/history.js.map +0 -1
  143. package/build/esm/instrument/location.js.map +0 -1
  144. package/build/esm/instrument/xhr.js.map +0 -1
  145. package/build/esm/metrics/browserMetrics.js.map +0 -1
  146. package/build/esm/metrics/elementTiming.js.map +0 -1
  147. package/build/esm/metrics/inp.js.map +0 -1
  148. package/build/esm/metrics/instrument.js.map +0 -1
  149. package/build/esm/metrics/lcp.js.map +0 -1
  150. package/build/esm/metrics/resourceTiming.js.map +0 -1
  151. package/build/esm/metrics/userTiming.js.map +0 -1
  152. package/build/esm/metrics/utils.js.map +0 -1
  153. package/build/esm/metrics/web-vitals/getCLS.js +0 -43
  154. package/build/esm/metrics/web-vitals/getCLS.js.map +0 -1
  155. package/build/esm/metrics/web-vitals/getINP.js +0 -57
  156. package/build/esm/metrics/web-vitals/getINP.js.map +0 -1
  157. package/build/esm/metrics/web-vitals/getLCP.js +0 -59
  158. package/build/esm/metrics/web-vitals/getLCP.js.map +0 -1
  159. package/build/esm/metrics/web-vitals/lib/InteractionManager.js +0 -85
  160. package/build/esm/metrics/web-vitals/lib/InteractionManager.js.map +0 -1
  161. package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js +0 -9
  162. package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js.map +0 -1
  163. package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js +0 -25
  164. package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js.map +0 -1
  165. package/build/esm/metrics/web-vitals/lib/bindReporter.js +0 -29
  166. package/build/esm/metrics/web-vitals/lib/bindReporter.js.map +0 -1
  167. package/build/esm/metrics/web-vitals/lib/generateUniqueID.js +0 -6
  168. package/build/esm/metrics/web-vitals/lib/generateUniqueID.js.map +0 -1
  169. package/build/esm/metrics/web-vitals/lib/getActivationStart.js +0 -9
  170. package/build/esm/metrics/web-vitals/lib/getActivationStart.js.map +0 -1
  171. package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js +0 -15
  172. package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js.map +0 -1
  173. package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js +0 -42
  174. package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js.map +0 -1
  175. package/build/esm/metrics/web-vitals/lib/globalListeners.js +0 -15
  176. package/build/esm/metrics/web-vitals/lib/globalListeners.js.map +0 -1
  177. package/build/esm/metrics/web-vitals/lib/initMetric.js +0 -32
  178. package/build/esm/metrics/web-vitals/lib/initMetric.js.map +0 -1
  179. package/build/esm/metrics/web-vitals/lib/initUnique.js +0 -14
  180. package/build/esm/metrics/web-vitals/lib/initUnique.js.map +0 -1
  181. package/build/esm/metrics/web-vitals/lib/observe.js +0 -18
  182. package/build/esm/metrics/web-vitals/lib/observe.js.map +0 -1
  183. package/build/esm/metrics/web-vitals/lib/onHidden.js +0 -14
  184. package/build/esm/metrics/web-vitals/lib/onHidden.js.map +0 -1
  185. package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +0 -29
  186. package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +0 -1
  187. package/build/esm/metrics/web-vitals/lib/runOnce.js +0 -12
  188. package/build/esm/metrics/web-vitals/lib/runOnce.js.map +0 -1
  189. package/build/esm/metrics/web-vitals/lib/whenActivated.js +0 -12
  190. package/build/esm/metrics/web-vitals/lib/whenActivated.js.map +0 -1
  191. package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -20
  192. package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js.map +0 -1
  193. package/build/esm/metrics/web-vitals/onFCP.js +0 -34
  194. package/build/esm/metrics/web-vitals/onFCP.js.map +0 -1
  195. package/build/esm/metrics/web-vitals/onTTFB.js +0 -32
  196. package/build/esm/metrics/web-vitals/onTTFB.js.map +0 -1
  197. package/build/esm/metrics/webVitalSpans.js.map +0 -1
  198. package/build/types/instrument/dom.d.ts.map +0 -1
  199. package/build/types/instrument/history.d.ts.map +0 -1
  200. package/build/types/instrument/location.d.ts.map +0 -1
  201. package/build/types/instrument/xhr.d.ts.map +0 -1
  202. package/build/types/metrics/browserMetrics.d.ts.map +0 -1
  203. package/build/types/metrics/elementTiming.d.ts.map +0 -1
  204. package/build/types/metrics/inp.d.ts.map +0 -1
  205. package/build/types/metrics/instrument.d.ts.map +0 -1
  206. package/build/types/metrics/lcp.d.ts.map +0 -1
  207. package/build/types/metrics/resourceTiming.d.ts.map +0 -1
  208. package/build/types/metrics/userTiming.d.ts.map +0 -1
  209. package/build/types/metrics/utils.d.ts.map +0 -1
  210. package/build/types/metrics/web-vitals/getCLS.d.ts +0 -26
  211. package/build/types/metrics/web-vitals/getCLS.d.ts.map +0 -1
  212. package/build/types/metrics/web-vitals/getINP.d.ts +0 -34
  213. package/build/types/metrics/web-vitals/getINP.d.ts.map +0 -1
  214. package/build/types/metrics/web-vitals/getLCP.d.ts +0 -16
  215. package/build/types/metrics/web-vitals/getLCP.d.ts.map +0 -1
  216. package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts +0 -37
  217. package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts.map +0 -1
  218. package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts +0 -5
  219. package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts.map +0 -1
  220. package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts +0 -7
  221. package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts.map +0 -1
  222. package/build/types/metrics/web-vitals/lib/bindReporter.d.ts +0 -7
  223. package/build/types/metrics/web-vitals/lib/bindReporter.d.ts.map +0 -1
  224. package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts +0 -7
  225. package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts.map +0 -1
  226. package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts +0 -2
  227. package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts.map +0 -1
  228. package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts +0 -2
  229. package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts.map +0 -1
  230. package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts +0 -5
  231. package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts.map +0 -1
  232. package/build/types/metrics/web-vitals/lib/globalListeners.d.ts.map +0 -1
  233. package/build/types/metrics/web-vitals/lib/initMetric.d.ts +0 -21
  234. package/build/types/metrics/web-vitals/lib/initMetric.d.ts.map +0 -1
  235. package/build/types/metrics/web-vitals/lib/initUnique.d.ts +0 -7
  236. package/build/types/metrics/web-vitals/lib/initUnique.d.ts.map +0 -1
  237. package/build/types/metrics/web-vitals/lib/observe.d.ts +0 -23
  238. package/build/types/metrics/web-vitals/lib/observe.d.ts.map +0 -1
  239. package/build/types/metrics/web-vitals/lib/onHidden.d.ts +0 -15
  240. package/build/types/metrics/web-vitals/lib/onHidden.d.ts.map +0 -1
  241. package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +0 -15
  242. package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts.map +0 -1
  243. package/build/types/metrics/web-vitals/lib/runOnce.d.ts +0 -2
  244. package/build/types/metrics/web-vitals/lib/runOnce.d.ts.map +0 -1
  245. package/build/types/metrics/web-vitals/lib/whenActivated.d.ts +0 -2
  246. package/build/types/metrics/web-vitals/lib/whenActivated.d.ts.map +0 -1
  247. package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts +0 -6
  248. package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts.map +0 -1
  249. package/build/types/metrics/web-vitals/onFCP.d.ts +0 -11
  250. package/build/types/metrics/web-vitals/onFCP.d.ts.map +0 -1
  251. package/build/types/metrics/web-vitals/onTTFB.d.ts +0 -20
  252. package/build/types/metrics/web-vitals/onTTFB.d.ts.map +0 -1
  253. package/build/types/metrics/web-vitals/types/base.d.ts +0 -103
  254. package/build/types/metrics/web-vitals/types/base.d.ts.map +0 -1
  255. package/build/types/metrics/web-vitals/types/cls.d.ts +0 -58
  256. package/build/types/metrics/web-vitals/types/cls.d.ts.map +0 -1
  257. package/build/types/metrics/web-vitals/types/fcp.d.ts +0 -47
  258. package/build/types/metrics/web-vitals/types/fcp.d.ts.map +0 -1
  259. package/build/types/metrics/web-vitals/types/inp.d.ts +0 -150
  260. package/build/types/metrics/web-vitals/types/inp.d.ts.map +0 -1
  261. package/build/types/metrics/web-vitals/types/lcp.d.ts +0 -74
  262. package/build/types/metrics/web-vitals/types/lcp.d.ts.map +0 -1
  263. package/build/types/metrics/web-vitals/types/ttfb.d.ts +0 -60
  264. package/build/types/metrics/web-vitals/types/ttfb.d.ts.map +0 -1
  265. package/build/types/metrics/web-vitals/types.d.ts +0 -78
  266. package/build/types/metrics/web-vitals/types.d.ts.map +0 -1
  267. package/build/types/metrics/webVitalSpans.d.ts.map +0 -1
  268. /package/build/cjs/{instrument → instrumentation}/dom.js +0 -0
  269. /package/build/cjs/{instrument → instrumentation}/history.js +0 -0
  270. /package/build/cjs/{instrument → instrumentation}/location.js +0 -0
  271. /package/build/cjs/{instrument → instrumentation}/xhr.js +0 -0
  272. /package/build/cjs/{metrics → performance}/resourceTiming.js +0 -0
  273. /package/build/cjs/{metrics → web-vitals}/lcp.js +0 -0
  274. /package/build/esm/{instrument → instrumentation}/dom.js +0 -0
  275. /package/build/esm/{instrument → instrumentation}/history.js +0 -0
  276. /package/build/esm/{instrument → instrumentation}/location.js +0 -0
  277. /package/build/esm/{instrument → instrumentation}/xhr.js +0 -0
  278. /package/build/esm/{metrics → performance}/resourceTiming.js +0 -0
  279. /package/build/esm/{metrics → web-vitals}/lcp.js +0 -0
  280. /package/build/types/{instrument → instrumentation}/dom.d.ts +0 -0
  281. /package/build/types/{instrument → instrumentation}/history.d.ts +0 -0
  282. /package/build/types/{instrument → instrumentation}/location.d.ts +0 -0
  283. /package/build/types/{instrument → instrumentation}/xhr.d.ts +0 -0
  284. /package/build/types/{metrics → performance}/elementTiming.d.ts +0 -0
  285. /package/build/types/{metrics → performance}/resourceTiming.d.ts +0 -0
  286. /package/build/types/{metrics → performance}/userTiming.d.ts +0 -0
  287. /package/build/types/{metrics → web-vitals}/inp.d.ts +0 -0
  288. /package/build/types/{metrics → web-vitals}/lcp.d.ts +0 -0
@@ -1,12 +1,11 @@
1
- import { spanToJSON, withActiveSpan, startInactiveSpan } from '@sentry/core';
1
+ import { spanToStaticSpanJSON, withActiveSpan, startInactiveSpan } from '@sentry/core';
2
2
  import { WINDOW } from '../types.js';
3
- import { onHidden } from './web-vitals/lib/onHidden.js';
4
3
 
5
4
  function isMeasurementValue(value) {
6
5
  return typeof value === "number" && isFinite(value);
7
6
  }
8
7
  function startAndEndSpan(parentSpan, startTimeInSeconds, endTime, { ...ctx }) {
9
- const parentStartTime = spanToJSON(parentSpan).start_timestamp;
8
+ const parentStartTime = spanToStaticSpanJSON(parentSpan).start_timestamp;
10
9
  if (parentStartTime && parentStartTime > startTimeInSeconds) {
11
10
  if (typeof parentSpan.updateStartTime === "function") {
12
11
  parentSpan.updateStartTime(startTimeInSeconds);
@@ -57,30 +56,6 @@ function supportsWebVital(entryType) {
57
56
  return false;
58
57
  }
59
58
  }
60
- function listenForWebVitalReportEvents(client, collectorCallback) {
61
- let pageloadSpan;
62
- let collected = false;
63
- function _runCollectorCallbackOnce(event) {
64
- if (!collected && pageloadSpan) {
65
- collectorCallback(event, pageloadSpan.spanContext().spanId, pageloadSpan);
66
- }
67
- collected = true;
68
- }
69
- onHidden(() => {
70
- _runCollectorCallbackOnce("pagehide");
71
- });
72
- const unsubscribeStartNavigation = client.on("beforeStartNavigationSpan", (_, options) => {
73
- if (!options?.isRedirect) {
74
- _runCollectorCallbackOnce("navigation");
75
- unsubscribeStartNavigation();
76
- unsubscribeAfterStartPageLoadSpan();
77
- }
78
- });
79
- const unsubscribeAfterStartPageLoadSpan = client.on("afterStartPageLoadSpan", (span) => {
80
- pageloadSpan = span;
81
- unsubscribeAfterStartPageLoadSpan();
82
- });
83
- }
84
59
 
85
- export { extractNetworkProtocol, getBrowserPerformanceAPI, isMeasurementValue, listenForWebVitalReportEvents, msToSec, startAndEndSpan, supportsWebVital };
60
+ export { extractNetworkProtocol, getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan, supportsWebVital };
86
61
  //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../../../src/performance/utils.ts"],"sourcesContent":["import type { SentrySpan, Span, SpanTimeInput, StartSpanOptions } from '@sentry/core';\nimport { spanToStaticSpanJSON, startInactiveSpan, withActiveSpan } from '@sentry/core';\nimport { WINDOW } from '../types';\n\n/**\n * Checks if a given value is a valid measurement value.\n */\nexport function isMeasurementValue(value: unknown): value is number {\n return typeof value === 'number' && isFinite(value);\n}\n\n/**\n * Helper function to start child on transactions. This function will make sure that the transaction will\n * use the start timestamp of the created child span if it is earlier than the transactions actual\n * start timestamp.\n */\nexport function startAndEndSpan(\n parentSpan: Span,\n startTimeInSeconds: number,\n endTime: SpanTimeInput,\n { ...ctx }: StartSpanOptions,\n): Span | undefined {\n const parentStartTime = spanToStaticSpanJSON(parentSpan).start_timestamp;\n if (parentStartTime && parentStartTime > startTimeInSeconds) {\n // We can only do this for SentrySpans...\n if (typeof (parentSpan as Partial<SentrySpan>).updateStartTime === 'function') {\n (parentSpan as SentrySpan).updateStartTime(startTimeInSeconds);\n }\n }\n\n // The return value only exists for tests\n return withActiveSpan(parentSpan, () => {\n const span = startInactiveSpan({\n startTime: startTimeInSeconds,\n ...ctx,\n });\n\n if (span) {\n span.end(endTime);\n }\n\n return span;\n });\n}\n\n/** Get the browser performance API. */\nexport function getBrowserPerformanceAPI(): Performance | undefined {\n // @ts-expect-error we want to make sure all of these are available, even if TS is sure they are\n return WINDOW.addEventListener && WINDOW.performance;\n}\n\n/**\n * Converts from milliseconds to seconds\n * @param time time in ms\n */\nexport function msToSec(time: number): number {\n return time / 1000;\n}\n\n/**\n * Converts ALPN protocol ids to name and version.\n *\n * (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids)\n * @param nextHopProtocol PerformanceResourceTiming.nextHopProtocol\n */\nexport function extractNetworkProtocol(nextHopProtocol: string): { name: string; version: string } {\n let name = 'unknown';\n let version = 'unknown';\n let _name = '';\n for (const char of nextHopProtocol) {\n // http/1.1 etc.\n if (char === '/') {\n [name, version] = nextHopProtocol.split('/') as [string, string];\n break;\n }\n // h2, h3 etc.\n if (!isNaN(Number(char))) {\n name = _name === 'h' ? 'http' : _name;\n version = nextHopProtocol.split(_name)[1] as string;\n break;\n }\n _name += char;\n }\n if (_name === nextHopProtocol) {\n // webrtc, ftp, etc.\n name = _name;\n }\n return { name, version };\n}\n\n/**\n * Generic support check for web vitals\n */\nexport function supportsWebVital(entryType: 'layout-shift' | 'largest-contentful-paint'): boolean {\n try {\n return PerformanceObserver.supportedEntryTypes.includes(entryType);\n } catch {\n return false;\n }\n}\n"],"names":[],"mappings":";;;AAOO,SAAS,mBAAmB,KAAA,EAAiC;AAClE,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,QAAA,CAAS,KAAK,CAAA;AACpD;AAOO,SAAS,gBACd,UAAA,EACA,kBAAA,EACA,SACA,EAAE,GAAG,KAAI,EACS;AAClB,EAAA,MAAM,eAAA,GAAkB,oBAAA,CAAqB,UAAU,CAAA,CAAE,eAAA;AACzD,EAAA,IAAI,eAAA,IAAmB,kBAAkB,kBAAA,EAAoB;AAE3D,IAAA,IAAI,OAAQ,UAAA,CAAmC,eAAA,KAAoB,UAAA,EAAY;AAC7E,MAAC,UAAA,CAA0B,gBAAgB,kBAAkB,CAAA;AAAA,IAC/D;AAAA,EACF;AAGA,EAAA,OAAO,cAAA,CAAe,YAAY,MAAM;AACtC,IAAA,MAAM,OAAO,iBAAA,CAAkB;AAAA,MAC7B,SAAA,EAAW,kBAAA;AAAA,MACX,GAAG;AAAA,KACJ,CAAA;AAED,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,IAClB;AAEA,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AACH;AAGO,SAAS,wBAAA,GAAoD;AAElE,EAAA,OAAO,MAAA,CAAO,oBAAoB,MAAA,CAAO,WAAA;AAC3C;AAMO,SAAS,QAAQ,IAAA,EAAsB;AAC5C,EAAA,OAAO,IAAA,GAAO,GAAA;AAChB;AAQO,SAAS,uBAAuB,eAAA,EAA4D;AACjG,EAAA,IAAI,IAAA,GAAO,SAAA;AACX,EAAA,IAAI,OAAA,GAAU,SAAA;AACd,EAAA,IAAI,KAAA,GAAQ,EAAA;AACZ,EAAA,KAAA,MAAW,QAAQ,eAAA,EAAiB;AAElC,IAAA,IAAI,SAAS,GAAA,EAAK;AAChB,MAAA,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,eAAA,CAAgB,MAAM,GAAG,CAAA;AAC3C,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,KAAA,CAAM,MAAA,CAAO,IAAI,CAAC,CAAA,EAAG;AACxB,MAAA,IAAA,GAAO,KAAA,KAAU,MAAM,MAAA,GAAS,KAAA;AAChC,MAAA,OAAA,GAAU,eAAA,CAAgB,KAAA,CAAM,KAAK,CAAA,CAAE,CAAC,CAAA;AACxC,MAAA;AAAA,IACF;AACA,IAAA,KAAA,IAAS,IAAA;AAAA,EACX;AACA,EAAA,IAAI,UAAU,eAAA,EAAiB;AAE7B,IAAA,IAAA,GAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,EAAE,MAAM,OAAA,EAAQ;AACzB;AAKO,SAAS,iBAAiB,SAAA,EAAiE;AAChG,EAAA,IAAI;AACF,IAAA,OAAO,mBAAA,CAAoB,mBAAA,CAAoB,QAAA,CAAS,SAAS,CAAA;AAAA,EACnE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;;;;"}
@@ -1,7 +1,7 @@
1
1
  import { isBrowser, getActiveSpan, getRootSpan } from '@sentry/core';
2
2
  import { htmlTreeAsString } from '../htmlTreeAsString.js';
3
3
  import { WINDOW } from '../types.js';
4
- import { addPerformanceInstrumentationHandler, isPerformanceEventTiming } from './instrument.js';
4
+ import { addPerformanceInstrumentationHandler, isPerformanceEventTiming } from '../instrumentation/performanceObserver.js';
5
5
 
6
6
  const LAST_INTERACTIONS = [];
7
7
  const INTERACTIONS_SPAN_MAP = /* @__PURE__ */ new Map();
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inp.js","sources":["../../../src/web-vitals/inp.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { getActiveSpan, getRootSpan, isBrowser } from '@sentry/core';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport { addPerformanceInstrumentationHandler, isPerformanceEventTiming } from '../instrumentation/performanceObserver';\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\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/**\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":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lcp.js","sources":["../../../src/web-vitals/lcp.ts"],"sourcesContent":["/**\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"],"names":[],"mappings":"AAGO,MAAM,0BAAA,GAA6B;AAEnC,SAAS,iBAAiB,QAAA,EAAkD;AACjF,EAAA,OAAO,QAAA,IAAY,IAAA,IAAQ,QAAA,GAAW,CAAA,IAAK,QAAA,IAAY,0BAAA;AACzD;;;;"}
@@ -0,0 +1,29 @@
1
+ import { onHidden } from './utils.js';
2
+
3
+ function listenForWebVitalReportEvents(client, collectorCallback) {
4
+ let pageloadSpan;
5
+ let collected = false;
6
+ function _runCollectorCallbackOnce(event) {
7
+ if (!collected && pageloadSpan) {
8
+ collectorCallback(event, pageloadSpan.spanContext().spanId, pageloadSpan);
9
+ }
10
+ collected = true;
11
+ }
12
+ onHidden(() => {
13
+ _runCollectorCallbackOnce("pagehide");
14
+ });
15
+ const unsubscribeStartNavigation = client.on("beforeStartNavigationSpan", (_, options) => {
16
+ if (!options?.isRedirect) {
17
+ _runCollectorCallbackOnce("navigation");
18
+ unsubscribeStartNavigation();
19
+ unsubscribeAfterStartPageLoadSpan();
20
+ }
21
+ });
22
+ const unsubscribeAfterStartPageLoadSpan = client.on("afterStartPageLoadSpan", (span) => {
23
+ pageloadSpan = span;
24
+ unsubscribeAfterStartPageLoadSpan();
25
+ });
26
+ }
27
+
28
+ export { listenForWebVitalReportEvents };
29
+ //# sourceMappingURL=reportEvents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reportEvents.js","sources":["../../../src/web-vitals/reportEvents.ts"],"sourcesContent":["import type { Client, Span } from '@sentry/core';\nimport { onHidden } from './utils';\n\nexport type WebVitalReportEvent = 'pagehide' | 'navigation';\n\n/**\n * Listens for events on which we want to collect a previously accumulated web vital value.\n * Currently, this includes:\n *\n * - pagehide (i.e. user minimizes browser window, hides tab, etc)\n * - soft navigation (we only care about the vital of the initially loaded route)\n *\n * As a \"side-effect\", this function will also collect the span id of the pageload span.\n *\n * @param collectorCallback the callback to be called when the first of these events is triggered. Parameters:\n * - event: the event that triggered the reporting of the web vital value.\n * - pageloadSpanId: the span id of the pageload span. This is used to link the web vital span to the pageload span.\n * - pageloadSpan: the pageload span instance. This is used for full access to the pageload span for span streaming.\n */\nexport function listenForWebVitalReportEvents(\n client: Client,\n collectorCallback: (event: WebVitalReportEvent, pageloadSpanId: string, pageloadSpan?: Span) => void,\n) {\n let pageloadSpan: Span | undefined;\n\n let collected = false;\n function _runCollectorCallbackOnce(event: WebVitalReportEvent) {\n if (!collected && pageloadSpan) {\n collectorCallback(event, pageloadSpan.spanContext().spanId, pageloadSpan);\n }\n collected = true;\n }\n\n onHidden(() => {\n _runCollectorCallbackOnce('pagehide');\n });\n\n const unsubscribeStartNavigation = client.on('beforeStartNavigationSpan', (_, options) => {\n // we only want to collect LCP if we actually navigate. Redirects should be ignored.\n if (!options?.isRedirect) {\n _runCollectorCallbackOnce('navigation');\n unsubscribeStartNavigation();\n unsubscribeAfterStartPageLoadSpan();\n }\n });\n\n const unsubscribeAfterStartPageLoadSpan = client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n unsubscribeAfterStartPageLoadSpan();\n });\n}\n"],"names":[],"mappings":";;AAmBO,SAAS,6BAAA,CACd,QACA,iBAAA,EACA;AACA,EAAA,IAAI,YAAA;AAEJ,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,SAAS,0BAA0B,KAAA,EAA4B;AAC7D,IAAA,IAAI,CAAC,aAAa,YAAA,EAAc;AAC9B,MAAA,iBAAA,CAAkB,KAAA,EAAO,YAAA,CAAa,WAAA,EAAY,CAAE,QAAQ,YAAY,CAAA;AAAA,IAC1E;AACA,IAAA,SAAA,GAAY,IAAA;AAAA,EACd;AAEA,EAAA,QAAA,CAAS,MAAM;AACb,IAAA,yBAAA,CAA0B,UAAU,CAAA;AAAA,EACtC,CAAC,CAAA;AAED,EAAA,MAAM,6BAA6B,MAAA,CAAO,EAAA,CAAG,2BAAA,EAA6B,CAAC,GAAG,OAAA,KAAY;AAExF,IAAA,IAAI,CAAC,SAAS,UAAA,EAAY;AACxB,MAAA,yBAAA,CAA0B,YAAY,CAAA;AACtC,MAAA,0BAAA,EAA2B;AAC3B,MAAA,iCAAA,EAAkC;AAAA,IACpC;AAAA,EACF,CAAC,CAAA;AAED,EAAA,MAAM,iCAAA,GAAoC,MAAA,CAAO,EAAA,CAAG,wBAAA,EAA0B,CAAA,IAAA,KAAQ;AACpF,IAAA,YAAA,GAAe,IAAA;AACf,IAAA,iCAAA,EAAkC;AAAA,EACpC,CAAC,CAAA;AACH;;;;"}
@@ -1,11 +1,12 @@
1
- import { browserPerformanceTimeOrigin, hasSpanStreamingEnabled, debug, timestampInSeconds, getCurrentScope, spanToStreamedSpanJSON, SEMANTIC_ATTRIBUTE_SENTRY_OP, startInactiveSpan, SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getClient, getActiveSpan, getRootSpan } from '@sentry/core';
1
+ import { browserPerformanceTimeOrigin, hasSpanStreamingEnabled, debug, timestampInSeconds, getCurrentScope, spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_OP, startInactiveSpan, SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getClient, getActiveSpan, getRootSpan } from '@sentry/core';
2
2
  import { DEBUG_BUILD } from '../debug-build.js';
3
3
  import { htmlTreeAsString } from '../htmlTreeAsString.js';
4
4
  import { WINDOW } from '../types.js';
5
5
  import { MAX_PLAUSIBLE_INP_DURATION, INP_ENTRY_MAP, getCachedInteractionContext } from './inp.js';
6
- import { addClsInstrumentationHandler, addInpInstrumentationHandler, addLcpInstrumentationHandler } from './instrument.js';
6
+ import { addClsInstrumentationHandler, addInpInstrumentationHandler, addLcpInstrumentationHandler } from '../instrumentation/performanceObserver.js';
7
7
  import { isValidLcpMetric } from './lcp.js';
8
- import { supportsWebVital, listenForWebVitalReportEvents, getBrowserPerformanceAPI, msToSec } from './utils.js';
8
+ import { listenForWebVitalReportEvents } from './reportEvents.js';
9
+ import { supportsWebVital, getBrowserPerformanceAPI, msToSec } from '../performance/utils.js';
9
10
  import { SENTRY_SEGMENT_NAME, SENTRY_TRANSACTION } from '@sentry/conventions/attributes';
10
11
 
11
12
  function _emitWebVitalSpan(options) {
@@ -35,7 +36,7 @@ function _emitWebVitalSpan(options) {
35
36
  "user_agent.original": WINDOW.navigator?.userAgent,
36
37
  ...passedAttributes
37
38
  };
38
- if (parentSpan && spanToStreamedSpanJSON(parentSpan).attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === "pageload") {
39
+ if (parentSpan && spanToJSON(parentSpan).attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === "pageload") {
39
40
  attributes["sentry.pageload.span_id"] = parentSpan.spanContext().spanId;
40
41
  }
41
42
  if (reportEvent) {
@@ -187,7 +188,7 @@ function _sendInpSpan(inpValue, entry, standalone = false) {
187
188
  const activeSpan = getActiveSpan();
188
189
  const rootSpan = activeSpan ? getRootSpan(activeSpan) : void 0;
189
190
  const spanToUse = cachedContext?.span || rootSpan;
190
- const routeName = spanToUse ? spanToStreamedSpanJSON(spanToUse).name : getCurrentScope().getScopeData().transactionName;
191
+ const routeName = spanToUse ? spanToJSON(spanToUse).name : getCurrentScope().getScopeData().transactionName;
191
192
  const name = cachedContext?.elementName || htmlTreeAsString(entry.target);
192
193
  _emitWebVitalSpan({
193
194
  name,
@@ -209,4 +210,4 @@ function _sendInpSpan(inpValue, entry, standalone = false) {
209
210
  }
210
211
 
211
212
  export { _emitWebVitalSpan, _sendClsSpan, _sendInpSpan, _sendLcpSpan, trackClsAsSpan, trackInpAsSpan, trackLcpAsSpan };
212
- //# sourceMappingURL=webVitalSpans.js.map
213
+ //# sourceMappingURL=spans.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spans.js","sources":["../../../src/web-vitals/spans.ts"],"sourcesContent":["import type { Client, Integration, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getClient,\n getCurrentScope,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n startInactiveSpan,\n timestampInSeconds,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION } from './inp';\nimport type { InstrumentationHandlerCallback } from '../instrumentation/performanceObserver';\nimport {\n addClsInstrumentationHandler,\n addInpInstrumentationHandler,\n addLcpInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport { isValidLcpMetric } from './lcp';\nimport type { WebVitalReportEvent } from './reportEvents';\nimport { listenForWebVitalReportEvents } from './reportEvents';\nimport { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';\nimport type { PerformanceEventTiming } from '../instrumentation/performanceObserver';\nimport { SENTRY_SEGMENT_NAME, SENTRY_TRANSACTION } from '@sentry/conventions/attributes';\n\n// Locally-defined interfaces to avoid leaking bare global type references into the\n// generated .d.ts. The `declare global` augmentations in web-vitals/types.ts make these\n// available during this package's compilation but are NOT carried to consumers.\n// This mirrors the pattern used for PerformanceEventTiming in instrument.ts.\nexport interface LayoutShift extends PerformanceEntry {\n value: number;\n sources: Array<{ node: Node | null }>;\n hadRecentInput: boolean;\n}\n\nexport interface LargestContentfulPaint extends PerformanceEntry {\n readonly renderTime: DOMHighResTimeStamp;\n readonly loadTime: DOMHighResTimeStamp;\n readonly size: number;\n readonly id: string;\n readonly url: string;\n readonly element: Element | null;\n}\n\ninterface WebVitalSpanOptions {\n name: string;\n op: string;\n origin: string;\n metricName: 'lcp' | 'cls' | 'inp';\n value: number;\n attributes?: SpanAttributes;\n parentSpan?: Span;\n reportEvent?: WebVitalReportEvent;\n startTime: number;\n endTime?: number;\n /**\n * When `true`, the span is sent on its own as a v2 streamed span instead of being folded into a\n * transaction. Used for INP when span streaming is disabled (it reports late, so it can't ride\n * the pageload transaction).\n *\n * TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always streams.\n */\n standalone?: boolean;\n}\n\n/**\n * Emits a web vital span. When `standalone` is set it is sent on its own as a v2 streamed span;\n * otherwise it flows through the span streaming pipeline as a child of `parentSpan`.\n */\nexport function _emitWebVitalSpan(options: WebVitalSpanOptions): void {\n const {\n name,\n op,\n origin,\n metricName,\n value,\n attributes: passedAttributes,\n parentSpan,\n reportEvent,\n startTime,\n endTime,\n standalone,\n } = options;\n\n const routeName = getCurrentScope().getScopeData().transactionName;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,\n [`browser.web_vital.${metricName}.value`]: value,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: routeName,\n [SENTRY_SEGMENT_NAME]: routeName,\n // Web vital score calculation relies on the user agent\n 'user_agent.original': WINDOW.navigator?.userAgent,\n ...passedAttributes,\n };\n\n if (parentSpan && spanToJSON(parentSpan).attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'pageload') {\n // for LCP and CLS, we collect the pageload span id as an attribute\n attributes['sentry.pageload.span_id'] = parentSpan.spanContext().spanId;\n }\n\n if (reportEvent) {\n attributes[`browser.web_vital.${metricName}.report_event`] = reportEvent;\n }\n\n // A standalone span is sent as a plain v2 span without running the `processSpan` hooks (see\n // `captureStandaloneSpanWithStaticCallback`), so Replay can't attach the replay id itself. Set it\n // here, mirroring Replay's `processSpan`, so INP keeps its replay association like it did on v1.\n // TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always\n // streams, at which point Replay's `processSpan` runs and attaches the replay id.\n if (standalone) {\n Object.assign(attributes, getReplayAttributes());\n }\n\n const span = startInactiveSpan({\n name,\n attributes,\n startTime,\n parentSpan,\n // oxlint-disable-next-line typescript/no-deprecated -- intentional during the v1/v2 transition; see the TODO(standalone) above\n experimental: standalone ? { standalone: true } : undefined,\n });\n\n if (span) {\n span.end(endTime ?? startTime);\n }\n}\n\ninterface ReplayIntegration extends Integration {\n getReplayId: (onlyIfSampled?: boolean) => string | undefined;\n getRecordingMode: () => 'session' | 'buffer' | undefined;\n}\n\n// TODO(standalone): remove once the static (transaction) trace lifecycle is dropped; Replay's\n// `processSpan` then attaches the replay id to the streamed INP span instead.\nfunction getReplayAttributes(): SpanAttributes {\n const replay = getClient()?.getIntegrationByName<ReplayIntegration>('Replay');\n const replayId = replay?.getReplayId(true);\n if (!replayId) {\n return {};\n }\n\n return {\n 'sentry.replay_id': replayId,\n 'sentry._internal.replay_is_buffering': replay!.getRecordingMode() === 'buffer' ? true : undefined,\n };\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client): void {\n let lcpValue = 0;\n let lcpEntry: 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 lcpValue = metric.value;\n lcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, reportEvent);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n): void {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin() || 0;\n const timeOrigin = msToSec(performanceTimeOrigin);\n const endTime = msToSec(performanceTimeOrigin + (entry?.startTime || 0));\n const name = entry ? htmlTreeAsString(entry.element) : 'Largest contentful paint';\n\n const attributes: SpanAttributes = {};\n\n entry?.element && (attributes['browser.web_vital.lcp.element'] = htmlTreeAsString(entry.element));\n entry?.id && (attributes['browser.web_vital.lcp.id'] = entry.id);\n entry?.url && (attributes['browser.web_vital.lcp.url'] = entry.url);\n entry?.loadTime != null && (attributes['browser.web_vital.lcp.load_time'] = entry.loadTime);\n entry?.renderTime != null && (attributes['browser.web_vital.lcp.render_time'] = entry.renderTime);\n entry?.size != null && (attributes['browser.web_vital.lcp.size'] = entry.size);\n\n _emitWebVitalSpan({\n name,\n op: 'ui.webvital.lcp',\n origin: 'auto.http.browser.lcp',\n metricName: 'lcp',\n value: lcpValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime: timeOrigin,\n endTime,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client): void {\n let clsValue = 0;\n let clsEntry: 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 clsValue = metric.value;\n clsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, reportEvent);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const startTime = entry ? msToSec((browserPerformanceTimeOrigin() || 0) + entry.startTime) : timestampInSeconds();\n const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';\n\n const attributes: SpanAttributes = {};\n\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`browser.web_vital.cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n _emitWebVitalSpan({\n name,\n op: 'ui.webvital.cls',\n origin: 'auto.http.browser.cls',\n metricName: 'cls',\n value: clsValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime,\n });\n}\n\n/**\n * Tracks INP and emits it as a web vital span, as a child of the interaction's root span.\n * Requires `registerInpInteractionListener()` to be called separately for cached element names and\n * root spans per interaction.\n */\nexport function trackInpAsSpan(client: Client): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n // INP reports late (on pagehide, after the pageload span has ended). With span streaming enabled\n // it rides the streaming pipeline. With streaming disabled it would be dropped as a late span, so\n // it is emitted as its own standalone v2 span instead (see `_emitWebVitalSpan`), overriding the\n // static trace lifecycle for INP only.\n // TODO(standalone): once the static trace lifecycle is dropped, INP always streams; drop this flag.\n const standalone = !hasSpanStreamingEnabled(client);\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (metric.value == null) {\n return;\n }\n\n const duration = msToSec(metric.value);\n\n if (duration > MAX_PLAUSIBLE_INP_DURATION) {\n return;\n }\n\n const entry = metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n\n if (!entry) {\n return;\n }\n\n _sendInpSpan(metric.value, entry, standalone);\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(inpValue: number, entry: PerformanceEventTiming, standalone = false): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const duration = msToSec(inpValue);\n const interactionType = INP_ENTRY_MAP[entry.name];\n\n const cachedContext = getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n const spanToUse = cachedContext?.span || rootSpan;\n const routeName = spanToUse ? spanToJSON(spanToUse).name : getCurrentScope().getScopeData().transactionName;\n const name = cachedContext?.elementName || htmlTreeAsString(entry.target);\n\n _emitWebVitalSpan({\n name,\n op: `ui.interaction.${interactionType}`,\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes: {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry.duration,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: routeName,\n [SENTRY_SEGMENT_NAME]: routeName,\n },\n startTime,\n endTime: startTime + duration,\n parentSpan: spanToUse,\n standalone,\n });\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ import { browserPerformanceTimeOrigin, spanToJSON, setMeasurement, debug } from '@sentry/core';
2
+ import { SENTRY_OP } from '@sentry/conventions/attributes';
3
+ import { DEBUG_BUILD } from '../debug-build.js';
4
+ import { htmlTreeAsString } from '../htmlTreeAsString.js';
5
+ import { addLcpInstrumentationHandler, addClsInstrumentationHandler, addTtfbInstrumentationHandler, addPerformanceInstrumentationHandler } from '../instrumentation/performanceObserver.js';
6
+ import { getBrowserPerformanceAPI, msToSec } from '../performance/utils.js';
7
+ import { isValidLcpMetric } from './lcp.js';
8
+ import { getActivationStart, getNavigationEntry, getVisibilityWatcher } from './utils.js';
9
+
10
+ let _measurements = {};
11
+ let _lcpEntry;
12
+ let _clsEntry;
13
+ function startTrackingWebVitals({ trackCls, trackLcp }) {
14
+ const performance = getBrowserPerformanceAPI();
15
+ if (performance && browserPerformanceTimeOrigin()) {
16
+ const lcpCleanupCallback = trackLcp ? _trackLCP() : void 0;
17
+ const clsCleanupCallback = trackCls ? _trackCLS() : void 0;
18
+ const ttfbCleanupCallback = _trackTtfb();
19
+ const fpFcpCleanupCallback = _trackFpFcp();
20
+ return () => {
21
+ ttfbCleanupCallback();
22
+ fpFcpCleanupCallback();
23
+ lcpCleanupCallback?.();
24
+ clsCleanupCallback?.();
25
+ };
26
+ }
27
+ return () => void 0;
28
+ }
29
+ function _trackCLS() {
30
+ return addClsInstrumentationHandler(({ metric }) => {
31
+ const entry = metric.entries[metric.entries.length - 1];
32
+ if (!entry) {
33
+ return;
34
+ }
35
+ _measurements["cls"] = { value: metric.value, unit: "" };
36
+ _clsEntry = entry;
37
+ }, true);
38
+ }
39
+ function _trackLCP() {
40
+ return addLcpInstrumentationHandler(({ metric }) => {
41
+ const entry = metric.entries[metric.entries.length - 1];
42
+ if (!entry || !isValidLcpMetric(metric.value)) {
43
+ return;
44
+ }
45
+ _measurements["lcp"] = { value: metric.value, unit: "millisecond" };
46
+ _lcpEntry = entry;
47
+ }, true);
48
+ }
49
+ function _trackTtfb() {
50
+ return addTtfbInstrumentationHandler(({ metric }) => {
51
+ const entry = metric.entries[metric.entries.length - 1];
52
+ if (!entry) {
53
+ return;
54
+ }
55
+ _measurements["ttfb"] = { value: metric.value, unit: "millisecond" };
56
+ });
57
+ }
58
+ function _trackFpFcp() {
59
+ return addPerformanceInstrumentationHandler("paint", ({ entries }) => {
60
+ const firstHidden = getVisibilityWatcher();
61
+ for (const entry of entries) {
62
+ const shouldRecord = entry.startTime < firstHidden.firstHiddenTime;
63
+ if (entry.name === "first-paint" && shouldRecord) {
64
+ _measurements["fp"] = { value: entry.startTime, unit: "millisecond" };
65
+ }
66
+ if (entry.name === "first-contentful-paint" && shouldRecord) {
67
+ _measurements["fcp"] = { value: entry.startTime, unit: "millisecond" };
68
+ }
69
+ }
70
+ });
71
+ }
72
+ function addWebVitalsToSpan(span, options) {
73
+ const origin = browserPerformanceTimeOrigin();
74
+ if (!getBrowserPerformanceAPI()?.getEntries || !origin) {
75
+ resetWebVitalState();
76
+ return;
77
+ }
78
+ const { spanStreamingEnabled, recordClsOnPageloadSpan, recordLcpOnPageloadSpan } = options;
79
+ const timeOrigin = msToSec(origin);
80
+ if (spanToJSON(span).attributes[SENTRY_OP] === "pageload") {
81
+ _addTtfbRequestTimeToMeasurements(_measurements);
82
+ if (spanStreamingEnabled) {
83
+ const setAttr = (shortWebVitalName, value, customAttrName) => {
84
+ const attrKey = customAttrName ?? `browser.web_vital.${shortWebVitalName}.value`;
85
+ span.setAttribute(attrKey, value);
86
+ DEBUG_BUILD && debug.log("Setting web vital attribute", { [attrKey]: value }, "on pageload span");
87
+ };
88
+ ["ttfb", "fp", "fcp"].forEach((measurementName) => {
89
+ if (_measurements[measurementName]) {
90
+ setAttr(measurementName, _measurements[measurementName].value);
91
+ }
92
+ });
93
+ if (_measurements["ttfb.requestTime"]) {
94
+ setAttr("ttfb.requestTime", _measurements["ttfb.requestTime"].value, "browser.web_vital.ttfb.request_time");
95
+ }
96
+ } else {
97
+ if (!recordClsOnPageloadSpan) {
98
+ delete _measurements.cls;
99
+ }
100
+ if (!recordLcpOnPageloadSpan) {
101
+ delete _measurements.lcp;
102
+ }
103
+ Object.entries(_measurements).forEach(([measurementName, measurement]) => {
104
+ setMeasurement(measurementName, measurement.value, measurement.unit, span);
105
+ });
106
+ _setWebVitalAttributes(span, options);
107
+ }
108
+ span.setAttribute(spanStreamingEnabled ? "browser.performance.time_origin" : "performance.timeOrigin", timeOrigin);
109
+ span.setAttribute(
110
+ spanStreamingEnabled ? "browser.performance.navigation.activation_start" : "performance.activationStart",
111
+ getActivationStart()
112
+ );
113
+ }
114
+ resetWebVitalState();
115
+ }
116
+ function resetWebVitalState() {
117
+ _lcpEntry = void 0;
118
+ _clsEntry = void 0;
119
+ _measurements = {};
120
+ }
121
+ function _setWebVitalAttributes(span, options) {
122
+ if (_lcpEntry && options.recordLcpOnPageloadSpan) {
123
+ if (_lcpEntry.element) {
124
+ span.setAttribute("lcp.element", htmlTreeAsString(_lcpEntry.element));
125
+ }
126
+ if (_lcpEntry.id) {
127
+ span.setAttribute("lcp.id", _lcpEntry.id);
128
+ }
129
+ if (_lcpEntry.url) {
130
+ span.setAttribute("lcp.url", _lcpEntry.url.trim().slice(0, 200));
131
+ }
132
+ if (_lcpEntry.loadTime != null) {
133
+ span.setAttribute("lcp.loadTime", _lcpEntry.loadTime);
134
+ }
135
+ if (_lcpEntry.renderTime != null) {
136
+ span.setAttribute("lcp.renderTime", _lcpEntry.renderTime);
137
+ }
138
+ span.setAttribute("lcp.size", _lcpEntry.size);
139
+ }
140
+ if (_clsEntry?.sources && options.recordClsOnPageloadSpan) {
141
+ _clsEntry.sources.forEach(
142
+ (source, index) => span.setAttribute(`cls.source.${index + 1}`, htmlTreeAsString(source.node))
143
+ );
144
+ }
145
+ }
146
+ function _addTtfbRequestTimeToMeasurements(_measurements2) {
147
+ const navEntry = getNavigationEntry(false);
148
+ if (!navEntry) {
149
+ return;
150
+ }
151
+ const { responseStart, requestStart } = navEntry;
152
+ if (requestStart <= responseStart) {
153
+ _measurements2["ttfb.requestTime"] = {
154
+ value: responseStart - requestStart,
155
+ unit: "millisecond"
156
+ };
157
+ }
158
+ }
159
+
160
+ export { addWebVitalsToSpan, startTrackingWebVitals };
161
+ //# sourceMappingURL=tracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracking.js","sources":["../../../src/web-vitals/tracking.ts"],"sourcesContent":["import type { Client, Measurements, Span } from '@sentry/core';\nimport { browserPerformanceTimeOrigin, debug, setMeasurement, spanToJSON } from '@sentry/core';\nimport { SENTRY_OP } from '@sentry/conventions/attributes';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport {\n addClsInstrumentationHandler,\n addLcpInstrumentationHandler,\n addPerformanceInstrumentationHandler,\n addTtfbInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport { getBrowserPerformanceAPI, msToSec } from '../performance/utils';\nimport { isValidLcpMetric } from './lcp';\nimport { getActivationStart, getNavigationEntry, getVisibilityWatcher } from './utils';\n\nlet _measurements: Measurements = {};\nlet _lcpEntry: LargestContentfulPaint | undefined;\nlet _clsEntry: LayoutShift | undefined;\n\ninterface StartTrackingWebVitalsOptions {\n trackCls: boolean;\n trackLcp: boolean;\n client: Client;\n}\n\n/**\n * Start tracking web vitals.\n * The callback returned by this function can be used to stop tracking & ensure all measurements are final & captured.\n *\n * @returns A function that forces web vitals collection\n */\nexport function startTrackingWebVitals({ trackCls, trackLcp }: StartTrackingWebVitalsOptions): () => void {\n const performance = getBrowserPerformanceAPI();\n if (performance && browserPerformanceTimeOrigin()) {\n const lcpCleanupCallback = trackLcp ? _trackLCP() : undefined;\n const clsCleanupCallback = trackCls ? _trackCLS() : undefined;\n const ttfbCleanupCallback = _trackTtfb();\n const fpFcpCleanupCallback = _trackFpFcp();\n\n return (): void => {\n ttfbCleanupCallback();\n fpFcpCleanupCallback();\n lcpCleanupCallback?.();\n clsCleanupCallback?.();\n };\n }\n\n return () => undefined;\n}\n\nexport { registerInpInteractionListener } from './inp';\n\n/**\n * Starts tracking the Cumulative Layout Shift on the current page and collects the value and last entry\n * to the `_measurements` object which ultimately is applied to the pageload span's measurements.\n */\nfunction _trackCLS(): () => void {\n return addClsInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n _measurements['cls'] = { value: metric.value, unit: '' };\n _clsEntry = entry;\n }, true);\n}\n\n/** Starts tracking the Largest Contentful Paint on the current page. */\nfunction _trackLCP(): () => void {\n return addLcpInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1];\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n\n _measurements['lcp'] = { value: metric.value, unit: 'millisecond' };\n _lcpEntry = entry as LargestContentfulPaint;\n }, true);\n}\n\nfunction _trackTtfb(): () => void {\n return addTtfbInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1];\n if (!entry) {\n return;\n }\n\n _measurements['ttfb'] = { value: metric.value, unit: 'millisecond' };\n });\n}\n\n/** Starts tracking First Paint and First Contentful Paint on the current page. */\nfunction _trackFpFcp(): () => void {\n return addPerformanceInstrumentationHandler('paint', ({ entries }) => {\n const firstHidden = getVisibilityWatcher();\n for (const entry of entries) {\n // Only report if the page wasn't hidden prior to the web vital.\n const shouldRecord = entry.startTime < firstHidden.firstHiddenTime;\n if (entry.name === 'first-paint' && shouldRecord) {\n _measurements['fp'] = { value: entry.startTime, unit: 'millisecond' };\n }\n if (entry.name === 'first-contentful-paint' && shouldRecord) {\n _measurements['fcp'] = { value: entry.startTime, unit: 'millisecond' };\n }\n }\n });\n}\n\ninterface AddWebVitalsToSpanOptions {\n /**\n * Flag to determine if CLS should be recorded as a measurement on the pageload span or\n * sent as a standalone span instead.\n * Sending it as a standalone span will yield more accurate LCP values.\n *\n * Default: `false` for backwards compatibility.\n */\n recordClsOnPageloadSpan: boolean;\n\n /**\n * Flag to determine if LCP should be recorded as a measurement on the pageload span or\n * sent as a standalone span instead.\n * Sending it as a standalone span will yield more accurate LCP values.\n *\n * Default: `false` for backwards compatibility.\n */\n recordLcpOnPageloadSpan: boolean;\n\n /**\n * Whether span streaming is enabled.\n */\n spanStreamingEnabled?: boolean;\n}\n\n/**\n * Writes the collected web vitals (LCP, CLS, INP, TTFB, FP, FCP) onto the pageload span,\n * either as measurements/attributes (v1) or as web vital attributes (span streaming).\n *\n * This should be called when the pageload span ends, after the web vitals have been finalized.\n * It is a no-op for non-pageload spans, but always resets the collected web vital state so it\n * doesn't leak into a subsequent navigation.\n */\nexport function addWebVitalsToSpan(span: Span, options: AddWebVitalsToSpanOptions): void {\n const origin = browserPerformanceTimeOrigin();\n if (!getBrowserPerformanceAPI()?.getEntries || !origin) {\n // Gatekeeper if performance API not available\n resetWebVitalState();\n return;\n }\n\n const { spanStreamingEnabled, recordClsOnPageloadSpan, recordLcpOnPageloadSpan } = options;\n const timeOrigin = msToSec(origin);\n\n // Measurements are only available for pageload transactions\n if (spanToJSON(span).attributes[SENTRY_OP] === 'pageload') {\n _addTtfbRequestTimeToMeasurements(_measurements);\n\n if (spanStreamingEnabled) {\n const setAttr = (shortWebVitalName: string, value: number, customAttrName?: string) => {\n const attrKey = customAttrName ?? `browser.web_vital.${shortWebVitalName}.value`;\n span.setAttribute(attrKey, value);\n DEBUG_BUILD && debug.log('Setting web vital attribute', { [attrKey]: value }, 'on pageload span');\n };\n // for streamed pageload spans, we add the web vital measurements as attributes.\n // We omit LCP, CLS and INP because they're tracked separately as spans\n ['ttfb', 'fp', 'fcp'].forEach(measurementName => {\n if (_measurements[measurementName]) {\n setAttr(measurementName, _measurements[measurementName].value);\n }\n });\n if (_measurements['ttfb.requestTime']) {\n setAttr('ttfb.requestTime', _measurements['ttfb.requestTime'].value, 'browser.web_vital.ttfb.request_time');\n }\n } else {\n // If CLS is tracked as a span (span streaming), don't record CLS as a measurement\n if (!recordClsOnPageloadSpan) {\n delete _measurements.cls;\n }\n\n // If LCP is tracked as a span (span streaming), don't record LCP as a measurement\n if (!recordLcpOnPageloadSpan) {\n delete _measurements.lcp;\n }\n\n Object.entries(_measurements).forEach(([measurementName, measurement]) => {\n setMeasurement(measurementName, measurement.value, measurement.unit, span);\n });\n\n _setWebVitalAttributes(span, options);\n }\n\n // Set timeOrigin which denotes the timestamp which to base the LCP/FCP/FP/TTFB measurements on\n span.setAttribute(spanStreamingEnabled ? 'browser.performance.time_origin' : 'performance.timeOrigin', timeOrigin);\n\n // In prerendering scenarios, where a page might be prefetched and pre-rendered before the user clicks the link,\n // the navigation starts earlier than when the user clicks it. Web Vitals should always be based on the\n // user-perceived time, so they are not reported from the actual start of the navigation, but rather from the\n // time where the user actively started the navigation, for example by clicking a link.\n // This is user action is called \"activation\" and the time between navigation and activation is stored in\n // the `activationStart` attribute of the \"navigation\" PerformanceEntry.\n span.setAttribute(\n spanStreamingEnabled ? 'browser.performance.navigation.activation_start' : 'performance.activationStart',\n getActivationStart(),\n );\n }\n\n resetWebVitalState();\n}\n\nfunction resetWebVitalState(): void {\n _lcpEntry = undefined;\n _clsEntry = undefined;\n _measurements = {};\n}\n\n/** Add LCP / CLS data to span to allow debugging */\nfunction _setWebVitalAttributes(span: Span, options: AddWebVitalsToSpanOptions): void {\n // Only add LCP attributes if LCP is being recorded on the pageload span\n if (_lcpEntry && options.recordLcpOnPageloadSpan) {\n // Capture Properties of the LCP element that contributes to the LCP.\n\n if (_lcpEntry.element) {\n span.setAttribute('lcp.element', htmlTreeAsString(_lcpEntry.element));\n }\n\n if (_lcpEntry.id) {\n span.setAttribute('lcp.id', _lcpEntry.id);\n }\n\n if (_lcpEntry.url) {\n // Trim URL to the first 200 characters.\n span.setAttribute('lcp.url', _lcpEntry.url.trim().slice(0, 200));\n }\n\n if (_lcpEntry.loadTime != null) {\n // loadTime is the time of LCP that's related to receiving the LCP element response..\n span.setAttribute('lcp.loadTime', _lcpEntry.loadTime);\n }\n\n if (_lcpEntry.renderTime != null) {\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 span.setAttribute('lcp.renderTime', _lcpEntry.renderTime);\n }\n\n span.setAttribute('lcp.size', _lcpEntry.size);\n }\n\n // Only add CLS attributes if CLS is being recorded on the pageload span\n if (_clsEntry?.sources && options.recordClsOnPageloadSpan) {\n _clsEntry.sources.forEach((source, index) =>\n span.setAttribute(`cls.source.${index + 1}`, htmlTreeAsString(source.node)),\n );\n }\n}\n\n/**\n * Add ttfb request time information to measurements.\n *\n * ttfb information is added via the web vitals library.\n */\nfunction _addTtfbRequestTimeToMeasurements(_measurements: Measurements): void {\n const navEntry = getNavigationEntry(false);\n if (!navEntry) {\n return;\n }\n\n const { responseStart, requestStart } = navEntry;\n\n if (requestStart <= responseStart) {\n _measurements['ttfb.requestTime'] = {\n value: responseStart - requestStart,\n unit: 'millisecond',\n };\n }\n}\n"],"names":["_measurements"],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import { WINDOW } from '../types.js';
2
+
3
+ function addPageListener(type, listener, options) {
4
+ if (WINDOW.document) {
5
+ WINDOW.addEventListener(type, listener, options);
6
+ }
7
+ }
8
+ function removePageListener(type, listener, options) {
9
+ if (WINDOW.document) {
10
+ WINDOW.removeEventListener(type, listener, options);
11
+ }
12
+ }
13
+ const getNavigationEntry = (checkResponseStart = true) => {
14
+ const navigationEntry = WINDOW.performance?.getEntriesByType?.("navigation")[0];
15
+ if (
16
+ // sentry-specific change:
17
+ // We don't want to check for responseStart for our own use of `getNavigationEntry`
18
+ !checkResponseStart || navigationEntry && navigationEntry.responseStart > 0 && navigationEntry.responseStart < performance.now()
19
+ ) {
20
+ return navigationEntry;
21
+ }
22
+ };
23
+ const getActivationStart = () => {
24
+ const navEntry = getNavigationEntry();
25
+ return navEntry?.activationStart ?? 0;
26
+ };
27
+ const onHidden = (cb) => {
28
+ const onHiddenCallback = (event) => {
29
+ if (WINDOW.document?.visibilityState === "hidden") {
30
+ cb(event);
31
+ }
32
+ };
33
+ addPageListener("visibilitychange", onHiddenCallback, { capture: true });
34
+ };
35
+ let firstHiddenTime = -1;
36
+ const onHiddenFunctions = /* @__PURE__ */ new Set();
37
+ const initHiddenTime = () => {
38
+ return WINDOW.document?.visibilityState === "hidden" && !WINDOW.document?.prerendering ? 0 : Infinity;
39
+ };
40
+ const onVisibilityUpdate = (event) => {
41
+ if (WINDOW.document?.visibilityState === "hidden" && firstHiddenTime > -1) {
42
+ if (event.type === "visibilitychange") {
43
+ for (const onHiddenFunction of onHiddenFunctions) {
44
+ onHiddenFunction();
45
+ }
46
+ }
47
+ if (!isFinite(firstHiddenTime)) {
48
+ firstHiddenTime = event.type === "visibilitychange" ? event.timeStamp : 0;
49
+ removePageListener("prerenderingchange", onVisibilityUpdate, true);
50
+ }
51
+ }
52
+ };
53
+ const getVisibilityWatcher = () => {
54
+ if (WINDOW.document && firstHiddenTime < 0) {
55
+ const activationStart = getActivationStart();
56
+ const firstVisibilityStateHiddenTime = !WINDOW.document.prerendering ? globalThis.performance.getEntriesByType("visibility-state").filter((e) => e.name === "hidden" && e.startTime > activationStart)[0]?.startTime : void 0;
57
+ firstHiddenTime = firstVisibilityStateHiddenTime ?? initHiddenTime();
58
+ addPageListener("visibilitychange", onVisibilityUpdate, true);
59
+ addPageListener("prerenderingchange", onVisibilityUpdate, true);
60
+ }
61
+ return {
62
+ get firstHiddenTime() {
63
+ return firstHiddenTime;
64
+ },
65
+ onHidden(cb) {
66
+ onHiddenFunctions.add(cb);
67
+ }
68
+ };
69
+ };
70
+ const whenIdleOrHidden = (cb) => {
71
+ const rIC = WINDOW.requestIdleCallback || WINDOW.setTimeout;
72
+ if (WINDOW.document?.visibilityState === "hidden") {
73
+ cb();
74
+ } else {
75
+ let called = false;
76
+ const runOnce = () => {
77
+ if (!called) {
78
+ cb();
79
+ called = true;
80
+ }
81
+ };
82
+ addPageListener("visibilitychange", runOnce, { once: true, capture: true });
83
+ rIC(() => {
84
+ runOnce();
85
+ removePageListener("visibilitychange", runOnce, { capture: true });
86
+ });
87
+ }
88
+ };
89
+
90
+ export { addPageListener, getActivationStart, getNavigationEntry, getVisibilityWatcher, onHidden, removePageListener, whenIdleOrHidden };
91
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../../../src/web-vitals/utils.ts"],"sourcesContent":["/*\n * Portions of this file are derived from Google's web-vitals library.\n *\n * Copyright 2020-2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../types';\n\n/**\n * web-vitals 5.1.0 switched listeners to be added on the window rather than the document.\n * Instead of having to check for window/document every time we add a listener, we can use this function.\n */\nexport function addPageListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions) {\n if (WINDOW.document) {\n WINDOW.addEventListener(type, listener, options);\n }\n}\n\n/**\n * web-vitals 5.1.0 switched listeners to be removed from the window rather than the document.\n * Instead of having to check for window/document every time we remove a listener, we can use this function.\n */\nexport function removePageListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions) {\n if (WINDOW.document) {\n WINDOW.removeEventListener(type, listener, options);\n }\n}\n\n// sentry-specific change:\n// add optional param to not check for responseStart (see comment below)\nexport const getNavigationEntry = (checkResponseStart = true): PerformanceNavigationTiming | void => {\n const navigationEntry = WINDOW.performance?.getEntriesByType?.('navigation')[0];\n // Check to ensure the `responseStart` property is present and valid.\n // In some cases a zero value is reported by the browser (for\n // privacy/security reasons), and in other cases (bugs) the value is\n // negative or is larger than the current page time. Ignore these cases:\n // - https://github.com/GoogleChrome/web-vitals/issues/137\n // - https://github.com/GoogleChrome/web-vitals/issues/162\n // - https://github.com/GoogleChrome/web-vitals/issues/275\n if (\n // sentry-specific change:\n // We don't want to check for responseStart for our own use of `getNavigationEntry`\n !checkResponseStart ||\n (navigationEntry && navigationEntry.responseStart > 0 && navigationEntry.responseStart < performance.now())\n ) {\n return navigationEntry;\n }\n};\n\nexport const getActivationStart = (): number => {\n const navEntry = getNavigationEntry();\n return navEntry?.activationStart ?? 0;\n};\n\nexport interface OnHiddenCallback {\n (event: Event): void;\n}\n\nexport const onHidden = (cb: OnHiddenCallback) => {\n const onHiddenCallback = (event: Event) => {\n if (WINDOW.document?.visibilityState === 'hidden') {\n cb(event);\n }\n };\n\n addPageListener('visibilitychange', onHiddenCallback, { capture: true });\n};\n\nlet firstHiddenTime = -1;\nconst onHiddenFunctions: Set<() => void> = new Set();\n\nconst initHiddenTime = () => {\n // If the document is hidden when this code runs, assume it was always\n // hidden and the page was loaded in the background, with the one exception\n // that visibility state is always 'hidden' during prerendering, so we have\n // to ignore that case until prerendering finishes (see: `prerenderingchange`\n // event logic below).\n return WINDOW.document?.visibilityState === 'hidden' && !WINDOW.document?.prerendering ? 0 : Infinity;\n};\n\nconst onVisibilityUpdate = (event: Event) => {\n // Handle changes to hidden state\n if (WINDOW.document?.visibilityState === 'hidden' && firstHiddenTime > -1) {\n // Call onHidden callbacks when the page becomes hidden\n if (event.type === 'visibilitychange') {\n for (const onHiddenFunction of onHiddenFunctions) {\n onHiddenFunction();\n }\n }\n\n // If the document is 'hidden' and no previous hidden timestamp has been\n // set (so is infinity), update it based on the current event data.\n if (!isFinite(firstHiddenTime)) {\n // If the event is a 'visibilitychange' event, it means the page was\n // visible prior to this change, so the event timestamp is the first\n // hidden time.\n // However, if the event is not a 'visibilitychange' event, then it must\n // be a 'prerenderingchange' event, and the fact that the document is\n // still 'hidden' from the above check means the tab was activated\n // in a background state and so has always been hidden.\n firstHiddenTime = event.type === 'visibilitychange' ? event.timeStamp : 0;\n\n // We no longer need the `prerenderingchange` event listener now we've\n // set an initial init time so remove that\n // (we'll keep the visibilitychange one for onHiddenFunction above)\n removePageListener('prerenderingchange', onVisibilityUpdate, true);\n }\n }\n};\n\nexport const getVisibilityWatcher = () => {\n if (WINDOW.document && firstHiddenTime < 0) {\n // Check if we have a previous hidden `visibility-state` performance entry.\n const activationStart = getActivationStart();\n const firstVisibilityStateHiddenTime = !WINDOW.document.prerendering\n ? globalThis.performance\n .getEntriesByType('visibility-state')\n .filter(e => e.name === 'hidden' && e.startTime > activationStart)[0]?.startTime\n : undefined;\n\n // Prefer that, but if it's not available and the document is hidden when\n // this code runs, assume it was hidden since navigation start. This isn't\n // a perfect heuristic, but it's the best we can do until the\n // `visibility-state` performance entry becomes available in all browsers.\n firstHiddenTime = firstVisibilityStateHiddenTime ?? initHiddenTime();\n // Listen for visibility changes so we can handle things like bfcache\n // restores and/or prerender without having to examine individual\n // timestamps in detail and also for onHidden function calls.\n addPageListener('visibilitychange', onVisibilityUpdate, true);\n\n // IMPORTANT: when a page is prerendering, its `visibilityState` is\n // 'hidden', so in order to account for cases where this module checks for\n // visibility during prerendering, an additional check after prerendering\n // completes is also required.\n addPageListener('prerenderingchange', onVisibilityUpdate, true);\n }\n\n return {\n get firstHiddenTime() {\n return firstHiddenTime;\n },\n onHidden(cb: () => void) {\n onHiddenFunctions.add(cb);\n },\n };\n};\n\n/**\n * Runs the passed callback during the next idle period, or immediately\n * if the browser's visibility state is (or becomes) hidden.\n */\nexport const whenIdleOrHidden = (cb: () => void) => {\n const rIC = WINDOW.requestIdleCallback || WINDOW.setTimeout;\n\n // If the document is hidden, run the callback immediately, otherwise\n // race an idle callback with the next `visibilitychange` event.\n if (WINDOW.document?.visibilityState === 'hidden') {\n cb();\n } else {\n // Ensure the callback only runs once, whichever of the two racers wins.\n let called = false;\n const runOnce = () => {\n if (!called) {\n cb();\n called = true;\n }\n };\n addPageListener('visibilitychange', runOnce, { once: true, capture: true });\n rIC(() => {\n runOnce();\n // Remove the above event listener since no longer required.\n // See: https://github.com/GoogleChrome/web-vitals/issues/622\n removePageListener('visibilitychange', runOnce, { capture: true });\n });\n }\n};\n"],"names":[],"mappings":"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"}
@@ -1,18 +1,19 @@
1
- export { addPerformanceInstrumentationHandler, addClsInstrumentationHandler, addTtfbInstrumentationHandler, addLcpInstrumentationHandler, addInpInstrumentationHandler, } from './metrics/instrument';
2
- export { addPerformanceEntries, addWebVitalsToSpan, startTrackingInteractions, startTrackingLongTasks, startTrackingLongAnimationFrames, startTrackingWebVitals, registerInpInteractionListener, } from './metrics/browserMetrics';
3
- export { elementTimingIntegration, startTrackingElementTiming } from './metrics/elementTiming';
4
- export { userTimingIntegration } from './metrics/userTiming';
5
- export { extractNetworkProtocol } from './metrics/utils';
6
- export { trackClsAsSpan, trackInpAsSpan, trackLcpAsSpan } from './metrics/webVitalSpans';
7
- export { whenIdleOrHidden } from './metrics/web-vitals/lib/whenIdleOrHidden';
8
- export { addClickKeypressInstrumentationHandler } from './instrument/dom';
9
- export { addHistoryInstrumentationHandler } from './instrument/history';
1
+ export { addPerformanceInstrumentationHandler, addClsInstrumentationHandler, addTtfbInstrumentationHandler, addLcpInstrumentationHandler, addInpInstrumentationHandler, } from './instrumentation/performanceObserver';
2
+ export { addPerformanceEntries, startTrackingInteractions, startTrackingLongTasks, startTrackingLongAnimationFrames, } from './performance/entries';
3
+ export { addWebVitalsToSpan, startTrackingWebVitals, registerInpInteractionListener, } from './web-vitals/tracking';
4
+ export { elementTimingIntegration, startTrackingElementTiming } from './performance/elementTiming';
5
+ export { userTimingIntegration } from './performance/userTiming';
6
+ export { extractNetworkProtocol } from './performance/utils';
7
+ export { trackClsAsSpan, trackInpAsSpan, trackLcpAsSpan } from './web-vitals/spans';
8
+ export { whenIdleOrHidden } from './web-vitals/utils';
9
+ export { addClickKeypressInstrumentationHandler } from './instrumentation/dom';
10
+ export { addHistoryInstrumentationHandler } from './instrumentation/history';
10
11
  export { fetch, setTimeout, clearCachedImplementation, getNativeImplementation } from './getNativeImplementation';
11
- export { addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY } from './instrument/xhr';
12
+ export { addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY } from './instrumentation/xhr';
12
13
  export { getBodyString, getFetchRequestArgBody, serializeFormData, parseXhrResponseHeaders } from './networkUtils';
13
- export { resourceTimingToSpanAttributes } from './metrics/resourceTiming';
14
+ export { resourceTimingToSpanAttributes } from './performance/resourceTiming';
14
15
  export { htmlTreeAsString } from './htmlTreeAsString';
15
16
  export { isElement } from './is';
16
- export { getAbsoluteUrl } from './instrument/location';
17
+ export { getAbsoluteUrl } from './instrumentation/location';
17
18
  export type { FetchHint, NetworkMetaWarning, XhrHint } from './types';
18
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oCAAoC,EACpC,4BAA4B,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,yBAAyB,EACzB,sBAAsB,EACtB,gCAAgC,EAEhC,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAE/F,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAE7E,OAAO,EAAE,sCAAsC,EAAE,MAAM,kBAAkB,CAAC;AAE1E,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAElH,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAErF,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAEnH,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAE1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,YAAY,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oCAAoC,EACpC,4BAA4B,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,sBAAsB,EACtB,gCAAgC,GACjC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,kBAAkB,EAElB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAEnG,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,sCAAsC,EAAE,MAAM,uBAAuB,CAAC;AAE/E,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC;AAE7E,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAElH,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE1F,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAEnH,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAE9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,YAAY,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../../src/instrumentation/dom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAiCnD;;;;;GAKG;AACH,wBAAgB,sCAAsC,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI,CAIpG;AAED,+BAA+B;AAC/B,wBAAgB,aAAa,IAAI,IAAI,CAuFpC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../../src/instrumentation/history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAMvD;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,GAAG,IAAI,CAIlG;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAmDxC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"location.d.ts","sourceRoot":"","sources":["../../../src/instrumentation/location.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQxD"}
@@ -60,13 +60,13 @@ interface Metric {
60
60
  */
61
61
  entries: PerformanceEntry[];
62
62
  /**
63
- * The type of navigation
63
+ * The type of navigation.
64
64
  *
65
65
  * Navigation Timing API (or `undefined` if the browser doesn't
66
66
  * support that API). For pages that are restored from the bfcache, this
67
67
  * value will be 'back-forward-cache'.
68
68
  */
69
- navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'restore';
69
+ navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'restore' | 'soft-navigation';
70
70
  }
71
71
  type CleanupHandlerCallback = () => void;
72
72
  /**
@@ -118,4 +118,4 @@ export declare function addPerformanceInstrumentationHandler(type: InstrumentHan
118
118
  */
119
119
  export declare function isPerformanceEventTiming(entry: PerformanceEntry): entry is PerformanceEventTiming;
120
120
  export {};
121
- //# sourceMappingURL=instrument.d.ts.map
121
+ //# sourceMappingURL=performanceObserver.d.ts.map