Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
1 line
13 KiB
Plaintext
1 line
13 KiB
Plaintext
{"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 htmlTreeAsString,\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 { 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 */\nconst 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\nconst 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 * Register a listener to cache route information for INP interactions.\n */\nexport function registerInpInteractionListener(): void {\n // Listen for all interaction events that could contribute to INP\n const interactionEvents = Object.keys(INP_ENTRY_MAP);\n if (isBrowser()) {\n interactionEvents.forEach(eventType => {\n WINDOW.addEventListener(eventType, captureElementFromEvent, { capture: true, passive: true });\n });\n }\n\n /**\n * Captures the element name from a DOM event and stores it in the ELEMENT_NAME_TIMESTAMP_MAP.\n */\n function captureElementFromEvent(event: Event): void {\n const target = event.target as HTMLElement | null;\n if (!target) {\n return;\n }\n\n const elementName = htmlTreeAsString(target);\n const timestamp = Math.round(event.timeStamp);\n\n // Store the element name by timestamp so we can match it with the PerformanceEntry\n ELEMENT_NAME_TIMESTAMP_MAP.set(timestamp, elementName);\n\n // Clean up old\n if (ELEMENT_NAME_TIMESTAMP_MAP.size > 50) {\n const firstKey = ELEMENT_NAME_TIMESTAMP_MAP.keys().next().value;\n if (firstKey !== undefined) {\n ELEMENT_NAME_TIMESTAMP_MAP.delete(firstKey);\n }\n }\n }\n\n /**\n * Tries to get the element name from the timestamp map.\n */\n function resolveElementNameFromEntry(entry: PerformanceEntry): string {\n const timestamp = Math.round(entry.startTime);\n let elementName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp);\n\n // try nearby timestamps (±5ms)\n if (!elementName) {\n for (let offset = -5; offset <= 5; offset++) {\n const nearbyName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp + offset);\n if (nearbyName) {\n elementName = nearbyName;\n break;\n }\n }\n }\n\n return elementName || '<unknown>';\n }\n\n const handleEntries = ({ entries }: { entries: PerformanceEntry[] }): void => {\n const activeSpan = getActiveSpan();\n const activeRootSpan = activeSpan && getRootSpan(activeSpan);\n\n entries.forEach(entry => {\n if (!isPerformanceEventTiming(entry)) {\n return;\n }\n\n const interactionId = entry.interactionId;\n if (interactionId == null) {\n return;\n }\n\n // If the interaction was already recorded before, nothing more to do\n if (INTERACTIONS_SPAN_MAP.has(interactionId)) {\n return;\n }\n\n const elementName = entry.target ? htmlTreeAsString(entry.target) : resolveElementNameFromEntry(entry);\n\n // We keep max. 10 interactions in the list, then remove the oldest one & clean up\n if (LAST_INTERACTIONS.length > 10) {\n const last = LAST_INTERACTIONS.shift() as number;\n INTERACTIONS_SPAN_MAP.delete(last);\n }\n\n // We add the interaction to the list of recorded interactions\n // and store both the span and element name for this interaction\n LAST_INTERACTIONS.push(interactionId);\n INTERACTIONS_SPAN_MAP.set(interactionId, {\n span: activeRootSpan,\n elementName,\n });\n });\n };\n\n addPerformanceInstrumentationHandler('event', handleEntries);\n addPerformanceInstrumentationHandler('first-input', handleEntries);\n}\n"],"names":[],"mappings":"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"} |