@sentry/browser-utils 10.70.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.
- package/build/cjs/htmlTreeAsString.js.map +1 -1
- package/build/cjs/index.js +30 -28
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/instrumentation/dom.js.map +1 -0
- package/build/cjs/instrumentation/history.js.map +1 -0
- package/build/cjs/instrumentation/location.js.map +1 -0
- package/build/cjs/{metrics/instrument.js → instrumentation/performanceObserver.js} +44 -32
- package/build/cjs/instrumentation/performanceObserver.js.map +1 -0
- package/build/cjs/instrumentation/xhr.js.map +1 -0
- package/build/cjs/{metrics → performance}/elementTiming.js +2 -2
- package/build/cjs/performance/elementTiming.js.map +1 -0
- package/build/cjs/{metrics/browserMetrics.js → performance/entries.js} +43 -262
- package/build/cjs/performance/entries.js.map +1 -0
- package/build/cjs/performance/resourceTiming.js.map +1 -0
- package/build/cjs/performance/userTiming.js +119 -0
- package/build/cjs/performance/userTiming.js.map +1 -0
- package/build/cjs/performance/utils.js +68 -0
- package/build/cjs/performance/utils.js.map +1 -0
- package/build/cjs/{metrics → web-vitals}/inp.js +4 -61
- package/build/cjs/web-vitals/inp.js.map +1 -0
- package/build/cjs/web-vitals/lcp.js +10 -0
- package/build/cjs/web-vitals/lcp.js.map +1 -0
- package/build/cjs/web-vitals/reportEvents.js +31 -0
- package/build/cjs/web-vitals/reportEvents.js.map +1 -0
- package/build/cjs/{metrics/webVitalSpans.js → web-vitals/spans.js} +36 -19
- package/build/cjs/web-vitals/spans.js.map +1 -0
- package/build/cjs/web-vitals/tracking.js +164 -0
- package/build/cjs/web-vitals/tracking.js.map +1 -0
- package/build/cjs/web-vitals/utils.js +99 -0
- package/build/cjs/web-vitals/utils.js.map +1 -0
- package/build/esm/htmlTreeAsString.js.map +1 -1
- package/build/esm/index.js +14 -12
- package/build/esm/index.js.map +1 -1
- package/build/esm/instrumentation/dom.js.map +1 -0
- package/build/esm/instrumentation/history.js.map +1 -0
- package/build/esm/instrumentation/location.js.map +1 -0
- package/build/esm/{metrics/instrument.js → instrumentation/performanceObserver.js} +42 -30
- package/build/esm/instrumentation/performanceObserver.js.map +1 -0
- package/build/esm/instrumentation/xhr.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/{metrics → performance}/elementTiming.js +1 -1
- package/build/esm/performance/elementTiming.js.map +1 -0
- package/build/esm/{metrics/browserMetrics.js → performance/entries.js} +36 -252
- package/build/esm/performance/entries.js.map +1 -0
- package/build/esm/performance/resourceTiming.js.map +1 -0
- package/build/esm/performance/userTiming.js +116 -0
- package/build/esm/performance/userTiming.js.map +1 -0
- package/build/esm/performance/utils.js +61 -0
- package/build/esm/performance/utils.js.map +1 -0
- package/build/esm/{metrics → web-vitals}/inp.js +3 -57
- package/build/esm/web-vitals/inp.js.map +1 -0
- package/build/esm/web-vitals/lcp.js +7 -0
- package/build/esm/web-vitals/lcp.js.map +1 -0
- package/build/esm/web-vitals/reportEvents.js +29 -0
- package/build/esm/web-vitals/reportEvents.js.map +1 -0
- package/build/esm/{metrics/webVitalSpans.js → web-vitals/spans.js} +32 -15
- package/build/esm/web-vitals/spans.js.map +1 -0
- package/build/esm/web-vitals/tracking.js +161 -0
- package/build/esm/web-vitals/tracking.js.map +1 -0
- package/build/esm/web-vitals/utils.js +91 -0
- package/build/esm/web-vitals/utils.js.map +1 -0
- package/build/types/index.d.ts +13 -11
- package/build/types/index.d.ts.map +1 -1
- package/build/types/instrumentation/dom.d.ts.map +1 -0
- package/build/types/instrumentation/history.d.ts.map +1 -0
- package/build/types/instrumentation/location.d.ts.map +1 -0
- package/build/types/{metrics/instrument.d.ts → instrumentation/performanceObserver.d.ts} +3 -3
- package/build/types/instrumentation/performanceObserver.d.ts.map +1 -0
- package/build/types/instrumentation/xhr.d.ts.map +1 -0
- package/build/types/performance/elementTiming.d.ts.map +1 -0
- package/build/types/performance/entries.d.ts +49 -0
- package/build/types/performance/entries.d.ts.map +1 -0
- package/build/types/performance/resourceTiming.d.ts.map +1 -0
- package/build/types/performance/userTiming.d.ts +37 -0
- package/build/types/performance/userTiming.d.ts.map +1 -0
- package/build/types/performance/utils.d.ts +33 -0
- package/build/types/performance/utils.d.ts.map +1 -0
- package/build/types/types.d.ts +1 -1
- package/build/types/{metrics → web-vitals}/inp.d.ts +0 -13
- package/build/types/web-vitals/inp.d.ts.map +1 -0
- package/build/types/web-vitals/lcp.d.ts +6 -0
- package/build/types/web-vitals/lcp.d.ts.map +1 -0
- package/build/types/web-vitals/reportEvents.d.ts +18 -0
- package/build/types/web-vitals/reportEvents.d.ts.map +1 -0
- package/build/types/{metrics/webVitalSpans.d.ts → web-vitals/spans.d.ts} +18 -12
- package/build/types/web-vitals/spans.d.ts.map +1 -0
- package/build/types/web-vitals/tracking.d.ts +46 -0
- package/build/types/web-vitals/tracking.d.ts.map +1 -0
- package/build/types/{metrics/web-vitals/lib/globalListeners.d.ts → web-vitals/utils.d.ts} +16 -1
- package/build/types/web-vitals/utils.d.ts.map +1 -0
- package/package.json +8 -16
- package/build/cjs/instrument/dom.js.map +0 -1
- package/build/cjs/instrument/history.js.map +0 -1
- package/build/cjs/instrument/location.js.map +0 -1
- package/build/cjs/instrument/xhr.js.map +0 -1
- package/build/cjs/metrics/browserMetrics.js.map +0 -1
- package/build/cjs/metrics/cls.js +0 -64
- package/build/cjs/metrics/cls.js.map +0 -1
- package/build/cjs/metrics/elementTiming.js.map +0 -1
- package/build/cjs/metrics/inp.js.map +0 -1
- package/build/cjs/metrics/instrument.js.map +0 -1
- package/build/cjs/metrics/lcp.js +0 -77
- package/build/cjs/metrics/lcp.js.map +0 -1
- package/build/cjs/metrics/resourceTiming.js.map +0 -1
- package/build/cjs/metrics/utils.js +0 -137
- package/build/cjs/metrics/utils.js.map +0 -1
- package/build/cjs/metrics/web-vitals/getCLS.js +0 -46
- package/build/cjs/metrics/web-vitals/getCLS.js.map +0 -1
- package/build/cjs/metrics/web-vitals/getINP.js +0 -60
- package/build/cjs/metrics/web-vitals/getINP.js.map +0 -1
- package/build/cjs/metrics/web-vitals/getLCP.js +0 -62
- package/build/cjs/metrics/web-vitals/getLCP.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/InteractionManager.js +0 -87
- package/build/cjs/metrics/web-vitals/lib/InteractionManager.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js +0 -11
- package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js +0 -27
- package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/bindReporter.js +0 -31
- package/build/cjs/metrics/web-vitals/lib/bindReporter.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js +0 -8
- package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/getActivationStart.js +0 -11
- package/build/cjs/metrics/web-vitals/lib/getActivationStart.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js +0 -17
- package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js +0 -48
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/globalListeners.js +0 -18
- package/build/cjs/metrics/web-vitals/lib/globalListeners.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/initMetric.js +0 -34
- package/build/cjs/metrics/web-vitals/lib/initMetric.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/initUnique.js +0 -16
- package/build/cjs/metrics/web-vitals/lib/initUnique.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/observe.js +0 -20
- package/build/cjs/metrics/web-vitals/lib/observe.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/onHidden.js +0 -17
- package/build/cjs/metrics/web-vitals/lib/onHidden.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +0 -32
- package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/runOnce.js +0 -14
- package/build/cjs/metrics/web-vitals/lib/runOnce.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/whenActivated.js +0 -14
- package/build/cjs/metrics/web-vitals/lib/whenActivated.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -24
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js.map +0 -1
- package/build/cjs/metrics/web-vitals/onFCP.js +0 -37
- package/build/cjs/metrics/web-vitals/onFCP.js.map +0 -1
- package/build/cjs/metrics/web-vitals/onTTFB.js +0 -35
- package/build/cjs/metrics/web-vitals/onTTFB.js.map +0 -1
- package/build/cjs/metrics/webVitalSpans.js.map +0 -1
- package/build/esm/instrument/dom.js.map +0 -1
- package/build/esm/instrument/history.js.map +0 -1
- package/build/esm/instrument/location.js.map +0 -1
- package/build/esm/instrument/xhr.js.map +0 -1
- package/build/esm/metrics/browserMetrics.js.map +0 -1
- package/build/esm/metrics/cls.js +0 -61
- package/build/esm/metrics/cls.js.map +0 -1
- package/build/esm/metrics/elementTiming.js.map +0 -1
- package/build/esm/metrics/inp.js.map +0 -1
- package/build/esm/metrics/instrument.js.map +0 -1
- package/build/esm/metrics/lcp.js +0 -72
- package/build/esm/metrics/lcp.js.map +0 -1
- package/build/esm/metrics/resourceTiming.js.map +0 -1
- package/build/esm/metrics/utils.js +0 -128
- package/build/esm/metrics/utils.js.map +0 -1
- package/build/esm/metrics/web-vitals/getCLS.js +0 -43
- package/build/esm/metrics/web-vitals/getCLS.js.map +0 -1
- package/build/esm/metrics/web-vitals/getINP.js +0 -57
- package/build/esm/metrics/web-vitals/getINP.js.map +0 -1
- package/build/esm/metrics/web-vitals/getLCP.js +0 -59
- package/build/esm/metrics/web-vitals/getLCP.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/InteractionManager.js +0 -85
- package/build/esm/metrics/web-vitals/lib/InteractionManager.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js +0 -9
- package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js +0 -25
- package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/bindReporter.js +0 -29
- package/build/esm/metrics/web-vitals/lib/bindReporter.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/generateUniqueID.js +0 -6
- package/build/esm/metrics/web-vitals/lib/generateUniqueID.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/getActivationStart.js +0 -9
- package/build/esm/metrics/web-vitals/lib/getActivationStart.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js +0 -15
- package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js +0 -46
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/globalListeners.js +0 -15
- package/build/esm/metrics/web-vitals/lib/globalListeners.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/initMetric.js +0 -32
- package/build/esm/metrics/web-vitals/lib/initMetric.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/initUnique.js +0 -14
- package/build/esm/metrics/web-vitals/lib/initUnique.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/observe.js +0 -18
- package/build/esm/metrics/web-vitals/lib/observe.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/onHidden.js +0 -15
- package/build/esm/metrics/web-vitals/lib/onHidden.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +0 -29
- package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/runOnce.js +0 -12
- package/build/esm/metrics/web-vitals/lib/runOnce.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/whenActivated.js +0 -12
- package/build/esm/metrics/web-vitals/lib/whenActivated.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -22
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js.map +0 -1
- package/build/esm/metrics/web-vitals/onFCP.js +0 -34
- package/build/esm/metrics/web-vitals/onFCP.js.map +0 -1
- package/build/esm/metrics/web-vitals/onTTFB.js +0 -32
- package/build/esm/metrics/web-vitals/onTTFB.js.map +0 -1
- package/build/esm/metrics/webVitalSpans.js.map +0 -1
- package/build/types/instrument/dom.d.ts.map +0 -1
- package/build/types/instrument/history.d.ts.map +0 -1
- package/build/types/instrument/location.d.ts.map +0 -1
- package/build/types/instrument/xhr.d.ts.map +0 -1
- package/build/types/metrics/browserMetrics.d.ts +0 -116
- package/build/types/metrics/browserMetrics.d.ts.map +0 -1
- package/build/types/metrics/cls.d.ts +0 -17
- package/build/types/metrics/cls.d.ts.map +0 -1
- package/build/types/metrics/elementTiming.d.ts.map +0 -1
- package/build/types/metrics/inp.d.ts.map +0 -1
- package/build/types/metrics/instrument.d.ts.map +0 -1
- package/build/types/metrics/lcp.d.ts +0 -22
- package/build/types/metrics/lcp.d.ts.map +0 -1
- package/build/types/metrics/resourceTiming.d.ts.map +0 -1
- package/build/types/metrics/utils.d.ts +0 -73
- package/build/types/metrics/utils.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/getCLS.d.ts +0 -26
- package/build/types/metrics/web-vitals/getCLS.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/getINP.d.ts +0 -34
- package/build/types/metrics/web-vitals/getINP.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/getLCP.d.ts +0 -16
- package/build/types/metrics/web-vitals/getLCP.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts +0 -37
- package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts +0 -5
- package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts +0 -7
- package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts +0 -7
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts +0 -7
- package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts +0 -2
- package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts +0 -2
- package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts +0 -5
- package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/globalListeners.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts +0 -21
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/initUnique.d.ts +0 -7
- package/build/types/metrics/web-vitals/lib/initUnique.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/observe.d.ts +0 -23
- package/build/types/metrics/web-vitals/lib/observe.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts +0 -27
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +0 -15
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/runOnce.d.ts +0 -2
- package/build/types/metrics/web-vitals/lib/runOnce.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/whenActivated.d.ts +0 -2
- package/build/types/metrics/web-vitals/lib/whenActivated.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts +0 -6
- package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/onFCP.d.ts +0 -11
- package/build/types/metrics/web-vitals/onFCP.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/onTTFB.d.ts +0 -20
- package/build/types/metrics/web-vitals/onTTFB.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/base.d.ts +0 -103
- package/build/types/metrics/web-vitals/types/base.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/cls.d.ts +0 -58
- package/build/types/metrics/web-vitals/types/cls.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/fcp.d.ts +0 -47
- package/build/types/metrics/web-vitals/types/fcp.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/inp.d.ts +0 -150
- package/build/types/metrics/web-vitals/types/inp.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/lcp.d.ts +0 -74
- package/build/types/metrics/web-vitals/types/lcp.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/ttfb.d.ts +0 -60
- package/build/types/metrics/web-vitals/types/ttfb.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types.d.ts +0 -78
- package/build/types/metrics/web-vitals/types.d.ts.map +0 -1
- package/build/types/metrics/webVitalSpans.d.ts.map +0 -1
- package/build/types-ts3.8/debug-build.d.ts +0 -7
- package/build/types-ts3.8/getNativeImplementation.d.ts +0 -69
- package/build/types-ts3.8/htmlTreeAsString.d.ts +0 -11
- package/build/types-ts3.8/index.d.ts +0 -17
- package/build/types-ts3.8/instrument/dom.d.ts +0 -11
- package/build/types-ts3.8/instrument/history.d.ts +0 -15
- package/build/types-ts3.8/instrument/location.d.ts +0 -13
- package/build/types-ts3.8/instrument/xhr.d.ts +0 -14
- package/build/types-ts3.8/is.d.ts +0 -7
- package/build/types-ts3.8/metrics/browserMetrics.d.ts +0 -119
- package/build/types-ts3.8/metrics/cls.d.ts +0 -17
- package/build/types-ts3.8/metrics/elementTiming.d.ts +0 -21
- package/build/types-ts3.8/metrics/inp.d.ts +0 -35
- package/build/types-ts3.8/metrics/instrument.d.ts +0 -121
- package/build/types-ts3.8/metrics/lcp.d.ts +0 -22
- package/build/types-ts3.8/metrics/resourceTiming.d.ts +0 -13
- package/build/types-ts3.8/metrics/utils.d.ts +0 -73
- package/build/types-ts3.8/metrics/web-vitals/getCLS.d.ts +0 -26
- package/build/types-ts3.8/metrics/web-vitals/getINP.d.ts +0 -34
- package/build/types-ts3.8/metrics/web-vitals/getLCP.d.ts +0 -16
- package/build/types-ts3.8/metrics/web-vitals/lib/InteractionManager.d.ts +0 -37
- package/build/types-ts3.8/metrics/web-vitals/lib/LCPEntryManager.d.ts +0 -5
- package/build/types-ts3.8/metrics/web-vitals/lib/LayoutShiftManager.d.ts +0 -7
- package/build/types-ts3.8/metrics/web-vitals/lib/bindReporter.d.ts +0 -7
- package/build/types-ts3.8/metrics/web-vitals/lib/generateUniqueID.d.ts +0 -7
- package/build/types-ts3.8/metrics/web-vitals/lib/getActivationStart.d.ts +0 -2
- package/build/types-ts3.8/metrics/web-vitals/lib/getNavigationEntry.d.ts +0 -2
- package/build/types-ts3.8/metrics/web-vitals/lib/getVisibilityWatcher.d.ts +0 -5
- package/build/types-ts3.8/metrics/web-vitals/lib/globalListeners.d.ts +0 -11
- package/build/types-ts3.8/metrics/web-vitals/lib/initMetric.d.ts +0 -21
- package/build/types-ts3.8/metrics/web-vitals/lib/initUnique.d.ts +0 -7
- package/build/types-ts3.8/metrics/web-vitals/lib/observe.d.ts +0 -23
- package/build/types-ts3.8/metrics/web-vitals/lib/onHidden.d.ts +0 -27
- package/build/types-ts3.8/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +0 -15
- package/build/types-ts3.8/metrics/web-vitals/lib/runOnce.d.ts +0 -2
- package/build/types-ts3.8/metrics/web-vitals/lib/whenActivated.d.ts +0 -2
- package/build/types-ts3.8/metrics/web-vitals/lib/whenIdleOrHidden.d.ts +0 -6
- package/build/types-ts3.8/metrics/web-vitals/onFCP.d.ts +0 -11
- package/build/types-ts3.8/metrics/web-vitals/onTTFB.d.ts +0 -20
- package/build/types-ts3.8/metrics/web-vitals/types/base.d.ts +0 -106
- package/build/types-ts3.8/metrics/web-vitals/types/cls.d.ts +0 -58
- package/build/types-ts3.8/metrics/web-vitals/types/fcp.d.ts +0 -47
- package/build/types-ts3.8/metrics/web-vitals/types/inp.d.ts +0 -150
- package/build/types-ts3.8/metrics/web-vitals/types/lcp.d.ts +0 -74
- package/build/types-ts3.8/metrics/web-vitals/types/ttfb.d.ts +0 -60
- package/build/types-ts3.8/metrics/web-vitals/types.d.ts +0 -78
- package/build/types-ts3.8/metrics/webVitalSpans.d.ts +0 -65
- package/build/types-ts3.8/networkUtils.d.ts +0 -28
- package/build/types-ts3.8/types.d.ts +0 -15
- /package/build/cjs/{instrument → instrumentation}/dom.js +0 -0
- /package/build/cjs/{instrument → instrumentation}/history.js +0 -0
- /package/build/cjs/{instrument → instrumentation}/location.js +0 -0
- /package/build/cjs/{instrument → instrumentation}/xhr.js +0 -0
- /package/build/cjs/{metrics → performance}/resourceTiming.js +0 -0
- /package/build/esm/{instrument → instrumentation}/dom.js +0 -0
- /package/build/esm/{instrument → instrumentation}/history.js +0 -0
- /package/build/esm/{instrument → instrumentation}/location.js +0 -0
- /package/build/esm/{instrument → instrumentation}/xhr.js +0 -0
- /package/build/esm/{metrics → performance}/resourceTiming.js +0 -0
- /package/build/types/{instrument → instrumentation}/dom.d.ts +0 -0
- /package/build/types/{instrument → instrumentation}/history.d.ts +0 -0
- /package/build/types/{instrument → instrumentation}/location.d.ts +0 -0
- /package/build/types/{instrument → instrumentation}/xhr.d.ts +0 -0
- /package/build/types/{metrics → performance}/elementTiming.d.ts +0 -0
- /package/build/types/{metrics → performance}/resourceTiming.d.ts +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"browserMetrics.js","sources":["../../../src/metrics/browserMetrics.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Measurements, Span, SpanAttributes, SpanAttributeValue, StartSpanOptions } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getComponentName,\n isPrimitive,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n setMeasurement,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport { trackClsAsStandaloneSpan } from './cls';\nimport {\n addClsInstrumentationHandler,\n addLcpInstrumentationHandler,\n addPerformanceInstrumentationHandler,\n addTtfbInstrumentationHandler,\n type PerformanceLongAnimationFrameTiming,\n} from './instrument';\nimport { isValidLcpMetric, trackLcpAsStandaloneSpan } from './lcp';\nimport { resourceTimingToSpanAttributes } from './resourceTiming';\nimport { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan } from './utils';\nimport { getActivationStart } from './web-vitals/lib/getActivationStart';\nimport { getNavigationEntry } from './web-vitals/lib/getNavigationEntry';\nimport { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { URL_FULL } from '@sentry/conventions/attributes';\ninterface NavigatorNetworkInformation {\n readonly connection?: NetworkInformation;\n}\n\n// http://wicg.github.io/netinfo/#connection-types\ntype ConnectionType = 'bluetooth' | 'cellular' | 'ethernet' | 'mixed' | 'none' | 'other' | 'unknown' | 'wifi' | 'wimax';\n\n// http://wicg.github.io/netinfo/#effectiveconnectiontype-enum\ntype EffectiveConnectionType = '2g' | '3g' | '4g' | 'slow-2g';\n\n// http://wicg.github.io/netinfo/#dom-megabit\ntype Megabit = number;\n// http://wicg.github.io/netinfo/#dom-millisecond\ntype Millisecond = number;\n\n// http://wicg.github.io/netinfo/#networkinformation-interface\ninterface NetworkInformation extends EventTarget {\n // http://wicg.github.io/netinfo/#type-attribute\n readonly type?: ConnectionType;\n // http://wicg.github.io/netinfo/#effectivetype-attribute\n readonly effectiveType?: EffectiveConnectionType;\n // http://wicg.github.io/netinfo/#downlinkmax-attribute\n readonly downlinkMax?: Megabit;\n // http://wicg.github.io/netinfo/#downlink-attribute\n readonly downlink?: Megabit;\n // http://wicg.github.io/netinfo/#rtt-attribute\n readonly rtt?: Millisecond;\n // http://wicg.github.io/netinfo/#savedata-attribute\n readonly saveData?: boolean;\n // http://wicg.github.io/netinfo/#handling-changes-to-the-underlying-connection\n onchange?: EventListener;\n}\n\n// https://w3c.github.io/device-memory/#sec-device-memory-js-api\ninterface NavigatorDeviceMemory {\n readonly deviceMemory?: number;\n}\n\nconst MAX_INT_AS_BYTES = 2147483647;\n\nlet _performanceCursor: number = 0;\n\nlet _measurements: Measurements = {};\nlet _lcpEntry: LargestContentfulPaint | undefined;\nlet _clsEntry: LayoutShift | undefined;\n\ninterface StartTrackingWebVitalsOptions {\n /**\n * When `true`, CLS is tracked as a standalone span. When `false`, CLS is\n * recorded as a measurement on the pageload span. When `undefined`, CLS\n * tracking is skipped entirely (e.g. because span streaming handles it).\n */\n recordClsStandaloneSpans: boolean | undefined;\n /**\n * When `true`, LCP is tracked as a standalone span. When `false`, LCP is\n * recorded as a measurement on the pageload span. When `undefined`, LCP\n * tracking is skipped entirely (e.g. because span streaming handles it).\n */\n recordLcpStandaloneSpans: boolean | undefined;\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 * @deprecated this function will be removed and streamlined once we stop supporting standalone v1\n * @returns A function that forces web vitals collection\n */\nexport function startTrackingWebVitals({\n recordClsStandaloneSpans,\n recordLcpStandaloneSpans,\n client,\n}: StartTrackingWebVitalsOptions): () => void {\n const performance = getBrowserPerformanceAPI();\n if (performance && browserPerformanceTimeOrigin()) {\n // @ts-expect-error we want to make sure all of these are available, even if TS is sure they are\n if (performance.mark) {\n WINDOW.performance.mark('sentry-tracing-init');\n }\n\n const lcpCleanupCallback = recordLcpStandaloneSpans\n ? trackLcpAsStandaloneSpan(client)\n : recordLcpStandaloneSpans === false\n ? _trackLCP()\n : undefined;\n\n const clsCleanupCallback = recordClsStandaloneSpans\n ? trackClsAsStandaloneSpan(client)\n : recordClsStandaloneSpans === false\n ? _trackCLS()\n : undefined;\n\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\n/**\n * Start tracking long tasks.\n */\nexport function startTrackingLongTasks(): void {\n addPerformanceInstrumentationHandler('longtask', ({ entries }) => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n\n const { op: parentOp, start_timestamp: parentStartTimestamp } = spanToJSON(parent);\n\n for (const entry of entries) {\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const duration = msToSec(entry.duration);\n\n if (parentOp === 'navigation' && parentStartTimestamp && startTime < parentStartTimestamp) {\n // Skip adding a span if the long task started before the navigation started.\n // `startAndEndSpan` will otherwise adjust the parent's start time to the span's start\n // time, potentially skewing the duration of the actual navigation as reported via our\n // routing instrumentations\n continue;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, {\n name: 'Main UI thread blocked',\n op: 'ui.long-task',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n }\n });\n}\n\n/**\n * Start tracking long animation frames.\n */\nexport function startTrackingLongAnimationFrames(): void {\n // NOTE: the current web-vitals version (3.5.2) does not support long-animation-frame, so\n // we directly observe `long-animation-frame` events instead of through the web-vitals\n // `observe` helper function.\n const observer = new PerformanceObserver(list => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n for (const entry of list.getEntries() as PerformanceLongAnimationFrameTiming[]) {\n if (!entry.scripts[0]) {\n continue;\n }\n\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n\n const { start_timestamp: parentStartTimestamp, op: parentOp } = spanToJSON(parent);\n\n if (parentOp === 'navigation' && parentStartTimestamp && startTime < parentStartTimestamp) {\n // Skip adding the span if the long animation frame started before the navigation started.\n // `startAndEndSpan` will otherwise adjust the parent's start time to the span's start\n // time, potentially skewing the duration of the actual navigation as reported via our\n // routing instrumentations\n continue;\n }\n const duration = msToSec(entry.duration);\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n };\n\n const initialScript = entry.scripts[0];\n const { invoker, invokerType, sourceURL, sourceFunctionName, sourceCharPosition } = initialScript;\n attributes['browser.script.invoker'] = invoker;\n attributes['browser.script.invoker_type'] = invokerType;\n if (sourceURL) {\n attributes['code.filepath'] = sourceURL;\n }\n if (sourceFunctionName) {\n attributes['code.function'] = sourceFunctionName;\n }\n if (sourceCharPosition !== -1) {\n attributes['browser.script.source_char_position'] = sourceCharPosition;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, {\n name: 'Main UI thread blocked',\n op: 'ui.long-animation-frame',\n attributes,\n });\n }\n });\n\n observer.observe({ type: 'long-animation-frame', buffered: true });\n}\n\n/**\n * Start tracking interaction events.\n */\nexport function startTrackingInteractions(): void {\n addPerformanceInstrumentationHandler('event', ({ entries }) => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n for (const entry of entries) {\n if (entry.name === 'click') {\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const duration = msToSec(entry.duration);\n\n const spanOptions: StartSpanOptions & Required<Pick<StartSpanOptions, 'attributes'>> = {\n name: htmlTreeAsString(entry.target),\n op: `ui.interaction.${entry.name}`,\n startTime: startTime,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n };\n\n const componentName = getComponentName(entry.target);\n if (componentName) {\n spanOptions.attributes['ui.component_name'] = componentName;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, spanOptions);\n }\n }\n });\n}\n\nexport { registerInpInteractionListener, startTrackingINP } 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 AddPerformanceEntriesOptions {\n /**\n * Resource spans with `op`s matching strings in the array will not be emitted.\n *\n * Default: []\n */\n ignoreResourceSpans: Array<'resouce.script' | 'resource.css' | 'resource.img' | 'resource.other' | string>;\n\n /**\n * Performance spans created from browser Performance APIs,\n * `performance.mark(...)` nand `performance.measure(...)`\n * with `name`s matching strings in the array will not be emitted.\n *\n * Default: []\n */\n ignorePerformanceApiSpans: Array<string | RegExp>;\n\n /**\n * Whether span streaming is enabled.\n */\n spanStreamingEnabled?: boolean;\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/** Add performance related spans to a transaction */\nexport function addPerformanceEntries(span: Span, options: AddPerformanceEntriesOptions): void {\n const performance = getBrowserPerformanceAPI();\n const origin = browserPerformanceTimeOrigin();\n if (!performance?.getEntries || !origin) {\n // Gatekeeper if performance API not available\n return;\n }\n\n const { spanStreamingEnabled, ignorePerformanceApiSpans, ignoreResourceSpans } = options;\n\n const timeOrigin = msToSec(origin);\n\n const performanceEntries = performance.getEntries();\n\n const { op, start_timestamp: transactionStartTime } = spanToJSON(span);\n\n performanceEntries.slice(_performanceCursor).forEach(entry => {\n const startTime = msToSec(entry.startTime);\n const duration = msToSec(\n // Inexplicably, Chrome sometimes emits a negative duration. We need to work around this.\n // There is a SO post attempting to explain this, but it leaves one with open questions: https://stackoverflow.com/questions/23191918/peformance-getentries-and-negative-duration-display\n // The way we clamp the value is probably not accurate, since we have observed this happen for things that may take a while to load, like for example the replay worker.\n // TODO: Investigate why this happens and how to properly mitigate. For now, this is a workaround to prevent transactions being dropped due to negative duration spans.\n Math.max(0, entry.duration),\n );\n\n if (op === 'navigation' && transactionStartTime && timeOrigin + startTime < transactionStartTime) {\n return;\n }\n\n switch (entry.entryType) {\n case 'navigation': {\n _addNavigationSpans(span, entry as PerformanceNavigationTiming, timeOrigin);\n break;\n }\n case 'mark':\n case 'paint':\n case 'measure': {\n _addMeasureSpans(span, entry, startTime, duration, timeOrigin, ignorePerformanceApiSpans);\n break;\n }\n case 'resource': {\n _addResourceSpans(\n span,\n entry as PerformanceResourceTiming,\n entry.name,\n startTime,\n duration,\n timeOrigin,\n ignoreResourceSpans,\n );\n break;\n }\n // Ignore other entry types.\n }\n });\n\n _performanceCursor = Math.max(performanceEntries.length - 1, 0);\n\n _trackNavigator(span, spanStreamingEnabled);\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).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 // TODO (V11): Remove this else branch once we remove v1 standalone spans and transactions\n\n // If CLS standalone spans are enabled, don't record CLS as a measurement\n if (!recordClsOnPageloadSpan) {\n delete _measurements.cls;\n }\n\n // If LCP standalone spans are enabled, 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/**\n * React 19.2+ creates performance.measure entries for component renders.\n * We can identify them by the `detail.devtools.track` property being set to 'Components ⚛'.\n * see: https://react.dev/reference/dev-tools/react-performance-tracks\n * see: https://github.com/facebook/react/blob/06fcc8f380c6a905c7bc18d94453f623cf8cbc81/packages/react-reconciler/src/ReactFiberPerformanceTrack.js#L454-L473\n */\nfunction isReact19MeasureEntry(entry: PerformanceEntry | null): boolean | void {\n if (entry?.entryType !== 'measure') {\n return;\n }\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return (entry as PerformanceMeasure).detail.devtools.track === 'Components ⚛';\n } catch {\n return;\n }\n}\n\n/**\n * Create measure related spans.\n * Exported only for tests.\n */\nexport function _addMeasureSpans(\n span: Span,\n entry: PerformanceEntry,\n startTime: number,\n duration: number,\n timeOrigin: number,\n ignorePerformanceApiSpans: AddPerformanceEntriesOptions['ignorePerformanceApiSpans'],\n): void {\n if (isReact19MeasureEntry(entry)) {\n return;\n }\n\n if (\n ['mark', 'measure'].includes(entry.entryType) &&\n stringMatchesSomePattern(entry.name, ignorePerformanceApiSpans)\n ) {\n return;\n }\n\n const navEntry = getNavigationEntry(false);\n\n const requestTime = msToSec(navEntry ? navEntry.requestStart : 0);\n // Because performance.measure accepts arbitrary timestamps it can produce\n // spans that happen before the browser even makes a request for the page.\n //\n // An example of this is the automatically generated Next.js-before-hydration\n // spans created by the Next.js framework.\n //\n // To prevent this we will pin the start timestamp to the request start time\n // This does make duration inaccurate, so if this does happen, we will add\n // an attribute to the span\n const measureStartTimestamp = timeOrigin + Math.max(startTime, requestTime);\n const startTimeStamp = timeOrigin + startTime;\n const measureEndTimestamp = startTimeStamp + duration;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',\n };\n\n if (measureStartTimestamp !== startTimeStamp) {\n attributes['sentry.browser.measure_happened_before_request'] = true;\n attributes['sentry.browser.measure_start_time'] = measureStartTimestamp;\n }\n\n _addDetailToSpanAttributes(attributes, entry as PerformanceMeasure);\n\n // Measurements from third parties can be off, which would create invalid spans, dropping transactions in the process.\n if (measureStartTimestamp <= measureEndTimestamp) {\n startAndEndSpan(span, measureStartTimestamp, measureEndTimestamp, {\n name: entry.name,\n op: entry.entryType,\n attributes,\n });\n }\n}\n\nfunction _addDetailToSpanAttributes(attributes: SpanAttributes, performanceMeasure: PerformanceMeasure): void {\n try {\n // Accessing detail might throw in some browsers (e.g., Firefox) due to security restrictions\n const detail = performanceMeasure.detail;\n\n if (!detail) {\n return;\n }\n\n // Process detail based on its type\n if (typeof detail === 'object') {\n // Handle object details\n for (const [key, value] of Object.entries(detail)) {\n if (value && isPrimitive(value)) {\n attributes[`sentry.browser.measure.detail.${key}`] = value as SpanAttributeValue;\n } else if (value !== undefined) {\n try {\n // This is user defined so we can't guarantee it's serializable\n attributes[`sentry.browser.measure.detail.${key}`] = JSON.stringify(value);\n } catch {\n // Skip values that can't be stringified\n }\n }\n }\n return;\n }\n\n if (isPrimitive(detail)) {\n // Handle primitive details\n attributes['sentry.browser.measure.detail'] = detail as SpanAttributeValue;\n return;\n }\n\n try {\n attributes['sentry.browser.measure.detail'] = JSON.stringify(detail);\n } catch {\n // Skip if stringification fails\n }\n } catch {\n // Silently ignore any errors when accessing detail\n // This handles the Firefox \"Permission denied to access object\" error\n }\n}\n\n/**\n * Instrument navigation entries\n * exported only for tests\n */\nexport function _addNavigationSpans(span: Span, entry: PerformanceNavigationTiming, timeOrigin: number): void {\n (['unloadEvent', 'redirect', 'domContentLoadedEvent', 'loadEvent', 'connect'] as const).forEach(event => {\n _addPerformanceNavigationTiming(span, entry, event, timeOrigin);\n });\n _addPerformanceNavigationTiming(span, entry, 'secureConnection', timeOrigin, 'TLS/SSL');\n _addPerformanceNavigationTiming(span, entry, 'fetch', timeOrigin, 'cache');\n _addPerformanceNavigationTiming(span, entry, 'domainLookup', timeOrigin, 'DNS');\n\n _addRequest(span, entry, timeOrigin);\n}\n\ntype StartEventName =\n | 'secureConnection'\n | 'fetch'\n | 'domainLookup'\n | 'unloadEvent'\n | 'redirect'\n | 'connect'\n | 'domContentLoadedEvent'\n | 'loadEvent';\n\ntype EndEventName =\n | 'domainLookupStart'\n | 'domainLookupEnd'\n | 'unloadEventEnd'\n | 'redirectEnd'\n | 'connectEnd'\n | 'domContentLoadedEventEnd'\n | 'loadEventEnd';\n\n/** Create performance navigation related spans */\nfunction _addPerformanceNavigationTiming(\n span: Span,\n entry: PerformanceNavigationTiming,\n event: StartEventName,\n timeOrigin: number,\n name: string = event,\n): void {\n const eventEnd = _getEndPropertyNameForNavigationTiming(event) satisfies keyof PerformanceNavigationTiming;\n const end = entry[eventEnd];\n const start = entry[`${event}Start`];\n if (!start || !end) {\n return;\n }\n startAndEndSpan(span, timeOrigin + msToSec(start), timeOrigin + msToSec(end), {\n op: `browser.${name}`,\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n ...(event === 'redirect' && entry.redirectCount != null ? { 'http.redirect_count': entry.redirectCount } : {}),\n },\n });\n}\n\nfunction _getEndPropertyNameForNavigationTiming(event: StartEventName): EndEventName {\n if (event === 'secureConnection') {\n return 'connectEnd';\n }\n if (event === 'fetch') {\n return 'domainLookupStart';\n }\n return `${event}End`;\n}\n\n/** Create request and response related spans */\nfunction _addRequest(span: Span, entry: PerformanceNavigationTiming, timeOrigin: number): void {\n const requestStartTimestamp = timeOrigin + msToSec(entry.requestStart);\n const responseEndTimestamp = timeOrigin + msToSec(entry.responseEnd);\n const responseStartTimestamp = timeOrigin + msToSec(entry.responseStart);\n if (entry.responseEnd) {\n // It is possible that we are collecting these metrics when the page hasn't finished loading yet, for example when the HTML slowly streams in.\n // In this case, ie. when the document request hasn't finished yet, `entry.responseEnd` will be 0.\n // In order not to produce faulty spans, where the end timestamp is before the start timestamp, we will only collect\n // these spans when the responseEnd value is available. The backend (Relay) would drop the entire span if it contained faulty spans.\n startAndEndSpan(span, requestStartTimestamp, responseEndTimestamp, {\n op: 'browser.request',\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n\n startAndEndSpan(span, responseStartTimestamp, responseEndTimestamp, {\n op: 'browser.response',\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n }\n}\n\n/**\n * Create resource-related spans.\n * Exported only for tests.\n */\nexport function _addResourceSpans(\n span: Span,\n entry: PerformanceResourceTiming,\n resourceUrl: string,\n startTime: number,\n duration: number,\n timeOrigin: number,\n ignoredResourceSpanOps?: Array<string>,\n): void {\n // we already instrument based on fetch and xhr, so we don't need to\n // duplicate spans here.\n if (entry.initiatorType === 'xmlhttprequest' || entry.initiatorType === 'fetch') {\n return;\n }\n\n const op = entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other';\n if (ignoredResourceSpanOps?.includes(op)) {\n return;\n }\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',\n };\n\n const parsedUrl = parseUrl(resourceUrl);\n\n if (parsedUrl.protocol) {\n attributes['url.scheme'] = parsedUrl.protocol.split(':').pop(); // the protocol returned by parseUrl includes a :, but OTEL spec does not, so we remove it.\n }\n\n if (parsedUrl.host) {\n attributes['server.address'] = parsedUrl.host;\n }\n\n attributes['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin);\n\n attributes[URL_FULL] = resourceUrl;\n\n _setResourceRequestAttributes(entry, attributes, [\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus\n ['responseStatus', 'http.response.status_code'],\n\n ['transferSize', 'http.response_transfer_size'],\n ['encodedBodySize', 'http.response_content_length'],\n ['decodedBodySize', 'http.decoded_response_content_length'],\n\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/renderBlockingStatus\n ['renderBlockingStatus', 'resource.render_blocking_status'],\n\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/deliveryType\n ['deliveryType', 'http.response_delivery_type'],\n ]);\n\n const attributesWithResourceTiming: SpanAttributes = { ...attributes, ...resourceTimingToSpanAttributes(entry) };\n\n const startTimestamp = timeOrigin + startTime;\n const endTimestamp = startTimestamp + duration;\n\n startAndEndSpan(span, startTimestamp, endTimestamp, {\n name: resourceUrl.replace(WINDOW.location.origin, ''),\n op,\n attributes: attributesWithResourceTiming,\n });\n}\n\n/**\n * Capture the information of the user agent.\n * TODO v11: Remove non-span-streaming attributes and measurements once we removed transactions\n */\nfunction _trackNavigator(span: Span, spanStreamingEnabled: boolean | undefined): void {\n const navigator = WINDOW.navigator as null | (Navigator & NavigatorNetworkInformation & NavigatorDeviceMemory);\n if (!navigator) {\n return;\n }\n\n // track network connectivity\n const connection = navigator.connection;\n if (connection) {\n if (connection.effectiveType) {\n span.setAttribute(\n spanStreamingEnabled ? 'network.connection.effective_type' : 'effectiveConnectionType',\n connection.effectiveType,\n );\n }\n\n if (connection.type) {\n span.setAttribute(spanStreamingEnabled ? 'network.connection.type' : 'connectionType', connection.type);\n }\n\n if (isMeasurementValue(connection.rtt)) {\n if (spanStreamingEnabled) {\n span.setAttribute('network.connection.rtt', connection.rtt);\n } else if (spanToJSON(span).op === 'pageload') {\n // Measurements are only recorded on the pageload span, matching the historical\n // behavior where `connection.rtt` was only flushed for pageload transactions.\n setMeasurement('connection.rtt', connection.rtt, 'millisecond');\n }\n }\n }\n\n if (isMeasurementValue(navigator.deviceMemory)) {\n if (spanStreamingEnabled) {\n span.setAttribute('device.memory.estimated_capacity', navigator.deviceMemory);\n } else {\n span.setAttribute('deviceMemory', `${navigator.deviceMemory} GB`);\n }\n }\n\n if (isMeasurementValue(navigator.hardwareConcurrency)) {\n if (spanStreamingEnabled) {\n span.setAttribute('device.processor_count', navigator.hardwareConcurrency);\n } else {\n span.setAttribute('hardwareConcurrency', String(navigator.hardwareConcurrency));\n }\n }\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\ntype ExperimentalResourceTimingProperty =\n | 'renderBlockingStatus'\n | 'deliveryType'\n // For some reason, TS during build, errors on `responseStatus` not being a property of\n // PerformanceResourceTiming while it actually is. Hence, we're adding it here.\n // Perhaps because response status is not yet available in Webkit/Safari.\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus\n | 'responseStatus';\n\n/**\n * Use this to set any attributes we can take directly form the PerformanceResourceTiming entry.\n *\n * This is just a mapping function for entry->attribute to keep bundle-size minimal.\n * Experimental properties are also accepted (see {@link ExperimentalResourceTimingProperty}).\n * Assumes that all entry properties might be undefined for browser-specific differences.\n * Only accepts string and number values for now and also sets 0-values.\n */\nexport function _setResourceRequestAttributes(\n entry: Partial<PerformanceResourceTiming> & Partial<Record<ExperimentalResourceTimingProperty, number | string>>,\n attributes: SpanAttributes,\n properties: [keyof PerformanceResourceTiming | ExperimentalResourceTimingProperty, string][],\n): void {\n properties.forEach(([entryKey, attributeKey]) => {\n const entryVal = entry[entryKey];\n if (\n entryVal != null &&\n ((typeof entryVal === 'number' && entryVal < MAX_INT_AS_BYTES) || typeof entryVal === 'string')\n ) {\n attributes[attributeKey] = entryVal;\n }\n });\n}\n\n/**\n * Add ttfb request time information to measurements.\n *\n * ttfb information is added via vendored 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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"}
|
package/build/esm/metrics/cls.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
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;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
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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"}
|
|
@@ -1 +0,0 @@
|
|
|
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":"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"}
|
package/build/esm/metrics/lcp.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resourceTiming.js","sources":["../../../src/metrics/resourceTiming.ts"],"sourcesContent":["import type { SpanAttributes } from '@sentry/core';\nimport { browserPerformanceTimeOrigin } from '@sentry/core';\nimport { extractNetworkProtocol, getBrowserPerformanceAPI } from './utils';\n\nfunction getAbsoluteTime(time: number | undefined): number | undefined {\n // falsy values should be preserved so that we can later on drop undefined values and\n // preserve 0 vals for cross-origin resources without proper `Timing-Allow-Origin` header.\n return time ? ((browserPerformanceTimeOrigin() || performance.timeOrigin) + time) / 1000 : time;\n}\n\n/**\n * Converts a PerformanceResourceTiming entry to span data for the resource span. Most importantly,\n * it converts the timing values from timestamps relative to the `performance.timeOrigin` to absolute timestamps\n * in seconds.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming#timestamps\n *\n * @param resourceTiming\n * @returns An array where the first element is the attribute name and the second element is the attribute value.\n */\nexport function resourceTimingToSpanAttributes(resourceTiming: PerformanceResourceTiming): SpanAttributes {\n const timingSpanData: SpanAttributes = {};\n // Checking for only `undefined` and `null` is intentional because it's\n // valid for `nextHopProtocol` to be an empty string.\n if (resourceTiming.nextHopProtocol != undefined) {\n const { name, version } = extractNetworkProtocol(resourceTiming.nextHopProtocol);\n timingSpanData['network.protocol.version'] = version;\n timingSpanData['network.protocol.name'] = name;\n }\n\n if (!(browserPerformanceTimeOrigin() || getBrowserPerformanceAPI()?.timeOrigin)) {\n return timingSpanData;\n }\n\n return dropUndefinedKeysFromObject({\n ...timingSpanData,\n\n 'http.request.redirect_start': getAbsoluteTime(resourceTiming.redirectStart),\n 'http.request.redirect_end': getAbsoluteTime(resourceTiming.redirectEnd),\n\n 'http.request.worker_start': getAbsoluteTime(resourceTiming.workerStart),\n\n 'http.request.fetch_start': getAbsoluteTime(resourceTiming.fetchStart),\n\n 'http.request.domain_lookup_start': getAbsoluteTime(resourceTiming.domainLookupStart),\n 'http.request.domain_lookup_end': getAbsoluteTime(resourceTiming.domainLookupEnd),\n\n 'http.request.connect_start': getAbsoluteTime(resourceTiming.connectStart),\n 'http.request.secure_connection_start': getAbsoluteTime(resourceTiming.secureConnectionStart),\n 'http.request.connection_end': getAbsoluteTime(resourceTiming.connectEnd),\n\n 'http.request.request_start': getAbsoluteTime(resourceTiming.requestStart),\n\n 'http.request.response_start': getAbsoluteTime(resourceTiming.responseStart),\n 'http.request.response_end': getAbsoluteTime(resourceTiming.responseEnd),\n\n // For TTFB we actually want the relative time from timeOrigin to responseStart\n // This way, TTFB always measures the \"first page load\" experience.\n // see: https://web.dev/articles/ttfb#measure-resource-requests\n 'http.request.time_to_first_byte':\n resourceTiming.responseStart != null ? resourceTiming.responseStart / 1000 : undefined,\n });\n}\n\n/**\n * Remove properties with `undefined` as value from an object.\n * In contrast to `dropUndefinedKeys` in core this funciton only works on first-level\n * key-value objects and does not recursively go into object properties or arrays.\n */\nfunction dropUndefinedKeysFromObject<T extends object>(attrs: T): Partial<T> {\n return Object.fromEntries(Object.entries(attrs).filter(([, value]) => value != null)) as Partial<T>;\n}\n"],"names":[],"mappings":";;;AAIA,SAAS,gBAAgB,IAAA,EAA8C;AAGrE,EAAA,OAAO,SAAS,4BAAA,EAA6B,IAAK,WAAA,CAAY,UAAA,IAAc,QAAQ,GAAA,GAAO,IAAA;AAC7F;AAYO,SAAS,+BAA+B,cAAA,EAA2D;AACxG,EAAA,MAAM,iBAAiC,EAAC;AAGxC,EAAA,IAAI,cAAA,CAAe,mBAAmB,MAAA,EAAW;AAC/C,IAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAQ,GAAI,sBAAA,CAAuB,eAAe,eAAe,CAAA;AAC/E,IAAA,cAAA,CAAe,0BAA0B,CAAA,GAAI,OAAA;AAC7C,IAAA,cAAA,CAAe,uBAAuB,CAAA,GAAI,IAAA;AAAA,EAC5C;AAEA,EAAA,IAAI,EAAE,4BAAA,EAA6B,IAAK,wBAAA,IAA4B,UAAA,CAAA,EAAa;AAC/E,IAAA,OAAO,cAAA;AAAA,EACT;AAEA,EAAA,OAAO,2BAAA,CAA4B;AAAA,IACjC,GAAG,cAAA;AAAA,IAEH,6BAAA,EAA+B,eAAA,CAAgB,cAAA,CAAe,aAAa,CAAA;AAAA,IAC3E,2BAAA,EAA6B,eAAA,CAAgB,cAAA,CAAe,WAAW,CAAA;AAAA,IAEvE,2BAAA,EAA6B,eAAA,CAAgB,cAAA,CAAe,WAAW,CAAA;AAAA,IAEvE,0BAAA,EAA4B,eAAA,CAAgB,cAAA,CAAe,UAAU,CAAA;AAAA,IAErE,kCAAA,EAAoC,eAAA,CAAgB,cAAA,CAAe,iBAAiB,CAAA;AAAA,IACpF,gCAAA,EAAkC,eAAA,CAAgB,cAAA,CAAe,eAAe,CAAA;AAAA,IAEhF,4BAAA,EAA8B,eAAA,CAAgB,cAAA,CAAe,YAAY,CAAA;AAAA,IACzE,sCAAA,EAAwC,eAAA,CAAgB,cAAA,CAAe,qBAAqB,CAAA;AAAA,IAC5F,6BAAA,EAA+B,eAAA,CAAgB,cAAA,CAAe,UAAU,CAAA;AAAA,IAExE,4BAAA,EAA8B,eAAA,CAAgB,cAAA,CAAe,YAAY,CAAA;AAAA,IAEzE,6BAAA,EAA+B,eAAA,CAAgB,cAAA,CAAe,aAAa,CAAA;AAAA,IAC3E,2BAAA,EAA6B,eAAA,CAAgB,cAAA,CAAe,WAAW,CAAA;AAAA;AAAA;AAAA;AAAA,IAKvE,mCACE,cAAA,CAAe,aAAA,IAAiB,IAAA,GAAO,cAAA,CAAe,gBAAgB,GAAA,GAAO;AAAA,GAChF,CAAA;AACH;AAOA,SAAS,4BAA8C,KAAA,EAAsB;AAC3E,EAAA,OAAO,MAAA,CAAO,WAAA,CAAY,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,MAAA,CAAO,CAAC,GAAG,KAAK,CAAA,KAAM,KAAA,IAAS,IAAI,CAAC,CAAA;AACtF;;;;"}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { spanToJSON, withActiveSpan, startInactiveSpan, getClient, getCurrentScope } from '@sentry/core';
|
|
2
|
-
import { WINDOW } from '../types.js';
|
|
3
|
-
import { onHidden } from './web-vitals/lib/onHidden.js';
|
|
4
|
-
|
|
5
|
-
function isMeasurementValue(value) {
|
|
6
|
-
return typeof value === "number" && isFinite(value);
|
|
7
|
-
}
|
|
8
|
-
function startAndEndSpan(parentSpan, startTimeInSeconds, endTime, { ...ctx }) {
|
|
9
|
-
const parentStartTime = spanToJSON(parentSpan).start_timestamp;
|
|
10
|
-
if (parentStartTime && parentStartTime > startTimeInSeconds) {
|
|
11
|
-
if (typeof parentSpan.updateStartTime === "function") {
|
|
12
|
-
parentSpan.updateStartTime(startTimeInSeconds);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return withActiveSpan(parentSpan, () => {
|
|
16
|
-
const span = startInactiveSpan({
|
|
17
|
-
startTime: startTimeInSeconds,
|
|
18
|
-
...ctx
|
|
19
|
-
});
|
|
20
|
-
if (span) {
|
|
21
|
-
span.end(endTime);
|
|
22
|
-
}
|
|
23
|
-
return span;
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
function startStandaloneWebVitalSpan(options) {
|
|
27
|
-
const client = getClient();
|
|
28
|
-
if (!client) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
const { name, transaction, attributes: passedAttributes, startTime } = options;
|
|
32
|
-
const { release, environment } = client.getOptions();
|
|
33
|
-
const { userInfo } = client.getDataCollectionOptions();
|
|
34
|
-
const replay = client.getIntegrationByName("Replay");
|
|
35
|
-
const replayId = replay?.getReplayId();
|
|
36
|
-
const scope = getCurrentScope();
|
|
37
|
-
const user = scope.getUser();
|
|
38
|
-
const userDisplay = user !== void 0 ? user.email || user.id || user.ip_address : void 0;
|
|
39
|
-
let profileId;
|
|
40
|
-
try {
|
|
41
|
-
profileId = scope.getScopeData().contexts.profile.profile_id;
|
|
42
|
-
} catch {
|
|
43
|
-
}
|
|
44
|
-
const attributes = {
|
|
45
|
-
release,
|
|
46
|
-
environment,
|
|
47
|
-
user: userDisplay || void 0,
|
|
48
|
-
profile_id: profileId || void 0,
|
|
49
|
-
replay_id: replayId || void 0,
|
|
50
|
-
transaction,
|
|
51
|
-
// Web vital score calculation relies on the user agent to account for different
|
|
52
|
-
// browsers setting different thresholds for what is considered a good/meh/bad value.
|
|
53
|
-
// For example: Chrome vs. Chrome Mobile
|
|
54
|
-
"user_agent.original": WINDOW.navigator?.userAgent,
|
|
55
|
-
// This tells Sentry to infer the IP address from the request
|
|
56
|
-
"client.address": userInfo ? "{{auto}}" : void 0,
|
|
57
|
-
...passedAttributes
|
|
58
|
-
};
|
|
59
|
-
return startInactiveSpan({
|
|
60
|
-
name,
|
|
61
|
-
attributes,
|
|
62
|
-
startTime,
|
|
63
|
-
experimental: {
|
|
64
|
-
standalone: true
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
function getBrowserPerformanceAPI() {
|
|
69
|
-
return WINDOW.addEventListener && WINDOW.performance;
|
|
70
|
-
}
|
|
71
|
-
function msToSec(time) {
|
|
72
|
-
return time / 1e3;
|
|
73
|
-
}
|
|
74
|
-
function extractNetworkProtocol(nextHopProtocol) {
|
|
75
|
-
let name = "unknown";
|
|
76
|
-
let version = "unknown";
|
|
77
|
-
let _name = "";
|
|
78
|
-
for (const char of nextHopProtocol) {
|
|
79
|
-
if (char === "/") {
|
|
80
|
-
[name, version] = nextHopProtocol.split("/");
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
if (!isNaN(Number(char))) {
|
|
84
|
-
name = _name === "h" ? "http" : _name;
|
|
85
|
-
version = nextHopProtocol.split(_name)[1];
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
_name += char;
|
|
89
|
-
}
|
|
90
|
-
if (_name === nextHopProtocol) {
|
|
91
|
-
name = _name;
|
|
92
|
-
}
|
|
93
|
-
return { name, version };
|
|
94
|
-
}
|
|
95
|
-
function supportsWebVital(entryType) {
|
|
96
|
-
try {
|
|
97
|
-
return PerformanceObserver.supportedEntryTypes.includes(entryType);
|
|
98
|
-
} catch {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
function listenForWebVitalReportEvents(client, collectorCallback) {
|
|
103
|
-
let pageloadSpan;
|
|
104
|
-
let collected = false;
|
|
105
|
-
function _runCollectorCallbackOnce(event) {
|
|
106
|
-
if (!collected && pageloadSpan) {
|
|
107
|
-
collectorCallback(event, pageloadSpan.spanContext().spanId, pageloadSpan);
|
|
108
|
-
}
|
|
109
|
-
collected = true;
|
|
110
|
-
}
|
|
111
|
-
onHidden(() => {
|
|
112
|
-
_runCollectorCallbackOnce("pagehide");
|
|
113
|
-
});
|
|
114
|
-
const unsubscribeStartNavigation = client.on("beforeStartNavigationSpan", (_, options) => {
|
|
115
|
-
if (!options?.isRedirect) {
|
|
116
|
-
_runCollectorCallbackOnce("navigation");
|
|
117
|
-
unsubscribeStartNavigation();
|
|
118
|
-
unsubscribeAfterStartPageLoadSpan();
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
const unsubscribeAfterStartPageLoadSpan = client.on("afterStartPageLoadSpan", (span) => {
|
|
122
|
-
pageloadSpan = span;
|
|
123
|
-
unsubscribeAfterStartPageLoadSpan();
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export { extractNetworkProtocol, getBrowserPerformanceAPI, isMeasurementValue, listenForWebVitalReportEvents, msToSec, startAndEndSpan, startStandaloneWebVitalSpan, supportsWebVital };
|
|
128
|
-
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../src/metrics/utils.ts"],"sourcesContent":["import type {\n Client,\n Integration,\n SentrySpan,\n Span,\n SpanAttributes,\n SpanTimeInput,\n StartSpanOptions,\n} from '@sentry/core';\nimport { getClient, getCurrentScope, spanToJSON, startInactiveSpan, withActiveSpan } from '@sentry/core';\nimport { WINDOW } from '../types';\nimport { onHidden } from './web-vitals/lib/onHidden';\n\nexport type WebVitalReportEvent = 'pagehide' | 'navigation';\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 = spanToJSON(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\ninterface StandaloneWebVitalSpanOptions {\n name: string;\n transaction?: string;\n attributes: SpanAttributes;\n startTime: number;\n}\n\n/**\n * Starts an inactive, standalone span used to send web vital values to Sentry.\n * DO NOT use this for arbitrary spans, as these spans require special handling\n * during ingestion to extract metrics.\n *\n * This function adds a bunch of attributes and data to the span that's shared\n * by all web vital standalone spans. However, you need to take care of adding\n * the actual web vital value as an event to the span. Also, you need to assign\n * a transaction name and some other values that are specific to the web vital.\n *\n * Ultimately, you also need to take care of ending the span to send it off.\n *\n * @param options\n *\n * @returns an inactive, standalone and NOT YET ended span\n */\nexport function startStandaloneWebVitalSpan(options: StandaloneWebVitalSpanOptions): Span | undefined {\n const client = getClient();\n if (!client) {\n return;\n }\n\n const { name, transaction, attributes: passedAttributes, startTime } = options;\n\n const { release, environment } = client.getOptions();\n const { userInfo } = client.getDataCollectionOptions();\n // We need to get the replay, user, and activeTransaction from the current scope\n // so that we can associate replay id, profile id, and a user display to the span\n const replay = client.getIntegrationByName<Integration & { getReplayId: () => string }>('Replay');\n const replayId = replay?.getReplayId();\n\n const scope = getCurrentScope();\n\n const user = scope.getUser();\n const userDisplay = user !== undefined ? user.email || user.id || user.ip_address : undefined;\n\n let profileId: string | undefined;\n try {\n // @ts-expect-error skip optional chaining to save bundle size with try catch\n profileId = scope.getScopeData().contexts.profile.profile_id;\n } catch {\n // do nothing\n }\n\n const attributes: SpanAttributes = {\n release,\n environment,\n\n user: userDisplay || undefined,\n profile_id: profileId || undefined,\n replay_id: replayId || undefined,\n\n transaction,\n\n // Web vital score calculation relies on the user agent to account for different\n // browsers setting different thresholds for what is considered a good/meh/bad value.\n // For example: Chrome vs. Chrome Mobile\n 'user_agent.original': WINDOW.navigator?.userAgent,\n\n // This tells Sentry to infer the IP address from the request\n 'client.address': userInfo ? '{{auto}}' : undefined,\n\n ...passedAttributes,\n };\n\n return startInactiveSpan({\n name,\n attributes,\n startTime,\n experimental: {\n standalone: true,\n },\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\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 // eslint-disable-next-line typescript/no-deprecated\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":"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"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { WINDOW } from '../../types.js';
|
|
2
|
-
import { bindReporter } from './lib/bindReporter.js';
|
|
3
|
-
import { getVisibilityWatcher } from './lib/getVisibilityWatcher.js';
|
|
4
|
-
import { initMetric } from './lib/initMetric.js';
|
|
5
|
-
import { initUnique } from './lib/initUnique.js';
|
|
6
|
-
import { LayoutShiftManager } from './lib/LayoutShiftManager.js';
|
|
7
|
-
import { observe } from './lib/observe.js';
|
|
8
|
-
import { runOnce } from './lib/runOnce.js';
|
|
9
|
-
import { onFCP } from './onFCP.js';
|
|
10
|
-
|
|
11
|
-
const CLSThresholds = [0.1, 0.25];
|
|
12
|
-
const onCLS = (onReport, opts = {}) => {
|
|
13
|
-
onFCP(
|
|
14
|
-
runOnce(() => {
|
|
15
|
-
const metric = initMetric("CLS", 0);
|
|
16
|
-
let report;
|
|
17
|
-
const visibilityWatcher = getVisibilityWatcher();
|
|
18
|
-
const layoutShiftManager = initUnique(opts, LayoutShiftManager);
|
|
19
|
-
const handleEntries = (entries) => {
|
|
20
|
-
for (const entry of entries) {
|
|
21
|
-
layoutShiftManager._processEntry(entry);
|
|
22
|
-
}
|
|
23
|
-
if (layoutShiftManager._sessionValue > metric.value) {
|
|
24
|
-
metric.value = layoutShiftManager._sessionValue;
|
|
25
|
-
metric.entries = layoutShiftManager._sessionEntries;
|
|
26
|
-
report();
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
const po = observe("layout-shift", handleEntries);
|
|
30
|
-
if (po) {
|
|
31
|
-
report = bindReporter(onReport, metric, CLSThresholds, opts.reportAllChanges);
|
|
32
|
-
visibilityWatcher.onHidden(() => {
|
|
33
|
-
handleEntries(po.takeRecords());
|
|
34
|
-
report(true);
|
|
35
|
-
});
|
|
36
|
-
WINDOW?.setTimeout?.(report);
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export { CLSThresholds, onCLS };
|
|
43
|
-
//# sourceMappingURL=getCLS.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getCLS.js","sources":["../../../../src/metrics/web-vitals/getCLS.ts"],"sourcesContent":["/*\n * Copyright 2020 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';\nimport { bindReporter } from './lib/bindReporter';\nimport { getVisibilityWatcher } from './lib/getVisibilityWatcher';\nimport { initMetric } from './lib/initMetric';\nimport { initUnique } from './lib/initUnique';\nimport { LayoutShiftManager } from './lib/LayoutShiftManager';\nimport { observe } from './lib/observe';\nimport { runOnce } from './lib/runOnce';\nimport { onFCP } from './onFCP';\nimport type { CLSMetric, MetricRatingThresholds, ReportOpts } from './types';\n\n/** Thresholds for CLS. See https://web.dev/articles/cls#what_is_a_good_cls_score */\nexport const CLSThresholds: MetricRatingThresholds = [0.1, 0.25];\n\n/**\n * Calculates the [CLS](https://web.dev/articles/cls) value for the current page and\n * calls the `callback` function once the value is ready to be reported, along\n * with all `layout-shift` performance entries that were used in the metric\n * value calculation. The reported value is a `double` (corresponding to a\n * [layout shift score](https://web.dev/articles/cls#layout_shift_score)).\n *\n * If the `reportAllChanges` configuration option is set to `true`, the\n * `callback` function will be called as soon as the value is initially\n * determined as well as any time the value changes throughout the page\n * lifespan.\n *\n * _**Important:** CLS should be continually monitored for changes throughout\n * the entire lifespan of a page—including if the user returns to the page after\n * it's been hidden/backgrounded. However, since browsers often [will not fire\n * additional callbacks once the user has backgrounded a\n * page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden),\n * `callback` is always called when the page's visibility state changes to\n * hidden. As a result, the `callback` function might be called multiple times\n * during the same page load._\n */\nexport const onCLS = (onReport: (metric: CLSMetric) => void, opts: ReportOpts = {}) => {\n // Start monitoring FCP so we can only report CLS if FCP is also reported.\n // Note: this is done to match the current behavior of CrUX.\n onFCP(\n runOnce(() => {\n const metric = initMetric('CLS', 0);\n let report: ReturnType<typeof bindReporter>;\n const visibilityWatcher = getVisibilityWatcher();\n\n const layoutShiftManager = initUnique(opts, LayoutShiftManager);\n\n const handleEntries = (entries: LayoutShift[]) => {\n for (const entry of entries) {\n layoutShiftManager._processEntry(entry);\n }\n\n // If the current session value is larger than the current CLS value,\n // update CLS and the entries contributing to it.\n if (layoutShiftManager._sessionValue > metric.value) {\n metric.value = layoutShiftManager._sessionValue;\n metric.entries = layoutShiftManager._sessionEntries;\n report();\n }\n };\n\n const po = observe('layout-shift', handleEntries);\n if (po) {\n report = bindReporter(onReport, metric, CLSThresholds, opts.reportAllChanges);\n\n visibilityWatcher.onHidden(() => {\n handleEntries(po.takeRecords() as CLSMetric['entries']);\n report(true);\n });\n\n // Queue a task to report (if nothing else triggers a report first).\n // This allows CLS to be reported as soon as FCP fires when\n // `reportAllChanges` is true.\n WINDOW?.setTimeout?.(report);\n }\n }),\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;AA4BO,MAAM,aAAA,GAAwC,CAAC,GAAA,EAAK,IAAI;AAuBxD,MAAM,KAAA,GAAQ,CAAC,QAAA,EAAuC,IAAA,GAAmB,EAAC,KAAM;AAGrF,EAAA,KAAA;AAAA,IACE,QAAQ,MAAM;AACZ,MAAA,MAAM,MAAA,GAAS,UAAA,CAAW,KAAA,EAAO,CAAC,CAAA;AAClC,MAAA,IAAI,MAAA;AACJ,MAAA,MAAM,oBAAoB,oBAAA,EAAqB;AAE/C,MAAA,MAAM,kBAAA,GAAqB,UAAA,CAAW,IAAA,EAAM,kBAAkB,CAAA;AAE9D,MAAA,MAAM,aAAA,GAAgB,CAAC,OAAA,KAA2B;AAChD,QAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,UAAA,kBAAA,CAAmB,cAAc,KAAK,CAAA;AAAA,QACxC;AAIA,QAAA,IAAI,kBAAA,CAAmB,aAAA,GAAgB,MAAA,CAAO,KAAA,EAAO;AACnD,UAAA,MAAA,CAAO,QAAQ,kBAAA,CAAmB,aAAA;AAClC,UAAA,MAAA,CAAO,UAAU,kBAAA,CAAmB,eAAA;AACpC,UAAA,MAAA,EAAO;AAAA,QACT;AAAA,MACF,CAAA;AAEA,MAAA,MAAM,EAAA,GAAK,OAAA,CAAQ,cAAA,EAAgB,aAAa,CAAA;AAChD,MAAA,IAAI,EAAA,EAAI;AACN,QAAA,MAAA,GAAS,YAAA,CAAa,QAAA,EAAU,MAAA,EAAQ,aAAA,EAAe,KAAK,gBAAgB,CAAA;AAE5E,QAAA,iBAAA,CAAkB,SAAS,MAAM;AAC/B,UAAA,aAAA,CAAc,EAAA,CAAG,aAAqC,CAAA;AACtD,UAAA,MAAA,CAAO,IAAI,CAAA;AAAA,QACb,CAAC,CAAA;AAKD,QAAA,MAAA,EAAQ,aAAa,MAAM,CAAA;AAAA,MAC7B;AAAA,IACF,CAAC;AAAA,GACH;AACF;;;;"}
|