@sentry/browser-utils 10.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +23 -0
- package/build/cjs/debug-build.js +6 -0
- package/build/cjs/debug-build.js.map +1 -0
- package/build/cjs/getNativeImplementation.js +51 -0
- package/build/cjs/getNativeImplementation.js.map +1 -0
- package/build/cjs/htmlTreeAsString.js +110 -0
- package/build/cjs/htmlTreeAsString.js.map +1 -0
- package/build/cjs/index.js +54 -0
- package/build/cjs/index.js.map +1 -0
- package/build/cjs/instrument/dom.js +137 -0
- package/build/cjs/instrument/dom.js.map +1 -0
- package/build/cjs/instrument/history.js +56 -0
- package/build/cjs/instrument/history.js.map +1 -0
- package/build/cjs/instrument/xhr.js +108 -0
- package/build/cjs/instrument/xhr.js.map +1 -0
- package/build/cjs/is.js +15 -0
- package/build/cjs/is.js.map +1 -0
- package/build/cjs/metrics/browserMetrics.js +535 -0
- package/build/cjs/metrics/browserMetrics.js.map +1 -0
- package/build/cjs/metrics/cls.js +64 -0
- package/build/cjs/metrics/cls.js.map +1 -0
- package/build/cjs/metrics/elementTiming.js +72 -0
- package/build/cjs/metrics/elementTiming.js.map +1 -0
- package/build/cjs/metrics/inp.js +170 -0
- package/build/cjs/metrics/inp.js.map +1 -0
- package/build/cjs/metrics/instrument.js +152 -0
- package/build/cjs/metrics/instrument.js.map +1 -0
- package/build/cjs/metrics/lcp.js +77 -0
- package/build/cjs/metrics/lcp.js.map +1 -0
- package/build/cjs/metrics/resourceTiming.js +44 -0
- package/build/cjs/metrics/resourceTiming.js.map +1 -0
- package/build/cjs/metrics/utils.js +137 -0
- package/build/cjs/metrics/utils.js.map +1 -0
- package/build/cjs/metrics/web-vitals/getCLS.js +46 -0
- package/build/cjs/metrics/web-vitals/getCLS.js.map +1 -0
- package/build/cjs/metrics/web-vitals/getINP.js +60 -0
- package/build/cjs/metrics/web-vitals/getINP.js.map +1 -0
- package/build/cjs/metrics/web-vitals/getLCP.js +62 -0
- package/build/cjs/metrics/web-vitals/getLCP.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/InteractionManager.js +87 -0
- package/build/cjs/metrics/web-vitals/lib/InteractionManager.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js +11 -0
- package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js +27 -0
- package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/bindReporter.js +31 -0
- package/build/cjs/metrics/web-vitals/lib/bindReporter.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js +8 -0
- package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/getActivationStart.js +11 -0
- package/build/cjs/metrics/web-vitals/lib/getActivationStart.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js +17 -0
- package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js +48 -0
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/globalListeners.js +18 -0
- package/build/cjs/metrics/web-vitals/lib/globalListeners.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/initMetric.js +34 -0
- package/build/cjs/metrics/web-vitals/lib/initMetric.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/initUnique.js +16 -0
- package/build/cjs/metrics/web-vitals/lib/initUnique.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/observe.js +20 -0
- package/build/cjs/metrics/web-vitals/lib/observe.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/onHidden.js +17 -0
- package/build/cjs/metrics/web-vitals/lib/onHidden.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +32 -0
- package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/runOnce.js +14 -0
- package/build/cjs/metrics/web-vitals/lib/runOnce.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/whenActivated.js +14 -0
- package/build/cjs/metrics/web-vitals/lib/whenActivated.js.map +1 -0
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js +24 -0
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js.map +1 -0
- package/build/cjs/metrics/web-vitals/onFCP.js +37 -0
- package/build/cjs/metrics/web-vitals/onFCP.js.map +1 -0
- package/build/cjs/metrics/web-vitals/onTTFB.js +35 -0
- package/build/cjs/metrics/web-vitals/onTTFB.js.map +1 -0
- package/build/cjs/metrics/webVitalSpans.js +199 -0
- package/build/cjs/metrics/webVitalSpans.js.map +1 -0
- package/build/cjs/networkUtils.js +70 -0
- package/build/cjs/networkUtils.js.map +1 -0
- package/build/cjs/types.js +8 -0
- package/build/cjs/types.js.map +1 -0
- package/build/esm/debug-build.js +4 -0
- package/build/esm/debug-build.js.map +1 -0
- package/build/esm/getNativeImplementation.js +46 -0
- package/build/esm/getNativeImplementation.js.map +1 -0
- package/build/esm/htmlTreeAsString.js +108 -0
- package/build/esm/htmlTreeAsString.js.map +1 -0
- package/build/esm/index.js +15 -0
- package/build/esm/index.js.map +1 -0
- package/build/esm/instrument/dom.js +134 -0
- package/build/esm/instrument/dom.js.map +1 -0
- package/build/esm/instrument/history.js +53 -0
- package/build/esm/instrument/history.js.map +1 -0
- package/build/esm/instrument/xhr.js +104 -0
- package/build/esm/instrument/xhr.js.map +1 -0
- package/build/esm/is.js +13 -0
- package/build/esm/is.js.map +1 -0
- package/build/esm/metrics/browserMetrics.js +524 -0
- package/build/esm/metrics/browserMetrics.js.map +1 -0
- package/build/esm/metrics/cls.js +61 -0
- package/build/esm/metrics/cls.js.map +1 -0
- package/build/esm/metrics/elementTiming.js +69 -0
- package/build/esm/metrics/elementTiming.js.map +1 -0
- package/build/esm/metrics/inp.js +162 -0
- package/build/esm/metrics/inp.js.map +1 -0
- package/build/esm/metrics/instrument.js +145 -0
- package/build/esm/metrics/instrument.js.map +1 -0
- package/build/esm/metrics/lcp.js +72 -0
- package/build/esm/metrics/lcp.js.map +1 -0
- package/build/esm/metrics/resourceTiming.js +42 -0
- package/build/esm/metrics/resourceTiming.js.map +1 -0
- package/build/esm/metrics/utils.js +128 -0
- package/build/esm/metrics/utils.js.map +1 -0
- package/build/esm/metrics/web-vitals/getCLS.js +43 -0
- package/build/esm/metrics/web-vitals/getCLS.js.map +1 -0
- package/build/esm/metrics/web-vitals/getINP.js +57 -0
- package/build/esm/metrics/web-vitals/getINP.js.map +1 -0
- package/build/esm/metrics/web-vitals/getLCP.js +59 -0
- package/build/esm/metrics/web-vitals/getLCP.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/InteractionManager.js +85 -0
- package/build/esm/metrics/web-vitals/lib/InteractionManager.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js +9 -0
- package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js +25 -0
- package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/bindReporter.js +29 -0
- package/build/esm/metrics/web-vitals/lib/bindReporter.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/generateUniqueID.js +6 -0
- package/build/esm/metrics/web-vitals/lib/generateUniqueID.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/getActivationStart.js +9 -0
- package/build/esm/metrics/web-vitals/lib/getActivationStart.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js +15 -0
- package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js +46 -0
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/globalListeners.js +15 -0
- package/build/esm/metrics/web-vitals/lib/globalListeners.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/initMetric.js +32 -0
- package/build/esm/metrics/web-vitals/lib/initMetric.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/initUnique.js +14 -0
- package/build/esm/metrics/web-vitals/lib/initUnique.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/observe.js +18 -0
- package/build/esm/metrics/web-vitals/lib/observe.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/onHidden.js +15 -0
- package/build/esm/metrics/web-vitals/lib/onHidden.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +29 -0
- package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/runOnce.js +12 -0
- package/build/esm/metrics/web-vitals/lib/runOnce.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/whenActivated.js +12 -0
- package/build/esm/metrics/web-vitals/lib/whenActivated.js.map +1 -0
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js +22 -0
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js.map +1 -0
- package/build/esm/metrics/web-vitals/onFCP.js +34 -0
- package/build/esm/metrics/web-vitals/onFCP.js.map +1 -0
- package/build/esm/metrics/web-vitals/onTTFB.js +32 -0
- package/build/esm/metrics/web-vitals/onTTFB.js.map +1 -0
- package/build/esm/metrics/webVitalSpans.js +191 -0
- package/build/esm/metrics/webVitalSpans.js.map +1 -0
- package/build/esm/networkUtils.js +64 -0
- package/build/esm/networkUtils.js.map +1 -0
- package/build/esm/package.json +1 -0
- package/build/esm/types.js +6 -0
- package/build/esm/types.js.map +1 -0
- package/build/types/debug-build.d.ts +7 -0
- package/build/types/debug-build.d.ts.map +1 -0
- package/build/types/getNativeImplementation.d.ts +69 -0
- package/build/types/getNativeImplementation.d.ts.map +1 -0
- package/build/types/htmlTreeAsString.d.ts +11 -0
- package/build/types/htmlTreeAsString.d.ts.map +1 -0
- package/build/types/index.d.ts +15 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/instrument/dom.d.ts +11 -0
- package/build/types/instrument/dom.d.ts.map +1 -0
- package/build/types/instrument/history.d.ts +15 -0
- package/build/types/instrument/history.d.ts.map +1 -0
- package/build/types/instrument/xhr.d.ts +14 -0
- package/build/types/instrument/xhr.d.ts.map +1 -0
- package/build/types/is.d.ts +7 -0
- package/build/types/is.d.ts.map +1 -0
- package/build/types/metrics/browserMetrics.d.ts +116 -0
- package/build/types/metrics/browserMetrics.d.ts.map +1 -0
- package/build/types/metrics/cls.d.ts +17 -0
- package/build/types/metrics/cls.d.ts.map +1 -0
- package/build/types/metrics/elementTiming.d.ts +19 -0
- package/build/types/metrics/elementTiming.d.ts.map +1 -0
- package/build/types/metrics/inp.d.ts +35 -0
- package/build/types/metrics/inp.d.ts.map +1 -0
- package/build/types/metrics/instrument.d.ts +121 -0
- package/build/types/metrics/instrument.d.ts.map +1 -0
- package/build/types/metrics/lcp.d.ts +22 -0
- package/build/types/metrics/lcp.d.ts.map +1 -0
- package/build/types/metrics/resourceTiming.d.ts +13 -0
- package/build/types/metrics/resourceTiming.d.ts.map +1 -0
- package/build/types/metrics/utils.d.ts +73 -0
- package/build/types/metrics/utils.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/getCLS.d.ts +26 -0
- package/build/types/metrics/web-vitals/getCLS.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/getINP.d.ts +34 -0
- package/build/types/metrics/web-vitals/getINP.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/getLCP.d.ts +16 -0
- package/build/types/metrics/web-vitals/getLCP.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts +37 -0
- package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts +5 -0
- package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts +7 -0
- package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts +7 -0
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts +7 -0
- package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts +2 -0
- package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts +2 -0
- package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts +5 -0
- package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/globalListeners.d.ts +11 -0
- package/build/types/metrics/web-vitals/lib/globalListeners.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts +21 -0
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/initUnique.d.ts +7 -0
- package/build/types/metrics/web-vitals/lib/initUnique.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/observe.d.ts +23 -0
- package/build/types/metrics/web-vitals/lib/observe.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts +27 -0
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +15 -0
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/runOnce.d.ts +2 -0
- package/build/types/metrics/web-vitals/lib/runOnce.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/whenActivated.d.ts +2 -0
- package/build/types/metrics/web-vitals/lib/whenActivated.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts +6 -0
- package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/onFCP.d.ts +11 -0
- package/build/types/metrics/web-vitals/onFCP.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/onTTFB.d.ts +20 -0
- package/build/types/metrics/web-vitals/onTTFB.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/types/base.d.ts +103 -0
- package/build/types/metrics/web-vitals/types/base.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/types/cls.d.ts +58 -0
- package/build/types/metrics/web-vitals/types/cls.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/types/fcp.d.ts +47 -0
- package/build/types/metrics/web-vitals/types/fcp.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/types/inp.d.ts +150 -0
- package/build/types/metrics/web-vitals/types/inp.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/types/lcp.d.ts +74 -0
- package/build/types/metrics/web-vitals/types/lcp.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/types/ttfb.d.ts +60 -0
- package/build/types/metrics/web-vitals/types/ttfb.d.ts.map +1 -0
- package/build/types/metrics/web-vitals/types.d.ts +78 -0
- package/build/types/metrics/web-vitals/types.d.ts.map +1 -0
- package/build/types/metrics/webVitalSpans.d.ts +65 -0
- package/build/types/metrics/webVitalSpans.d.ts.map +1 -0
- package/build/types/networkUtils.d.ts +25 -0
- package/build/types/networkUtils.d.ts.map +1 -0
- package/build/types/types.d.ts +15 -0
- package/build/types/types.d.ts.map +1 -0
- package/build/types-ts3.8/debug-build.d.ts +7 -0
- package/build/types-ts3.8/getNativeImplementation.d.ts +69 -0
- package/build/types-ts3.8/htmlTreeAsString.d.ts +11 -0
- package/build/types-ts3.8/index.d.ts +15 -0
- package/build/types-ts3.8/instrument/dom.d.ts +11 -0
- package/build/types-ts3.8/instrument/history.d.ts +15 -0
- package/build/types-ts3.8/instrument/xhr.d.ts +14 -0
- package/build/types-ts3.8/is.d.ts +7 -0
- package/build/types-ts3.8/metrics/browserMetrics.d.ts +119 -0
- package/build/types-ts3.8/metrics/cls.d.ts +17 -0
- package/build/types-ts3.8/metrics/elementTiming.d.ts +19 -0
- package/build/types-ts3.8/metrics/inp.d.ts +35 -0
- package/build/types-ts3.8/metrics/instrument.d.ts +121 -0
- package/build/types-ts3.8/metrics/lcp.d.ts +22 -0
- package/build/types-ts3.8/metrics/resourceTiming.d.ts +13 -0
- package/build/types-ts3.8/metrics/utils.d.ts +73 -0
- package/build/types-ts3.8/metrics/web-vitals/getCLS.d.ts +26 -0
- package/build/types-ts3.8/metrics/web-vitals/getINP.d.ts +34 -0
- package/build/types-ts3.8/metrics/web-vitals/getLCP.d.ts +16 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/InteractionManager.d.ts +37 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/LCPEntryManager.d.ts +5 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/LayoutShiftManager.d.ts +7 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/bindReporter.d.ts +7 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/generateUniqueID.d.ts +7 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/getActivationStart.d.ts +2 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/getNavigationEntry.d.ts +2 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/getVisibilityWatcher.d.ts +5 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/globalListeners.d.ts +11 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/initMetric.d.ts +21 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/initUnique.d.ts +7 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/observe.d.ts +23 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/onHidden.d.ts +27 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +15 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/runOnce.d.ts +2 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/whenActivated.d.ts +2 -0
- package/build/types-ts3.8/metrics/web-vitals/lib/whenIdleOrHidden.d.ts +6 -0
- package/build/types-ts3.8/metrics/web-vitals/onFCP.d.ts +11 -0
- package/build/types-ts3.8/metrics/web-vitals/onTTFB.d.ts +20 -0
- package/build/types-ts3.8/metrics/web-vitals/types/base.d.ts +106 -0
- package/build/types-ts3.8/metrics/web-vitals/types/cls.d.ts +58 -0
- package/build/types-ts3.8/metrics/web-vitals/types/fcp.d.ts +47 -0
- package/build/types-ts3.8/metrics/web-vitals/types/inp.d.ts +150 -0
- package/build/types-ts3.8/metrics/web-vitals/types/lcp.d.ts +74 -0
- package/build/types-ts3.8/metrics/web-vitals/types/ttfb.d.ts +60 -0
- package/build/types-ts3.8/metrics/web-vitals/types.d.ts +78 -0
- package/build/types-ts3.8/metrics/webVitalSpans.d.ts +65 -0
- package/build/types-ts3.8/networkUtils.d.ts +28 -0
- package/build/types-ts3.8/types.d.ts +15 -0
- package/package.json +69 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrument.js","sources":["../../../src/metrics/instrument.ts"],"sourcesContent":["import { debug, getFunctionName } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { onCLS } from './web-vitals/getCLS';\nimport { onINP } from './web-vitals/getINP';\nimport { onLCP } from './web-vitals/getLCP';\nimport { observe } from './web-vitals/lib/observe';\nimport { onTTFB } from './web-vitals/onTTFB';\n\ntype InstrumentHandlerTypePerformanceObserver =\n | 'longtask'\n | 'event'\n | 'navigation'\n | 'paint'\n | 'resource'\n | 'element'\n // fist-input is still needed for INP\n | 'first-input';\n\ntype InstrumentHandlerTypeMetric = 'cls' | 'lcp' | 'ttfb' | 'inp';\n\n// We provide this here manually instead of relying on a global, as this is not available in non-browser environements\n// And we do not want to expose such types\ninterface PerformanceEntry {\n readonly duration: number;\n readonly entryType: string;\n readonly name: string;\n readonly startTime: number;\n toJSON(): Record<string, unknown>;\n}\nexport interface PerformanceEventTiming extends PerformanceEntry {\n processingStart: number;\n processingEnd: number;\n duration: number;\n cancelable?: boolean;\n target?: unknown | null;\n interactionId?: number;\n}\n\ninterface PerformanceScriptTiming extends PerformanceEntry {\n sourceURL: string;\n sourceFunctionName: string;\n sourceCharPosition: number;\n invoker: string;\n invokerType: string;\n}\nexport interface PerformanceLongAnimationFrameTiming extends PerformanceEntry {\n scripts: PerformanceScriptTiming[];\n}\n\ninterface Metric {\n /**\n * The name of the metric (in acronym form).\n */\n name: 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB';\n\n /**\n * The current value of the metric.\n */\n value: number;\n\n /**\n * The rating as to whether the metric value is within the \"good\",\n * \"needs improvement\", or \"poor\" thresholds of the metric.\n */\n rating: 'good' | 'needs-improvement' | 'poor';\n\n /**\n * The delta between the current value and the last-reported value.\n * On the first report, `delta` and `value` will always be the same.\n */\n delta: number;\n\n /**\n * A unique ID representing this particular metric instance. This ID can\n * be used by an analytics tool to dedupe multiple values sent for the same\n * metric instance, or to group multiple deltas together and calculate a\n * total. It can also be used to differentiate multiple different metric\n * instances sent from the same page, which can happen if the page is\n * restored from the back/forward cache (in that case new metrics object\n * get created).\n */\n id: string;\n\n /**\n * Any performance entries relevant to the metric value calculation.\n * The array may also be empty if the metric value was not based on any\n * entries (e.g. a CLS value of 0 given no layout shifts).\n */\n entries: PerformanceEntry[];\n\n /**\n * The type of navigation\n *\n * Navigation Timing API (or `undefined` if the browser doesn't\n * support that API). For pages that are restored from the bfcache, this\n * value will be 'back-forward-cache'.\n */\n navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'restore';\n}\n\ntype InstrumentHandlerType = InstrumentHandlerTypeMetric | InstrumentHandlerTypePerformanceObserver;\n\ntype StopListening = undefined | void | (() => void);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InstrumentHandlerCallback = (data: any) => void;\n\ntype CleanupHandlerCallback = () => void;\n\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\nlet _previousCls: Metric | undefined;\nlet _previousLcp: Metric | undefined;\nlet _previousTtfb: Metric | undefined;\nlet _previousInp: Metric | undefined;\n\n/**\n * Add a callback that will be triggered when a CLS metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called.\n * This will lead to the CLS being finalized and frozen.\n */\nexport function addClsInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a LCP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called.\n * This will lead to the LCP being finalized and frozen.\n */\nexport function addLcpInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a TTFD metric is available.\n */\nexport function addTtfbInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('ttfb', callback, instrumentTtfb, _previousTtfb);\n}\n\nexport type InstrumentationHandlerCallback = (data: {\n metric: Omit<Metric, 'entries'> & {\n entries: PerformanceEventTiming[];\n };\n}) => void;\n\n/**\n * Add a callback that will be triggered when a INP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addInpInstrumentationHandler(callback: InstrumentationHandlerCallback): CleanupHandlerCallback {\n return addMetricObserver('inp', callback, instrumentInp, _previousInp);\n}\n\nexport function addPerformanceInstrumentationHandler(\n type: 'event',\n callback: (data: { entries: ((PerformanceEntry & { target?: unknown | null }) | PerformanceEventTiming)[] }) => void,\n): CleanupHandlerCallback;\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback;\n\n/**\n * Add a callback that will be triggered when a performance observer is triggered,\n * and receives the entries of the observer.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumentPerformanceObserver(type);\n instrumented[type] = true;\n }\n\n return getCleanupCallback(type, callback);\n}\n\n/** Trigger all handlers of a given type. */\nfunction triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = handlers[type];\n\n if (!typeHandlers?.length) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n debug.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n\nfunction instrumentCls(): StopListening {\n return onCLS(\n metric => {\n triggerHandlers('cls', {\n metric,\n });\n _previousCls = metric;\n },\n // We want the callback to be called whenever the CLS value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: true },\n );\n}\n\nfunction instrumentLcp(): StopListening {\n return onLCP(\n metric => {\n triggerHandlers('lcp', {\n metric,\n });\n _previousLcp = metric;\n },\n // We want the callback to be called whenever the LCP value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: true },\n );\n}\n\nfunction instrumentTtfb(): StopListening {\n return onTTFB(metric => {\n triggerHandlers('ttfb', {\n metric,\n });\n _previousTtfb = metric;\n });\n}\n\nfunction instrumentInp(): void {\n return onINP(metric => {\n triggerHandlers('inp', {\n metric,\n });\n _previousInp = metric;\n });\n}\n\nfunction addMetricObserver(\n type: InstrumentHandlerTypeMetric,\n callback: InstrumentHandlerCallback,\n instrumentFn: () => StopListening,\n previousValue: Metric | undefined,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n let stopListening: StopListening | undefined;\n\n if (!instrumented[type]) {\n stopListening = instrumentFn();\n instrumented[type] = true;\n }\n\n if (previousValue) {\n callback({ metric: previousValue });\n }\n\n return getCleanupCallback(type, callback, stopOnCallback ? stopListening : undefined);\n}\n\nfunction instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObserver): void {\n const options: PerformanceObserverInit = {};\n\n // Special per-type options we want to use\n if (type === 'event') {\n options.durationThreshold = 0;\n }\n\n observe(\n type,\n entries => {\n triggerHandlers(type, { entries });\n },\n options,\n );\n}\n\nfunction addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n handlers[type].push(handler);\n}\n\n// Get a callback which can be called to remove the instrumentation handler\nfunction getCleanupCallback(\n type: InstrumentHandlerType,\n callback: InstrumentHandlerCallback,\n stopListening: StopListening,\n): CleanupHandlerCallback {\n return () => {\n if (stopListening) {\n stopListening();\n }\n\n const typeHandlers = handlers[type];\n\n if (!typeHandlers) {\n return;\n }\n\n const index = typeHandlers.indexOf(callback);\n if (index !== -1) {\n typeHandlers.splice(index, 1);\n }\n };\n}\n\n/**\n * Check if a PerformanceEntry is a PerformanceEventTiming by checking for the `duration` property.\n */\nexport function isPerformanceEventTiming(entry: PerformanceEntry): entry is PerformanceEventTiming {\n return 'duration' in entry;\n}\n"],"names":["DEBUG_BUILD","debug","getFunctionName","onCLS","onLCP","onTTFB","onINP","observe"],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
const debugBuild = require('../debug-build.js');
|
|
5
|
+
const htmlTreeAsString = require('../htmlTreeAsString.js');
|
|
6
|
+
const instrument = require('./instrument.js');
|
|
7
|
+
const utils = require('./utils.js');
|
|
8
|
+
|
|
9
|
+
const MAX_PLAUSIBLE_LCP_DURATION = 6e4;
|
|
10
|
+
function isValidLcpMetric(lcpValue) {
|
|
11
|
+
return lcpValue != null && lcpValue > 0 && lcpValue <= MAX_PLAUSIBLE_LCP_DURATION;
|
|
12
|
+
}
|
|
13
|
+
function trackLcpAsStandaloneSpan(client) {
|
|
14
|
+
let standaloneLcpValue = 0;
|
|
15
|
+
let standaloneLcpEntry;
|
|
16
|
+
if (!utils.supportsWebVital("largest-contentful-paint")) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const cleanupLcpHandler = instrument.addLcpInstrumentationHandler(({ metric }) => {
|
|
20
|
+
const entry = metric.entries[metric.entries.length - 1];
|
|
21
|
+
if (!entry || !isValidLcpMetric(metric.value)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
standaloneLcpValue = metric.value;
|
|
25
|
+
standaloneLcpEntry = entry;
|
|
26
|
+
}, true);
|
|
27
|
+
utils.listenForWebVitalReportEvents(client, (reportEvent, pageloadSpanId) => {
|
|
28
|
+
_sendStandaloneLcpSpan(standaloneLcpValue, standaloneLcpEntry, pageloadSpanId, reportEvent);
|
|
29
|
+
cleanupLcpHandler();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function _sendStandaloneLcpSpan(lcpValue, entry, pageloadSpanId, reportEvent) {
|
|
33
|
+
if (!isValidLcpMetric(lcpValue)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
debugBuild.DEBUG_BUILD && core.debug.log(`Sending LCP span (${lcpValue})`);
|
|
37
|
+
const startTime = utils.msToSec((core.browserPerformanceTimeOrigin() || 0) + (entry?.startTime || 0));
|
|
38
|
+
const routeName = core.getCurrentScope().getScopeData().transactionName;
|
|
39
|
+
const name = entry ? htmlTreeAsString.htmlTreeAsString(entry.element) : "Largest contentful paint";
|
|
40
|
+
const attributes = {
|
|
41
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.browser.lcp",
|
|
42
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "ui.webvital.lcp",
|
|
43
|
+
[core.SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,
|
|
44
|
+
// LCP is a point-in-time metric
|
|
45
|
+
// attach the pageload span id to the LCP span so that we can link them in the UI
|
|
46
|
+
"sentry.pageload.span_id": pageloadSpanId,
|
|
47
|
+
// describes what triggered the web vital to be reported
|
|
48
|
+
"sentry.report_event": reportEvent
|
|
49
|
+
};
|
|
50
|
+
if (entry) {
|
|
51
|
+
entry.element && (attributes["lcp.element"] = htmlTreeAsString.htmlTreeAsString(entry.element));
|
|
52
|
+
entry.id && (attributes["lcp.id"] = entry.id);
|
|
53
|
+
entry.url && (attributes["lcp.url"] = entry.url);
|
|
54
|
+
entry.loadTime != null && (attributes["lcp.loadTime"] = entry.loadTime);
|
|
55
|
+
entry.renderTime != null && (attributes["lcp.renderTime"] = entry.renderTime);
|
|
56
|
+
entry.size != null && (attributes["lcp.size"] = entry.size);
|
|
57
|
+
}
|
|
58
|
+
const span = utils.startStandaloneWebVitalSpan({
|
|
59
|
+
name,
|
|
60
|
+
transaction: routeName,
|
|
61
|
+
attributes,
|
|
62
|
+
startTime
|
|
63
|
+
});
|
|
64
|
+
if (span) {
|
|
65
|
+
span.addEvent("lcp", {
|
|
66
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: "millisecond",
|
|
67
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: lcpValue
|
|
68
|
+
});
|
|
69
|
+
span.end(startTime);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
exports.MAX_PLAUSIBLE_LCP_DURATION = MAX_PLAUSIBLE_LCP_DURATION;
|
|
74
|
+
exports._sendStandaloneLcpSpan = _sendStandaloneLcpSpan;
|
|
75
|
+
exports.isValidLcpMetric = isValidLcpMetric;
|
|
76
|
+
exports.trackLcpAsStandaloneSpan = trackLcpAsStandaloneSpan;
|
|
77
|
+
//# sourceMappingURL=lcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lcp.js","sources":["../../../src/metrics/lcp.ts"],"sourcesContent":["import type { Client, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { addLcpInstrumentationHandler } from './instrument';\nimport type { WebVitalReportEvent } from './utils';\nimport { listenForWebVitalReportEvents, msToSec, startStandaloneWebVitalSpan, supportsWebVital } from './utils';\n\n/**\n * 60 seconds is the maximum for a plausible LCP value.\n */\nexport const MAX_PLAUSIBLE_LCP_DURATION = 60_000;\n\nexport function isValidLcpMetric(lcpValue: number | undefined): lcpValue is number {\n return lcpValue != null && lcpValue > 0 && lcpValue <= MAX_PLAUSIBLE_LCP_DURATION;\n}\n\n/**\n * Starts tracking the Largest Contentful Paint on the current page and collects the value once\n *\n * - the page visibility is hidden\n * - a navigation span is started (to stop LCP measurement for SPA soft navigations)\n *\n * Once either of these events triggers, the LCP value is sent as a standalone span and we stop\n * measuring LCP for subsequent routes.\n */\nexport function trackLcpAsStandaloneSpan(client: Client): void {\n let standaloneLcpValue = 0;\n let standaloneLcpEntry: LargestContentfulPaint | undefined;\n\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n standaloneLcpValue = metric.value;\n standaloneLcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, pageloadSpanId) => {\n _sendStandaloneLcpSpan(standaloneLcpValue, standaloneLcpEntry, pageloadSpanId, reportEvent);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing!\n */\nexport function _sendStandaloneLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpanId: string,\n reportEvent: WebVitalReportEvent,\n) {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const startTime = msToSec((browserPerformanceTimeOrigin() || 0) + (entry?.startTime || 0));\n const routeName = getCurrentScope().getScopeData().transactionName;\n\n const name = entry ? htmlTreeAsString(entry.element) : 'Largest contentful paint';\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.lcp',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'ui.webvital.lcp',\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0, // LCP is a point-in-time metric\n // attach the pageload span id to the LCP span so that we can link them in the UI\n 'sentry.pageload.span_id': pageloadSpanId,\n // describes what triggered the web vital to be reported\n 'sentry.report_event': reportEvent,\n };\n\n if (entry) {\n entry.element && (attributes['lcp.element'] = htmlTreeAsString(entry.element));\n entry.id && (attributes['lcp.id'] = entry.id);\n\n entry.url && (attributes['lcp.url'] = entry.url);\n\n // loadTime is the time of LCP that's related to receiving the LCP element response..\n entry.loadTime != null && (attributes['lcp.loadTime'] = entry.loadTime);\n\n // renderTime is loadTime + rendering time\n // it's 0 if the LCP element is loaded from a 3rd party origin that doesn't send the\n // `Timing-Allow-Origin` header.\n entry.renderTime != null && (attributes['lcp.renderTime'] = entry.renderTime);\n\n entry.size != null && (attributes['lcp.size'] = entry.size);\n }\n\n const span = startStandaloneWebVitalSpan({\n name,\n transaction: routeName,\n attributes,\n startTime,\n });\n\n if (span) {\n span.addEvent('lcp', {\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: 'millisecond',\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: lcpValue,\n });\n\n // LCP is a point-in-time metric, so we end the span immediately\n span.end(startTime);\n }\n}\n"],"names":["supportsWebVital","addLcpInstrumentationHandler","listenForWebVitalReportEvents","DEBUG_BUILD","debug","msToSec","browserPerformanceTimeOrigin","getCurrentScope","htmlTreeAsString","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME","startStandaloneWebVitalSpan","SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT","SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
const utils = require('./utils.js');
|
|
5
|
+
|
|
6
|
+
function getAbsoluteTime(time) {
|
|
7
|
+
return time ? ((core.browserPerformanceTimeOrigin() || performance.timeOrigin) + time) / 1e3 : time;
|
|
8
|
+
}
|
|
9
|
+
function resourceTimingToSpanAttributes(resourceTiming) {
|
|
10
|
+
const timingSpanData = {};
|
|
11
|
+
if (resourceTiming.nextHopProtocol != void 0) {
|
|
12
|
+
const { name, version } = utils.extractNetworkProtocol(resourceTiming.nextHopProtocol);
|
|
13
|
+
timingSpanData["network.protocol.version"] = version;
|
|
14
|
+
timingSpanData["network.protocol.name"] = name;
|
|
15
|
+
}
|
|
16
|
+
if (!(core.browserPerformanceTimeOrigin() || utils.getBrowserPerformanceAPI()?.timeOrigin)) {
|
|
17
|
+
return timingSpanData;
|
|
18
|
+
}
|
|
19
|
+
return dropUndefinedKeysFromObject({
|
|
20
|
+
...timingSpanData,
|
|
21
|
+
"http.request.redirect_start": getAbsoluteTime(resourceTiming.redirectStart),
|
|
22
|
+
"http.request.redirect_end": getAbsoluteTime(resourceTiming.redirectEnd),
|
|
23
|
+
"http.request.worker_start": getAbsoluteTime(resourceTiming.workerStart),
|
|
24
|
+
"http.request.fetch_start": getAbsoluteTime(resourceTiming.fetchStart),
|
|
25
|
+
"http.request.domain_lookup_start": getAbsoluteTime(resourceTiming.domainLookupStart),
|
|
26
|
+
"http.request.domain_lookup_end": getAbsoluteTime(resourceTiming.domainLookupEnd),
|
|
27
|
+
"http.request.connect_start": getAbsoluteTime(resourceTiming.connectStart),
|
|
28
|
+
"http.request.secure_connection_start": getAbsoluteTime(resourceTiming.secureConnectionStart),
|
|
29
|
+
"http.request.connection_end": getAbsoluteTime(resourceTiming.connectEnd),
|
|
30
|
+
"http.request.request_start": getAbsoluteTime(resourceTiming.requestStart),
|
|
31
|
+
"http.request.response_start": getAbsoluteTime(resourceTiming.responseStart),
|
|
32
|
+
"http.request.response_end": getAbsoluteTime(resourceTiming.responseEnd),
|
|
33
|
+
// For TTFB we actually want the relative time from timeOrigin to responseStart
|
|
34
|
+
// This way, TTFB always measures the "first page load" experience.
|
|
35
|
+
// see: https://web.dev/articles/ttfb#measure-resource-requests
|
|
36
|
+
"http.request.time_to_first_byte": resourceTiming.responseStart != null ? resourceTiming.responseStart / 1e3 : void 0
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function dropUndefinedKeysFromObject(attrs) {
|
|
40
|
+
return Object.fromEntries(Object.entries(attrs).filter(([, value]) => value != null));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
exports.resourceTimingToSpanAttributes = resourceTimingToSpanAttributes;
|
|
44
|
+
//# sourceMappingURL=resourceTiming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":["browserPerformanceTimeOrigin","extractNetworkProtocol","getBrowserPerformanceAPI"],"mappings":";;;;;AAIA,SAAS,gBAAgB,IAAA,EAA8C;AAGrE,EAAA,OAAO,SAASA,iCAAA,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,GAAIC,4BAAA,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,EAAED,iCAAA,EAA6B,IAAKE,8BAAA,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;;;;"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
const types = require('../types.js');
|
|
5
|
+
const onHidden = require('./web-vitals/lib/onHidden.js');
|
|
6
|
+
|
|
7
|
+
function isMeasurementValue(value) {
|
|
8
|
+
return typeof value === "number" && isFinite(value);
|
|
9
|
+
}
|
|
10
|
+
function startAndEndSpan(parentSpan, startTimeInSeconds, endTime, { ...ctx }) {
|
|
11
|
+
const parentStartTime = core.spanToJSON(parentSpan).start_timestamp;
|
|
12
|
+
if (parentStartTime && parentStartTime > startTimeInSeconds) {
|
|
13
|
+
if (typeof parentSpan.updateStartTime === "function") {
|
|
14
|
+
parentSpan.updateStartTime(startTimeInSeconds);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return core.withActiveSpan(parentSpan, () => {
|
|
18
|
+
const span = core.startInactiveSpan({
|
|
19
|
+
startTime: startTimeInSeconds,
|
|
20
|
+
...ctx
|
|
21
|
+
});
|
|
22
|
+
if (span) {
|
|
23
|
+
span.end(endTime);
|
|
24
|
+
}
|
|
25
|
+
return span;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function startStandaloneWebVitalSpan(options) {
|
|
29
|
+
const client = core.getClient();
|
|
30
|
+
if (!client) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const { name, transaction, attributes: passedAttributes, startTime } = options;
|
|
34
|
+
const { release, environment } = client.getOptions();
|
|
35
|
+
const { userInfo } = client.getDataCollectionOptions();
|
|
36
|
+
const replay = client.getIntegrationByName("Replay");
|
|
37
|
+
const replayId = replay?.getReplayId();
|
|
38
|
+
const scope = core.getCurrentScope();
|
|
39
|
+
const user = scope.getUser();
|
|
40
|
+
const userDisplay = user !== void 0 ? user.email || user.id || user.ip_address : void 0;
|
|
41
|
+
let profileId;
|
|
42
|
+
try {
|
|
43
|
+
profileId = scope.getScopeData().contexts.profile.profile_id;
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
const attributes = {
|
|
47
|
+
release,
|
|
48
|
+
environment,
|
|
49
|
+
user: userDisplay || void 0,
|
|
50
|
+
profile_id: profileId || void 0,
|
|
51
|
+
replay_id: replayId || void 0,
|
|
52
|
+
transaction,
|
|
53
|
+
// Web vital score calculation relies on the user agent to account for different
|
|
54
|
+
// browsers setting different thresholds for what is considered a good/meh/bad value.
|
|
55
|
+
// For example: Chrome vs. Chrome Mobile
|
|
56
|
+
"user_agent.original": types.WINDOW.navigator?.userAgent,
|
|
57
|
+
// This tells Sentry to infer the IP address from the request
|
|
58
|
+
"client.address": userInfo ? "{{auto}}" : void 0,
|
|
59
|
+
...passedAttributes
|
|
60
|
+
};
|
|
61
|
+
return core.startInactiveSpan({
|
|
62
|
+
name,
|
|
63
|
+
attributes,
|
|
64
|
+
startTime,
|
|
65
|
+
experimental: {
|
|
66
|
+
standalone: true
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function getBrowserPerformanceAPI() {
|
|
71
|
+
return types.WINDOW.addEventListener && types.WINDOW.performance;
|
|
72
|
+
}
|
|
73
|
+
function msToSec(time) {
|
|
74
|
+
return time / 1e3;
|
|
75
|
+
}
|
|
76
|
+
function extractNetworkProtocol(nextHopProtocol) {
|
|
77
|
+
let name = "unknown";
|
|
78
|
+
let version = "unknown";
|
|
79
|
+
let _name = "";
|
|
80
|
+
for (const char of nextHopProtocol) {
|
|
81
|
+
if (char === "/") {
|
|
82
|
+
[name, version] = nextHopProtocol.split("/");
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
if (!isNaN(Number(char))) {
|
|
86
|
+
name = _name === "h" ? "http" : _name;
|
|
87
|
+
version = nextHopProtocol.split(_name)[1];
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
_name += char;
|
|
91
|
+
}
|
|
92
|
+
if (_name === nextHopProtocol) {
|
|
93
|
+
name = _name;
|
|
94
|
+
}
|
|
95
|
+
return { name, version };
|
|
96
|
+
}
|
|
97
|
+
function supportsWebVital(entryType) {
|
|
98
|
+
try {
|
|
99
|
+
return PerformanceObserver.supportedEntryTypes.includes(entryType);
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function listenForWebVitalReportEvents(client, collectorCallback) {
|
|
105
|
+
let pageloadSpan;
|
|
106
|
+
let collected = false;
|
|
107
|
+
function _runCollectorCallbackOnce(event) {
|
|
108
|
+
if (!collected && pageloadSpan) {
|
|
109
|
+
collectorCallback(event, pageloadSpan.spanContext().spanId, pageloadSpan);
|
|
110
|
+
}
|
|
111
|
+
collected = true;
|
|
112
|
+
}
|
|
113
|
+
onHidden.onHidden(() => {
|
|
114
|
+
_runCollectorCallbackOnce("pagehide");
|
|
115
|
+
});
|
|
116
|
+
const unsubscribeStartNavigation = client.on("beforeStartNavigationSpan", (_, options) => {
|
|
117
|
+
if (!options?.isRedirect) {
|
|
118
|
+
_runCollectorCallbackOnce("navigation");
|
|
119
|
+
unsubscribeStartNavigation();
|
|
120
|
+
unsubscribeAfterStartPageLoadSpan();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
const unsubscribeAfterStartPageLoadSpan = client.on("afterStartPageLoadSpan", (span) => {
|
|
124
|
+
pageloadSpan = span;
|
|
125
|
+
unsubscribeAfterStartPageLoadSpan();
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
exports.extractNetworkProtocol = extractNetworkProtocol;
|
|
130
|
+
exports.getBrowserPerformanceAPI = getBrowserPerformanceAPI;
|
|
131
|
+
exports.isMeasurementValue = isMeasurementValue;
|
|
132
|
+
exports.listenForWebVitalReportEvents = listenForWebVitalReportEvents;
|
|
133
|
+
exports.msToSec = msToSec;
|
|
134
|
+
exports.startAndEndSpan = startAndEndSpan;
|
|
135
|
+
exports.startStandaloneWebVitalSpan = startStandaloneWebVitalSpan;
|
|
136
|
+
exports.supportsWebVital = supportsWebVital;
|
|
137
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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 deprecation/deprecation\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":["spanToJSON","withActiveSpan","startInactiveSpan","getClient","getCurrentScope","WINDOW","onHidden"],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const types = require('../../types.js');
|
|
4
|
+
const bindReporter = require('./lib/bindReporter.js');
|
|
5
|
+
const getVisibilityWatcher = require('./lib/getVisibilityWatcher.js');
|
|
6
|
+
const initMetric = require('./lib/initMetric.js');
|
|
7
|
+
const initUnique = require('./lib/initUnique.js');
|
|
8
|
+
const LayoutShiftManager = require('./lib/LayoutShiftManager.js');
|
|
9
|
+
const observe = require('./lib/observe.js');
|
|
10
|
+
const runOnce = require('./lib/runOnce.js');
|
|
11
|
+
const onFCP = require('./onFCP.js');
|
|
12
|
+
|
|
13
|
+
const CLSThresholds = [0.1, 0.25];
|
|
14
|
+
const onCLS = (onReport, opts = {}) => {
|
|
15
|
+
onFCP.onFCP(
|
|
16
|
+
runOnce.runOnce(() => {
|
|
17
|
+
const metric = initMetric.initMetric("CLS", 0);
|
|
18
|
+
let report;
|
|
19
|
+
const visibilityWatcher = getVisibilityWatcher.getVisibilityWatcher();
|
|
20
|
+
const layoutShiftManager = initUnique.initUnique(opts, LayoutShiftManager.LayoutShiftManager);
|
|
21
|
+
const handleEntries = (entries) => {
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
layoutShiftManager._processEntry(entry);
|
|
24
|
+
}
|
|
25
|
+
if (layoutShiftManager._sessionValue > metric.value) {
|
|
26
|
+
metric.value = layoutShiftManager._sessionValue;
|
|
27
|
+
metric.entries = layoutShiftManager._sessionEntries;
|
|
28
|
+
report();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const po = observe.observe("layout-shift", handleEntries);
|
|
32
|
+
if (po) {
|
|
33
|
+
report = bindReporter.bindReporter(onReport, metric, CLSThresholds, opts.reportAllChanges);
|
|
34
|
+
visibilityWatcher.onHidden(() => {
|
|
35
|
+
handleEntries(po.takeRecords());
|
|
36
|
+
report(true);
|
|
37
|
+
});
|
|
38
|
+
types.WINDOW?.setTimeout?.(report);
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
exports.CLSThresholds = CLSThresholds;
|
|
45
|
+
exports.onCLS = onCLS;
|
|
46
|
+
//# sourceMappingURL=getCLS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":["onFCP","runOnce","initMetric","getVisibilityWatcher","initUnique","LayoutShiftManager","observe","bindReporter","WINDOW"],"mappings":";;;;;;;;;;;;AA4BO,MAAM,aAAA,GAAwC,CAAC,GAAA,EAAK,IAAI;AAuBxD,MAAM,KAAA,GAAQ,CAAC,QAAA,EAAuC,IAAA,GAAmB,EAAC,KAAM;AAGrF,EAAAA,WAAA;AAAA,IACEC,gBAAQ,MAAM;AACZ,MAAA,MAAM,MAAA,GAASC,qBAAA,CAAW,KAAA,EAAO,CAAC,CAAA;AAClC,MAAA,IAAI,MAAA;AACJ,MAAA,MAAM,oBAAoBC,yCAAA,EAAqB;AAE/C,MAAA,MAAM,kBAAA,GAAqBC,qBAAA,CAAW,IAAA,EAAMC,qCAAkB,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,GAAKC,eAAA,CAAQ,cAAA,EAAgB,aAAa,CAAA;AAChD,MAAA,IAAI,EAAA,EAAI;AACN,QAAA,MAAA,GAASC,yBAAA,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,QAAAC,YAAA,EAAQ,aAAa,MAAM,CAAA;AAAA,MAC7B;AAAA,IACF,CAAC;AAAA,GACH;AACF;;;;;"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const bindReporter = require('./lib/bindReporter.js');
|
|
4
|
+
const getVisibilityWatcher = require('./lib/getVisibilityWatcher.js');
|
|
5
|
+
const initMetric = require('./lib/initMetric.js');
|
|
6
|
+
const initUnique = require('./lib/initUnique.js');
|
|
7
|
+
const InteractionManager = require('./lib/InteractionManager.js');
|
|
8
|
+
const observe = require('./lib/observe.js');
|
|
9
|
+
const interactionCountPolyfill = require('./lib/polyfills/interactionCountPolyfill.js');
|
|
10
|
+
const whenActivated = require('./lib/whenActivated.js');
|
|
11
|
+
const whenIdleOrHidden = require('./lib/whenIdleOrHidden.js');
|
|
12
|
+
|
|
13
|
+
const INPThresholds = [200, 500];
|
|
14
|
+
const DEFAULT_DURATION_THRESHOLD = 40;
|
|
15
|
+
const onINP = (onReport, opts = {}) => {
|
|
16
|
+
if (!(globalThis.PerformanceEventTiming && "interactionId" in PerformanceEventTiming.prototype)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const visibilityWatcher = getVisibilityWatcher.getVisibilityWatcher();
|
|
20
|
+
whenActivated.whenActivated(() => {
|
|
21
|
+
interactionCountPolyfill.initInteractionCountPolyfill();
|
|
22
|
+
const metric = initMetric.initMetric("INP");
|
|
23
|
+
let report;
|
|
24
|
+
const interactionManager = initUnique.initUnique(opts, InteractionManager.InteractionManager);
|
|
25
|
+
const handleEntries = (entries) => {
|
|
26
|
+
whenIdleOrHidden.whenIdleOrHidden(() => {
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
interactionManager._processEntry(entry);
|
|
29
|
+
}
|
|
30
|
+
const inp = interactionManager._estimateP98LongestInteraction();
|
|
31
|
+
if (inp && inp._latency !== metric.value) {
|
|
32
|
+
metric.value = inp._latency;
|
|
33
|
+
metric.entries = inp.entries;
|
|
34
|
+
report();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
const po = observe.observe("event", handleEntries, {
|
|
39
|
+
// Event Timing entries have their durations rounded to the nearest 8ms,
|
|
40
|
+
// so a duration of 40ms would be any event that spans 2.5 or more frames
|
|
41
|
+
// at 60Hz. This threshold is chosen to strike a balance between usefulness
|
|
42
|
+
// and performance. Running this callback for any interaction that spans
|
|
43
|
+
// just one or two frames is likely not worth the insight that could be
|
|
44
|
+
// gained.
|
|
45
|
+
durationThreshold: opts.durationThreshold ?? DEFAULT_DURATION_THRESHOLD
|
|
46
|
+
});
|
|
47
|
+
report = bindReporter.bindReporter(onReport, metric, INPThresholds, opts.reportAllChanges);
|
|
48
|
+
if (po) {
|
|
49
|
+
po.observe({ type: "first-input", buffered: true });
|
|
50
|
+
visibilityWatcher.onHidden(() => {
|
|
51
|
+
handleEntries(po.takeRecords());
|
|
52
|
+
report(true);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
exports.INPThresholds = INPThresholds;
|
|
59
|
+
exports.onINP = onINP;
|
|
60
|
+
//# sourceMappingURL=getINP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getINP.js","sources":["../../../../src/metrics/web-vitals/getINP.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { bindReporter } from './lib/bindReporter';\nimport { getVisibilityWatcher } from './lib/getVisibilityWatcher';\nimport { initMetric } from './lib/initMetric';\nimport { initUnique } from './lib/initUnique';\nimport { InteractionManager } from './lib/InteractionManager';\nimport { observe } from './lib/observe';\nimport { initInteractionCountPolyfill } from './lib/polyfills/interactionCountPolyfill';\nimport { whenActivated } from './lib/whenActivated';\nimport { whenIdleOrHidden } from './lib/whenIdleOrHidden';\nimport type { INPMetric, INPReportOpts, MetricRatingThresholds } from './types';\n\n/** Thresholds for INP. See https://web.dev/articles/inp#what_is_a_good_inp_score */\nexport const INPThresholds: MetricRatingThresholds = [200, 500];\n\n// The default `durationThreshold` used across this library for observing\n// `event` entries via PerformanceObserver.\nconst DEFAULT_DURATION_THRESHOLD = 40;\n\n/**\n * Calculates the [INP](https://web.dev/articles/inp) value for the current\n * page and calls the `callback` function once the value is ready, along with\n * the `event` performance entries reported for that interaction. The reported\n * value is a `DOMHighResTimeStamp`.\n *\n * A custom `durationThreshold` configuration option can optionally be passed\n * to control what `event-timing` entries are considered for INP reporting. The\n * default threshold is `40`, which means INP scores of less than 40 will not\n * be reported. To avoid reporting no interactions in these cases, the library\n * will fall back to the input delay of the first interaction. Note that this\n * will not affect your 75th percentile INP value unless that value is also\n * less than 40 (well below the recommended\n * [good](https://web.dev/articles/inp#what_is_a_good_inp_score) threshold).\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:** INP 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 onINP = (onReport: (metric: INPMetric) => void, opts: INPReportOpts = {}) => {\n // Return if the browser doesn't support all APIs needed to measure INP.\n if (!(globalThis.PerformanceEventTiming && 'interactionId' in PerformanceEventTiming.prototype)) {\n return;\n }\n\n const visibilityWatcher = getVisibilityWatcher();\n\n whenActivated(() => {\n // TODO(philipwalton): remove once the polyfill is no longer needed.\n initInteractionCountPolyfill();\n\n const metric = initMetric('INP');\n // eslint-disable-next-line prefer-const\n let report: ReturnType<typeof bindReporter>;\n\n const interactionManager = initUnique(opts, InteractionManager);\n\n const handleEntries = (entries: INPMetric['entries']) => {\n // Queue the `handleEntries()` callback in the next idle task.\n // This is needed to increase the chances that all event entries that\n // occurred between the user interaction and the next paint\n // have been dispatched. Note: there is currently an experiment\n // running in Chrome (EventTimingKeypressAndCompositionInteractionId)\n // 123+ that if rolled out fully may make this no longer necessary.\n whenIdleOrHidden(() => {\n for (const entry of entries) {\n interactionManager._processEntry(entry);\n }\n\n const inp = interactionManager._estimateP98LongestInteraction();\n\n if (inp && inp._latency !== metric.value) {\n metric.value = inp._latency;\n metric.entries = inp.entries;\n report();\n }\n });\n };\n\n const po = observe('event', handleEntries, {\n // Event Timing entries have their durations rounded to the nearest 8ms,\n // so a duration of 40ms would be any event that spans 2.5 or more frames\n // at 60Hz. This threshold is chosen to strike a balance between usefulness\n // and performance. Running this callback for any interaction that spans\n // just one or two frames is likely not worth the insight that could be\n // gained.\n durationThreshold: opts.durationThreshold ?? DEFAULT_DURATION_THRESHOLD,\n });\n\n report = bindReporter(onReport, metric, INPThresholds, opts.reportAllChanges);\n\n if (po) {\n // Also observe entries of type `first-input`. This is useful in cases\n // where the first interaction is less than the `durationThreshold`.\n po.observe({ type: 'first-input', buffered: true });\n\n visibilityWatcher.onHidden(() => {\n handleEntries(po.takeRecords() as INPMetric['entries']);\n report(true);\n });\n }\n });\n};\n"],"names":["getVisibilityWatcher","whenActivated","initInteractionCountPolyfill","initMetric","initUnique","InteractionManager","whenIdleOrHidden","observe","bindReporter"],"mappings":";;;;;;;;;;;;AA4BO,MAAM,aAAA,GAAwC,CAAC,GAAA,EAAK,GAAG;AAI9D,MAAM,0BAAA,GAA6B,EAAA;AA+B5B,MAAM,KAAA,GAAQ,CAAC,QAAA,EAAuC,IAAA,GAAsB,EAAC,KAAM;AAExF,EAAA,IAAI,EAAE,UAAA,CAAW,sBAAA,IAA0B,eAAA,IAAmB,uBAAuB,SAAA,CAAA,EAAY;AAC/F,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,oBAAoBA,yCAAA,EAAqB;AAE/C,EAAAC,2BAAA,CAAc,MAAM;AAElB,IAAAC,qDAAA,EAA6B;AAE7B,IAAA,MAAM,MAAA,GAASC,sBAAW,KAAK,CAAA;AAE/B,IAAA,IAAI,MAAA;AAEJ,IAAA,MAAM,kBAAA,GAAqBC,qBAAA,CAAW,IAAA,EAAMC,qCAAkB,CAAA;AAE9D,IAAA,MAAM,aAAA,GAAgB,CAAC,OAAA,KAAkC;AAOvD,MAAAC,iCAAA,CAAiB,MAAM;AACrB,QAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,UAAA,kBAAA,CAAmB,cAAc,KAAK,CAAA;AAAA,QACxC;AAEA,QAAA,MAAM,GAAA,GAAM,mBAAmB,8BAAA,EAA+B;AAE9D,QAAA,IAAI,GAAA,IAAO,GAAA,CAAI,QAAA,KAAa,MAAA,CAAO,KAAA,EAAO;AACxC,UAAA,MAAA,CAAO,QAAQ,GAAA,CAAI,QAAA;AACnB,UAAA,MAAA,CAAO,UAAU,GAAA,CAAI,OAAA;AACrB,UAAA,MAAA,EAAO;AAAA,QACT;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA;AAEA,IAAA,MAAM,EAAA,GAAKC,eAAA,CAAQ,OAAA,EAAS,aAAA,EAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOzC,iBAAA,EAAmB,KAAK,iBAAA,IAAqB;AAAA,KAC9C,CAAA;AAED,IAAA,MAAA,GAASC,yBAAA,CAAa,QAAA,EAAU,MAAA,EAAQ,aAAA,EAAe,KAAK,gBAAgB,CAAA;AAE5E,IAAA,IAAI,EAAA,EAAI;AAGN,MAAA,EAAA,CAAG,QAAQ,EAAE,IAAA,EAAM,aAAA,EAAe,QAAA,EAAU,MAAM,CAAA;AAElD,MAAA,iBAAA,CAAkB,SAAS,MAAM;AAC/B,QAAA,aAAA,CAAc,EAAA,CAAG,aAAqC,CAAA;AACtD,QAAA,MAAA,CAAO,IAAI,CAAA;AAAA,MACb,CAAC,CAAA;AAAA,IACH;AAAA,EACF,CAAC,CAAA;AACH;;;;;"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const bindReporter = require('./lib/bindReporter.js');
|
|
4
|
+
const getActivationStart = require('./lib/getActivationStart.js');
|
|
5
|
+
const getVisibilityWatcher = require('./lib/getVisibilityWatcher.js');
|
|
6
|
+
const globalListeners = require('./lib/globalListeners.js');
|
|
7
|
+
const initMetric = require('./lib/initMetric.js');
|
|
8
|
+
const initUnique = require('./lib/initUnique.js');
|
|
9
|
+
const LCPEntryManager = require('./lib/LCPEntryManager.js');
|
|
10
|
+
const observe = require('./lib/observe.js');
|
|
11
|
+
const runOnce = require('./lib/runOnce.js');
|
|
12
|
+
const whenActivated = require('./lib/whenActivated.js');
|
|
13
|
+
const whenIdleOrHidden = require('./lib/whenIdleOrHidden.js');
|
|
14
|
+
|
|
15
|
+
const LCPThresholds = [2500, 4e3];
|
|
16
|
+
const onLCP = (onReport, opts = {}) => {
|
|
17
|
+
whenActivated.whenActivated(() => {
|
|
18
|
+
const visibilityWatcher = getVisibilityWatcher.getVisibilityWatcher();
|
|
19
|
+
const metric = initMetric.initMetric("LCP");
|
|
20
|
+
let report;
|
|
21
|
+
const lcpEntryManager = initUnique.initUnique(opts, LCPEntryManager.LCPEntryManager);
|
|
22
|
+
const handleEntries = (entries) => {
|
|
23
|
+
if (!opts.reportAllChanges) {
|
|
24
|
+
entries = entries.slice(-1);
|
|
25
|
+
}
|
|
26
|
+
for (const entry of entries) {
|
|
27
|
+
lcpEntryManager._processEntry(entry);
|
|
28
|
+
if (entry.startTime < visibilityWatcher.firstHiddenTime) {
|
|
29
|
+
metric.value = Math.max(entry.startTime - getActivationStart.getActivationStart(), 0);
|
|
30
|
+
metric.entries = [entry];
|
|
31
|
+
report();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const po = observe.observe("largest-contentful-paint", handleEntries);
|
|
36
|
+
if (po) {
|
|
37
|
+
report = bindReporter.bindReporter(onReport, metric, LCPThresholds, opts.reportAllChanges);
|
|
38
|
+
const stopListening = runOnce.runOnce(() => {
|
|
39
|
+
handleEntries(po.takeRecords());
|
|
40
|
+
po.disconnect();
|
|
41
|
+
report(true);
|
|
42
|
+
});
|
|
43
|
+
const stopListeningWrapper = (event) => {
|
|
44
|
+
if (event.isTrusted) {
|
|
45
|
+
whenIdleOrHidden.whenIdleOrHidden(stopListening);
|
|
46
|
+
globalListeners.removePageListener(event.type, stopListeningWrapper, {
|
|
47
|
+
capture: true
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
for (const type of ["keydown", "click", "visibilitychange"]) {
|
|
52
|
+
globalListeners.addPageListener(type, stopListeningWrapper, {
|
|
53
|
+
capture: true
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
exports.LCPThresholds = LCPThresholds;
|
|
61
|
+
exports.onLCP = onLCP;
|
|
62
|
+
//# sourceMappingURL=getLCP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getLCP.js","sources":["../../../../src/metrics/web-vitals/getLCP.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 { bindReporter } from './lib/bindReporter';\nimport { getActivationStart } from './lib/getActivationStart';\nimport { getVisibilityWatcher } from './lib/getVisibilityWatcher';\nimport { addPageListener, removePageListener } from './lib/globalListeners';\nimport { initMetric } from './lib/initMetric';\nimport { initUnique } from './lib/initUnique';\nimport { LCPEntryManager } from './lib/LCPEntryManager';\nimport { observe } from './lib/observe';\nimport { runOnce } from './lib/runOnce';\nimport { whenActivated } from './lib/whenActivated';\nimport { whenIdleOrHidden } from './lib/whenIdleOrHidden';\nimport type { LCPMetric, MetricRatingThresholds, ReportOpts } from './types';\n\n/** Thresholds for LCP. See https://web.dev/articles/lcp#what_is_a_good_lcp_score */\nexport const LCPThresholds: MetricRatingThresholds = [2500, 4000];\n\n/**\n * Calculates the [LCP](https://web.dev/articles/lcp) value for the current page and\n * calls the `callback` function once the value is ready (along with the\n * relevant `largest-contentful-paint` performance entry used to determine the\n * value). The reported value is a `DOMHighResTimeStamp`.\n *\n * If the `reportAllChanges` configuration option is set to `true`, the\n * `callback` function will be called any time a new `largest-contentful-paint`\n * performance entry is dispatched, or once the final value of the metric has\n * been determined.\n */\nexport const onLCP = (onReport: (metric: LCPMetric) => void, opts: ReportOpts = {}) => {\n whenActivated(() => {\n const visibilityWatcher = getVisibilityWatcher();\n const metric = initMetric('LCP');\n let report: ReturnType<typeof bindReporter>;\n\n const lcpEntryManager = initUnique(opts, LCPEntryManager);\n\n const handleEntries = (entries: LCPMetric['entries']) => {\n // If reportAllChanges is set then call this function for each entry,\n // otherwise only consider the last one.\n if (!opts.reportAllChanges) {\n // eslint-disable-next-line no-param-reassign\n entries = entries.slice(-1);\n }\n\n for (const entry of entries) {\n lcpEntryManager._processEntry(entry);\n\n // Only report if the page wasn't hidden prior to LCP.\n if (entry.startTime < visibilityWatcher.firstHiddenTime) {\n // The startTime attribute returns the value of the renderTime if it is\n // not 0, and the value of the loadTime otherwise. The activationStart\n // reference is used because LCP should be relative to page activation\n // rather than navigation start if the page was prerendered. But in cases\n // where `activationStart` occurs after the LCP, this time should be\n // clamped at 0.\n metric.value = Math.max(entry.startTime - getActivationStart(), 0);\n metric.entries = [entry];\n report();\n }\n }\n };\n\n const po = observe('largest-contentful-paint', handleEntries);\n\n if (po) {\n report = bindReporter(onReport, metric, LCPThresholds, opts.reportAllChanges);\n\n // Ensure this logic only runs once, since it can be triggered from\n // any of three different event listeners below.\n const stopListening = runOnce(() => {\n handleEntries(po.takeRecords() as LCPMetric['entries']);\n po.disconnect();\n report(true);\n });\n\n // Need a separate wrapper to ensure the `runOnce` function above is\n // common for all three functions\n const stopListeningWrapper = (event: Event) => {\n if (event.isTrusted) {\n // Wrap the listener in an idle callback so it's run in a separate\n // task to reduce potential INP impact.\n // https://github.com/GoogleChrome/web-vitals/issues/383\n whenIdleOrHidden(stopListening);\n removePageListener(event.type, stopListeningWrapper, {\n capture: true,\n });\n }\n };\n\n // Stop listening after input or visibilitychange.\n // Note: while scrolling is an input that stops LCP observation, it's\n // unreliable since it can be programmatically generated.\n // See: https://github.com/GoogleChrome/web-vitals/issues/75\n for (const type of ['keydown', 'click', 'visibilitychange']) {\n addPageListener(type, stopListeningWrapper, {\n capture: true,\n });\n }\n }\n });\n};\n"],"names":["whenActivated","getVisibilityWatcher","initMetric","initUnique","LCPEntryManager","getActivationStart","observe","bindReporter","runOnce","whenIdleOrHidden","removePageListener","addPageListener"],"mappings":";;;;;;;;;;;;;;AA8BO,MAAM,aAAA,GAAwC,CAAC,IAAA,EAAM,GAAI;AAazD,MAAM,KAAA,GAAQ,CAAC,QAAA,EAAuC,IAAA,GAAmB,EAAC,KAAM;AACrF,EAAAA,2BAAA,CAAc,MAAM;AAClB,IAAA,MAAM,oBAAoBC,yCAAA,EAAqB;AAC/C,IAAA,MAAM,MAAA,GAASC,sBAAW,KAAK,CAAA;AAC/B,IAAA,IAAI,MAAA;AAEJ,IAAA,MAAM,eAAA,GAAkBC,qBAAA,CAAW,IAAA,EAAMC,+BAAe,CAAA;AAExD,IAAA,MAAM,aAAA,GAAgB,CAAC,OAAA,KAAkC;AAGvD,MAAA,IAAI,CAAC,KAAK,gBAAA,EAAkB;AAE1B,QAAA,OAAA,GAAU,OAAA,CAAQ,MAAM,EAAE,CAAA;AAAA,MAC5B;AAEA,MAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,QAAA,eAAA,CAAgB,cAAc,KAAK,CAAA;AAGnC,QAAA,IAAI,KAAA,CAAM,SAAA,GAAY,iBAAA,CAAkB,eAAA,EAAiB;AAOvD,UAAA,MAAA,CAAO,QAAQ,IAAA,CAAK,GAAA,CAAI,MAAM,SAAA,GAAYC,qCAAA,IAAsB,CAAC,CAAA;AACjE,UAAA,MAAA,CAAO,OAAA,GAAU,CAAC,KAAK,CAAA;AACvB,UAAA,MAAA,EAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,EAAA,GAAKC,eAAA,CAAQ,0BAAA,EAA4B,aAAa,CAAA;AAE5D,IAAA,IAAI,EAAA,EAAI;AACN,MAAA,MAAA,GAASC,yBAAA,CAAa,QAAA,EAAU,MAAA,EAAQ,aAAA,EAAe,KAAK,gBAAgB,CAAA;AAI5E,MAAA,MAAM,aAAA,GAAgBC,gBAAQ,MAAM;AAClC,QAAA,aAAA,CAAc,EAAA,CAAG,aAAqC,CAAA;AACtD,QAAA,EAAA,CAAG,UAAA,EAAW;AACd,QAAA,MAAA,CAAO,IAAI,CAAA;AAAA,MACb,CAAC,CAAA;AAID,MAAA,MAAM,oBAAA,GAAuB,CAAC,KAAA,KAAiB;AAC7C,QAAA,IAAI,MAAM,SAAA,EAAW;AAInB,UAAAC,iCAAA,CAAiB,aAAa,CAAA;AAC9B,UAAAC,kCAAA,CAAmB,KAAA,CAAM,MAAM,oBAAA,EAAsB;AAAA,YACnD,OAAA,EAAS;AAAA,WACV,CAAA;AAAA,QACH;AAAA,MACF,CAAA;AAMA,MAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,SAAA,EAAW,OAAA,EAAS,kBAAkB,CAAA,EAAG;AAC3D,QAAAC,+BAAA,CAAgB,MAAM,oBAAA,EAAsB;AAAA,UAC1C,OAAA,EAAS;AAAA,SACV,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;;;;;"}
|