@sentry/browser-utils 10.69.0 → 11.0.0-alpha.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/build/cjs/htmlTreeAsString.js.map +1 -1
- package/build/cjs/index.js +2 -1
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/metrics/browserMetrics.js +25 -91
- package/build/cjs/metrics/browserMetrics.js.map +1 -1
- package/build/cjs/metrics/inp.js +0 -57
- package/build/cjs/metrics/inp.js.map +1 -1
- package/build/cjs/metrics/lcp.js +0 -67
- package/build/cjs/metrics/lcp.js.map +1 -1
- package/build/cjs/metrics/userTiming.js +118 -0
- package/build/cjs/metrics/userTiming.js.map +1 -0
- package/build/cjs/metrics/utils.js +0 -43
- package/build/cjs/metrics/utils.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js +2 -6
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/initUnique.js +1 -1
- package/build/cjs/metrics/web-vitals/lib/initUnique.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/onHidden.js +3 -4
- package/build/cjs/metrics/web-vitals/lib/onHidden.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -2
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js.map +1 -1
- package/build/cjs/metrics/webVitalSpans.js +25 -9
- package/build/cjs/metrics/webVitalSpans.js.map +1 -1
- package/build/esm/htmlTreeAsString.js.map +1 -1
- package/build/esm/index.js +2 -1
- package/build/esm/index.js.map +1 -1
- package/build/esm/metrics/browserMetrics.js +29 -94
- package/build/esm/metrics/browserMetrics.js.map +1 -1
- package/build/esm/metrics/inp.js +3 -57
- package/build/esm/metrics/inp.js.map +1 -1
- package/build/esm/metrics/lcp.js +1 -66
- package/build/esm/metrics/lcp.js.map +1 -1
- package/build/esm/metrics/userTiming.js +115 -0
- package/build/esm/metrics/userTiming.js.map +1 -0
- package/build/esm/metrics/utils.js +2 -44
- package/build/esm/metrics/utils.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js +2 -6
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/initUnique.js +1 -1
- package/build/esm/metrics/web-vitals/lib/initUnique.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/onHidden.js +3 -4
- package/build/esm/metrics/web-vitals/lib/onHidden.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -2
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js.map +1 -1
- package/build/esm/metrics/webVitalSpans.js +26 -10
- package/build/esm/metrics/webVitalSpans.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/types/index.d.ts +2 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/metrics/browserMetrics.d.ts +5 -29
- package/build/types/metrics/browserMetrics.d.ts.map +1 -1
- package/build/types/metrics/inp.d.ts +0 -13
- package/build/types/metrics/inp.d.ts.map +1 -1
- package/build/types/metrics/lcp.d.ts +0 -16
- package/build/types/metrics/lcp.d.ts.map +1 -1
- package/build/types/metrics/userTiming.d.ts +37 -0
- package/build/types/metrics/userTiming.d.ts.map +1 -0
- package/build/types/metrics/utils.d.ts +1 -25
- package/build/types/metrics/utils.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/getCLS.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/getINP.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/getLCP.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts +1 -1
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts +3 -3
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/observe.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts +4 -16
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +1 -1
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/runOnce.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/whenActivated.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/onFCP.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/onTTFB.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/types.d.ts +1 -1
- package/build/types/metrics/web-vitals/types.d.ts.map +1 -1
- package/build/types/metrics/webVitalSpans.d.ts +15 -9
- package/build/types/metrics/webVitalSpans.d.ts.map +1 -1
- package/build/types/types.d.ts +1 -1
- package/package.json +6 -15
- package/build/cjs/metrics/cls.js +0 -64
- package/build/cjs/metrics/cls.js.map +0 -1
- package/build/esm/metrics/cls.js +0 -61
- package/build/esm/metrics/cls.js.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-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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inp.js","sources":["../../../src/metrics/inp.ts"],"sourcesContent":["import type { Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n isBrowser,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport type { InstrumentationHandlerCallback } from './instrument';\nimport {\n addInpInstrumentationHandler,\n addPerformanceInstrumentationHandler,\n isPerformanceEventTiming,\n} from './instrument';\nimport { getBrowserPerformanceAPI, msToSec, startStandaloneWebVitalSpan } from './utils';\n\ninterface InteractionContext {\n span: Span | undefined;\n elementName: string;\n}\n\nconst LAST_INTERACTIONS: number[] = [];\nconst INTERACTIONS_SPAN_MAP = new Map<number, InteractionContext>();\n\n// Map to store element names by timestamp, since we get the DOM event before the PerformanceObserver entry\nconst ELEMENT_NAME_TIMESTAMP_MAP = new Map<number, string>();\n\n/**\n * 60 seconds is the maximum for a plausible INP value\n * (source: Me)\n */\nexport const MAX_PLAUSIBLE_INP_DURATION = 60;\n/**\n * Start tracking INP webvital events.\n */\nexport function startTrackingINP(): () => void {\n const performance = getBrowserPerformanceAPI();\n if (performance && browserPerformanceTimeOrigin()) {\n const inpCallback = _trackINP();\n\n return (): void => {\n inpCallback();\n };\n }\n\n return () => undefined;\n}\n\nexport const INP_ENTRY_MAP: Record<string, 'click' | 'hover' | 'drag' | 'press'> = {\n click: 'click',\n pointerdown: 'click',\n pointerup: 'click',\n mousedown: 'click',\n mouseup: 'click',\n touchstart: 'click',\n touchend: 'click',\n mouseover: 'hover',\n mouseout: 'hover',\n mouseenter: 'hover',\n mouseleave: 'hover',\n pointerover: 'hover',\n pointerout: 'hover',\n pointerenter: 'hover',\n pointerleave: 'hover',\n dragstart: 'drag',\n dragend: 'drag',\n drag: 'drag',\n dragenter: 'drag',\n dragleave: 'drag',\n dragover: 'drag',\n drop: 'drag',\n keydown: 'press',\n keyup: 'press',\n keypress: 'press',\n input: 'press',\n};\n\n/** Starts tracking the Interaction to Next Paint on the current page. #\n * exported only for testing\n */\nexport function _trackINP(): () => void {\n return addInpInstrumentationHandler(_onInp);\n}\n\n/**\n * exported only for testing\n */\nexport const _onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (metric.value == undefined) {\n return;\n }\n\n const duration = msToSec(metric.value);\n\n // We received occasional reports of hour-long INP values.\n // Therefore, we add a sanity check to avoid creating spans for\n // unrealistically long INP durations.\n if (duration > MAX_PLAUSIBLE_INP_DURATION) {\n return;\n }\n\n const entry = metric.entries.find(entry => entry.duration === metric.value && INP_ENTRY_MAP[entry.name]);\n\n if (!entry) {\n return;\n }\n\n const { interactionId } = entry;\n const interactionType = INP_ENTRY_MAP[entry.name];\n\n /** Build the INP span, create an envelope from the span, and then send the envelope */\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // We first try to lookup the interaction context from our INTERACTIONS_SPAN_MAP,\n // where we cache the route and element name per interactionId\n const cachedInteractionContext = interactionId != null ? INTERACTIONS_SPAN_MAP.get(interactionId) : undefined;\n\n const spanToUse = cachedInteractionContext?.span || rootSpan;\n\n // Else, we try to use the active span.\n // Finally, we fall back to look at the transactionName on the scope\n const routeName = spanToUse ? spanToJSON(spanToUse).description : getCurrentScope().getScopeData().transactionName;\n\n const name = cachedInteractionContext?.elementName || htmlTreeAsString(entry.target);\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.inp',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `ui.interaction.${interactionType}`,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry.duration,\n };\n\n const span = startStandaloneWebVitalSpan({\n name,\n transaction: routeName,\n attributes,\n startTime,\n });\n\n if (span) {\n span.addEvent('inp', {\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: 'millisecond',\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: metric.value,\n });\n\n span.end(startTime + duration);\n }\n};\n\n/**\n * Look up a cached interaction context (element name + root span) by interactionId.\n * Returns undefined if no context was cached for this interaction.\n */\nexport function getCachedInteractionContext(interactionId: number | undefined): InteractionContext | undefined {\n return interactionId != null ? INTERACTIONS_SPAN_MAP.get(interactionId) : undefined;\n}\n\n/**\n * Register a listener to cache route information for INP interactions.\n */\nexport function registerInpInteractionListener(): void {\n // Listen for all interaction events that could contribute to INP\n const interactionEvents = Object.keys(INP_ENTRY_MAP);\n if (isBrowser()) {\n interactionEvents.forEach(eventType => {\n WINDOW.addEventListener(eventType, captureElementFromEvent, { capture: true, passive: true });\n });\n }\n\n /**\n * Captures the element name from a DOM event and stores it in the ELEMENT_NAME_TIMESTAMP_MAP.\n */\n function captureElementFromEvent(event: Event): void {\n const target = event.target as HTMLElement | null;\n if (!target) {\n return;\n }\n\n const elementName = htmlTreeAsString(target);\n const timestamp = Math.round(event.timeStamp);\n\n // Store the element name by timestamp so we can match it with the PerformanceEntry\n ELEMENT_NAME_TIMESTAMP_MAP.set(timestamp, elementName);\n\n // Clean up old\n if (ELEMENT_NAME_TIMESTAMP_MAP.size > 50) {\n const firstKey = ELEMENT_NAME_TIMESTAMP_MAP.keys().next().value;\n if (firstKey !== undefined) {\n ELEMENT_NAME_TIMESTAMP_MAP.delete(firstKey);\n }\n }\n }\n\n /**\n * Tries to get the element name from the timestamp map.\n */\n function resolveElementNameFromEntry(entry: PerformanceEntry): string {\n const timestamp = Math.round(entry.startTime);\n let elementName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp);\n\n // try nearby timestamps (±5ms)\n if (!elementName) {\n for (let offset = -5; offset <= 5; offset++) {\n const nearbyName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp + offset);\n if (nearbyName) {\n elementName = nearbyName;\n break;\n }\n }\n }\n\n return elementName || '<unknown>';\n }\n\n const handleEntries = ({ entries }: { entries: PerformanceEntry[] }): void => {\n const activeSpan = getActiveSpan();\n const activeRootSpan = activeSpan && getRootSpan(activeSpan);\n\n entries.forEach(entry => {\n if (!isPerformanceEventTiming(entry)) {\n return;\n }\n\n const interactionId = entry.interactionId;\n if (interactionId == null) {\n return;\n }\n\n // If the interaction was already recorded before, nothing more to do\n if (INTERACTIONS_SPAN_MAP.has(interactionId)) {\n return;\n }\n\n const elementName = entry.target ? htmlTreeAsString(entry.target) : resolveElementNameFromEntry(entry);\n\n // We keep max. 10 interactions in the list, then remove the oldest one & clean up\n if (LAST_INTERACTIONS.length > 10) {\n const last = LAST_INTERACTIONS.shift() as number;\n INTERACTIONS_SPAN_MAP.delete(last);\n }\n\n // We add the interaction to the list of recorded interactions\n // and store both the span and element name for this interaction\n LAST_INTERACTIONS.push(interactionId);\n INTERACTIONS_SPAN_MAP.set(interactionId, {\n span: activeRootSpan,\n elementName,\n });\n });\n };\n\n addPerformanceInstrumentationHandler('event', handleEntries);\n addPerformanceInstrumentationHandler('first-input', handleEntries);\n}\n"],"names":["getBrowserPerformanceAPI","browserPerformanceTimeOrigin","addInpInstrumentationHandler","msToSec","entry","getActiveSpan","getRootSpan","spanToJSON","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","isBrowser","WINDOW","isPerformanceEventTiming","addPerformanceInstrumentationHandler"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"inp.js","sources":["../../../src/metrics/inp.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { getActiveSpan, getRootSpan, isBrowser } from '@sentry/core';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport { addPerformanceInstrumentationHandler, isPerformanceEventTiming } from './instrument';\n\ninterface InteractionContext {\n span: Span | undefined;\n elementName: string;\n}\n\nconst LAST_INTERACTIONS: number[] = [];\nconst INTERACTIONS_SPAN_MAP = new Map<number, InteractionContext>();\n\n// Map to store element names by timestamp, since we get the DOM event before the PerformanceObserver entry\nconst ELEMENT_NAME_TIMESTAMP_MAP = new Map<number, string>();\n\n/**\n * 60 seconds is the maximum for a plausible INP value\n * (source: Me)\n */\nexport const MAX_PLAUSIBLE_INP_DURATION = 60;\n\nexport const INP_ENTRY_MAP: Record<string, 'click' | 'hover' | 'drag' | 'press'> = {\n click: 'click',\n pointerdown: 'click',\n pointerup: 'click',\n mousedown: 'click',\n mouseup: 'click',\n touchstart: 'click',\n touchend: 'click',\n mouseover: 'hover',\n mouseout: 'hover',\n mouseenter: 'hover',\n mouseleave: 'hover',\n pointerover: 'hover',\n pointerout: 'hover',\n pointerenter: 'hover',\n pointerleave: 'hover',\n dragstart: 'drag',\n dragend: 'drag',\n drag: 'drag',\n dragenter: 'drag',\n dragleave: 'drag',\n dragover: 'drag',\n drop: 'drag',\n keydown: 'press',\n keyup: 'press',\n keypress: 'press',\n input: 'press',\n};\n\n/**\n * Look up a cached interaction context (element name + root span) by interactionId.\n * Returns undefined if no context was cached for this interaction.\n */\nexport function getCachedInteractionContext(interactionId: number | undefined): InteractionContext | undefined {\n return interactionId != null ? INTERACTIONS_SPAN_MAP.get(interactionId) : undefined;\n}\n\n/**\n * Register a listener to cache route information for INP interactions.\n */\nexport function registerInpInteractionListener(): void {\n // Listen for all interaction events that could contribute to INP\n const interactionEvents = Object.keys(INP_ENTRY_MAP);\n if (isBrowser()) {\n interactionEvents.forEach(eventType => {\n WINDOW.addEventListener(eventType, captureElementFromEvent, { capture: true, passive: true });\n });\n }\n\n /**\n * Captures the element name from a DOM event and stores it in the ELEMENT_NAME_TIMESTAMP_MAP.\n */\n function captureElementFromEvent(event: Event): void {\n const target = event.target as HTMLElement | null;\n if (!target) {\n return;\n }\n\n const elementName = htmlTreeAsString(target);\n const timestamp = Math.round(event.timeStamp);\n\n // Store the element name by timestamp so we can match it with the PerformanceEntry\n ELEMENT_NAME_TIMESTAMP_MAP.set(timestamp, elementName);\n\n // Clean up old\n if (ELEMENT_NAME_TIMESTAMP_MAP.size > 50) {\n const firstKey = ELEMENT_NAME_TIMESTAMP_MAP.keys().next().value;\n if (firstKey !== undefined) {\n ELEMENT_NAME_TIMESTAMP_MAP.delete(firstKey);\n }\n }\n }\n\n /**\n * Tries to get the element name from the timestamp map.\n */\n function resolveElementNameFromEntry(entry: PerformanceEntry): string {\n const timestamp = Math.round(entry.startTime);\n let elementName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp);\n\n // try nearby timestamps (±5ms)\n if (!elementName) {\n for (let offset = -5; offset <= 5; offset++) {\n const nearbyName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp + offset);\n if (nearbyName) {\n elementName = nearbyName;\n break;\n }\n }\n }\n\n return elementName || '<unknown>';\n }\n\n const handleEntries = ({ entries }: { entries: PerformanceEntry[] }): void => {\n const activeSpan = getActiveSpan();\n const activeRootSpan = activeSpan && getRootSpan(activeSpan);\n\n entries.forEach(entry => {\n if (!isPerformanceEventTiming(entry)) {\n return;\n }\n\n const interactionId = entry.interactionId;\n if (interactionId == null) {\n return;\n }\n\n // If the interaction was already recorded before, nothing more to do\n if (INTERACTIONS_SPAN_MAP.has(interactionId)) {\n return;\n }\n\n const elementName = entry.target ? htmlTreeAsString(entry.target) : resolveElementNameFromEntry(entry);\n\n // We keep max. 10 interactions in the list, then remove the oldest one & clean up\n if (LAST_INTERACTIONS.length > 10) {\n const last = LAST_INTERACTIONS.shift() as number;\n INTERACTIONS_SPAN_MAP.delete(last);\n }\n\n // We add the interaction to the list of recorded interactions\n // and store both the span and element name for this interaction\n LAST_INTERACTIONS.push(interactionId);\n INTERACTIONS_SPAN_MAP.set(interactionId, {\n span: activeRootSpan,\n elementName,\n });\n });\n };\n\n addPerformanceInstrumentationHandler('event', handleEntries);\n addPerformanceInstrumentationHandler('first-input', handleEntries);\n}\n"],"names":["isBrowser","WINDOW","htmlTreeAsString","getActiveSpan","getRootSpan","isPerformanceEventTiming","addPerformanceInstrumentationHandler"],"mappings":";;;;;;;AAWA,MAAM,oBAA8B,EAAC;AACrC,MAAM,qBAAA,uBAA4B,GAAA,EAAgC;AAGlE,MAAM,0BAAA,uBAAiC,GAAA,EAAoB;AAMpD,MAAM,0BAAA,GAA6B;AAEnC,MAAM,aAAA,GAAsE;AAAA,EACjF,KAAA,EAAO,OAAA;AAAA,EACP,WAAA,EAAa,OAAA;AAAA,EACb,SAAA,EAAW,OAAA;AAAA,EACX,SAAA,EAAW,OAAA;AAAA,EACX,OAAA,EAAS,OAAA;AAAA,EACT,UAAA,EAAY,OAAA;AAAA,EACZ,QAAA,EAAU,OAAA;AAAA,EACV,SAAA,EAAW,OAAA;AAAA,EACX,QAAA,EAAU,OAAA;AAAA,EACV,UAAA,EAAY,OAAA;AAAA,EACZ,UAAA,EAAY,OAAA;AAAA,EACZ,WAAA,EAAa,OAAA;AAAA,EACb,UAAA,EAAY,OAAA;AAAA,EACZ,YAAA,EAAc,OAAA;AAAA,EACd,YAAA,EAAc,OAAA;AAAA,EACd,SAAA,EAAW,MAAA;AAAA,EACX,OAAA,EAAS,MAAA;AAAA,EACT,IAAA,EAAM,MAAA;AAAA,EACN,SAAA,EAAW,MAAA;AAAA,EACX,SAAA,EAAW,MAAA;AAAA,EACX,QAAA,EAAU,MAAA;AAAA,EACV,IAAA,EAAM,MAAA;AAAA,EACN,OAAA,EAAS,OAAA;AAAA,EACT,KAAA,EAAO,OAAA;AAAA,EACP,QAAA,EAAU,OAAA;AAAA,EACV,KAAA,EAAO;AACT;AAMO,SAAS,4BAA4B,aAAA,EAAmE;AAC7G,EAAA,OAAO,aAAA,IAAiB,IAAA,GAAO,qBAAA,CAAsB,GAAA,CAAI,aAAa,CAAA,GAAI,MAAA;AAC5E;AAKO,SAAS,8BAAA,GAAuC;AAErD,EAAA,MAAM,iBAAA,GAAoB,MAAA,CAAO,IAAA,CAAK,aAAa,CAAA;AACnD,EAAA,IAAIA,gBAAU,EAAG;AACf,IAAA,iBAAA,CAAkB,QAAQ,CAAA,SAAA,KAAa;AACrC,MAAAC,YAAA,CAAO,gBAAA,CAAiB,WAAW,uBAAA,EAAyB,EAAE,SAAS,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AAAA,IAC9F,CAAC,CAAA;AAAA,EACH;AAKA,EAAA,SAAS,wBAAwB,KAAA,EAAoB;AACnD,IAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,WAAA,GAAcC,kCAAiB,MAAM,CAAA;AAC3C,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,SAAS,CAAA;AAG5C,IAAA,0BAAA,CAA2B,GAAA,CAAI,WAAW,WAAW,CAAA;AAGrD,IAAA,IAAI,0BAAA,CAA2B,OAAO,EAAA,EAAI;AACxC,MAAA,MAAM,QAAA,GAAW,0BAAA,CAA2B,IAAA,EAAK,CAAE,MAAK,CAAE,KAAA;AAC1D,MAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,QAAA,0BAAA,CAA2B,OAAO,QAAQ,CAAA;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAKA,EAAA,SAAS,4BAA4B,KAAA,EAAiC;AACpE,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,SAAS,CAAA;AAC5C,IAAA,IAAI,WAAA,GAAc,0BAAA,CAA2B,GAAA,CAAI,SAAS,CAAA;AAG1D,IAAA,IAAI,CAAC,WAAA,EAAa;AAChB,MAAA,KAAA,IAAS,MAAA,GAAS,EAAA,EAAI,MAAA,IAAU,CAAA,EAAG,MAAA,EAAA,EAAU;AAC3C,QAAA,MAAM,UAAA,GAAa,0BAAA,CAA2B,GAAA,CAAI,SAAA,GAAY,MAAM,CAAA;AACpE,QAAA,IAAI,UAAA,EAAY;AACd,UAAA,WAAA,GAAc,UAAA;AACd,UAAA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,WAAA,IAAe,WAAA;AAAA,EACxB;AAEA,EAAA,MAAM,aAAA,GAAgB,CAAC,EAAE,OAAA,EAAQ,KAA6C;AAC5E,IAAA,MAAM,aAAaC,kBAAA,EAAc;AACjC,IAAA,MAAM,cAAA,GAAiB,UAAA,IAAcC,gBAAA,CAAY,UAAU,CAAA;AAE3D,IAAA,OAAA,CAAQ,QAAQ,CAAA,KAAA,KAAS;AACvB,MAAA,IAAI,CAACC,mCAAA,CAAyB,KAAK,CAAA,EAAG;AACpC,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,gBAAgB,KAAA,CAAM,aAAA;AAC5B,MAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,QAAA;AAAA,MACF;AAGA,MAAA,IAAI,qBAAA,CAAsB,GAAA,CAAI,aAAa,CAAA,EAAG;AAC5C,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,WAAA,GAAc,MAAM,MAAA,GAASH,iCAAA,CAAiB,MAAM,MAAM,CAAA,GAAI,4BAA4B,KAAK,CAAA;AAGrG,MAAA,IAAI,iBAAA,CAAkB,SAAS,EAAA,EAAI;AACjC,QAAA,MAAM,IAAA,GAAO,kBAAkB,KAAA,EAAM;AACrC,QAAA,qBAAA,CAAsB,OAAO,IAAI,CAAA;AAAA,MACnC;AAIA,MAAA,iBAAA,CAAkB,KAAK,aAAa,CAAA;AACpC,MAAA,qBAAA,CAAsB,IAAI,aAAA,EAAe;AAAA,QACvC,IAAA,EAAM,cAAA;AAAA,QACN;AAAA,OACD,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAAI,+CAAA,CAAqC,SAAS,aAAa,CAAA;AAC3D,EAAAA,+CAAA,CAAqC,eAAe,aAAa,CAAA;AACnE;;;;;;;"}
|
package/build/cjs/metrics/lcp.js
CHANGED
|
@@ -1,77 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
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
3
|
const MAX_PLAUSIBLE_LCP_DURATION = 6e4;
|
|
10
4
|
function isValidLcpMetric(lcpValue) {
|
|
11
5
|
return lcpValue != null && lcpValue > 0 && lcpValue <= MAX_PLAUSIBLE_LCP_DURATION;
|
|
12
6
|
}
|
|
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
7
|
|
|
73
8
|
exports.MAX_PLAUSIBLE_LCP_DURATION = MAX_PLAUSIBLE_LCP_DURATION;
|
|
74
|
-
exports._sendStandaloneLcpSpan = _sendStandaloneLcpSpan;
|
|
75
9
|
exports.isValidLcpMetric = isValidLcpMetric;
|
|
76
|
-
exports.trackLcpAsStandaloneSpan = trackLcpAsStandaloneSpan;
|
|
77
10
|
//# sourceMappingURL=lcp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lcp.js","sources":["../../../src/metrics/lcp.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"lcp.js","sources":["../../../src/metrics/lcp.ts"],"sourcesContent":["/**\n * 60 seconds is the maximum for a plausible LCP value.\n */\nexport const MAX_PLAUSIBLE_LCP_DURATION = 60_000;\n\nexport function isValidLcpMetric(lcpValue: number | undefined): lcpValue is number {\n return lcpValue != null && lcpValue > 0 && lcpValue <= MAX_PLAUSIBLE_LCP_DURATION;\n}\n"],"names":[],"mappings":";;AAGO,MAAM,0BAAA,GAA6B;AAEnC,SAAS,iBAAiB,QAAA,EAAkD;AACjF,EAAA,OAAO,QAAA,IAAY,IAAA,IAAQ,QAAA,GAAW,CAAA,IAAK,QAAA,IAAY,0BAAA;AACzD;;;;;"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const attributes = require('@sentry/conventions/attributes');
|
|
4
|
+
const core = require('@sentry/core');
|
|
5
|
+
const utils = require('./utils.js');
|
|
6
|
+
const getNavigationEntry = require('./web-vitals/lib/getNavigationEntry.js');
|
|
7
|
+
|
|
8
|
+
const INTEGRATION_NAME = "UserTiming";
|
|
9
|
+
const _userTimingIntegration = ((options = {}) => {
|
|
10
|
+
return {
|
|
11
|
+
name: INTEGRATION_NAME,
|
|
12
|
+
setup(client) {
|
|
13
|
+
const performance = utils.getBrowserPerformanceAPI();
|
|
14
|
+
const timeOrigin = core.browserPerformanceTimeOrigin();
|
|
15
|
+
if (!performance?.getEntries || !timeOrigin) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const timeOriginInSeconds = utils.msToSec(timeOrigin);
|
|
19
|
+
let performanceCursor = 0;
|
|
20
|
+
client.on("beforeIdleSpanEnd", (idleSpan) => {
|
|
21
|
+
const { op: parentOp, start_timestamp: parentStartTimestamp } = core.spanToJSON(idleSpan);
|
|
22
|
+
if (parentOp !== "pageload" && parentOp !== "navigation") {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const requestTime = utils.msToSec(getNavigationEntry.getNavigationEntry(false)?.requestStart ?? 0);
|
|
26
|
+
const performanceEntries = performance.getEntries();
|
|
27
|
+
for (const entry of performanceEntries.slice(performanceCursor)) {
|
|
28
|
+
if (entry.entryType !== "mark" && entry.entryType !== "measure") {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const startTime = utils.msToSec(entry.startTime);
|
|
32
|
+
const absoluteStartTime = timeOriginInSeconds + startTime;
|
|
33
|
+
if (parentOp === "navigation" && parentStartTimestamp && absoluteStartTime < parentStartTimestamp) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
_addUserTimingSpan(
|
|
37
|
+
idleSpan,
|
|
38
|
+
entry,
|
|
39
|
+
startTime,
|
|
40
|
+
utils.msToSec(Math.max(0, entry.duration)),
|
|
41
|
+
timeOriginInSeconds,
|
|
42
|
+
requestTime,
|
|
43
|
+
options.ignore ?? []
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
performanceCursor = performanceEntries.length;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
const userTimingIntegration = core.defineIntegration(_userTimingIntegration);
|
|
52
|
+
function _addUserTimingSpan(parentSpan, entry, startTime, duration, timeOrigin, requestTime, ignore) {
|
|
53
|
+
if (isReact19MeasureEntry(entry) || core.stringMatchesSomePattern(entry.name, ignore)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const spanStartTimestamp = timeOrigin + Math.max(startTime, requestTime);
|
|
57
|
+
const originalStartTimestamp = timeOrigin + startTime;
|
|
58
|
+
const spanEndTimestamp = originalStartTimestamp + duration;
|
|
59
|
+
const attributes$1 = {
|
|
60
|
+
[attributes.SENTRY_ORIGIN]: `auto.browser.user_timing.${entry.entryType}`
|
|
61
|
+
};
|
|
62
|
+
if (spanStartTimestamp !== originalStartTimestamp) {
|
|
63
|
+
attributes$1["sentry.browser.measure_happened_before_request"] = true;
|
|
64
|
+
attributes$1["sentry.browser.measure_start_time"] = spanStartTimestamp;
|
|
65
|
+
}
|
|
66
|
+
addDetailToSpanAttributes(attributes$1, entry);
|
|
67
|
+
if (spanStartTimestamp <= spanEndTimestamp) {
|
|
68
|
+
utils.startAndEndSpan(parentSpan, spanStartTimestamp, spanEndTimestamp, {
|
|
69
|
+
name: entry.name,
|
|
70
|
+
op: entry.entryType,
|
|
71
|
+
attributes: attributes$1
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function isReact19MeasureEntry(entry) {
|
|
76
|
+
if (entry.entryType !== "measure") {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return entry.detail.devtools.track === "Components \u269B";
|
|
81
|
+
} catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function addDetailToSpanAttributes(attributes, entry) {
|
|
86
|
+
try {
|
|
87
|
+
const detail = entry.detail;
|
|
88
|
+
if (!detail) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (typeof detail === "object") {
|
|
92
|
+
for (const [key, value] of Object.entries(detail)) {
|
|
93
|
+
if (value && core.isPrimitive(value)) {
|
|
94
|
+
attributes[`sentry.browser.measure.detail.${key}`] = value;
|
|
95
|
+
} else if (value !== void 0) {
|
|
96
|
+
try {
|
|
97
|
+
attributes[`sentry.browser.measure.detail.${key}`] = JSON.stringify(value);
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (core.isPrimitive(detail)) {
|
|
105
|
+
attributes["sentry.browser.measure.detail"] = detail;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
attributes["sentry.browser.measure.detail"] = JSON.stringify(detail);
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
exports._addUserTimingSpan = _addUserTimingSpan;
|
|
117
|
+
exports.userTimingIntegration = userTimingIntegration;
|
|
118
|
+
//# sourceMappingURL=userTiming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userTiming.js","sources":["../../../src/metrics/userTiming.ts"],"sourcesContent":["import { SENTRY_ORIGIN } from '@sentry/conventions/attributes';\nimport type { IntegrationFn, Span, SpanAttributes, SpanAttributeValue } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n defineIntegration,\n isPrimitive,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core';\nimport { getBrowserPerformanceAPI, msToSec, startAndEndSpan } from './utils';\nimport { getNavigationEntry } from './web-vitals/lib/getNavigationEntry';\n\ninterface UserTimingOptions {\n /**\n * User Timing entries with names matching any of these strings or regular expressions will not be emitted.\n *\n * Default: []\n */\n ignore?: Array<string | RegExp>;\n}\n\nconst INTEGRATION_NAME = 'UserTiming';\n\nconst _userTimingIntegration = ((options: UserTimingOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n const performance = getBrowserPerformanceAPI();\n const timeOrigin = browserPerformanceTimeOrigin();\n if (!performance?.getEntries || !timeOrigin) {\n return;\n }\n const timeOriginInSeconds = msToSec(timeOrigin);\n let performanceCursor = 0;\n\n client.on('beforeIdleSpanEnd', idleSpan => {\n const { op: parentOp, start_timestamp: parentStartTimestamp } = spanToJSON(idleSpan);\n if (parentOp !== 'pageload' && parentOp !== 'navigation') {\n return;\n }\n\n const requestTime = msToSec(getNavigationEntry(false)?.requestStart ?? 0);\n const performanceEntries = performance.getEntries();\n\n for (const entry of performanceEntries.slice(performanceCursor)) {\n if (entry.entryType !== 'mark' && entry.entryType !== 'measure') {\n continue;\n }\n\n const startTime = msToSec(entry.startTime);\n const absoluteStartTime = timeOriginInSeconds + startTime;\n\n if (parentOp === 'navigation' && parentStartTimestamp && absoluteStartTime < parentStartTimestamp) {\n continue;\n }\n\n _addUserTimingSpan(\n idleSpan,\n entry,\n startTime,\n msToSec(Math.max(0, entry.duration)),\n timeOriginInSeconds,\n requestTime,\n options.ignore ?? [],\n );\n }\n\n performanceCursor = performanceEntries.length;\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Captures spans created with the browser's User Timing APIs, `performance.mark` and `performance.measure`.\n *\n * The integration must be explicitly added to `Sentry.init`. Entries are attached to the active pageload or\n * navigation span when it ends.\n *\n * @example\n * ```ts\n * Sentry.init({\n * integrations: [\n * Sentry.browserTracingIntegration(),\n * Sentry.userTimingIntegration({\n * ignore: ['third-party-mark', /framework-measure/],\n * }),\n * ],\n * });\n * ```\n */\nexport const userTimingIntegration = defineIntegration(_userTimingIntegration);\n\n/**\n * Creates a span for a browser User Timing entry.\n * Exported only for tests.\n */\nexport function _addUserTimingSpan(\n parentSpan: Span,\n entry: PerformanceEntry,\n startTime: number,\n duration: number,\n timeOrigin: number,\n requestTime: number,\n ignore: Array<string | RegExp>,\n): void {\n if (isReact19MeasureEntry(entry) || stringMatchesSomePattern(entry.name, ignore)) {\n return;\n }\n\n // Measures can reference arbitrary timestamps, including timestamps before the page request started.\n const spanStartTimestamp = timeOrigin + Math.max(startTime, requestTime);\n const originalStartTimestamp = timeOrigin + startTime;\n const spanEndTimestamp = originalStartTimestamp + duration;\n\n const attributes: SpanAttributes = {\n [SENTRY_ORIGIN]: `auto.browser.user_timing.${entry.entryType}`,\n };\n\n if (spanStartTimestamp !== originalStartTimestamp) {\n attributes['sentry.browser.measure_happened_before_request'] = true;\n attributes['sentry.browser.measure_start_time'] = spanStartTimestamp;\n }\n\n addDetailToSpanAttributes(attributes, entry as PerformanceMeasure);\n\n // Third-party measurements can contain timestamps which would produce invalid spans.\n if (spanStartTimestamp <= spanEndTimestamp) {\n startAndEndSpan(parentSpan, spanStartTimestamp, spanEndTimestamp, {\n name: entry.name,\n op: entry.entryType,\n attributes,\n });\n }\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 */\nfunction isReact19MeasureEntry(entry: PerformanceEntry): boolean | void {\n if (entry.entryType !== 'measure') {\n return;\n }\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\nfunction addDetailToSpanAttributes(attributes: SpanAttributes, entry: PerformanceMeasure): void {\n try {\n // Accessing detail can throw in some browsers due to security restrictions.\n const detail = entry.detail;\n if (!detail) {\n return;\n }\n\n if (typeof detail === 'object') {\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 attributes[`sentry.browser.measure.detail.${key}`] = JSON.stringify(value);\n } catch {\n // User-provided detail values are not guaranteed to be serializable.\n }\n }\n }\n return;\n }\n\n if (isPrimitive(detail)) {\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 // User-provided detail values are not guaranteed to be serializable.\n }\n } catch {\n // Accessing detail can throw in some browsers due to security restrictions.\n }\n}\n"],"names":["getBrowserPerformanceAPI","browserPerformanceTimeOrigin","msToSec","spanToJSON","getNavigationEntry","defineIntegration","stringMatchesSomePattern","attributes","SENTRY_ORIGIN","startAndEndSpan","isPrimitive"],"mappings":";;;;;;;AAqBA,MAAM,gBAAA,GAAmB,YAAA;AAEzB,MAAM,sBAAA,IAA0B,CAAC,OAAA,GAA6B,EAAC,KAAM;AACnE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,MAAM,MAAA,EAAQ;AACZ,MAAA,MAAM,cAAcA,8BAAA,EAAyB;AAC7C,MAAA,MAAM,aAAaC,iCAAA,EAA6B;AAChD,MAAA,IAAI,CAAC,WAAA,EAAa,UAAA,IAAc,CAAC,UAAA,EAAY;AAC3C,QAAA;AAAA,MACF;AACA,MAAA,MAAM,mBAAA,GAAsBC,cAAQ,UAAU,CAAA;AAC9C,MAAA,IAAI,iBAAA,GAAoB,CAAA;AAExB,MAAA,MAAA,CAAO,EAAA,CAAG,qBAAqB,CAAA,QAAA,KAAY;AACzC,QAAA,MAAM,EAAE,EAAA,EAAI,QAAA,EAAU,iBAAiB,oBAAA,EAAqB,GAAIC,gBAAW,QAAQ,CAAA;AACnF,QAAA,IAAI,QAAA,KAAa,UAAA,IAAc,QAAA,KAAa,YAAA,EAAc;AACxD,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,cAAcD,aAAA,CAAQE,qCAAA,CAAmB,KAAK,CAAA,EAAG,gBAAgB,CAAC,CAAA;AACxE,QAAA,MAAM,kBAAA,GAAqB,YAAY,UAAA,EAAW;AAElD,QAAA,KAAA,MAAW,KAAA,IAAS,kBAAA,CAAmB,KAAA,CAAM,iBAAiB,CAAA,EAAG;AAC/D,UAAA,IAAI,KAAA,CAAM,SAAA,KAAc,MAAA,IAAU,KAAA,CAAM,cAAc,SAAA,EAAW;AAC/D,YAAA;AAAA,UACF;AAEA,UAAA,MAAM,SAAA,GAAYF,aAAA,CAAQ,KAAA,CAAM,SAAS,CAAA;AACzC,UAAA,MAAM,oBAAoB,mBAAA,GAAsB,SAAA;AAEhD,UAAA,IAAI,QAAA,KAAa,YAAA,IAAgB,oBAAA,IAAwB,iBAAA,GAAoB,oBAAA,EAAsB;AACjG,YAAA;AAAA,UACF;AAEA,UAAA,kBAAA;AAAA,YACE,QAAA;AAAA,YACA,KAAA;AAAA,YACA,SAAA;AAAA,YACAA,cAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAA,CAAM,QAAQ,CAAC,CAAA;AAAA,YACnC,mBAAA;AAAA,YACA,WAAA;AAAA,YACA,OAAA,CAAQ,UAAU;AAAC,WACrB;AAAA,QACF;AAEA,QAAA,iBAAA,GAAoB,kBAAA,CAAmB,MAAA;AAAA,MACzC,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAoBO,MAAM,qBAAA,GAAwBG,uBAAkB,sBAAsB;AAMtE,SAAS,mBACd,UAAA,EACA,KAAA,EACA,WACA,QAAA,EACA,UAAA,EACA,aACA,MAAA,EACM;AACN,EAAA,IAAI,sBAAsB,KAAK,CAAA,IAAKC,8BAAyB,KAAA,CAAM,IAAA,EAAM,MAAM,CAAA,EAAG;AAChF,IAAA;AAAA,EACF;AAGA,EAAA,MAAM,kBAAA,GAAqB,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,WAAW,WAAW,CAAA;AACvE,EAAA,MAAM,yBAAyB,UAAA,GAAa,SAAA;AAC5C,EAAA,MAAM,mBAAmB,sBAAA,GAAyB,QAAA;AAElD,EAAA,MAAMC,YAAA,GAA6B;AAAA,IACjC,CAACC,wBAAa,GAAG,CAAA,yBAAA,EAA4B,MAAM,SAAS,CAAA;AAAA,GAC9D;AAEA,EAAA,IAAI,uBAAuB,sBAAA,EAAwB;AACjD,IAAAD,YAAA,CAAW,gDAAgD,CAAA,GAAI,IAAA;AAC/D,IAAAA,YAAA,CAAW,mCAAmC,CAAA,GAAI,kBAAA;AAAA,EACpD;AAEA,EAAA,yBAAA,CAA0BA,cAAY,KAA2B,CAAA;AAGjE,EAAA,IAAI,sBAAsB,gBAAA,EAAkB;AAC1C,IAAAE,qBAAA,CAAgB,UAAA,EAAY,oBAAoB,gBAAA,EAAkB;AAAA,MAChE,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,IAAI,KAAA,CAAM,SAAA;AAAA,kBACVF;AAAA,KACD,CAAA;AAAA,EACH;AACF;AAOA,SAAS,sBAAsB,KAAA,EAAyC;AACtE,EAAA,IAAI,KAAA,CAAM,cAAc,SAAA,EAAW;AACjC,IAAA;AAAA,EACF;AAEA,EAAA,IAAI;AAEF,IAAA,OAAQ,KAAA,CAA6B,MAAA,CAAO,QAAA,CAAS,KAAA,KAAU,mBAAA;AAAA,EACjE,CAAA,CAAA,MAAQ;AACN,IAAA;AAAA,EACF;AACF;AAEA,SAAS,yBAAA,CAA0B,YAA4B,KAAA,EAAiC;AAC9F,EAAA,IAAI;AAEF,IAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,WAAW,QAAA,EAAU;AAC9B,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AACjD,QAAA,IAAI,KAAA,IAASG,gBAAA,CAAY,KAAK,CAAA,EAAG;AAC/B,UAAA,UAAA,CAAW,CAAA,8BAAA,EAAiC,GAAG,CAAA,CAAE,CAAA,GAAI,KAAA;AAAA,QACvD,CAAA,MAAA,IAAW,UAAU,KAAA,CAAA,EAAW;AAC9B,UAAA,IAAI;AACF,YAAA,UAAA,CAAW,iCAAiC,GAAG,CAAA,CAAE,CAAA,GAAI,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,UAC3E,CAAA,CAAA,MAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAIA,gBAAA,CAAY,MAAM,CAAA,EAAG;AACvB,MAAA,UAAA,CAAW,+BAA+B,CAAA,GAAI,MAAA;AAC9C,MAAA;AAAA,IACF;AAEA,IAAA,IAAI;AACF,MAAA,UAAA,CAAW,+BAA+B,CAAA,GAAI,IAAA,CAAK,SAAA,CAAU,MAAM,CAAA;AAAA,IACrE,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;;;;;"}
|
|
@@ -25,48 +25,6 @@ function startAndEndSpan(parentSpan, startTimeInSeconds, endTime, { ...ctx }) {
|
|
|
25
25
|
return span;
|
|
26
26
|
});
|
|
27
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
28
|
function getBrowserPerformanceAPI() {
|
|
71
29
|
return types.WINDOW.addEventListener && types.WINDOW.performance;
|
|
72
30
|
}
|
|
@@ -132,6 +90,5 @@ exports.isMeasurementValue = isMeasurementValue;
|
|
|
132
90
|
exports.listenForWebVitalReportEvents = listenForWebVitalReportEvents;
|
|
133
91
|
exports.msToSec = msToSec;
|
|
134
92
|
exports.startAndEndSpan = startAndEndSpan;
|
|
135
|
-
exports.startStandaloneWebVitalSpan = startStandaloneWebVitalSpan;
|
|
136
93
|
exports.supportsWebVital = supportsWebVital;
|
|
137
94
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +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 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":["spanToJSON","withActiveSpan","startInactiveSpan","getClient","getCurrentScope","WINDOW","onHidden"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/metrics/utils.ts"],"sourcesContent":["import type { Client, SentrySpan, Span, SpanTimeInput, StartSpanOptions } from '@sentry/core';\nimport { 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\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":["spanToJSON","withActiveSpan","startInactiveSpan","WINDOW","onHidden"],"mappings":"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"}
|
|
@@ -10,8 +10,8 @@ const initHiddenTime = () => {
|
|
|
10
10
|
return types.WINDOW.document?.visibilityState === "hidden" && !types.WINDOW.document?.prerendering ? 0 : Infinity;
|
|
11
11
|
};
|
|
12
12
|
const onVisibilityUpdate = (event) => {
|
|
13
|
-
if (
|
|
14
|
-
if (event.type === "visibilitychange"
|
|
13
|
+
if (types.WINDOW.document?.visibilityState === "hidden" && firstHiddenTime > -1) {
|
|
14
|
+
if (event.type === "visibilitychange") {
|
|
15
15
|
for (const onHiddenFunction of onHiddenFunctions) {
|
|
16
16
|
onHiddenFunction();
|
|
17
17
|
}
|
|
@@ -28,7 +28,6 @@ const getVisibilityWatcher = () => {
|
|
|
28
28
|
const firstVisibilityStateHiddenTime = !types.WINDOW.document.prerendering ? globalThis.performance.getEntriesByType("visibility-state").filter((e) => e.name === "hidden" && e.startTime > activationStart)[0]?.startTime : void 0;
|
|
29
29
|
firstHiddenTime = firstVisibilityStateHiddenTime ?? initHiddenTime();
|
|
30
30
|
globalListeners.addPageListener("visibilitychange", onVisibilityUpdate, true);
|
|
31
|
-
globalListeners.addPageListener("pagehide", onVisibilityUpdate, true);
|
|
32
31
|
globalListeners.addPageListener("prerenderingchange", onVisibilityUpdate, true);
|
|
33
32
|
}
|
|
34
33
|
return {
|
|
@@ -40,9 +39,6 @@ const getVisibilityWatcher = () => {
|
|
|
40
39
|
}
|
|
41
40
|
};
|
|
42
41
|
};
|
|
43
|
-
function isPageHidden(event) {
|
|
44
|
-
return event.type === "pagehide" || types.WINDOW.document?.visibilityState === "hidden";
|
|
45
|
-
}
|
|
46
42
|
|
|
47
43
|
exports.getVisibilityWatcher = getVisibilityWatcher;
|
|
48
44
|
//# sourceMappingURL=getVisibilityWatcher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getVisibilityWatcher.js","sources":["../../../../../src/metrics/web-vitals/lib/getVisibilityWatcher.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 { getActivationStart } from './getActivationStart';\nimport { addPageListener, removePageListener } from './globalListeners';\n\nlet firstHiddenTime = -1;\nconst onHiddenFunctions: Set<() => void> = new Set();\n\nconst initHiddenTime = () => {\n // If the document is hidden when this code runs, assume it was always\n // hidden and the page was loaded in the background, with the one exception\n // that visibility state is always 'hidden' during prerendering, so we have\n // to ignore that case until prerendering finishes (see: `prerenderingchange`\n // event logic below).\n return WINDOW.document?.visibilityState === 'hidden' && !WINDOW.document?.prerendering ? 0 : Infinity;\n};\n\nconst onVisibilityUpdate = (event: Event) => {\n // Handle changes to hidden state\n if (
|
|
1
|
+
{"version":3,"file":"getVisibilityWatcher.js","sources":["../../../../../src/metrics/web-vitals/lib/getVisibilityWatcher.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 { getActivationStart } from './getActivationStart';\nimport { addPageListener, removePageListener } from './globalListeners';\n\nlet firstHiddenTime = -1;\nconst onHiddenFunctions: Set<() => void> = new Set();\n\nconst initHiddenTime = () => {\n // If the document is hidden when this code runs, assume it was always\n // hidden and the page was loaded in the background, with the one exception\n // that visibility state is always 'hidden' during prerendering, so we have\n // to ignore that case until prerendering finishes (see: `prerenderingchange`\n // event logic below).\n return WINDOW.document?.visibilityState === 'hidden' && !WINDOW.document?.prerendering ? 0 : Infinity;\n};\n\nconst onVisibilityUpdate = (event: Event) => {\n // Handle changes to hidden state\n if (WINDOW.document?.visibilityState === 'hidden' && firstHiddenTime > -1) {\n // Call onHidden callbacks when the page becomes hidden\n if (event.type === 'visibilitychange') {\n for (const onHiddenFunction of onHiddenFunctions) {\n onHiddenFunction();\n }\n }\n\n // If the document is 'hidden' and no previous hidden timestamp has been\n // set (so is infinity), update it based on the current event data.\n if (!isFinite(firstHiddenTime)) {\n // If the event is a 'visibilitychange' event, it means the page was\n // visible prior to this change, so the event timestamp is the first\n // hidden time.\n // However, if the event is not a 'visibilitychange' event, then it must\n // be a 'prerenderingchange' event, and the fact that the document is\n // still 'hidden' from the above check means the tab was activated\n // in a background state and so has always been hidden.\n firstHiddenTime = event.type === 'visibilitychange' ? event.timeStamp : 0;\n\n // We no longer need the `prerenderingchange` event listener now we've\n // set an initial init time so remove that\n // (we'll keep the visibilitychange one for onHiddenFunction above)\n removePageListener('prerenderingchange', onVisibilityUpdate, true);\n }\n }\n};\n\nexport const getVisibilityWatcher = () => {\n if (WINDOW.document && firstHiddenTime < 0) {\n // Check if we have a previous hidden `visibility-state` performance entry.\n const activationStart = getActivationStart();\n const firstVisibilityStateHiddenTime = !WINDOW.document.prerendering\n ? globalThis.performance\n .getEntriesByType('visibility-state')\n .filter(e => e.name === 'hidden' && e.startTime > activationStart)[0]?.startTime\n : undefined;\n\n // Prefer that, but if it's not available and the document is hidden when\n // this code runs, assume it was hidden since navigation start. This isn't\n // a perfect heuristic, but it's the best we can do until the\n // `visibility-state` performance entry becomes available in all browsers.\n firstHiddenTime = firstVisibilityStateHiddenTime ?? initHiddenTime();\n // Listen for visibility changes so we can handle things like bfcache\n // restores and/or prerender without having to examine individual\n // timestamps in detail and also for onHidden function calls.\n addPageListener('visibilitychange', onVisibilityUpdate, true);\n\n // IMPORTANT: when a page is prerendering, its `visibilityState` is\n // 'hidden', so in order to account for cases where this module checks for\n // visibility during prerendering, an additional check after prerendering\n // completes is also required.\n addPageListener('prerenderingchange', onVisibilityUpdate, true);\n }\n\n return {\n get firstHiddenTime() {\n return firstHiddenTime;\n },\n onHidden(cb: () => void) {\n onHiddenFunctions.add(cb);\n },\n };\n};\n"],"names":["WINDOW","removePageListener","getActivationStart","addPageListener"],"mappings":";;;;;;AAoBA,IAAI,eAAA,GAAkB,EAAA;AACtB,MAAM,iBAAA,uBAAyC,GAAA,EAAI;AAEnD,MAAM,iBAAiB,MAAM;AAM3B,EAAA,OAAOA,YAAA,CAAO,UAAU,eAAA,KAAoB,QAAA,IAAY,CAACA,YAAA,CAAO,QAAA,EAAU,eAAe,CAAA,GAAI,QAAA;AAC/F,CAAA;AAEA,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAAiB;AAE3C,EAAA,IAAIA,YAAA,CAAO,QAAA,EAAU,eAAA,KAAoB,QAAA,IAAY,kBAAkB,EAAA,EAAI;AAEzE,IAAA,IAAI,KAAA,CAAM,SAAS,kBAAA,EAAoB;AACrC,MAAA,KAAA,MAAW,oBAAoB,iBAAA,EAAmB;AAChD,QAAA,gBAAA,EAAiB;AAAA,MACnB;AAAA,IACF;AAIA,IAAA,IAAI,CAAC,QAAA,CAAS,eAAe,CAAA,EAAG;AAQ9B,MAAA,eAAA,GAAkB,KAAA,CAAM,IAAA,KAAS,kBAAA,GAAqB,KAAA,CAAM,SAAA,GAAY,CAAA;AAKxE,MAAAC,kCAAA,CAAmB,oBAAA,EAAsB,oBAAoB,IAAI,CAAA;AAAA,IACnE;AAAA,EACF;AACF,CAAA;AAEO,MAAM,uBAAuB,MAAM;AACxC,EAAA,IAAID,YAAA,CAAO,QAAA,IAAY,eAAA,GAAkB,CAAA,EAAG;AAE1C,IAAA,MAAM,kBAAkBE,qCAAA,EAAmB;AAC3C,IAAA,MAAM,8BAAA,GAAiC,CAACF,YAAA,CAAO,QAAA,CAAS,eACpD,UAAA,CAAW,WAAA,CACR,iBAAiB,kBAAkB,CAAA,CACnC,OAAO,CAAA,CAAA,KAAK,CAAA,CAAE,SAAS,QAAA,IAAY,CAAA,CAAE,YAAY,eAAe,CAAA,CAAE,CAAC,CAAA,EAAG,SAAA,GACzE,MAAA;AAMJ,IAAA,eAAA,GAAkB,kCAAkC,cAAA,EAAe;AAInE,IAAAG,+BAAA,CAAgB,kBAAA,EAAoB,oBAAoB,IAAI,CAAA;AAM5D,IAAAA,+BAAA,CAAgB,oBAAA,EAAsB,oBAAoB,IAAI,CAAA;AAAA,EAChE;AAEA,EAAA,OAAO;AAAA,IACL,IAAI,eAAA,GAAkB;AACpB,MAAA,OAAO,eAAA;AAAA,IACT,CAAA;AAAA,IACA,SAAS,EAAA,EAAgB;AACvB,MAAA,iBAAA,CAAkB,IAAI,EAAE,CAAA;AAAA,IAC1B;AAAA,GACF;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initUnique.js","sources":["../../../../../src/metrics/web-vitals/lib/initUnique.ts"],"sourcesContent":["/*\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst instanceMap: WeakMap<object, unknown> = new WeakMap();\n\n/**\n * A function that accepts and identity object and a class object and returns\n * either a new instance of that class or an existing instance, if the\n * identity object was previously used.\n */\nexport function initUnique<T>(identityObj: object, ClassObj: new () => T): T {\n try {\n if (!instanceMap.get(identityObj)) {\n instanceMap.set(identityObj, new ClassObj());\n }\n return instanceMap.get(identityObj)! as T;\n } catch
|
|
1
|
+
{"version":3,"file":"initUnique.js","sources":["../../../../../src/metrics/web-vitals/lib/initUnique.ts"],"sourcesContent":["/*\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst instanceMap: WeakMap<object, unknown> = new WeakMap();\n\n/**\n * A function that accepts and identity object and a class object and returns\n * either a new instance of that class or an existing instance, if the\n * identity object was previously used.\n */\nexport function initUnique<T>(identityObj: object, ClassObj: new () => T): T {\n try {\n if (!instanceMap.get(identityObj)) {\n instanceMap.set(identityObj, new ClassObj());\n }\n return instanceMap.get(identityObj)! as T;\n } catch {\n // --- START Sentry-custom code (try/catch wrapping) ---\n // Fix for cases where identityObj is not a valid key for WeakMap (sometimes a problem in Safari)\n // Just return a new instance without caching it in instanceMap\n return new ClassObj();\n }\n // --- END Sentry-custom code ---\n}\n"],"names":[],"mappings":";;AAgBA,MAAM,WAAA,uBAA4C,OAAA,EAAQ;AAOnD,SAAS,UAAA,CAAc,aAAqB,QAAA,EAA0B;AAC3E,EAAA,IAAI;AACF,IAAA,IAAI,CAAC,WAAA,CAAY,GAAA,CAAI,WAAW,CAAA,EAAG;AACjC,MAAA,WAAA,CAAY,GAAA,CAAI,WAAA,EAAa,IAAI,QAAA,EAAU,CAAA;AAAA,IAC7C;AACA,IAAA,OAAO,WAAA,CAAY,IAAI,WAAW,CAAA;AAAA,EACpC,CAAA,CAAA,MAAQ;AAIN,IAAA,OAAO,IAAI,QAAA,EAAS;AAAA,EACtB;AAEF;;;;"}
|
|
@@ -4,13 +4,12 @@ const types = require('../../../types.js');
|
|
|
4
4
|
const globalListeners = require('./globalListeners.js');
|
|
5
5
|
|
|
6
6
|
const onHidden = (cb) => {
|
|
7
|
-
const
|
|
8
|
-
if (
|
|
7
|
+
const onHiddenCallback = (event) => {
|
|
8
|
+
if (types.WINDOW.document?.visibilityState === "hidden") {
|
|
9
9
|
cb(event);
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
|
-
globalListeners.addPageListener("visibilitychange",
|
|
13
|
-
globalListeners.addPageListener("pagehide", onHiddenOrPageHide, { capture: true, once: true });
|
|
12
|
+
globalListeners.addPageListener("visibilitychange", onHiddenCallback, { capture: true });
|
|
14
13
|
};
|
|
15
14
|
|
|
16
15
|
exports.onHidden = onHidden;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onHidden.js","sources":["../../../../../src/metrics/web-vitals/lib/onHidden.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 { addPageListener } from './globalListeners';\n\nexport interface OnHiddenCallback {\n (event: Event): void;\n}\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"onHidden.js","sources":["../../../../../src/metrics/web-vitals/lib/onHidden.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 { addPageListener } from './globalListeners';\n\nexport interface OnHiddenCallback {\n (event: Event): void;\n}\n\n/**\n * Calls the passed callback when the page transitions to hidden.\n *\n * Uses the `visibilitychange` event exclusively, which is well-supported\n * across all modern browsers.\n *\n * @param {OnHiddenCallback} cb - Callback to be executed when the page is hidden.\n *\n * @deprecated use `whenIdleOrHidden` or `addPageListener('visibilitychange')` instead\n */\nexport const onHidden = (cb: OnHiddenCallback) => {\n const onHiddenCallback = (event: Event) => {\n if (WINDOW.document?.visibilityState === 'hidden') {\n cb(event);\n }\n };\n\n addPageListener('visibilitychange', onHiddenCallback, { capture: true });\n};\n"],"names":["WINDOW","addPageListener"],"mappings":";;;;;AAiCO,MAAM,QAAA,GAAW,CAAC,EAAA,KAAyB;AAChD,EAAA,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAAiB;AACzC,IAAA,IAAIA,YAAA,CAAO,QAAA,EAAU,eAAA,KAAoB,QAAA,EAAU;AACjD,MAAA,EAAA,CAAG,KAAK,CAAA;AAAA,IACV;AAAA,EACF,CAAA;AAEA,EAAAC,+BAAA,CAAgB,kBAAA,EAAoB,gBAAA,EAAkB,EAAE,OAAA,EAAS,MAAM,CAAA;AACzE;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactionCountPolyfill.js","sources":["../../../../../../src/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.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 { observe } from '../observe';\n\ndeclare global {\n interface Performance {\n interactionCount: number;\n }\n}\n\nlet interactionCountEstimate = 0;\nlet minKnownInteractionId = Infinity;\nlet maxKnownInteractionId = 0;\n\nconst updateEstimate = (entries: PerformanceEventTiming[]) => {\n entries.forEach(e => {\n if (e.interactionId) {\n minKnownInteractionId = Math.min(minKnownInteractionId, e.interactionId);\n maxKnownInteractionId = Math.max(maxKnownInteractionId, e.interactionId);\n\n interactionCountEstimate = maxKnownInteractionId ? (maxKnownInteractionId - minKnownInteractionId) / 7 + 1 : 0;\n }\n });\n};\n\nlet po: PerformanceObserver | undefined;\n\n/**\n * Returns the `interactionCount` value using the native API (if available)\n * or the polyfill estimate in this module.\n */\nexport const getInteractionCount = (): number => {\n return po ? interactionCountEstimate : performance.interactionCount || 0;\n};\n\n/**\n * Feature detects native support or initializes the polyfill if needed.\n */\nexport const initInteractionCountPolyfill = (): void => {\n if ('interactionCount' in performance || po) return;\n\n po = observe('event', updateEstimate, {\n type: 'event',\n buffered: true,\n durationThreshold: 0,\n }
|
|
1
|
+
{"version":3,"file":"interactionCountPolyfill.js","sources":["../../../../../../src/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.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 { observe } from '../observe';\n\ndeclare global {\n interface Performance {\n readonly interactionCount: number;\n }\n}\n\nlet interactionCountEstimate = 0;\nlet minKnownInteractionId = Infinity;\nlet maxKnownInteractionId = 0;\n\nconst updateEstimate = (entries: PerformanceEventTiming[]) => {\n entries.forEach(e => {\n if (e.interactionId) {\n minKnownInteractionId = Math.min(minKnownInteractionId, e.interactionId);\n maxKnownInteractionId = Math.max(maxKnownInteractionId, e.interactionId);\n\n interactionCountEstimate = maxKnownInteractionId ? (maxKnownInteractionId - minKnownInteractionId) / 7 + 1 : 0;\n }\n });\n};\n\nlet po: PerformanceObserver | undefined;\n\n/**\n * Returns the `interactionCount` value using the native API (if available)\n * or the polyfill estimate in this module.\n */\nexport const getInteractionCount = (): number => {\n return po ? interactionCountEstimate : performance.interactionCount || 0;\n};\n\n/**\n * Feature detects native support or initializes the polyfill if needed.\n */\nexport const initInteractionCountPolyfill = (): void => {\n if ('interactionCount' in performance || po) return;\n\n po = observe('event', updateEstimate, {\n type: 'event',\n buffered: true,\n durationThreshold: 0,\n });\n};\n"],"names":["observe"],"mappings":";;;;AAwBA,IAAI,wBAAA,GAA2B,CAAA;AAC/B,IAAI,qBAAA,GAAwB,QAAA;AAC5B,IAAI,qBAAA,GAAwB,CAAA;AAE5B,MAAM,cAAA,GAAiB,CAAC,OAAA,KAAsC;AAC5D,EAAA,OAAA,CAAQ,QAAQ,CAAA,CAAA,KAAK;AACnB,IAAA,IAAI,EAAE,aAAA,EAAe;AACnB,MAAA,qBAAA,GAAwB,IAAA,CAAK,GAAA,CAAI,qBAAA,EAAuB,CAAA,CAAE,aAAa,CAAA;AACvE,MAAA,qBAAA,GAAwB,IAAA,CAAK,GAAA,CAAI,qBAAA,EAAuB,CAAA,CAAE,aAAa,CAAA;AAEvE,MAAA,wBAAA,GAA2B,qBAAA,GAAA,CAAyB,qBAAA,GAAwB,qBAAA,IAAyB,CAAA,GAAI,CAAA,GAAI,CAAA;AAAA,IAC/G;AAAA,EACF,CAAC,CAAA;AACH,CAAA;AAEA,IAAI,EAAA;AAMG,MAAM,sBAAsB,MAAc;AAC/C,EAAA,OAAO,EAAA,GAAK,wBAAA,GAA2B,WAAA,CAAY,gBAAA,IAAoB,CAAA;AACzE;AAKO,MAAM,+BAA+B,MAAY;AACtD,EAAA,IAAI,kBAAA,IAAsB,eAAe,EAAA,EAAI;AAE7C,EAAA,EAAA,GAAKA,eAAA,CAAQ,SAAS,cAAA,EAAgB;AAAA,IACpC,IAAA,EAAM,OAAA;AAAA,IACN,QAAA,EAAU,IAAA;AAAA,IACV,iBAAA,EAAmB;AAAA,GACpB,CAAA;AACH;;;;;"}
|
|
@@ -11,11 +11,9 @@ const whenIdleOrHidden = (cb) => {
|
|
|
11
11
|
} else {
|
|
12
12
|
cb = runOnce.runOnce(cb);
|
|
13
13
|
globalListeners.addPageListener("visibilitychange", cb, { once: true, capture: true });
|
|
14
|
-
globalListeners.addPageListener("pagehide", cb, { once: true, capture: true });
|
|
15
14
|
rIC(() => {
|
|
16
15
|
cb();
|
|
17
16
|
globalListeners.removePageListener("visibilitychange", cb, { capture: true });
|
|
18
|
-
globalListeners.removePageListener("pagehide", cb, { capture: true });
|
|
19
17
|
});
|
|
20
18
|
}
|
|
21
19
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whenIdleOrHidden.js","sources":["../../../../../src/metrics/web-vitals/lib/whenIdleOrHidden.ts"],"sourcesContent":["/*\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../../types.js';\nimport { addPageListener, removePageListener } from './globalListeners.js';\nimport { runOnce } from './runOnce.js';\n\n/**\n * Runs the passed callback during the next idle period, or immediately\n * if the browser's visibility state is (or becomes) hidden.\n */\nexport const whenIdleOrHidden = (cb: () => void) => {\n const rIC = WINDOW.requestIdleCallback || WINDOW.setTimeout;\n\n // If the document is hidden, run the callback immediately, otherwise\n // race an idle callback with the next `visibilitychange` event.\n if (WINDOW.document?.visibilityState === 'hidden') {\n cb();\n } else {\n // eslint-disable-next-line no-param-reassign\n cb = runOnce(cb);\n addPageListener('visibilitychange', cb, { once: true, capture: true });\n
|
|
1
|
+
{"version":3,"file":"whenIdleOrHidden.js","sources":["../../../../../src/metrics/web-vitals/lib/whenIdleOrHidden.ts"],"sourcesContent":["/*\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../../types.js';\nimport { addPageListener, removePageListener } from './globalListeners.js';\nimport { runOnce } from './runOnce.js';\n\n/**\n * Runs the passed callback during the next idle period, or immediately\n * if the browser's visibility state is (or becomes) hidden.\n */\nexport const whenIdleOrHidden = (cb: () => void) => {\n const rIC = WINDOW.requestIdleCallback || WINDOW.setTimeout;\n\n // If the document is hidden, run the callback immediately, otherwise\n // race an idle callback with the next `visibilitychange` event.\n if (WINDOW.document?.visibilityState === 'hidden') {\n cb();\n } else {\n // eslint-disable-next-line no-param-reassign\n cb = runOnce(cb);\n addPageListener('visibilitychange', cb, { once: true, capture: true });\n rIC(() => {\n cb();\n // Remove the above event listener since no longer required.\n // See: https://github.com/GoogleChrome/web-vitals/issues/622\n removePageListener('visibilitychange', cb, { capture: true });\n });\n }\n};\n"],"names":["WINDOW","runOnce","addPageListener","removePageListener"],"mappings":";;;;;;AAwBO,MAAM,gBAAA,GAAmB,CAAC,EAAA,KAAmB;AAClD,EAAA,MAAM,GAAA,GAAMA,YAAA,CAAO,mBAAA,IAAuBA,YAAA,CAAO,UAAA;AAIjD,EAAA,IAAIA,YAAA,CAAO,QAAA,EAAU,eAAA,KAAoB,QAAA,EAAU;AACjD,IAAA,EAAA,EAAG;AAAA,EACL,CAAA,MAAO;AAEL,IAAA,EAAA,GAAKC,gBAAQ,EAAE,CAAA;AACf,IAAAC,+BAAA,CAAgB,oBAAoB,EAAA,EAAI,EAAE,MAAM,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AACrE,IAAA,GAAA,CAAI,MAAM;AACR,MAAA,EAAA,EAAG;AAGH,MAAAC,kCAAA,CAAmB,kBAAA,EAAoB,EAAA,EAAI,EAAE,OAAA,EAAS,MAAM,CAAA;AAAA,IAC9D,CAAC,CAAA;AAAA,EACH;AACF;;;;"}
|