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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"performanceObserver.js","sources":["../../../src/instrumentation/performanceObserver.ts"],"sourcesContent":["import { debug, getFunctionName } from '@sentry/core';\nimport { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';\nimport { DEBUG_BUILD } from '../debug-build';\n\ntype InstrumentHandlerTypePerformanceObserver =\n | 'longtask'\n | 'event'\n | 'navigation'\n | 'paint'\n | 'resource'\n | 'element'\n | 'soft-navigation'\n // fist-input is still needed for INP\n | 'first-input';\n\ntype InstrumentHandlerTypeMetric = 'cls' | 'lcp' | 'ttfb' | 'inp' | 'fcp';\n\n// We provide this here manually instead of relying on a global, as this is not available in non-browser environements\n// And we do not want to expose such types\ninterface PerformanceEntry {\n readonly duration: number;\n readonly entryType: string;\n readonly name: string;\n readonly startTime: number;\n toJSON(): Record<string, unknown>;\n}\nexport interface PerformanceEventTiming extends PerformanceEntry {\n processingStart: number;\n processingEnd: number;\n duration: number;\n cancelable?: boolean;\n target?: unknown | null;\n interactionId?: number;\n}\n\n/**\n * A `soft-navigation` entry, minted by the browser once a history change is followed by a\n * confirming paint. `interactionId` is the id of the `PerformanceEventTiming` entry for the\n * interaction that drove the navigation, which is how we join it back to a Sentry navigation span.\n */\nexport interface PerformanceSoftNavigation extends PerformanceEntry {\n readonly interactionId: number;\n readonly navigationId: number;\n}\n\ninterface PerformanceScriptTiming extends PerformanceEntry {\n sourceURL: string;\n sourceFunctionName: string;\n sourceCharPosition: number;\n invoker: string;\n invokerType: string;\n}\nexport interface PerformanceLongAnimationFrameTiming extends PerformanceEntry {\n scripts: PerformanceScriptTiming[];\n}\n\n// Locally-defined to match web-vitals' `Metric` shape without importing it: web-vitals' type\n// entrypoint carries a `declare global` block that references DOM globals not present in every\n// TypeScript lib version (e.g. `NavigationType`), which leaks into and breaks consumers on older\n// TS. Keeping this local keeps web-vitals' global augmentations out of our published types.\n/**\n * The navigation types web-vitals reports a metric for. Wider than the set the\n * `browser.navigation.type` attribute uses - see `toBrowserNavigationType`.\n */\nexport type MetricNavigationType =\n | 'navigate'\n | 'reload'\n | 'back-forward'\n | 'back-forward-cache'\n | 'prerender'\n | 'restore'\n | 'soft-navigation';\n\ninterface Metric {\n /**\n * The name of the metric (in acronym form).\n */\n name: 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB';\n\n /**\n * The current value of the metric.\n */\n value: number;\n\n /**\n * The rating as to whether the metric value is within the \"good\",\n * \"needs improvement\", or \"poor\" thresholds of the metric.\n */\n rating: 'good' | 'needs-improvement' | 'poor';\n\n /**\n * The delta between the current value and the last-reported value.\n * On the first report, `delta` and `value` will always be the same.\n */\n delta: number;\n\n /**\n * A unique ID representing this particular metric instance. This ID can\n * be used by an analytics tool to dedupe multiple values sent for the same\n * metric instance, or to group multiple deltas together and calculate a\n * total. It can also be used to differentiate multiple different metric\n * instances sent from the same page, which can happen if the page is\n * restored from the back/forward cache (in that case new metrics object\n * get created).\n */\n id: string;\n\n /**\n * Any performance entries relevant to the metric value calculation.\n * The array may also be empty if the metric value was not based on any\n * entries (e.g. a CLS value of 0 given no layout shifts).\n */\n entries: PerformanceEntry[];\n\n /**\n * The type of navigation.\n *\n * Navigation Timing API (or `undefined` if the browser doesn't\n * support that API). For pages that are restored from the bfcache, this\n * value will be 'back-forward-cache'.\n */\n navigationType: MetricNavigationType;\n\n /**\n * The id of the navigation the metric belongs to. For soft navigations this is the\n * `navigationId` of the `soft-navigation` entry, otherwise it's the id of the hard navigation.\n */\n navigationId: number;\n\n /**\n * For soft navigations, the `interactionId` of the interaction that triggered the navigation.\n */\n navigationInteractionId?: number;\n\n /**\n * The start time the metric value is relative to. Non-zero for soft navigations, where the\n * time origin is the triggering interaction rather than the start of the document.\n */\n navigationStartTime?: number;\n\n /**\n * The URL the metric was recorded for. Relevant for soft navigations, where a metric can be\n * reported long after the URL has moved on.\n */\n navigationURL?: string;\n}\n\ntype InstrumentHandlerType = InstrumentHandlerTypeMetric | InstrumentHandlerTypePerformanceObserver;\n\ntype StopListening = undefined | void | (() => void);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InstrumentHandlerCallback = (data: any) => void;\n\ntype CleanupHandlerCallback = () => void;\n\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\nlet _previousCls: Metric | undefined;\nlet _previousLcp: Metric | undefined;\nlet _previousTtfb: Metric | undefined;\nlet _previousInp: Metric | undefined;\nlet _previousFcp: Metric | undefined;\n\nconst stopListeners: Partial<Record<InstrumentHandlerType, StopListening>> = {};\n\nlet _reportSoftNavs = false;\nlet _reportBfcache = false;\n\n/**\n * Opt the CLS, LCP and INP observers into reporting metrics for soft navigations.\n *\n * This also turns `reportAllChanges` off for CLS and LCP. web-vitals force-reports a metric when\n * the navigation it belongs to is over, so without the intermediate updates every value a handler\n * receives is already the final one for its navigation. That only holds because soft navigations\n * are limited to span streaming, where CLS and LCP are sent as their own spans - the static\n * lifecycle instead writes them onto the pageload span as it ends, which is what `reportAllChanges`\n * was originally added for (#11934, #12360).\n *\n * Each observer is instrumented lazily, on its first handler, and web-vitals takes its options at\n * that point only. So this has to be called before any of the `add*InstrumentationHandler`\n * functions, otherwise it won't take effect for observers that are already running.\n *\n * On browsers without the Soft Navigation API this is a no-op: web-vitals feature-detects the API\n * and keeps reporting hard-navigation metrics as usual.\n */\nexport function enableSoftNavigationReporting(): void {\n _reportSoftNavs = true;\n}\n\n/**\n * Opt the CLS, LCP and INP observers into reporting metrics for back/forward-cache restores.\n *\n * web-vitals re-reports each metric after a restore, tagged with a `back-forward-cache` navigation\n * type. A restore is a new page view measured against a document that was never reloaded, so the\n * values only mean anything if there is a fresh root span for them to belong to. Without one they\n * would attach to the span the page had before it was frozen, which is why this is off by default.\n *\n * Like `enableSoftNavigationReporting`, this only affects observers instrumented after it is\n * called.\n */\nexport function enableBfcacheReporting(): void {\n _reportBfcache = true;\n}\n\n/**\n * Add a callback that will be triggered when a CLS metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called.\n * This will lead to the CLS being finalized and frozen.\n */\nexport function addClsInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a LCP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called.\n * This will lead to the LCP being finalized and frozen.\n */\nexport function addLcpInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a TTFD metric is available.\n */\nexport function addTtfbInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('ttfb', callback, instrumentTtfb, _previousTtfb);\n}\n\n/**\n * Add a callback that will be triggered when a FCP metric is available.\n */\nexport function addFcpInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('fcp', callback, instrumentFcp, _previousFcp);\n}\n\nexport type InstrumentationHandlerCallback = (data: {\n metric: Omit<Metric, 'entries'> & {\n entries: PerformanceEventTiming[];\n };\n}) => void;\n\n/**\n * Add a callback that will be triggered when a INP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addInpInstrumentationHandler(callback: InstrumentationHandlerCallback): CleanupHandlerCallback {\n return addMetricObserver('inp', callback, instrumentInp, _previousInp);\n}\n\nexport function addPerformanceInstrumentationHandler(\n type: 'event',\n callback: (data: { entries: ((PerformanceEntry & { target?: unknown | null }) | PerformanceEventTiming)[] }) => void,\n): CleanupHandlerCallback;\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback;\n\n/**\n * Add a callback that will be triggered when a performance observer is triggered,\n * and receives the entries of the observer.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumentPerformanceObserver(type);\n instrumented[type] = true;\n }\n\n return getCleanupCallback(type, callback);\n}\n\n/** Trigger all handlers of a given type. */\nfunction triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = handlers[type];\n\n if (!typeHandlers?.length) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n debug.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n\n/**\n * Wraps a metric callback so that metrics reported after a back/forward-cache restore are dropped\n * unless `enableBfcacheReporting` was called. See there for why they are off by default.\n */\nfunction unlessBfcacheDisabled(callback: (metric: Metric) => void): (metric: Metric) => void {\n return metric => {\n if (!_reportBfcache && metric.navigationType === 'back-forward-cache') {\n return;\n }\n callback(metric);\n };\n}\n\nfunction instrumentCls(): StopListening {\n return onCLS(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('cls', {\n metric,\n });\n _previousCls = metric;\n }),\n // We want the callback to be called whenever the CLS value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: !_reportSoftNavs && !_reportBfcache, reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction instrumentLcp(): StopListening {\n return onLCP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('lcp', {\n metric,\n });\n _previousLcp = metric;\n }),\n // We want the callback to be called whenever the LCP value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: !_reportSoftNavs && !_reportBfcache, reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction instrumentTtfb(): StopListening {\n return onTTFB(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('ttfb', {\n metric,\n });\n _previousTtfb = metric;\n }),\n );\n}\n\nfunction instrumentFcp(): StopListening {\n return onFCP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('fcp', {\n metric,\n });\n _previousFcp = metric;\n }),\n );\n}\n\nfunction instrumentInp(): StopListening {\n return onINP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('inp', {\n metric,\n });\n _previousInp = metric;\n }),\n { reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction addMetricObserver(\n type: InstrumentHandlerTypeMetric,\n callback: InstrumentHandlerCallback,\n instrumentFn: () => StopListening,\n previousValue: Metric | undefined,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumented[type] = true;\n // Deferred by a microtask rather than started here, because web-vitals reads its options once,\n // when the observer is created. Registering a handler would otherwise pin those options for\n // every other consumer of this observer, so whichever integration happened to run first would\n // decide whether soft navigations and bfcache restores are reported. Client setup is\n // synchronous, so every `enable*Reporting()` call has landed by the time this runs, and the\n // observers are buffered so no entries are missed in the meantime.\n void Promise.resolve().then(() => {\n stopListeners[type] = instrumentFn();\n });\n }\n\n if (previousValue) {\n callback({ metric: previousValue });\n }\n\n return getCleanupCallback(type, callback, stopOnCallback);\n}\n\nfunction instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObserver): void {\n const options: PerformanceObserverInit = { type, buffered: true };\n\n // Special per-type options we want to use\n if (type === 'event') {\n (options as PerformanceObserverInit & { durationThreshold?: number }).durationThreshold = 0;\n }\n\n try {\n if (PerformanceObserver.supportedEntryTypes.includes(type)) {\n const po = new PerformanceObserver(list => {\n // Delay by a microtask to work around a bug in Safari where the\n // callback is invoked synchronously rather than in a separate task.\n // See: https://github.com/GoogleChrome/web-vitals/issues/277\n void Promise.resolve().then(() => {\n triggerHandlers(type, { entries: list.getEntries() });\n });\n });\n po.observe(options);\n }\n } catch {\n // Unsupported entry type; nothing to observe.\n }\n}\n\nfunction addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n handlers[type].push(handler);\n}\n\n// Get a callback which can be called to remove the instrumentation handler\nfunction getCleanupCallback(\n type: InstrumentHandlerType,\n callback: InstrumentHandlerCallback,\n stopOnCleanup = false,\n): CleanupHandlerCallback {\n return () => {\n // Looked up rather than captured: the observer is started in a microtask, so its stop function\n // does not exist yet when this callback is built.\n if (stopOnCleanup) {\n stopListeners[type]?.();\n }\n\n const typeHandlers = handlers[type];\n\n if (!typeHandlers) {\n return;\n }\n\n const index = typeHandlers.indexOf(callback);\n if (index !== -1) {\n typeHandlers.splice(index, 1);\n }\n };\n}\n\n/**\n * Check if a PerformanceEntry is a PerformanceEventTiming by checking for the `duration` property.\n */\nexport function isPerformanceEventTiming(entry: PerformanceEntry): entry is PerformanceEventTiming {\n return 'duration' in entry;\n}\n"],"names":["DEBUG_BUILD","debug","getFunctionName","onCLS","onLCP","onTTFB","onFCP","onINP"],"mappings":"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"}
1
+ {"version":3,"file":"performanceObserver.js","sources":["../../../src/instrumentation/performanceObserver.ts"],"sourcesContent":["import { debug, getFunctionName } from '@sentry/core';\nimport { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';\nimport { DEBUG_BUILD } from '../debug-build';\n\ntype InstrumentHandlerTypePerformanceObserver =\n | 'longtask'\n | 'event'\n | 'navigation'\n | 'paint'\n | 'resource'\n | 'element'\n | 'soft-navigation'\n // fist-input is still needed for INP\n | 'first-input';\n\ntype InstrumentHandlerTypeMetric = 'cls' | 'lcp' | 'ttfb' | 'inp' | 'fcp';\n\n// We provide this here manually instead of relying on a global, as this is not available in non-browser environements\n// And we do not want to expose such types\ninterface PerformanceEntry {\n readonly duration: number;\n readonly entryType: string;\n readonly name: string;\n readonly startTime: number;\n toJSON(): Record<string, unknown>;\n}\nexport interface PerformanceEventTiming extends PerformanceEntry {\n processingStart: number;\n processingEnd: number;\n duration: number;\n cancelable?: boolean;\n target?: unknown | null;\n interactionId?: number;\n}\n\n/**\n * A `soft-navigation` entry, minted by the browser once a history change is followed by a\n * confirming paint. `interactionId` is the id of the `PerformanceEventTiming` entry for the\n * interaction that drove the navigation, which is how we join it back to a Sentry navigation span.\n */\nexport interface PerformanceSoftNavigation extends PerformanceEntry {\n readonly interactionId: number;\n readonly navigationId: number;\n}\n\ninterface PerformanceScriptTiming extends PerformanceEntry {\n sourceURL: string;\n sourceFunctionName: string;\n sourceCharPosition: number;\n invoker: string;\n invokerType: string;\n}\nexport interface PerformanceLongAnimationFrameTiming extends PerformanceEntry {\n scripts: PerformanceScriptTiming[];\n}\n\n// Locally-defined to match web-vitals' `Metric` shape without importing it: web-vitals' type\n// entrypoint carries a `declare global` block that references DOM globals not present in every\n// TypeScript lib version (e.g. `NavigationType`), which leaks into and breaks consumers on older\n// TS. Keeping this local keeps web-vitals' global augmentations out of our published types.\n/**\n * The navigation types web-vitals reports a metric for, reported as-is on `browser.navigation.type`.\n */\nexport type MetricNavigationType =\n | 'navigate'\n | 'reload'\n | 'back-forward'\n | 'back-forward-cache'\n | 'prerender'\n | 'restore'\n | 'soft-navigation';\n\ninterface Metric {\n /**\n * The name of the metric (in acronym form).\n */\n name: 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB';\n\n /**\n * The current value of the metric.\n */\n value: number;\n\n /**\n * The rating as to whether the metric value is within the \"good\",\n * \"needs improvement\", or \"poor\" thresholds of the metric.\n */\n rating: 'good' | 'needs-improvement' | 'poor';\n\n /**\n * The delta between the current value and the last-reported value.\n * On the first report, `delta` and `value` will always be the same.\n */\n delta: number;\n\n /**\n * A unique ID representing this particular metric instance. This ID can\n * be used by an analytics tool to dedupe multiple values sent for the same\n * metric instance, or to group multiple deltas together and calculate a\n * total. It can also be used to differentiate multiple different metric\n * instances sent from the same page, which can happen if the page is\n * restored from the back/forward cache (in that case new metrics object\n * get created).\n */\n id: string;\n\n /**\n * Any performance entries relevant to the metric value calculation.\n * The array may also be empty if the metric value was not based on any\n * entries (e.g. a CLS value of 0 given no layout shifts).\n */\n entries: PerformanceEntry[];\n\n /**\n * The type of navigation.\n *\n * Navigation Timing API (or `undefined` if the browser doesn't\n * support that API). For pages that are restored from the bfcache, this\n * value will be 'back-forward-cache'.\n */\n navigationType: MetricNavigationType;\n\n /**\n * The id of the navigation the metric belongs to. For soft navigations this is the\n * `navigationId` of the `soft-navigation` entry, otherwise it's the id of the hard navigation.\n */\n navigationId: number;\n\n /**\n * For soft navigations, the `interactionId` of the interaction that triggered the navigation.\n */\n navigationInteractionId?: number;\n\n /**\n * The start time the metric value is relative to. Non-zero for soft navigations, where the\n * time origin is the triggering interaction rather than the start of the document.\n */\n navigationStartTime?: number;\n\n /**\n * The URL the metric was recorded for. Relevant for soft navigations, where a metric can be\n * reported long after the URL has moved on.\n */\n navigationURL?: string;\n}\n\ntype InstrumentHandlerType = InstrumentHandlerTypeMetric | InstrumentHandlerTypePerformanceObserver;\n\ntype StopListening = undefined | void | (() => void);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InstrumentHandlerCallback = (data: any) => void;\n\ntype CleanupHandlerCallback = () => void;\n\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\nlet _previousCls: Metric | undefined;\nlet _previousLcp: Metric | undefined;\nlet _previousTtfb: Metric | undefined;\nlet _previousInp: Metric | undefined;\nlet _previousFcp: Metric | undefined;\n\nconst stopListeners: Partial<Record<InstrumentHandlerType, StopListening>> = {};\n\nlet _reportSoftNavs = false;\nlet _reportBfcache = false;\n\n/**\n * Opt the CLS, LCP and INP observers into reporting metrics for soft navigations.\n *\n * This also turns `reportAllChanges` off for CLS and LCP. web-vitals force-reports a metric when\n * the navigation it belongs to is over, so without the intermediate updates every value a handler\n * receives is already the final one for its navigation. That only holds because soft navigations\n * are limited to span streaming, where CLS and LCP are sent as their own spans - the static\n * lifecycle instead writes them onto the pageload span as it ends, which is what `reportAllChanges`\n * was originally added for (#11934, #12360).\n *\n * Each observer is instrumented lazily, on its first handler, and web-vitals takes its options at\n * that point only. So this has to be called before any of the `add*InstrumentationHandler`\n * functions, otherwise it won't take effect for observers that are already running.\n *\n * On browsers without the Soft Navigation API this is a no-op: web-vitals feature-detects the API\n * and keeps reporting hard-navigation metrics as usual.\n */\nexport function enableSoftNavigationReporting(): void {\n _reportSoftNavs = true;\n}\n\n/**\n * Opt the CLS, LCP and INP observers into reporting metrics for back/forward-cache restores.\n *\n * web-vitals re-reports each metric after a restore, tagged with a `back-forward-cache` navigation\n * type. A restore is a new page view measured against a document that was never reloaded, so the\n * values only mean anything if there is a fresh root span for them to belong to. Without one they\n * would attach to the span the page had before it was frozen, which is why this is off by default.\n *\n * Like `enableSoftNavigationReporting`, this only affects observers instrumented after it is\n * called.\n */\nexport function enableBfcacheReporting(): void {\n _reportBfcache = true;\n}\n\n/**\n * Add a callback that will be triggered when a CLS metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called.\n * This will lead to the CLS being finalized and frozen.\n */\nexport function addClsInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a LCP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called.\n * This will lead to the LCP being finalized and frozen.\n */\nexport function addLcpInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a TTFD metric is available.\n */\nexport function addTtfbInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('ttfb', callback, instrumentTtfb, _previousTtfb);\n}\n\n/**\n * Add a callback that will be triggered when a FCP metric is available.\n */\nexport function addFcpInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('fcp', callback, instrumentFcp, _previousFcp);\n}\n\nexport type InstrumentationHandlerCallback = (data: {\n metric: Omit<Metric, 'entries'> & {\n entries: PerformanceEventTiming[];\n };\n}) => void;\n\n/**\n * Add a callback that will be triggered when a INP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addInpInstrumentationHandler(callback: InstrumentationHandlerCallback): CleanupHandlerCallback {\n return addMetricObserver('inp', callback, instrumentInp, _previousInp);\n}\n\nexport function addPerformanceInstrumentationHandler(\n type: 'event',\n callback: (data: { entries: ((PerformanceEntry & { target?: unknown | null }) | PerformanceEventTiming)[] }) => void,\n): CleanupHandlerCallback;\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback;\n\n/**\n * Add a callback that will be triggered when a performance observer is triggered,\n * and receives the entries of the observer.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumentPerformanceObserver(type);\n instrumented[type] = true;\n }\n\n return getCleanupCallback(type, callback);\n}\n\n/** Trigger all handlers of a given type. */\nfunction triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = handlers[type];\n\n if (!typeHandlers?.length) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n debug.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n\n/**\n * Wraps a metric callback so that metrics reported after a back/forward-cache restore are dropped\n * unless `enableBfcacheReporting` was called. See there for why they are off by default.\n */\nfunction unlessBfcacheDisabled(callback: (metric: Metric) => void): (metric: Metric) => void {\n return metric => {\n if (!_reportBfcache && metric.navigationType === 'back-forward-cache') {\n return;\n }\n callback(metric);\n };\n}\n\nfunction instrumentCls(): StopListening {\n return onCLS(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('cls', {\n metric,\n });\n _previousCls = metric;\n }),\n // We want the callback to be called whenever the CLS value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: !_reportSoftNavs && !_reportBfcache, reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction instrumentLcp(): StopListening {\n return onLCP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('lcp', {\n metric,\n });\n _previousLcp = metric;\n }),\n // We want the callback to be called whenever the LCP value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: !_reportSoftNavs && !_reportBfcache, reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction instrumentTtfb(): StopListening {\n return onTTFB(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('ttfb', {\n metric,\n });\n _previousTtfb = metric;\n }),\n );\n}\n\nfunction instrumentFcp(): StopListening {\n return onFCP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('fcp', {\n metric,\n });\n _previousFcp = metric;\n }),\n );\n}\n\nfunction instrumentInp(): StopListening {\n return onINP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('inp', {\n metric,\n });\n _previousInp = metric;\n }),\n { reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction addMetricObserver(\n type: InstrumentHandlerTypeMetric,\n callback: InstrumentHandlerCallback,\n instrumentFn: () => StopListening,\n previousValue: Metric | undefined,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumented[type] = true;\n // Deferred by a microtask rather than started here, because web-vitals reads its options once,\n // when the observer is created. Registering a handler would otherwise pin those options for\n // every other consumer of this observer, so whichever integration happened to run first would\n // decide whether soft navigations and bfcache restores are reported. Client setup is\n // synchronous, so every `enable*Reporting()` call has landed by the time this runs, and the\n // observers are buffered so no entries are missed in the meantime.\n void Promise.resolve().then(() => {\n stopListeners[type] = instrumentFn();\n });\n }\n\n if (previousValue) {\n callback({ metric: previousValue });\n }\n\n return getCleanupCallback(type, callback, stopOnCallback);\n}\n\nfunction instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObserver): void {\n const options: PerformanceObserverInit = { type, buffered: true };\n\n // Special per-type options we want to use\n if (type === 'event') {\n (options as PerformanceObserverInit & { durationThreshold?: number }).durationThreshold = 0;\n }\n\n try {\n if (PerformanceObserver.supportedEntryTypes.includes(type)) {\n const po = new PerformanceObserver(list => {\n // Delay by a microtask to work around a bug in Safari where the\n // callback is invoked synchronously rather than in a separate task.\n // See: https://github.com/GoogleChrome/web-vitals/issues/277\n void Promise.resolve().then(() => {\n triggerHandlers(type, { entries: list.getEntries() });\n });\n });\n po.observe(options);\n }\n } catch {\n // Unsupported entry type; nothing to observe.\n }\n}\n\nfunction addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n handlers[type].push(handler);\n}\n\n// Get a callback which can be called to remove the instrumentation handler\nfunction getCleanupCallback(\n type: InstrumentHandlerType,\n callback: InstrumentHandlerCallback,\n stopOnCleanup = false,\n): CleanupHandlerCallback {\n return () => {\n // Looked up rather than captured: the observer is started in a microtask, so its stop function\n // does not exist yet when this callback is built.\n if (stopOnCleanup) {\n stopListeners[type]?.();\n }\n\n const typeHandlers = handlers[type];\n\n if (!typeHandlers) {\n return;\n }\n\n const index = typeHandlers.indexOf(callback);\n if (index !== -1) {\n typeHandlers.splice(index, 1);\n }\n };\n}\n\n/**\n * Check if a PerformanceEntry is a PerformanceEventTiming by checking for the `duration` property.\n */\nexport function isPerformanceEventTiming(entry: PerformanceEntry): entry is PerformanceEventTiming {\n return 'duration' in entry;\n}\n"],"names":["DEBUG_BUILD","debug","getFunctionName","onCLS","onLCP","onTTFB","onFCP","onINP"],"mappings":";;;;;;AA2JA,MAAM,WAA6E,EAAC;AACpF,MAAM,eAA6D,EAAC;AAEpE,IAAI,YAAA;AACJ,IAAI,YAAA;AACJ,IAAI,aAAA;AACJ,IAAI,YAAA;AACJ,IAAI,YAAA;AAEJ,MAAM,gBAAuE,EAAC;AAE9E,IAAI,eAAA,GAAkB,KAAA;AACtB,IAAI,cAAA,GAAiB,KAAA;AAmBd,SAAS,6BAAA,GAAsC;AACpD,EAAA,eAAA,GAAkB,IAAA;AACpB;AAaO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,cAAA,GAAiB,IAAA;AACnB;AASO,SAAS,4BAAA,CACd,QAAA,EACA,cAAA,GAAiB,KAAA,EACO;AACxB,EAAA,OAAO,iBAAA,CAAkB,KAAA,EAAO,QAAA,EAAU,aAAA,EAAe,cAAc,cAAc,CAAA;AACvF;AASO,SAAS,4BAAA,CACd,QAAA,EACA,cAAA,GAAiB,KAAA,EACO;AACxB,EAAA,OAAO,iBAAA,CAAkB,KAAA,EAAO,QAAA,EAAU,aAAA,EAAe,cAAc,cAAc,CAAA;AACvF;AAKO,SAAS,8BAA8B,QAAA,EAAsE;AAClH,EAAA,OAAO,iBAAA,CAAkB,MAAA,EAAQ,QAAA,EAAU,cAAA,EAAgB,aAAa,CAAA;AAC1E;AAKO,SAAS,6BAA6B,QAAA,EAAsE;AACjH,EAAA,OAAO,iBAAA,CAAkB,KAAA,EAAO,QAAA,EAAU,aAAA,EAAe,YAAY,CAAA;AACvE;AAYO,SAAS,6BAA6B,QAAA,EAAkE;AAC7G,EAAA,OAAO,iBAAA,CAAkB,KAAA,EAAO,QAAA,EAAU,aAAA,EAAe,YAAY,CAAA;AACvE;AAgBO,SAAS,oCAAA,CACd,MACA,QAAA,EACwB;AACxB,EAAA,UAAA,CAAW,MAAM,QAAQ,CAAA;AAEzB,EAAA,IAAI,CAAC,YAAA,CAAa,IAAI,CAAA,EAAG;AACvB,IAAA,6BAAA,CAA8B,IAAI,CAAA;AAClC,IAAA,YAAA,CAAa,IAAI,CAAA,GAAI,IAAA;AAAA,EACvB;AAEA,EAAA,OAAO,kBAAA,CAAmB,MAAM,QAAQ,CAAA;AAC1C;AAGA,SAAS,eAAA,CAAgB,MAA6B,IAAA,EAAqB;AACzE,EAAA,MAAM,YAAA,GAAe,SAAS,IAAI,CAAA;AAElC,EAAA,IAAI,CAAC,cAAc,MAAA,EAAQ;AACzB,IAAA;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,WAAW,YAAA,EAAc;AAClC,IAAA,IAAI;AACF,MAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,IACd,SAAS,CAAA,EAAG;AACV,MAAAA,sBAAA,IACEC,UAAA,CAAM,KAAA;AAAA,QACJ,CAAA;AAAA,MAAA,EAA0D,IAAI;AAAA,MAAA,EAAWC,oBAAA,CAAgB,OAAO,CAAC;AAAA,MAAA,CAAA;AAAA,QACjG;AAAA,OACF;AAAA,IACJ;AAAA,EACF;AACF;AAMA,SAAS,sBAAsB,QAAA,EAA8D;AAC3F,EAAA,OAAO,CAAA,MAAA,KAAU;AACf,IAAA,IAAI,CAAC,cAAA,IAAkB,MAAA,CAAO,cAAA,KAAmB,oBAAA,EAAsB;AACrE,MAAA;AAAA,IACF;AACA,IAAA,QAAA,CAAS,MAAM,CAAA;AAAA,EACjB,CAAA;AACF;AAEA,SAAS,aAAA,GAA+B;AACtC,EAAA,OAAOC,eAAA;AAAA,IACL,sBAAsB,CAAA,MAAA,KAAU;AAC9B,MAAA,eAAA,CAAgB,KAAA,EAAO;AAAA,QACrB;AAAA,OACD,CAAA;AACD,MAAA,YAAA,GAAe,MAAA;AAAA,IACjB,CAAC,CAAA;AAAA;AAAA;AAAA,IAGD,EAAE,gBAAA,EAAkB,CAAC,mBAAmB,CAAC,cAAA,EAAgB,gBAAgB,eAAA;AAAgB,GAC3F;AACF;AAEA,SAAS,aAAA,GAA+B;AACtC,EAAA,OAAOC,eAAA;AAAA,IACL,sBAAsB,CAAA,MAAA,KAAU;AAC9B,MAAA,eAAA,CAAgB,KAAA,EAAO;AAAA,QACrB;AAAA,OACD,CAAA;AACD,MAAA,YAAA,GAAe,MAAA;AAAA,IACjB,CAAC,CAAA;AAAA;AAAA;AAAA,IAGD,EAAE,gBAAA,EAAkB,CAAC,mBAAmB,CAAC,cAAA,EAAgB,gBAAgB,eAAA;AAAgB,GAC3F;AACF;AAEA,SAAS,cAAA,GAAgC;AACvC,EAAA,OAAOC,gBAAA;AAAA,IACL,sBAAsB,CAAA,MAAA,KAAU;AAC9B,MAAA,eAAA,CAAgB,MAAA,EAAQ;AAAA,QACtB;AAAA,OACD,CAAA;AACD,MAAA,aAAA,GAAgB,MAAA;AAAA,IAClB,CAAC;AAAA,GACH;AACF;AAEA,SAAS,aAAA,GAA+B;AACtC,EAAA,OAAOC,eAAA;AAAA,IACL,sBAAsB,CAAA,MAAA,KAAU;AAC9B,MAAA,eAAA,CAAgB,KAAA,EAAO;AAAA,QACrB;AAAA,OACD,CAAA;AACD,MAAA,YAAA,GAAe,MAAA;AAAA,IACjB,CAAC;AAAA,GACH;AACF;AAEA,SAAS,aAAA,GAA+B;AACtC,EAAA,OAAOC,eAAA;AAAA,IACL,sBAAsB,CAAA,MAAA,KAAU;AAC9B,MAAA,eAAA,CAAgB,KAAA,EAAO;AAAA,QACrB;AAAA,OACD,CAAA;AACD,MAAA,YAAA,GAAe,MAAA;AAAA,IACjB,CAAC,CAAA;AAAA,IACD,EAAE,gBAAgB,eAAA;AAAgB,GACpC;AACF;AAEA,SAAS,kBACP,IAAA,EACA,QAAA,EACA,YAAA,EACA,aAAA,EACA,iBAAiB,KAAA,EACO;AACxB,EAAA,UAAA,CAAW,MAAM,QAAQ,CAAA;AAEzB,EAAA,IAAI,CAAC,YAAA,CAAa,IAAI,CAAA,EAAG;AACvB,IAAA,YAAA,CAAa,IAAI,CAAA,GAAI,IAAA;AAOrB,IAAA,KAAK,OAAA,CAAQ,OAAA,EAAQ,CAAE,IAAA,CAAK,MAAM;AAChC,MAAA,aAAA,CAAc,IAAI,IAAI,YAAA,EAAa;AAAA,IACrC,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,QAAA,CAAS,EAAE,MAAA,EAAQ,aAAA,EAAe,CAAA;AAAA,EACpC;AAEA,EAAA,OAAO,kBAAA,CAAmB,IAAA,EAAM,QAAA,EAAU,cAAc,CAAA;AAC1D;AAEA,SAAS,8BAA8B,IAAA,EAAsD;AAC3F,EAAA,MAAM,OAAA,GAAmC,EAAE,IAAA,EAAM,QAAA,EAAU,IAAA,EAAK;AAGhE,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAC,QAAqE,iBAAA,GAAoB,CAAA;AAAA,EAC5F;AAEA,EAAA,IAAI;AACF,IAAA,IAAI,mBAAA,CAAoB,mBAAA,CAAoB,QAAA,CAAS,IAAI,CAAA,EAAG;AAC1D,MAAA,MAAM,EAAA,GAAK,IAAI,mBAAA,CAAoB,CAAA,IAAA,KAAQ;AAIzC,QAAA,KAAK,OAAA,CAAQ,OAAA,EAAQ,CAAE,IAAA,CAAK,MAAM;AAChC,UAAA,eAAA,CAAgB,MAAM,EAAE,OAAA,EAAS,IAAA,CAAK,UAAA,IAAc,CAAA;AAAA,QACtD,CAAC,CAAA;AAAA,MACH,CAAC,CAAA;AACD,MAAA,EAAA,CAAG,QAAQ,OAAO,CAAA;AAAA,IACpB;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAEA,SAAS,UAAA,CAAW,MAA6B,OAAA,EAA0C;AACzF,EAAA,QAAA,CAAS,IAAI,CAAA,GAAI,QAAA,CAAS,IAAI,KAAK,EAAC;AACpC,EAAA,QAAA,CAAS,IAAI,CAAA,CAAE,IAAA,CAAK,OAAO,CAAA;AAC7B;AAGA,SAAS,kBAAA,CACP,IAAA,EACA,QAAA,EACA,aAAA,GAAgB,KAAA,EACQ;AACxB,EAAA,OAAO,MAAM;AAGX,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,aAAA,CAAc,IAAI,CAAA,IAAI;AAAA,IACxB;AAEA,IAAA,MAAM,YAAA,GAAe,SAAS,IAAI,CAAA;AAElC,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA;AAC3C,IAAA,IAAI,UAAU,EAAA,EAAI;AAChB,MAAA,YAAA,CAAa,MAAA,CAAO,OAAO,CAAC,CAAA;AAAA,IAC9B;AAAA,EACF,CAAA;AACF;AAKO,SAAS,yBAAyB,KAAA,EAA0D;AACjG,EAAA,OAAO,UAAA,IAAc,KAAA;AACvB;;;;;;;;;;;;"}
@@ -5,15 +5,6 @@ const browser = require('@sentry/core/browser');
5
5
  const attributes = require('@sentry/conventions/attributes');
6
6
  const types = require('../types.js');
7
7
 
8
- const BROWSER_NAVIGATION_TYPES = {
9
- reload: "reload",
10
- prerender: "prerender",
11
- "back-forward-cache": "bfcache",
12
- "soft-navigation": "soft-navigation"
13
- };
14
- function toBrowserNavigationType(navigationType) {
15
- return BROWSER_NAVIGATION_TYPES[navigationType] ?? "navigate";
16
- }
17
8
  function _emitWebVitalSpan(options) {
18
9
  const {
19
10
  name,
@@ -54,7 +45,7 @@ function _emitWebVitalSpan(options) {
54
45
  attributes$1[attributes.BROWSER_NAVIGATION_ID] = softNavigationId;
55
46
  }
56
47
  if (navigationType) {
57
- attributes$1[attributes.BROWSER_NAVIGATION_TYPE] = toBrowserNavigationType(navigationType);
48
+ attributes$1[attributes.BROWSER_NAVIGATION_TYPE] = navigationType;
58
49
  }
59
50
  if (standalone) {
60
51
  Object.assign(attributes$1, getReplayAttributes());
@@ -1 +1 @@
1
- {"version":3,"file":"emitSpan.js","sources":["../../../src/web-vitals/emitSpan.ts"],"sourcesContent":["import type { Integration, Span, SpanAttributes } from '@sentry/core';\nimport {\n getClient,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport { startInactiveSpan } from '@sentry/core/browser';\nimport {\n BROWSER_NAVIGATION_ID,\n BROWSER_NAVIGATION_TYPE,\n SENTRY_REPLAY_ID,\n SENTRY_SEGMENT_NAME,\n SENTRY_TRANSACTION,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { WINDOW } from '../types';\nimport type { MetricNavigationType } from '../instrumentation/performanceObserver';\nimport type { WebVitalReportEvent } from './reportEvents';\n\n// web-vitals reports a wider set of navigation types than the attribute defines. Only the states\n// Navigation Timing cannot express keep their own value; every ordinary document navigation folds\n// into `navigate`, including a back/forward that missed the bfcache and a discarded-tab restore.\nconst BROWSER_NAVIGATION_TYPES: Partial<Record<MetricNavigationType, string>> = {\n reload: 'reload',\n prerender: 'prerender',\n 'back-forward-cache': 'bfcache',\n 'soft-navigation': 'soft-navigation',\n};\n\nfunction toBrowserNavigationType(navigationType: MetricNavigationType): string {\n return BROWSER_NAVIGATION_TYPES[navigationType] ?? 'navigate';\n}\n\n// Locally-defined interfaces to avoid leaking bare global type references into the\n// generated .d.ts. The `declare global` augmentations in web-vitals/types.ts make these\n// available during this package's compilation but are NOT carried to consumers.\n// This mirrors the pattern used for PerformanceEventTiming in instrument.ts.\nexport interface LayoutShift extends PerformanceEntry {\n value: number;\n sources: Array<{ node: Node | null }>;\n hadRecentInput: boolean;\n}\n\nexport interface LargestContentfulPaint extends PerformanceEntry {\n readonly renderTime: DOMHighResTimeStamp;\n readonly loadTime: DOMHighResTimeStamp;\n readonly size: number;\n readonly id: string;\n readonly url: string;\n readonly element: Element | null;\n}\n\ninterface WebVitalSpanOptions {\n name: string;\n op: string;\n origin: string;\n metricName: 'lcp' | 'cls' | 'inp';\n value: number;\n attributes?: SpanAttributes;\n parentSpan?: Span;\n reportEvent?: WebVitalReportEvent;\n startTime: number;\n endTime?: number;\n /** Set when the vital was reported for a soft navigation rather than the initial page load. */\n softNavigationId?: number;\n /** The navigation the vital was measured on, as reported by web-vitals. */\n navigationType?: MetricNavigationType;\n /**\n * When `true`, the span is sent on its own as a v2 streamed span instead of being folded into a\n * transaction. Used for INP when span streaming is disabled (it reports late, so it can't ride\n * the pageload transaction).\n *\n * TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always streams.\n */\n standalone?: boolean;\n}\n\n/**\n * Emits a web vital span. When `standalone` is set it is sent on its own as a v2 streamed span;\n * otherwise it flows through the span streaming pipeline as a child of `parentSpan`.\n */\nexport function _emitWebVitalSpan(options: WebVitalSpanOptions): void {\n const {\n name,\n op,\n origin,\n metricName,\n value,\n attributes: passedAttributes,\n parentSpan,\n reportEvent,\n startTime,\n endTime,\n standalone,\n softNavigationId,\n navigationType,\n } = options;\n\n // Taken off the segment span itself, so it can't diverge from it: a routing instrumentation may\n // rename that span (a pageload span is named `Pageload` until its route resolves), and the scope's\n // transaction name is deliberately not kept in sync with it. Only a standalone span, which is sent\n // without its segment span, has to fall back to the scope.\n const segmentSpan = parentSpan && getRootSpan(parentSpan);\n const segmentName = segmentSpan ? spanToJSON(segmentSpan).name : getCurrentScope().getScopeData().transactionName;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,\n [`browser.web_vital.${metricName}.value`]: value,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: segmentName,\n [SENTRY_SEGMENT_NAME]: segmentName,\n // Web vital score calculation relies on the user agent\n [USER_AGENT_ORIGINAL]: WINDOW.navigator?.userAgent,\n ...passedAttributes,\n };\n\n if (parentSpan && spanToJSON(parentSpan).attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'pageload') {\n // for LCP and CLS, we collect the pageload span id as an attribute\n attributes['sentry.pageload.span_id'] = parentSpan.spanContext().spanId;\n }\n\n if (reportEvent) {\n attributes[`browser.web_vital.${metricName}.report_event`] = reportEvent;\n }\n\n if (softNavigationId != null) {\n attributes[BROWSER_NAVIGATION_ID] = softNavigationId;\n }\n\n if (navigationType) {\n attributes[BROWSER_NAVIGATION_TYPE] = toBrowserNavigationType(navigationType);\n }\n\n // A standalone span is sent as a plain v2 span without running the `processSpan` hooks (see\n // `captureStandaloneSpanWithStaticCallback`), so Replay can't attach the replay id itself. Set it\n // here, mirroring Replay's `processSpan`, so INP keeps its replay association like it did on v1.\n // TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always\n // streams, at which point Replay's `processSpan` runs and attaches the replay id.\n if (standalone) {\n Object.assign(attributes, getReplayAttributes());\n }\n\n const span = startInactiveSpan({\n name,\n attributes,\n startTime,\n parentSpan,\n // oxlint-disable-next-line typescript/no-deprecated -- intentional during the v1/v2 transition; see the TODO(standalone) above\n experimental: standalone ? { standalone: true } : undefined,\n });\n\n if (span) {\n span.end(endTime ?? startTime);\n }\n}\n\ninterface ReplayIntegration extends Integration {\n getReplayId: (onlyIfSampled?: boolean) => string | undefined;\n getRecordingMode: () => 'session' | 'buffer' | undefined;\n}\n\n// TODO(standalone): remove once the static (transaction) trace lifecycle is dropped; Replay's\n// `processSpan` then attaches the replay id to the streamed INP span instead.\nfunction getReplayAttributes(): SpanAttributes {\n const replay = getClient()?.getIntegrationByName<ReplayIntegration>('Replay');\n const replayId = replay?.getReplayId(true);\n if (!replayId) {\n return {};\n }\n\n return {\n [SENTRY_REPLAY_ID]: replayId,\n // Not the `SENTRY_REPLAY_IS_BUFFERING` convention: that one has no `sentry._internal.` prefix, and\n // the rest of the SDK sets the prefixed key (see `logs/internal.ts`, `metrics/internal.ts`).\n 'sentry._internal.replay_is_buffering': replay!.getRecordingMode() === 'buffer' ? true : undefined,\n };\n}\n"],"names":["getRootSpan","spanToJSON","getCurrentScope","attributes","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME","SENTRY_TRANSACTION","SENTRY_SEGMENT_NAME","USER_AGENT_ORIGINAL","WINDOW","BROWSER_NAVIGATION_ID","BROWSER_NAVIGATION_TYPE","startInactiveSpan","getClient","SENTRY_REPLAY_ID"],"mappings":"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"}
1
+ {"version":3,"file":"emitSpan.js","sources":["../../../src/web-vitals/emitSpan.ts"],"sourcesContent":["import type { Integration, Span, SpanAttributes } from '@sentry/core';\nimport {\n getClient,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport { startInactiveSpan } from '@sentry/core/browser';\nimport {\n BROWSER_NAVIGATION_ID,\n BROWSER_NAVIGATION_TYPE,\n SENTRY_REPLAY_ID,\n SENTRY_SEGMENT_NAME,\n SENTRY_TRANSACTION,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { WINDOW } from '../types';\nimport type { MetricNavigationType } from '../instrumentation/performanceObserver';\nimport type { WebVitalReportEvent } from './reportEvents';\n\n// Locally-defined interfaces to avoid leaking bare global type references into the\n// generated .d.ts. The `declare global` augmentations in web-vitals/types.ts make these\n// available during this package's compilation but are NOT carried to consumers.\n// This mirrors the pattern used for PerformanceEventTiming in instrument.ts.\nexport interface LayoutShift extends PerformanceEntry {\n value: number;\n sources: Array<{ node: Node | null }>;\n hadRecentInput: boolean;\n}\n\nexport interface LargestContentfulPaint extends PerformanceEntry {\n readonly renderTime: DOMHighResTimeStamp;\n readonly loadTime: DOMHighResTimeStamp;\n readonly size: number;\n readonly id: string;\n readonly url: string;\n readonly element: Element | null;\n}\n\ninterface WebVitalSpanOptions {\n name: string;\n op: string;\n origin: string;\n metricName: 'lcp' | 'cls' | 'inp';\n value: number;\n attributes?: SpanAttributes;\n parentSpan?: Span;\n reportEvent?: WebVitalReportEvent;\n startTime: number;\n endTime?: number;\n /** Set when the vital was reported for a soft navigation rather than the initial page load. */\n softNavigationId?: number;\n /** The navigation the vital was measured on, as reported by web-vitals. */\n navigationType?: MetricNavigationType;\n /**\n * When `true`, the span is sent on its own as a v2 streamed span instead of being folded into a\n * transaction. Used for INP when span streaming is disabled (it reports late, so it can't ride\n * the pageload transaction).\n *\n * TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always streams.\n */\n standalone?: boolean;\n}\n\n/**\n * Emits a web vital span. When `standalone` is set it is sent on its own as a v2 streamed span;\n * otherwise it flows through the span streaming pipeline as a child of `parentSpan`.\n */\nexport function _emitWebVitalSpan(options: WebVitalSpanOptions): void {\n const {\n name,\n op,\n origin,\n metricName,\n value,\n attributes: passedAttributes,\n parentSpan,\n reportEvent,\n startTime,\n endTime,\n standalone,\n softNavigationId,\n navigationType,\n } = options;\n\n // Taken off the segment span itself, so it can't diverge from it: a routing instrumentation may\n // rename that span (a pageload span is named `Pageload` until its route resolves), and the scope's\n // transaction name is deliberately not kept in sync with it. Only a standalone span, which is sent\n // without its segment span, has to fall back to the scope.\n const segmentSpan = parentSpan && getRootSpan(parentSpan);\n const segmentName = segmentSpan ? spanToJSON(segmentSpan).name : getCurrentScope().getScopeData().transactionName;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,\n [`browser.web_vital.${metricName}.value`]: value,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: segmentName,\n [SENTRY_SEGMENT_NAME]: segmentName,\n // Web vital score calculation relies on the user agent\n [USER_AGENT_ORIGINAL]: WINDOW.navigator?.userAgent,\n ...passedAttributes,\n };\n\n if (parentSpan && spanToJSON(parentSpan).attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'pageload') {\n // for LCP and CLS, we collect the pageload span id as an attribute\n attributes['sentry.pageload.span_id'] = parentSpan.spanContext().spanId;\n }\n\n if (reportEvent) {\n attributes[`browser.web_vital.${metricName}.report_event`] = reportEvent;\n }\n\n if (softNavigationId != null) {\n attributes[BROWSER_NAVIGATION_ID] = softNavigationId;\n }\n\n if (navigationType) {\n attributes[BROWSER_NAVIGATION_TYPE] = navigationType;\n }\n\n // A standalone span is sent as a plain v2 span without running the `processSpan` hooks (see\n // `captureStandaloneSpanWithStaticCallback`), so Replay can't attach the replay id itself. Set it\n // here, mirroring Replay's `processSpan`, so INP keeps its replay association like it did on v1.\n // TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always\n // streams, at which point Replay's `processSpan` runs and attaches the replay id.\n if (standalone) {\n Object.assign(attributes, getReplayAttributes());\n }\n\n const span = startInactiveSpan({\n name,\n attributes,\n startTime,\n parentSpan,\n // oxlint-disable-next-line typescript/no-deprecated -- intentional during the v1/v2 transition; see the TODO(standalone) above\n experimental: standalone ? { standalone: true } : undefined,\n });\n\n if (span) {\n span.end(endTime ?? startTime);\n }\n}\n\ninterface ReplayIntegration extends Integration {\n getReplayId: (onlyIfSampled?: boolean) => string | undefined;\n getRecordingMode: () => 'session' | 'buffer' | undefined;\n}\n\n// TODO(standalone): remove once the static (transaction) trace lifecycle is dropped; Replay's\n// `processSpan` then attaches the replay id to the streamed INP span instead.\nfunction getReplayAttributes(): SpanAttributes {\n const replay = getClient()?.getIntegrationByName<ReplayIntegration>('Replay');\n const replayId = replay?.getReplayId(true);\n if (!replayId) {\n return {};\n }\n\n return {\n [SENTRY_REPLAY_ID]: replayId,\n // Not the `SENTRY_REPLAY_IS_BUFFERING` convention: that one has no `sentry._internal.` prefix, and\n // the rest of the SDK sets the prefixed key (see `logs/internal.ts`, `metrics/internal.ts`).\n 'sentry._internal.replay_is_buffering': replay!.getRecordingMode() === 'buffer' ? true : undefined,\n };\n}\n"],"names":["getRootSpan","spanToJSON","getCurrentScope","attributes","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME","SENTRY_TRANSACTION","SENTRY_SEGMENT_NAME","USER_AGENT_ORIGINAL","WINDOW","BROWSER_NAVIGATION_ID","BROWSER_NAVIGATION_TYPE","startInactiveSpan","getClient","SENTRY_REPLAY_ID"],"mappings":";;;;;;;AAuEO,SAAS,kBAAkB,OAAA,EAAoC;AACpE,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,EAAA;AAAA,IACA,MAAA;AAAA,IACA,UAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA,EAAY,gBAAA;AAAA,IACZ,UAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,gBAAA;AAAA,IACA;AAAA,GACF,GAAI,OAAA;AAMJ,EAAA,MAAM,WAAA,GAAc,UAAA,IAAcA,gBAAA,CAAY,UAAU,CAAA;AACxD,EAAA,MAAM,WAAA,GAAc,cAAcC,eAAA,CAAW,WAAW,EAAE,IAAA,GAAOC,oBAAA,EAAgB,CAAE,YAAA,EAAa,CAAE,eAAA;AAElG,EAAA,MAAMC,YAAA,GAA6B;AAAA,IACjC,CAACC,qCAAgC,GAAG,MAAA;AAAA,IACpC,CAACC,iCAA4B,GAAG,EAAA;AAAA,IAChC,CAACC,sCAAiC,GAAG,CAAA;AAAA,IACrC,CAAC,CAAA,kBAAA,EAAqB,UAAU,CAAA,MAAA,CAAQ,GAAG,KAAA;AAAA;AAAA,IAE3C,CAACC,6BAAkB,GAAG,WAAA;AAAA,IACtB,CAACC,8BAAmB,GAAG,WAAA;AAAA;AAAA,IAEvB,CAACC,8BAAmB,GAAGC,YAAA,CAAO,SAAA,EAAW,SAAA;AAAA,IACzC,GAAG;AAAA,GACL;AAEA,EAAA,IAAI,cAAcT,eAAA,CAAW,UAAU,EAAE,UAAA,CAAWI,iCAA4B,MAAM,UAAA,EAAY;AAEhG,IAAAF,YAAA,CAAW,yBAAyB,CAAA,GAAI,UAAA,CAAW,WAAA,EAAY,CAAE,MAAA;AAAA,EACnE;AAEA,EAAA,IAAI,WAAA,EAAa;AACf,IAAAA,YAAA,CAAW,CAAA,kBAAA,EAAqB,UAAU,CAAA,aAAA,CAAe,CAAA,GAAI,WAAA;AAAA,EAC/D;AAEA,EAAA,IAAI,oBAAoB,IAAA,EAAM;AAC5B,IAAAA,YAAA,CAAWQ,gCAAqB,CAAA,GAAI,gBAAA;AAAA,EACtC;AAEA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAAR,YAAA,CAAWS,kCAAuB,CAAA,GAAI,cAAA;AAAA,EACxC;AAOA,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,MAAA,CAAO,MAAA,CAAOT,YAAA,EAAY,mBAAA,EAAqB,CAAA;AAAA,EACjD;AAEA,EAAA,MAAM,OAAOU,yBAAA,CAAkB;AAAA,IAC7B,IAAA;AAAA,gBACAV,YAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA;AAAA,IAEA,YAAA,EAAc,UAAA,GAAa,EAAE,UAAA,EAAY,MAAK,GAAI;AAAA,GACnD,CAAA;AAED,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,IAAA,CAAK,GAAA,CAAI,WAAW,SAAS,CAAA;AAAA,EAC/B;AACF;AASA,SAAS,mBAAA,GAAsC;AAC7C,EAAA,MAAM,MAAA,GAASW,cAAA,EAAU,EAAG,oBAAA,CAAwC,QAAQ,CAAA;AAC5E,EAAA,MAAM,QAAA,GAAW,MAAA,EAAQ,WAAA,CAAY,IAAI,CAAA;AACzC,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,OAAO;AAAA,IACL,CAACC,2BAAgB,GAAG,QAAA;AAAA;AAAA;AAAA,IAGpB,sCAAA,EAAwC,MAAA,CAAQ,gBAAA,EAAiB,KAAM,WAAW,IAAA,GAAO;AAAA,GAC3F;AACF;;;;"}
@@ -27,7 +27,7 @@ function trackWebVitalPerNavigation(client, addInstrumentationHandler, send) {
27
27
  let bfcacheNavigationSpan;
28
28
  client.on("spanStart", (span) => {
29
29
  const attributes$1 = core.spanToJSON(span).attributes;
30
- if (attributes$1?.[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] === op.NAVIGATION && attributes$1[attributes.BROWSER_NAVIGATION_TYPE] === "bfcache") {
30
+ if (attributes$1?.[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] === op.NAVIGATION && attributes$1[attributes.BROWSER_NAVIGATION_TYPE] === "back-forward-cache") {
31
31
  bfcacheNavigationSpan = span;
32
32
  }
33
33
  });
@@ -1 +1 @@
1
- {"version":3,"file":"spans.js","sources":["../../../src/web-vitals/spans.ts"],"sourcesContent":["import type { Client, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n timestampInSeconds,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport type { InteractionType } from './inp';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION } from './inp';\nimport type { InstrumentationHandlerCallback, MetricNavigationType } from '../instrumentation/performanceObserver';\nimport {\n addClsInstrumentationHandler,\n addInpInstrumentationHandler,\n addLcpInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport type { LargestContentfulPaint, LayoutShift } from './emitSpan';\nimport { BROWSER_NAVIGATION_TYPE } from '@sentry/conventions/attributes';\nimport { _emitWebVitalSpan } from './emitSpan';\nimport { isValidLcpMetric } from './lcp';\nimport type { WebVitalReportEvent } from './reportEvents';\nimport { listenForWebVitalReportEvents } from './reportEvents';\nimport { getNavigationSpanForMetric } from './softNavs';\nimport { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';\nimport type { PerformanceEventTiming } from '../instrumentation/performanceObserver';\nimport {\n NAVIGATION,\n UI_INTERACTION_CLICK,\n UI_INTERACTION_DRAG,\n UI_INTERACTION_HOVER,\n UI_INTERACTION_PRESS,\n UI_WEBVITAL_CLS,\n UI_WEBVITAL_LCP,\n} from '@sentry/conventions/op';\n\nconst INTERACTION_TYPE_TO_SPAN_OP: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK,\n hover: UI_INTERACTION_HOVER,\n drag: UI_INTERACTION_DRAG,\n press: UI_INTERACTION_PRESS,\n};\n\ntype WebVitalMetric = Parameters<Parameters<typeof addLcpInstrumentationHandler>[0]>[0]['metric'];\ntype InpMetric = Parameters<InstrumentationHandlerCallback>[0]['metric'];\n\n/**\n * Reports a web vital once per navigation, rather than once per page load.\n *\n * web-vitals restarts the metric on every soft navigation and force-reports the previous one just\n * before it does (and again on pagehide), and re-reports every metric after a bfcache restore.\n * Since `reportAllChanges` is off in this mode, every value we're handed is already the final one\n * for its navigation, so there is nothing to accumulate: each report is a span.\n */\nfunction trackWebVitalPerNavigation<M extends WebVitalMetric>(\n client: Client,\n addInstrumentationHandler: (callback: (data: { metric: M }) => void) => unknown,\n send: (metric: M, parentSpan: Span | undefined, softNavigationId: number | undefined) => void,\n): void {\n let pageloadSpan: Span | undefined;\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n });\n\n // Remembered when the restore happens rather than read back at report time: the restore\n // navigation span is an idle span, and CLS and INP are only finalized on pagehide, by which point\n // it has long ended and is no longer what is active.\n let bfcacheNavigationSpan: Span | undefined;\n client.on('spanStart', span => {\n // The op has to be checked too: the web vital spans emitted for a restore carry the same\n // `bfcache` navigation type, so matching on that alone lets the first of them replace the\n // navigation span, and every later vital then hangs off a sibling vital instead.\n const attributes = spanToJSON(span).attributes;\n if (\n attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION &&\n attributes[BROWSER_NAVIGATION_TYPE] === 'bfcache'\n ) {\n bfcacheNavigationSpan = span;\n }\n });\n\n addInstrumentationHandler(({ metric }) => {\n const navigationSpan = getNavigationSpanForMetric(metric);\n if (metric.navigationType === 'soft-navigation') {\n // Reporting an uncorrelated soft navigation vital would attribute it to the wrong route, so\n // it's dropped instead.\n if (navigationSpan) {\n send(metric, navigationSpan, metric.navigationId);\n } else {\n DEBUG_BUILD &&\n debug.log(`[SoftNav] Dropping ${metric.name} for uncorrelated soft navigation ${metric.navigationId}`);\n }\n return;\n }\n\n if (metric.navigationType === 'back-forward-cache') {\n // A restore reuses the frozen document, so the pageload span above belongs to the page view\n // from before the freeze. The navigation span started for the restore is the page view these\n // values were actually measured on.\n send(metric, bfcacheNavigationSpan, undefined);\n return;\n }\n\n send(metric, pageloadSpan, undefined);\n });\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addLcpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n _sendLcpSpan(\n metric.value,\n entry,\n parentSpan,\n undefined,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n let lcpNavigationType: MetricNavigationType | undefined;\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n // The navigation type describes the page, not the entry, so it is worth keeping even for a\n // report we otherwise discard.\n lcpNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n lcpValue = metric.value;\n lcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, reportEvent, undefined, lcpNavigationType);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin() || 0;\n // A soft navigation's LCP is measured from the triggering interaction, not the document time\n // origin. Starting the span there too keeps it inside the navigation span it is parented to and\n // keeps its duration equal to the value it reports.\n const startTime = msToSec(performanceTimeOrigin + (navigationStartTime || 0));\n // Without an entry there is no render time to end at, so the span lasts the value it reports,\n // like an entry-less INP does. Ending at the time origin instead would invert the span.\n const endTime = entry ? msToSec(performanceTimeOrigin + entry.startTime) : startTime + msToSec(lcpValue);\n const name = entry ? htmlTreeAsString(entry.element) : 'Largest contentful paint';\n\n const attributes: SpanAttributes = {};\n\n entry?.element && (attributes['browser.web_vital.lcp.element'] = htmlTreeAsString(entry.element));\n entry?.id && (attributes['browser.web_vital.lcp.id'] = entry.id);\n entry?.url && (attributes['browser.web_vital.lcp.url'] = entry.url);\n entry?.loadTime != null && (attributes['browser.web_vital.lcp.load_time'] = entry.loadTime);\n entry?.renderTime != null && (attributes['browser.web_vital.lcp.render_time'] = entry.renderTime);\n entry?.size != null && (attributes['browser.web_vital.lcp.size'] = entry.size);\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_LCP,\n origin: 'auto.http.browser.lcp',\n metricName: 'lcp',\n value: lcpValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime,\n endTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addClsInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n _sendClsSpan(\n metric.value,\n entry,\n parentSpan,\n undefined,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n let clsNavigationType: MetricNavigationType | undefined;\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n // A CLS of 0 is reported with no entries and still emits a span, so the navigation type has to\n // be captured before the entry check rather than alongside the value.\n clsNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n clsValue = metric.value;\n clsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, reportEvent, undefined, clsNavigationType);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin();\n // A CLS of 0 has no shift to place the span at. It is reported when the navigation it was\n // measured on is already over - the next soft navigation, or pagehide - so the current time would\n // land it outside that navigation, on the route that follows it.\n const offset = entry?.startTime ?? navigationStartTime ?? 0;\n const startTime = performanceTimeOrigin ? msToSec(performanceTimeOrigin + offset) : timestampInSeconds();\n const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';\n\n const attributes: SpanAttributes = {};\n\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`browser.web_vital.cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_CLS,\n origin: 'auto.http.browser.cls',\n metricName: 'cls',\n value: clsValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks INP and emits it as a web vital span, as a child of the interaction's root span.\n * Requires `registerInpInteractionListener()` to be called separately for cached element names and\n * root spans per interaction.\n */\nexport function trackInpAsSpan(client: Client, perNavigation = false): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n // INP reports late (on pagehide, after the pageload span has ended). With span streaming enabled\n // it rides the streaming pipeline. With streaming disabled it would be dropped as a late span, so\n // it is emitted as its own standalone v2 span instead (see `_emitWebVitalSpan`), overriding the\n // static trace lifecycle for INP only.\n // TODO(standalone): once the static trace lifecycle is dropped, INP always streams; drop this flag.\n const standalone = !hasSpanStreamingEnabled(client);\n\n if (perNavigation) {\n // INP restarts per navigation and reports once that navigation is over, by which point the\n // navigation span has ended and the interaction cache no longer knows about it. The metric\n // says which navigation it belongs to, so INP is attributed exactly like LCP and CLS.\n trackWebVitalPerNavigation(client, addInpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, parentSpan, softNavigationId, metric);\n }\n });\n return;\n }\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, undefined, undefined, metric);\n }\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\nfunction isPlausibleInp(metric: InpMetric): boolean {\n return metric.value != null && msToSec(metric.value) <= MAX_PLAUSIBLE_INP_DURATION;\n}\n\n/**\n * The entry an INP span is built from: the one whose duration the reported value came from.\n *\n * There isn't always one. When every interaction of a soft navigation stayed below the Event Timing\n * threshold, web-vitals reports a synthetic value with no entries at all - see\n * `_estimateP98LongestInteraction`. The span still gets reported in that case, just without the\n * element and interaction type an entry would have supplied.\n */\nfunction findInpEntry(metric: InpMetric): PerformanceEventTiming | undefined {\n return metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(\n inpValue: number,\n entry: PerformanceEventTiming | undefined,\n standalone = false,\n attributedSpan?: Span,\n softNavigationId?: number,\n metric?: InpMetric,\n): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n // A web vital span carries the metric, not a real interaction timing, so an INP without an entry\n // is still worth reporting. It just has no element or interaction type to describe, and is placed\n // at the start of the navigation it belongs to rather than at the interaction.\n const startTime = msToSec(\n (browserPerformanceTimeOrigin() as number) + (entry?.startTime ?? metric?.navigationStartTime ?? 0),\n );\n const duration = msToSec(inpValue);\n // An INP without an entry has no interaction type to report. It still has to land inside the\n // `ui.interaction.*` family, because falling outside it would hide exactly the fast navigations\n // that web-vitals synthesizes these values for (GoogleChrome/web-vitals#724), reintroducing the\n // reporting bias they were added to remove.\n const interactionType = (entry && INP_ENTRY_MAP[entry.name]) || 'click';\n\n const cachedContext = entry && getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // With soft navigations the caller knows exactly which navigation the metric belongs to. Without\n // them we fall back to the span that was active when the interaction was observed.\n const spanToUse = attributedSpan || cachedContext?.span || rootSpan;\n const name = cachedContext?.elementName || (entry ? htmlTreeAsString(entry.target) : 'Interaction to next paint');\n\n _emitWebVitalSpan({\n name,\n op: INTERACTION_TYPE_TO_SPAN_OP[interactionType],\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes: {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue,\n },\n startTime,\n endTime: startTime + duration,\n navigationType: metric?.navigationType,\n parentSpan: spanToUse,\n standalone,\n softNavigationId,\n });\n}\n"],"names":["UI_INTERACTION_CLICK","UI_INTERACTION_HOVER","UI_INTERACTION_DRAG","UI_INTERACTION_PRESS","attributes","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","NAVIGATION","BROWSER_NAVIGATION_TYPE","getNavigationSpanForMetric","DEBUG_BUILD","debug","supportsWebVital","addLcpInstrumentationHandler","isValidLcpMetric","listenForWebVitalReportEvents","browserPerformanceTimeOrigin","msToSec","htmlTreeAsString","_emitWebVitalSpan","UI_WEBVITAL_LCP","addClsInstrumentationHandler","timestampInSeconds","UI_WEBVITAL_CLS","getBrowserPerformanceAPI","hasSpanStreamingEnabled","addInpInstrumentationHandler","MAX_PLAUSIBLE_INP_DURATION","INP_ENTRY_MAP","getCachedInteractionContext","getActiveSpan","getRootSpan","SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME"],"mappings":"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"}
1
+ {"version":3,"file":"spans.js","sources":["../../../src/web-vitals/spans.ts"],"sourcesContent":["import type { Client, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n timestampInSeconds,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport type { InteractionType } from './inp';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION } from './inp';\nimport type { InstrumentationHandlerCallback, MetricNavigationType } from '../instrumentation/performanceObserver';\nimport {\n addClsInstrumentationHandler,\n addInpInstrumentationHandler,\n addLcpInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport type { LargestContentfulPaint, LayoutShift } from './emitSpan';\nimport { BROWSER_NAVIGATION_TYPE } from '@sentry/conventions/attributes';\nimport { _emitWebVitalSpan } from './emitSpan';\nimport { isValidLcpMetric } from './lcp';\nimport type { WebVitalReportEvent } from './reportEvents';\nimport { listenForWebVitalReportEvents } from './reportEvents';\nimport { getNavigationSpanForMetric } from './softNavs';\nimport { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';\nimport type { PerformanceEventTiming } from '../instrumentation/performanceObserver';\nimport {\n NAVIGATION,\n UI_INTERACTION_CLICK,\n UI_INTERACTION_DRAG,\n UI_INTERACTION_HOVER,\n UI_INTERACTION_PRESS,\n UI_WEBVITAL_CLS,\n UI_WEBVITAL_LCP,\n} from '@sentry/conventions/op';\n\nconst INTERACTION_TYPE_TO_SPAN_OP: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK,\n hover: UI_INTERACTION_HOVER,\n drag: UI_INTERACTION_DRAG,\n press: UI_INTERACTION_PRESS,\n};\n\ntype WebVitalMetric = Parameters<Parameters<typeof addLcpInstrumentationHandler>[0]>[0]['metric'];\ntype InpMetric = Parameters<InstrumentationHandlerCallback>[0]['metric'];\n\n/**\n * Reports a web vital once per navigation, rather than once per page load.\n *\n * web-vitals restarts the metric on every soft navigation and force-reports the previous one just\n * before it does (and again on pagehide), and re-reports every metric after a bfcache restore.\n * Since `reportAllChanges` is off in this mode, every value we're handed is already the final one\n * for its navigation, so there is nothing to accumulate: each report is a span.\n */\nfunction trackWebVitalPerNavigation<M extends WebVitalMetric>(\n client: Client,\n addInstrumentationHandler: (callback: (data: { metric: M }) => void) => unknown,\n send: (metric: M, parentSpan: Span | undefined, softNavigationId: number | undefined) => void,\n): void {\n let pageloadSpan: Span | undefined;\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n });\n\n // Remembered when the restore happens rather than read back at report time: the restore\n // navigation span is an idle span, and CLS and INP are only finalized on pagehide, by which point\n // it has long ended and is no longer what is active.\n let bfcacheNavigationSpan: Span | undefined;\n client.on('spanStart', span => {\n // The op has to be checked too: the web vital spans emitted for a restore carry the same\n // `back-forward-cache` navigation type, so matching on that alone lets the first of them replace the\n // navigation span, and every later vital then hangs off a sibling vital instead.\n const attributes = spanToJSON(span).attributes;\n if (\n attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION &&\n attributes[BROWSER_NAVIGATION_TYPE] === 'back-forward-cache'\n ) {\n bfcacheNavigationSpan = span;\n }\n });\n\n addInstrumentationHandler(({ metric }) => {\n const navigationSpan = getNavigationSpanForMetric(metric);\n if (metric.navigationType === 'soft-navigation') {\n // Reporting an uncorrelated soft navigation vital would attribute it to the wrong route, so\n // it's dropped instead.\n if (navigationSpan) {\n send(metric, navigationSpan, metric.navigationId);\n } else {\n DEBUG_BUILD &&\n debug.log(`[SoftNav] Dropping ${metric.name} for uncorrelated soft navigation ${metric.navigationId}`);\n }\n return;\n }\n\n if (metric.navigationType === 'back-forward-cache') {\n // A restore reuses the frozen document, so the pageload span above belongs to the page view\n // from before the freeze. The navigation span started for the restore is the page view these\n // values were actually measured on.\n send(metric, bfcacheNavigationSpan, undefined);\n return;\n }\n\n send(metric, pageloadSpan, undefined);\n });\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addLcpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n _sendLcpSpan(\n metric.value,\n entry,\n parentSpan,\n undefined,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n let lcpNavigationType: MetricNavigationType | undefined;\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n // The navigation type describes the page, not the entry, so it is worth keeping even for a\n // report we otherwise discard.\n lcpNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n lcpValue = metric.value;\n lcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, reportEvent, undefined, lcpNavigationType);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin() || 0;\n // A soft navigation's LCP is measured from the triggering interaction, not the document time\n // origin. Starting the span there too keeps it inside the navigation span it is parented to and\n // keeps its duration equal to the value it reports.\n const startTime = msToSec(performanceTimeOrigin + (navigationStartTime || 0));\n // Without an entry there is no render time to end at, so the span lasts the value it reports,\n // like an entry-less INP does. Ending at the time origin instead would invert the span.\n const endTime = entry ? msToSec(performanceTimeOrigin + entry.startTime) : startTime + msToSec(lcpValue);\n const name = entry ? htmlTreeAsString(entry.element) : 'Largest contentful paint';\n\n const attributes: SpanAttributes = {};\n\n entry?.element && (attributes['browser.web_vital.lcp.element'] = htmlTreeAsString(entry.element));\n entry?.id && (attributes['browser.web_vital.lcp.id'] = entry.id);\n entry?.url && (attributes['browser.web_vital.lcp.url'] = entry.url);\n entry?.loadTime != null && (attributes['browser.web_vital.lcp.load_time'] = entry.loadTime);\n entry?.renderTime != null && (attributes['browser.web_vital.lcp.render_time'] = entry.renderTime);\n entry?.size != null && (attributes['browser.web_vital.lcp.size'] = entry.size);\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_LCP,\n origin: 'auto.http.browser.lcp',\n metricName: 'lcp',\n value: lcpValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime,\n endTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addClsInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n _sendClsSpan(\n metric.value,\n entry,\n parentSpan,\n undefined,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n let clsNavigationType: MetricNavigationType | undefined;\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n // A CLS of 0 is reported with no entries and still emits a span, so the navigation type has to\n // be captured before the entry check rather than alongside the value.\n clsNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n clsValue = metric.value;\n clsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, reportEvent, undefined, clsNavigationType);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin();\n // A CLS of 0 has no shift to place the span at. It is reported when the navigation it was\n // measured on is already over - the next soft navigation, or pagehide - so the current time would\n // land it outside that navigation, on the route that follows it.\n const offset = entry?.startTime ?? navigationStartTime ?? 0;\n const startTime = performanceTimeOrigin ? msToSec(performanceTimeOrigin + offset) : timestampInSeconds();\n const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';\n\n const attributes: SpanAttributes = {};\n\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`browser.web_vital.cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_CLS,\n origin: 'auto.http.browser.cls',\n metricName: 'cls',\n value: clsValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks INP and emits it as a web vital span, as a child of the interaction's root span.\n * Requires `registerInpInteractionListener()` to be called separately for cached element names and\n * root spans per interaction.\n */\nexport function trackInpAsSpan(client: Client, perNavigation = false): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n // INP reports late (on pagehide, after the pageload span has ended). With span streaming enabled\n // it rides the streaming pipeline. With streaming disabled it would be dropped as a late span, so\n // it is emitted as its own standalone v2 span instead (see `_emitWebVitalSpan`), overriding the\n // static trace lifecycle for INP only.\n // TODO(standalone): once the static trace lifecycle is dropped, INP always streams; drop this flag.\n const standalone = !hasSpanStreamingEnabled(client);\n\n if (perNavigation) {\n // INP restarts per navigation and reports once that navigation is over, by which point the\n // navigation span has ended and the interaction cache no longer knows about it. The metric\n // says which navigation it belongs to, so INP is attributed exactly like LCP and CLS.\n trackWebVitalPerNavigation(client, addInpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, parentSpan, softNavigationId, metric);\n }\n });\n return;\n }\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, undefined, undefined, metric);\n }\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\nfunction isPlausibleInp(metric: InpMetric): boolean {\n return metric.value != null && msToSec(metric.value) <= MAX_PLAUSIBLE_INP_DURATION;\n}\n\n/**\n * The entry an INP span is built from: the one whose duration the reported value came from.\n *\n * There isn't always one. When every interaction of a soft navigation stayed below the Event Timing\n * threshold, web-vitals reports a synthetic value with no entries at all - see\n * `_estimateP98LongestInteraction`. The span still gets reported in that case, just without the\n * element and interaction type an entry would have supplied.\n */\nfunction findInpEntry(metric: InpMetric): PerformanceEventTiming | undefined {\n return metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(\n inpValue: number,\n entry: PerformanceEventTiming | undefined,\n standalone = false,\n attributedSpan?: Span,\n softNavigationId?: number,\n metric?: InpMetric,\n): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n // A web vital span carries the metric, not a real interaction timing, so an INP without an entry\n // is still worth reporting. It just has no element or interaction type to describe, and is placed\n // at the start of the navigation it belongs to rather than at the interaction.\n const startTime = msToSec(\n (browserPerformanceTimeOrigin() as number) + (entry?.startTime ?? metric?.navigationStartTime ?? 0),\n );\n const duration = msToSec(inpValue);\n // An INP without an entry has no interaction type to report. It still has to land inside the\n // `ui.interaction.*` family, because falling outside it would hide exactly the fast navigations\n // that web-vitals synthesizes these values for (GoogleChrome/web-vitals#724), reintroducing the\n // reporting bias they were added to remove.\n const interactionType = (entry && INP_ENTRY_MAP[entry.name]) || 'click';\n\n const cachedContext = entry && getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // With soft navigations the caller knows exactly which navigation the metric belongs to. Without\n // them we fall back to the span that was active when the interaction was observed.\n const spanToUse = attributedSpan || cachedContext?.span || rootSpan;\n const name = cachedContext?.elementName || (entry ? htmlTreeAsString(entry.target) : 'Interaction to next paint');\n\n _emitWebVitalSpan({\n name,\n op: INTERACTION_TYPE_TO_SPAN_OP[interactionType],\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes: {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue,\n },\n startTime,\n endTime: startTime + duration,\n navigationType: metric?.navigationType,\n parentSpan: spanToUse,\n standalone,\n softNavigationId,\n });\n}\n"],"names":["UI_INTERACTION_CLICK","UI_INTERACTION_HOVER","UI_INTERACTION_DRAG","UI_INTERACTION_PRESS","attributes","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","NAVIGATION","BROWSER_NAVIGATION_TYPE","getNavigationSpanForMetric","DEBUG_BUILD","debug","supportsWebVital","addLcpInstrumentationHandler","isValidLcpMetric","listenForWebVitalReportEvents","browserPerformanceTimeOrigin","msToSec","htmlTreeAsString","_emitWebVitalSpan","UI_WEBVITAL_LCP","addClsInstrumentationHandler","timestampInSeconds","UI_WEBVITAL_CLS","getBrowserPerformanceAPI","hasSpanStreamingEnabled","addInpInstrumentationHandler","MAX_PLAUSIBLE_INP_DURATION","INP_ENTRY_MAP","getCachedInteractionContext","getActiveSpan","getRootSpan","SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"performanceObserver.js","sources":["../../../src/instrumentation/performanceObserver.ts"],"sourcesContent":["import { debug, getFunctionName } from '@sentry/core';\nimport { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';\nimport { DEBUG_BUILD } from '../debug-build';\n\ntype InstrumentHandlerTypePerformanceObserver =\n | 'longtask'\n | 'event'\n | 'navigation'\n | 'paint'\n | 'resource'\n | 'element'\n | 'soft-navigation'\n // fist-input is still needed for INP\n | 'first-input';\n\ntype InstrumentHandlerTypeMetric = 'cls' | 'lcp' | 'ttfb' | 'inp' | 'fcp';\n\n// We provide this here manually instead of relying on a global, as this is not available in non-browser environements\n// And we do not want to expose such types\ninterface PerformanceEntry {\n readonly duration: number;\n readonly entryType: string;\n readonly name: string;\n readonly startTime: number;\n toJSON(): Record<string, unknown>;\n}\nexport interface PerformanceEventTiming extends PerformanceEntry {\n processingStart: number;\n processingEnd: number;\n duration: number;\n cancelable?: boolean;\n target?: unknown | null;\n interactionId?: number;\n}\n\n/**\n * A `soft-navigation` entry, minted by the browser once a history change is followed by a\n * confirming paint. `interactionId` is the id of the `PerformanceEventTiming` entry for the\n * interaction that drove the navigation, which is how we join it back to a Sentry navigation span.\n */\nexport interface PerformanceSoftNavigation extends PerformanceEntry {\n readonly interactionId: number;\n readonly navigationId: number;\n}\n\ninterface PerformanceScriptTiming extends PerformanceEntry {\n sourceURL: string;\n sourceFunctionName: string;\n sourceCharPosition: number;\n invoker: string;\n invokerType: string;\n}\nexport interface PerformanceLongAnimationFrameTiming extends PerformanceEntry {\n scripts: PerformanceScriptTiming[];\n}\n\n// Locally-defined to match web-vitals' `Metric` shape without importing it: web-vitals' type\n// entrypoint carries a `declare global` block that references DOM globals not present in every\n// TypeScript lib version (e.g. `NavigationType`), which leaks into and breaks consumers on older\n// TS. Keeping this local keeps web-vitals' global augmentations out of our published types.\n/**\n * The navigation types web-vitals reports a metric for. Wider than the set the\n * `browser.navigation.type` attribute uses - see `toBrowserNavigationType`.\n */\nexport type MetricNavigationType =\n | 'navigate'\n | 'reload'\n | 'back-forward'\n | 'back-forward-cache'\n | 'prerender'\n | 'restore'\n | 'soft-navigation';\n\ninterface Metric {\n /**\n * The name of the metric (in acronym form).\n */\n name: 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB';\n\n /**\n * The current value of the metric.\n */\n value: number;\n\n /**\n * The rating as to whether the metric value is within the \"good\",\n * \"needs improvement\", or \"poor\" thresholds of the metric.\n */\n rating: 'good' | 'needs-improvement' | 'poor';\n\n /**\n * The delta between the current value and the last-reported value.\n * On the first report, `delta` and `value` will always be the same.\n */\n delta: number;\n\n /**\n * A unique ID representing this particular metric instance. This ID can\n * be used by an analytics tool to dedupe multiple values sent for the same\n * metric instance, or to group multiple deltas together and calculate a\n * total. It can also be used to differentiate multiple different metric\n * instances sent from the same page, which can happen if the page is\n * restored from the back/forward cache (in that case new metrics object\n * get created).\n */\n id: string;\n\n /**\n * Any performance entries relevant to the metric value calculation.\n * The array may also be empty if the metric value was not based on any\n * entries (e.g. a CLS value of 0 given no layout shifts).\n */\n entries: PerformanceEntry[];\n\n /**\n * The type of navigation.\n *\n * Navigation Timing API (or `undefined` if the browser doesn't\n * support that API). For pages that are restored from the bfcache, this\n * value will be 'back-forward-cache'.\n */\n navigationType: MetricNavigationType;\n\n /**\n * The id of the navigation the metric belongs to. For soft navigations this is the\n * `navigationId` of the `soft-navigation` entry, otherwise it's the id of the hard navigation.\n */\n navigationId: number;\n\n /**\n * For soft navigations, the `interactionId` of the interaction that triggered the navigation.\n */\n navigationInteractionId?: number;\n\n /**\n * The start time the metric value is relative to. Non-zero for soft navigations, where the\n * time origin is the triggering interaction rather than the start of the document.\n */\n navigationStartTime?: number;\n\n /**\n * The URL the metric was recorded for. Relevant for soft navigations, where a metric can be\n * reported long after the URL has moved on.\n */\n navigationURL?: string;\n}\n\ntype InstrumentHandlerType = InstrumentHandlerTypeMetric | InstrumentHandlerTypePerformanceObserver;\n\ntype StopListening = undefined | void | (() => void);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InstrumentHandlerCallback = (data: any) => void;\n\ntype CleanupHandlerCallback = () => void;\n\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\nlet _previousCls: Metric | undefined;\nlet _previousLcp: Metric | undefined;\nlet _previousTtfb: Metric | undefined;\nlet _previousInp: Metric | undefined;\nlet _previousFcp: Metric | undefined;\n\nconst stopListeners: Partial<Record<InstrumentHandlerType, StopListening>> = {};\n\nlet _reportSoftNavs = false;\nlet _reportBfcache = false;\n\n/**\n * Opt the CLS, LCP and INP observers into reporting metrics for soft navigations.\n *\n * This also turns `reportAllChanges` off for CLS and LCP. web-vitals force-reports a metric when\n * the navigation it belongs to is over, so without the intermediate updates every value a handler\n * receives is already the final one for its navigation. That only holds because soft navigations\n * are limited to span streaming, where CLS and LCP are sent as their own spans - the static\n * lifecycle instead writes them onto the pageload span as it ends, which is what `reportAllChanges`\n * was originally added for (#11934, #12360).\n *\n * Each observer is instrumented lazily, on its first handler, and web-vitals takes its options at\n * that point only. So this has to be called before any of the `add*InstrumentationHandler`\n * functions, otherwise it won't take effect for observers that are already running.\n *\n * On browsers without the Soft Navigation API this is a no-op: web-vitals feature-detects the API\n * and keeps reporting hard-navigation metrics as usual.\n */\nexport function enableSoftNavigationReporting(): void {\n _reportSoftNavs = true;\n}\n\n/**\n * Opt the CLS, LCP and INP observers into reporting metrics for back/forward-cache restores.\n *\n * web-vitals re-reports each metric after a restore, tagged with a `back-forward-cache` navigation\n * type. A restore is a new page view measured against a document that was never reloaded, so the\n * values only mean anything if there is a fresh root span for them to belong to. Without one they\n * would attach to the span the page had before it was frozen, which is why this is off by default.\n *\n * Like `enableSoftNavigationReporting`, this only affects observers instrumented after it is\n * called.\n */\nexport function enableBfcacheReporting(): void {\n _reportBfcache = true;\n}\n\n/**\n * Add a callback that will be triggered when a CLS metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called.\n * This will lead to the CLS being finalized and frozen.\n */\nexport function addClsInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a LCP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called.\n * This will lead to the LCP being finalized and frozen.\n */\nexport function addLcpInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a TTFD metric is available.\n */\nexport function addTtfbInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('ttfb', callback, instrumentTtfb, _previousTtfb);\n}\n\n/**\n * Add a callback that will be triggered when a FCP metric is available.\n */\nexport function addFcpInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('fcp', callback, instrumentFcp, _previousFcp);\n}\n\nexport type InstrumentationHandlerCallback = (data: {\n metric: Omit<Metric, 'entries'> & {\n entries: PerformanceEventTiming[];\n };\n}) => void;\n\n/**\n * Add a callback that will be triggered when a INP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addInpInstrumentationHandler(callback: InstrumentationHandlerCallback): CleanupHandlerCallback {\n return addMetricObserver('inp', callback, instrumentInp, _previousInp);\n}\n\nexport function addPerformanceInstrumentationHandler(\n type: 'event',\n callback: (data: { entries: ((PerformanceEntry & { target?: unknown | null }) | PerformanceEventTiming)[] }) => void,\n): CleanupHandlerCallback;\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback;\n\n/**\n * Add a callback that will be triggered when a performance observer is triggered,\n * and receives the entries of the observer.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumentPerformanceObserver(type);\n instrumented[type] = true;\n }\n\n return getCleanupCallback(type, callback);\n}\n\n/** Trigger all handlers of a given type. */\nfunction triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = handlers[type];\n\n if (!typeHandlers?.length) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n debug.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n\n/**\n * Wraps a metric callback so that metrics reported after a back/forward-cache restore are dropped\n * unless `enableBfcacheReporting` was called. See there for why they are off by default.\n */\nfunction unlessBfcacheDisabled(callback: (metric: Metric) => void): (metric: Metric) => void {\n return metric => {\n if (!_reportBfcache && metric.navigationType === 'back-forward-cache') {\n return;\n }\n callback(metric);\n };\n}\n\nfunction instrumentCls(): StopListening {\n return onCLS(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('cls', {\n metric,\n });\n _previousCls = metric;\n }),\n // We want the callback to be called whenever the CLS value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: !_reportSoftNavs && !_reportBfcache, reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction instrumentLcp(): StopListening {\n return onLCP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('lcp', {\n metric,\n });\n _previousLcp = metric;\n }),\n // We want the callback to be called whenever the LCP value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: !_reportSoftNavs && !_reportBfcache, reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction instrumentTtfb(): StopListening {\n return onTTFB(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('ttfb', {\n metric,\n });\n _previousTtfb = metric;\n }),\n );\n}\n\nfunction instrumentFcp(): StopListening {\n return onFCP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('fcp', {\n metric,\n });\n _previousFcp = metric;\n }),\n );\n}\n\nfunction instrumentInp(): StopListening {\n return onINP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('inp', {\n metric,\n });\n _previousInp = metric;\n }),\n { reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction addMetricObserver(\n type: InstrumentHandlerTypeMetric,\n callback: InstrumentHandlerCallback,\n instrumentFn: () => StopListening,\n previousValue: Metric | undefined,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumented[type] = true;\n // Deferred by a microtask rather than started here, because web-vitals reads its options once,\n // when the observer is created. Registering a handler would otherwise pin those options for\n // every other consumer of this observer, so whichever integration happened to run first would\n // decide whether soft navigations and bfcache restores are reported. Client setup is\n // synchronous, so every `enable*Reporting()` call has landed by the time this runs, and the\n // observers are buffered so no entries are missed in the meantime.\n void Promise.resolve().then(() => {\n stopListeners[type] = instrumentFn();\n });\n }\n\n if (previousValue) {\n callback({ metric: previousValue });\n }\n\n return getCleanupCallback(type, callback, stopOnCallback);\n}\n\nfunction instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObserver): void {\n const options: PerformanceObserverInit = { type, buffered: true };\n\n // Special per-type options we want to use\n if (type === 'event') {\n (options as PerformanceObserverInit & { durationThreshold?: number }).durationThreshold = 0;\n }\n\n try {\n if (PerformanceObserver.supportedEntryTypes.includes(type)) {\n const po = new PerformanceObserver(list => {\n // Delay by a microtask to work around a bug in Safari where the\n // callback is invoked synchronously rather than in a separate task.\n // See: https://github.com/GoogleChrome/web-vitals/issues/277\n void Promise.resolve().then(() => {\n triggerHandlers(type, { entries: list.getEntries() });\n });\n });\n po.observe(options);\n }\n } catch {\n // Unsupported entry type; nothing to observe.\n }\n}\n\nfunction addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n handlers[type].push(handler);\n}\n\n// Get a callback which can be called to remove the instrumentation handler\nfunction getCleanupCallback(\n type: InstrumentHandlerType,\n callback: InstrumentHandlerCallback,\n stopOnCleanup = false,\n): CleanupHandlerCallback {\n return () => {\n // Looked up rather than captured: the observer is started in a microtask, so its stop function\n // does not exist yet when this callback is built.\n if (stopOnCleanup) {\n stopListeners[type]?.();\n }\n\n const typeHandlers = handlers[type];\n\n if (!typeHandlers) {\n return;\n }\n\n const index = typeHandlers.indexOf(callback);\n if (index !== -1) {\n typeHandlers.splice(index, 1);\n }\n };\n}\n\n/**\n * Check if a PerformanceEntry is a PerformanceEventTiming by checking for the `duration` property.\n */\nexport function isPerformanceEventTiming(entry: PerformanceEntry): entry is PerformanceEventTiming {\n return 'duration' in entry;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"performanceObserver.js","sources":["../../../src/instrumentation/performanceObserver.ts"],"sourcesContent":["import { debug, getFunctionName } from '@sentry/core';\nimport { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';\nimport { DEBUG_BUILD } from '../debug-build';\n\ntype InstrumentHandlerTypePerformanceObserver =\n | 'longtask'\n | 'event'\n | 'navigation'\n | 'paint'\n | 'resource'\n | 'element'\n | 'soft-navigation'\n // fist-input is still needed for INP\n | 'first-input';\n\ntype InstrumentHandlerTypeMetric = 'cls' | 'lcp' | 'ttfb' | 'inp' | 'fcp';\n\n// We provide this here manually instead of relying on a global, as this is not available in non-browser environements\n// And we do not want to expose such types\ninterface PerformanceEntry {\n readonly duration: number;\n readonly entryType: string;\n readonly name: string;\n readonly startTime: number;\n toJSON(): Record<string, unknown>;\n}\nexport interface PerformanceEventTiming extends PerformanceEntry {\n processingStart: number;\n processingEnd: number;\n duration: number;\n cancelable?: boolean;\n target?: unknown | null;\n interactionId?: number;\n}\n\n/**\n * A `soft-navigation` entry, minted by the browser once a history change is followed by a\n * confirming paint. `interactionId` is the id of the `PerformanceEventTiming` entry for the\n * interaction that drove the navigation, which is how we join it back to a Sentry navigation span.\n */\nexport interface PerformanceSoftNavigation extends PerformanceEntry {\n readonly interactionId: number;\n readonly navigationId: number;\n}\n\ninterface PerformanceScriptTiming extends PerformanceEntry {\n sourceURL: string;\n sourceFunctionName: string;\n sourceCharPosition: number;\n invoker: string;\n invokerType: string;\n}\nexport interface PerformanceLongAnimationFrameTiming extends PerformanceEntry {\n scripts: PerformanceScriptTiming[];\n}\n\n// Locally-defined to match web-vitals' `Metric` shape without importing it: web-vitals' type\n// entrypoint carries a `declare global` block that references DOM globals not present in every\n// TypeScript lib version (e.g. `NavigationType`), which leaks into and breaks consumers on older\n// TS. Keeping this local keeps web-vitals' global augmentations out of our published types.\n/**\n * The navigation types web-vitals reports a metric for, reported as-is on `browser.navigation.type`.\n */\nexport type MetricNavigationType =\n | 'navigate'\n | 'reload'\n | 'back-forward'\n | 'back-forward-cache'\n | 'prerender'\n | 'restore'\n | 'soft-navigation';\n\ninterface Metric {\n /**\n * The name of the metric (in acronym form).\n */\n name: 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB';\n\n /**\n * The current value of the metric.\n */\n value: number;\n\n /**\n * The rating as to whether the metric value is within the \"good\",\n * \"needs improvement\", or \"poor\" thresholds of the metric.\n */\n rating: 'good' | 'needs-improvement' | 'poor';\n\n /**\n * The delta between the current value and the last-reported value.\n * On the first report, `delta` and `value` will always be the same.\n */\n delta: number;\n\n /**\n * A unique ID representing this particular metric instance. This ID can\n * be used by an analytics tool to dedupe multiple values sent for the same\n * metric instance, or to group multiple deltas together and calculate a\n * total. It can also be used to differentiate multiple different metric\n * instances sent from the same page, which can happen if the page is\n * restored from the back/forward cache (in that case new metrics object\n * get created).\n */\n id: string;\n\n /**\n * Any performance entries relevant to the metric value calculation.\n * The array may also be empty if the metric value was not based on any\n * entries (e.g. a CLS value of 0 given no layout shifts).\n */\n entries: PerformanceEntry[];\n\n /**\n * The type of navigation.\n *\n * Navigation Timing API (or `undefined` if the browser doesn't\n * support that API). For pages that are restored from the bfcache, this\n * value will be 'back-forward-cache'.\n */\n navigationType: MetricNavigationType;\n\n /**\n * The id of the navigation the metric belongs to. For soft navigations this is the\n * `navigationId` of the `soft-navigation` entry, otherwise it's the id of the hard navigation.\n */\n navigationId: number;\n\n /**\n * For soft navigations, the `interactionId` of the interaction that triggered the navigation.\n */\n navigationInteractionId?: number;\n\n /**\n * The start time the metric value is relative to. Non-zero for soft navigations, where the\n * time origin is the triggering interaction rather than the start of the document.\n */\n navigationStartTime?: number;\n\n /**\n * The URL the metric was recorded for. Relevant for soft navigations, where a metric can be\n * reported long after the URL has moved on.\n */\n navigationURL?: string;\n}\n\ntype InstrumentHandlerType = InstrumentHandlerTypeMetric | InstrumentHandlerTypePerformanceObserver;\n\ntype StopListening = undefined | void | (() => void);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InstrumentHandlerCallback = (data: any) => void;\n\ntype CleanupHandlerCallback = () => void;\n\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\nlet _previousCls: Metric | undefined;\nlet _previousLcp: Metric | undefined;\nlet _previousTtfb: Metric | undefined;\nlet _previousInp: Metric | undefined;\nlet _previousFcp: Metric | undefined;\n\nconst stopListeners: Partial<Record<InstrumentHandlerType, StopListening>> = {};\n\nlet _reportSoftNavs = false;\nlet _reportBfcache = false;\n\n/**\n * Opt the CLS, LCP and INP observers into reporting metrics for soft navigations.\n *\n * This also turns `reportAllChanges` off for CLS and LCP. web-vitals force-reports a metric when\n * the navigation it belongs to is over, so without the intermediate updates every value a handler\n * receives is already the final one for its navigation. That only holds because soft navigations\n * are limited to span streaming, where CLS and LCP are sent as their own spans - the static\n * lifecycle instead writes them onto the pageload span as it ends, which is what `reportAllChanges`\n * was originally added for (#11934, #12360).\n *\n * Each observer is instrumented lazily, on its first handler, and web-vitals takes its options at\n * that point only. So this has to be called before any of the `add*InstrumentationHandler`\n * functions, otherwise it won't take effect for observers that are already running.\n *\n * On browsers without the Soft Navigation API this is a no-op: web-vitals feature-detects the API\n * and keeps reporting hard-navigation metrics as usual.\n */\nexport function enableSoftNavigationReporting(): void {\n _reportSoftNavs = true;\n}\n\n/**\n * Opt the CLS, LCP and INP observers into reporting metrics for back/forward-cache restores.\n *\n * web-vitals re-reports each metric after a restore, tagged with a `back-forward-cache` navigation\n * type. A restore is a new page view measured against a document that was never reloaded, so the\n * values only mean anything if there is a fresh root span for them to belong to. Without one they\n * would attach to the span the page had before it was frozen, which is why this is off by default.\n *\n * Like `enableSoftNavigationReporting`, this only affects observers instrumented after it is\n * called.\n */\nexport function enableBfcacheReporting(): void {\n _reportBfcache = true;\n}\n\n/**\n * Add a callback that will be triggered when a CLS metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called.\n * This will lead to the CLS being finalized and frozen.\n */\nexport function addClsInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a LCP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called.\n * This will lead to the LCP being finalized and frozen.\n */\nexport function addLcpInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a TTFD metric is available.\n */\nexport function addTtfbInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('ttfb', callback, instrumentTtfb, _previousTtfb);\n}\n\n/**\n * Add a callback that will be triggered when a FCP metric is available.\n */\nexport function addFcpInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('fcp', callback, instrumentFcp, _previousFcp);\n}\n\nexport type InstrumentationHandlerCallback = (data: {\n metric: Omit<Metric, 'entries'> & {\n entries: PerformanceEventTiming[];\n };\n}) => void;\n\n/**\n * Add a callback that will be triggered when a INP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addInpInstrumentationHandler(callback: InstrumentationHandlerCallback): CleanupHandlerCallback {\n return addMetricObserver('inp', callback, instrumentInp, _previousInp);\n}\n\nexport function addPerformanceInstrumentationHandler(\n type: 'event',\n callback: (data: { entries: ((PerformanceEntry & { target?: unknown | null }) | PerformanceEventTiming)[] }) => void,\n): CleanupHandlerCallback;\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback;\n\n/**\n * Add a callback that will be triggered when a performance observer is triggered,\n * and receives the entries of the observer.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumentPerformanceObserver(type);\n instrumented[type] = true;\n }\n\n return getCleanupCallback(type, callback);\n}\n\n/** Trigger all handlers of a given type. */\nfunction triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = handlers[type];\n\n if (!typeHandlers?.length) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n debug.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n\n/**\n * Wraps a metric callback so that metrics reported after a back/forward-cache restore are dropped\n * unless `enableBfcacheReporting` was called. See there for why they are off by default.\n */\nfunction unlessBfcacheDisabled(callback: (metric: Metric) => void): (metric: Metric) => void {\n return metric => {\n if (!_reportBfcache && metric.navigationType === 'back-forward-cache') {\n return;\n }\n callback(metric);\n };\n}\n\nfunction instrumentCls(): StopListening {\n return onCLS(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('cls', {\n metric,\n });\n _previousCls = metric;\n }),\n // We want the callback to be called whenever the CLS value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: !_reportSoftNavs && !_reportBfcache, reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction instrumentLcp(): StopListening {\n return onLCP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('lcp', {\n metric,\n });\n _previousLcp = metric;\n }),\n // We want the callback to be called whenever the LCP value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: !_reportSoftNavs && !_reportBfcache, reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction instrumentTtfb(): StopListening {\n return onTTFB(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('ttfb', {\n metric,\n });\n _previousTtfb = metric;\n }),\n );\n}\n\nfunction instrumentFcp(): StopListening {\n return onFCP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('fcp', {\n metric,\n });\n _previousFcp = metric;\n }),\n );\n}\n\nfunction instrumentInp(): StopListening {\n return onINP(\n unlessBfcacheDisabled(metric => {\n triggerHandlers('inp', {\n metric,\n });\n _previousInp = metric;\n }),\n { reportSoftNavs: _reportSoftNavs },\n );\n}\n\nfunction addMetricObserver(\n type: InstrumentHandlerTypeMetric,\n callback: InstrumentHandlerCallback,\n instrumentFn: () => StopListening,\n previousValue: Metric | undefined,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumented[type] = true;\n // Deferred by a microtask rather than started here, because web-vitals reads its options once,\n // when the observer is created. Registering a handler would otherwise pin those options for\n // every other consumer of this observer, so whichever integration happened to run first would\n // decide whether soft navigations and bfcache restores are reported. Client setup is\n // synchronous, so every `enable*Reporting()` call has landed by the time this runs, and the\n // observers are buffered so no entries are missed in the meantime.\n void Promise.resolve().then(() => {\n stopListeners[type] = instrumentFn();\n });\n }\n\n if (previousValue) {\n callback({ metric: previousValue });\n }\n\n return getCleanupCallback(type, callback, stopOnCallback);\n}\n\nfunction instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObserver): void {\n const options: PerformanceObserverInit = { type, buffered: true };\n\n // Special per-type options we want to use\n if (type === 'event') {\n (options as PerformanceObserverInit & { durationThreshold?: number }).durationThreshold = 0;\n }\n\n try {\n if (PerformanceObserver.supportedEntryTypes.includes(type)) {\n const po = new PerformanceObserver(list => {\n // Delay by a microtask to work around a bug in Safari where the\n // callback is invoked synchronously rather than in a separate task.\n // See: https://github.com/GoogleChrome/web-vitals/issues/277\n void Promise.resolve().then(() => {\n triggerHandlers(type, { entries: list.getEntries() });\n });\n });\n po.observe(options);\n }\n } catch {\n // Unsupported entry type; nothing to observe.\n }\n}\n\nfunction addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n handlers[type].push(handler);\n}\n\n// Get a callback which can be called to remove the instrumentation handler\nfunction getCleanupCallback(\n type: InstrumentHandlerType,\n callback: InstrumentHandlerCallback,\n stopOnCleanup = false,\n): CleanupHandlerCallback {\n return () => {\n // Looked up rather than captured: the observer is started in a microtask, so its stop function\n // does not exist yet when this callback is built.\n if (stopOnCleanup) {\n stopListeners[type]?.();\n }\n\n const typeHandlers = handlers[type];\n\n if (!typeHandlers) {\n return;\n }\n\n const index = typeHandlers.indexOf(callback);\n if (index !== -1) {\n typeHandlers.splice(index, 1);\n }\n };\n}\n\n/**\n * Check if a PerformanceEntry is a PerformanceEventTiming by checking for the `duration` property.\n */\nexport function isPerformanceEventTiming(entry: PerformanceEntry): entry is PerformanceEventTiming {\n return 'duration' in entry;\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"type":"module","version":"11.0.0-rc.0","sideEffects":false}
1
+ {"type":"module","version":"11.0.0-rc.1","sideEffects":false}
@@ -3,15 +3,6 @@ import { startInactiveSpan } from '@sentry/core/browser';
3
3
  import { USER_AGENT_ORIGINAL, BROWSER_NAVIGATION_ID, BROWSER_NAVIGATION_TYPE, SENTRY_SEGMENT_NAME, SENTRY_TRANSACTION, SENTRY_REPLAY_ID } from '@sentry/conventions/attributes';
4
4
  import { WINDOW } from '../types.js';
5
5
 
6
- const BROWSER_NAVIGATION_TYPES = {
7
- reload: "reload",
8
- prerender: "prerender",
9
- "back-forward-cache": "bfcache",
10
- "soft-navigation": "soft-navigation"
11
- };
12
- function toBrowserNavigationType(navigationType) {
13
- return BROWSER_NAVIGATION_TYPES[navigationType] ?? "navigate";
14
- }
15
6
  function _emitWebVitalSpan(options) {
16
7
  const {
17
8
  name,
@@ -52,7 +43,7 @@ function _emitWebVitalSpan(options) {
52
43
  attributes[BROWSER_NAVIGATION_ID] = softNavigationId;
53
44
  }
54
45
  if (navigationType) {
55
- attributes[BROWSER_NAVIGATION_TYPE] = toBrowserNavigationType(navigationType);
46
+ attributes[BROWSER_NAVIGATION_TYPE] = navigationType;
56
47
  }
57
48
  if (standalone) {
58
49
  Object.assign(attributes, getReplayAttributes());
@@ -1 +1 @@
1
- {"version":3,"file":"emitSpan.js","sources":["../../../src/web-vitals/emitSpan.ts"],"sourcesContent":["import type { Integration, Span, SpanAttributes } from '@sentry/core';\nimport {\n getClient,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport { startInactiveSpan } from '@sentry/core/browser';\nimport {\n BROWSER_NAVIGATION_ID,\n BROWSER_NAVIGATION_TYPE,\n SENTRY_REPLAY_ID,\n SENTRY_SEGMENT_NAME,\n SENTRY_TRANSACTION,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { WINDOW } from '../types';\nimport type { MetricNavigationType } from '../instrumentation/performanceObserver';\nimport type { WebVitalReportEvent } from './reportEvents';\n\n// web-vitals reports a wider set of navigation types than the attribute defines. Only the states\n// Navigation Timing cannot express keep their own value; every ordinary document navigation folds\n// into `navigate`, including a back/forward that missed the bfcache and a discarded-tab restore.\nconst BROWSER_NAVIGATION_TYPES: Partial<Record<MetricNavigationType, string>> = {\n reload: 'reload',\n prerender: 'prerender',\n 'back-forward-cache': 'bfcache',\n 'soft-navigation': 'soft-navigation',\n};\n\nfunction toBrowserNavigationType(navigationType: MetricNavigationType): string {\n return BROWSER_NAVIGATION_TYPES[navigationType] ?? 'navigate';\n}\n\n// Locally-defined interfaces to avoid leaking bare global type references into the\n// generated .d.ts. The `declare global` augmentations in web-vitals/types.ts make these\n// available during this package's compilation but are NOT carried to consumers.\n// This mirrors the pattern used for PerformanceEventTiming in instrument.ts.\nexport interface LayoutShift extends PerformanceEntry {\n value: number;\n sources: Array<{ node: Node | null }>;\n hadRecentInput: boolean;\n}\n\nexport interface LargestContentfulPaint extends PerformanceEntry {\n readonly renderTime: DOMHighResTimeStamp;\n readonly loadTime: DOMHighResTimeStamp;\n readonly size: number;\n readonly id: string;\n readonly url: string;\n readonly element: Element | null;\n}\n\ninterface WebVitalSpanOptions {\n name: string;\n op: string;\n origin: string;\n metricName: 'lcp' | 'cls' | 'inp';\n value: number;\n attributes?: SpanAttributes;\n parentSpan?: Span;\n reportEvent?: WebVitalReportEvent;\n startTime: number;\n endTime?: number;\n /** Set when the vital was reported for a soft navigation rather than the initial page load. */\n softNavigationId?: number;\n /** The navigation the vital was measured on, as reported by web-vitals. */\n navigationType?: MetricNavigationType;\n /**\n * When `true`, the span is sent on its own as a v2 streamed span instead of being folded into a\n * transaction. Used for INP when span streaming is disabled (it reports late, so it can't ride\n * the pageload transaction).\n *\n * TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always streams.\n */\n standalone?: boolean;\n}\n\n/**\n * Emits a web vital span. When `standalone` is set it is sent on its own as a v2 streamed span;\n * otherwise it flows through the span streaming pipeline as a child of `parentSpan`.\n */\nexport function _emitWebVitalSpan(options: WebVitalSpanOptions): void {\n const {\n name,\n op,\n origin,\n metricName,\n value,\n attributes: passedAttributes,\n parentSpan,\n reportEvent,\n startTime,\n endTime,\n standalone,\n softNavigationId,\n navigationType,\n } = options;\n\n // Taken off the segment span itself, so it can't diverge from it: a routing instrumentation may\n // rename that span (a pageload span is named `Pageload` until its route resolves), and the scope's\n // transaction name is deliberately not kept in sync with it. Only a standalone span, which is sent\n // without its segment span, has to fall back to the scope.\n const segmentSpan = parentSpan && getRootSpan(parentSpan);\n const segmentName = segmentSpan ? spanToJSON(segmentSpan).name : getCurrentScope().getScopeData().transactionName;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,\n [`browser.web_vital.${metricName}.value`]: value,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: segmentName,\n [SENTRY_SEGMENT_NAME]: segmentName,\n // Web vital score calculation relies on the user agent\n [USER_AGENT_ORIGINAL]: WINDOW.navigator?.userAgent,\n ...passedAttributes,\n };\n\n if (parentSpan && spanToJSON(parentSpan).attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'pageload') {\n // for LCP and CLS, we collect the pageload span id as an attribute\n attributes['sentry.pageload.span_id'] = parentSpan.spanContext().spanId;\n }\n\n if (reportEvent) {\n attributes[`browser.web_vital.${metricName}.report_event`] = reportEvent;\n }\n\n if (softNavigationId != null) {\n attributes[BROWSER_NAVIGATION_ID] = softNavigationId;\n }\n\n if (navigationType) {\n attributes[BROWSER_NAVIGATION_TYPE] = toBrowserNavigationType(navigationType);\n }\n\n // A standalone span is sent as a plain v2 span without running the `processSpan` hooks (see\n // `captureStandaloneSpanWithStaticCallback`), so Replay can't attach the replay id itself. Set it\n // here, mirroring Replay's `processSpan`, so INP keeps its replay association like it did on v1.\n // TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always\n // streams, at which point Replay's `processSpan` runs and attaches the replay id.\n if (standalone) {\n Object.assign(attributes, getReplayAttributes());\n }\n\n const span = startInactiveSpan({\n name,\n attributes,\n startTime,\n parentSpan,\n // oxlint-disable-next-line typescript/no-deprecated -- intentional during the v1/v2 transition; see the TODO(standalone) above\n experimental: standalone ? { standalone: true } : undefined,\n });\n\n if (span) {\n span.end(endTime ?? startTime);\n }\n}\n\ninterface ReplayIntegration extends Integration {\n getReplayId: (onlyIfSampled?: boolean) => string | undefined;\n getRecordingMode: () => 'session' | 'buffer' | undefined;\n}\n\n// TODO(standalone): remove once the static (transaction) trace lifecycle is dropped; Replay's\n// `processSpan` then attaches the replay id to the streamed INP span instead.\nfunction getReplayAttributes(): SpanAttributes {\n const replay = getClient()?.getIntegrationByName<ReplayIntegration>('Replay');\n const replayId = replay?.getReplayId(true);\n if (!replayId) {\n return {};\n }\n\n return {\n [SENTRY_REPLAY_ID]: replayId,\n // Not the `SENTRY_REPLAY_IS_BUFFERING` convention: that one has no `sentry._internal.` prefix, and\n // the rest of the SDK sets the prefixed key (see `logs/internal.ts`, `metrics/internal.ts`).\n 'sentry._internal.replay_is_buffering': replay!.getRecordingMode() === 'buffer' ? true : undefined,\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"emitSpan.js","sources":["../../../src/web-vitals/emitSpan.ts"],"sourcesContent":["import type { Integration, Span, SpanAttributes } from '@sentry/core';\nimport {\n getClient,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport { startInactiveSpan } from '@sentry/core/browser';\nimport {\n BROWSER_NAVIGATION_ID,\n BROWSER_NAVIGATION_TYPE,\n SENTRY_REPLAY_ID,\n SENTRY_SEGMENT_NAME,\n SENTRY_TRANSACTION,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { WINDOW } from '../types';\nimport type { MetricNavigationType } from '../instrumentation/performanceObserver';\nimport type { WebVitalReportEvent } from './reportEvents';\n\n// Locally-defined interfaces to avoid leaking bare global type references into the\n// generated .d.ts. The `declare global` augmentations in web-vitals/types.ts make these\n// available during this package's compilation but are NOT carried to consumers.\n// This mirrors the pattern used for PerformanceEventTiming in instrument.ts.\nexport interface LayoutShift extends PerformanceEntry {\n value: number;\n sources: Array<{ node: Node | null }>;\n hadRecentInput: boolean;\n}\n\nexport interface LargestContentfulPaint extends PerformanceEntry {\n readonly renderTime: DOMHighResTimeStamp;\n readonly loadTime: DOMHighResTimeStamp;\n readonly size: number;\n readonly id: string;\n readonly url: string;\n readonly element: Element | null;\n}\n\ninterface WebVitalSpanOptions {\n name: string;\n op: string;\n origin: string;\n metricName: 'lcp' | 'cls' | 'inp';\n value: number;\n attributes?: SpanAttributes;\n parentSpan?: Span;\n reportEvent?: WebVitalReportEvent;\n startTime: number;\n endTime?: number;\n /** Set when the vital was reported for a soft navigation rather than the initial page load. */\n softNavigationId?: number;\n /** The navigation the vital was measured on, as reported by web-vitals. */\n navigationType?: MetricNavigationType;\n /**\n * When `true`, the span is sent on its own as a v2 streamed span instead of being folded into a\n * transaction. Used for INP when span streaming is disabled (it reports late, so it can't ride\n * the pageload transaction).\n *\n * TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always streams.\n */\n standalone?: boolean;\n}\n\n/**\n * Emits a web vital span. When `standalone` is set it is sent on its own as a v2 streamed span;\n * otherwise it flows through the span streaming pipeline as a child of `parentSpan`.\n */\nexport function _emitWebVitalSpan(options: WebVitalSpanOptions): void {\n const {\n name,\n op,\n origin,\n metricName,\n value,\n attributes: passedAttributes,\n parentSpan,\n reportEvent,\n startTime,\n endTime,\n standalone,\n softNavigationId,\n navigationType,\n } = options;\n\n // Taken off the segment span itself, so it can't diverge from it: a routing instrumentation may\n // rename that span (a pageload span is named `Pageload` until its route resolves), and the scope's\n // transaction name is deliberately not kept in sync with it. Only a standalone span, which is sent\n // without its segment span, has to fall back to the scope.\n const segmentSpan = parentSpan && getRootSpan(parentSpan);\n const segmentName = segmentSpan ? spanToJSON(segmentSpan).name : getCurrentScope().getScopeData().transactionName;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,\n [`browser.web_vital.${metricName}.value`]: value,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: segmentName,\n [SENTRY_SEGMENT_NAME]: segmentName,\n // Web vital score calculation relies on the user agent\n [USER_AGENT_ORIGINAL]: WINDOW.navigator?.userAgent,\n ...passedAttributes,\n };\n\n if (parentSpan && spanToJSON(parentSpan).attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'pageload') {\n // for LCP and CLS, we collect the pageload span id as an attribute\n attributes['sentry.pageload.span_id'] = parentSpan.spanContext().spanId;\n }\n\n if (reportEvent) {\n attributes[`browser.web_vital.${metricName}.report_event`] = reportEvent;\n }\n\n if (softNavigationId != null) {\n attributes[BROWSER_NAVIGATION_ID] = softNavigationId;\n }\n\n if (navigationType) {\n attributes[BROWSER_NAVIGATION_TYPE] = navigationType;\n }\n\n // A standalone span is sent as a plain v2 span without running the `processSpan` hooks (see\n // `captureStandaloneSpanWithStaticCallback`), so Replay can't attach the replay id itself. Set it\n // here, mirroring Replay's `processSpan`, so INP keeps its replay association like it did on v1.\n // TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always\n // streams, at which point Replay's `processSpan` runs and attaches the replay id.\n if (standalone) {\n Object.assign(attributes, getReplayAttributes());\n }\n\n const span = startInactiveSpan({\n name,\n attributes,\n startTime,\n parentSpan,\n // oxlint-disable-next-line typescript/no-deprecated -- intentional during the v1/v2 transition; see the TODO(standalone) above\n experimental: standalone ? { standalone: true } : undefined,\n });\n\n if (span) {\n span.end(endTime ?? startTime);\n }\n}\n\ninterface ReplayIntegration extends Integration {\n getReplayId: (onlyIfSampled?: boolean) => string | undefined;\n getRecordingMode: () => 'session' | 'buffer' | undefined;\n}\n\n// TODO(standalone): remove once the static (transaction) trace lifecycle is dropped; Replay's\n// `processSpan` then attaches the replay id to the streamed INP span instead.\nfunction getReplayAttributes(): SpanAttributes {\n const replay = getClient()?.getIntegrationByName<ReplayIntegration>('Replay');\n const replayId = replay?.getReplayId(true);\n if (!replayId) {\n return {};\n }\n\n return {\n [SENTRY_REPLAY_ID]: replayId,\n // Not the `SENTRY_REPLAY_IS_BUFFERING` convention: that one has no `sentry._internal.` prefix, and\n // the rest of the SDK sets the prefixed key (see `logs/internal.ts`, `metrics/internal.ts`).\n 'sentry._internal.replay_is_buffering': replay!.getRecordingMode() === 'buffer' ? true : undefined,\n };\n}\n"],"names":[],"mappings":";;;;;AAuEO,SAAS,kBAAkB,OAAA,EAAoC;AACpE,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,EAAA;AAAA,IACA,MAAA;AAAA,IACA,UAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA,EAAY,gBAAA;AAAA,IACZ,UAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,gBAAA;AAAA,IACA;AAAA,GACF,GAAI,OAAA;AAMJ,EAAA,MAAM,WAAA,GAAc,UAAA,IAAc,WAAA,CAAY,UAAU,CAAA;AACxD,EAAA,MAAM,WAAA,GAAc,cAAc,UAAA,CAAW,WAAW,EAAE,IAAA,GAAO,eAAA,EAAgB,CAAE,YAAA,EAAa,CAAE,eAAA;AAElG,EAAA,MAAM,UAAA,GAA6B;AAAA,IACjC,CAAC,gCAAgC,GAAG,MAAA;AAAA,IACpC,CAAC,4BAA4B,GAAG,EAAA;AAAA,IAChC,CAAC,iCAAiC,GAAG,CAAA;AAAA,IACrC,CAAC,CAAA,kBAAA,EAAqB,UAAU,CAAA,MAAA,CAAQ,GAAG,KAAA;AAAA;AAAA,IAE3C,CAAC,kBAAkB,GAAG,WAAA;AAAA,IACtB,CAAC,mBAAmB,GAAG,WAAA;AAAA;AAAA,IAEvB,CAAC,mBAAmB,GAAG,MAAA,CAAO,SAAA,EAAW,SAAA;AAAA,IACzC,GAAG;AAAA,GACL;AAEA,EAAA,IAAI,cAAc,UAAA,CAAW,UAAU,EAAE,UAAA,CAAW,4BAA4B,MAAM,UAAA,EAAY;AAEhG,IAAA,UAAA,CAAW,yBAAyB,CAAA,GAAI,UAAA,CAAW,WAAA,EAAY,CAAE,MAAA;AAAA,EACnE;AAEA,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,UAAA,CAAW,CAAA,kBAAA,EAAqB,UAAU,CAAA,aAAA,CAAe,CAAA,GAAI,WAAA;AAAA,EAC/D;AAEA,EAAA,IAAI,oBAAoB,IAAA,EAAM;AAC5B,IAAA,UAAA,CAAW,qBAAqB,CAAA,GAAI,gBAAA;AAAA,EACtC;AAEA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,UAAA,CAAW,uBAAuB,CAAA,GAAI,cAAA;AAAA,EACxC;AAOA,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,mBAAA,EAAqB,CAAA;AAAA,EACjD;AAEA,EAAA,MAAM,OAAO,iBAAA,CAAkB;AAAA,IAC7B,IAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA;AAAA,IAEA,YAAA,EAAc,UAAA,GAAa,EAAE,UAAA,EAAY,MAAK,GAAI;AAAA,GACnD,CAAA;AAED,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,IAAA,CAAK,GAAA,CAAI,WAAW,SAAS,CAAA;AAAA,EAC/B;AACF;AASA,SAAS,mBAAA,GAAsC;AAC7C,EAAA,MAAM,MAAA,GAAS,SAAA,EAAU,EAAG,oBAAA,CAAwC,QAAQ,CAAA;AAC5E,EAAA,MAAM,QAAA,GAAW,MAAA,EAAQ,WAAA,CAAY,IAAI,CAAA;AACzC,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,OAAO;AAAA,IACL,CAAC,gBAAgB,GAAG,QAAA;AAAA;AAAA;AAAA,IAGpB,sCAAA,EAAwC,MAAA,CAAQ,gBAAA,EAAiB,KAAM,WAAW,IAAA,GAAO;AAAA,GAC3F;AACF;;;;"}
@@ -25,7 +25,7 @@ function trackWebVitalPerNavigation(client, addInstrumentationHandler, send) {
25
25
  let bfcacheNavigationSpan;
26
26
  client.on("spanStart", (span) => {
27
27
  const attributes = spanToJSON(span).attributes;
28
- if (attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION && attributes[BROWSER_NAVIGATION_TYPE] === "bfcache") {
28
+ if (attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION && attributes[BROWSER_NAVIGATION_TYPE] === "back-forward-cache") {
29
29
  bfcacheNavigationSpan = span;
30
30
  }
31
31
  });
@@ -1 +1 @@
1
- {"version":3,"file":"spans.js","sources":["../../../src/web-vitals/spans.ts"],"sourcesContent":["import type { Client, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n timestampInSeconds,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport type { InteractionType } from './inp';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION } from './inp';\nimport type { InstrumentationHandlerCallback, MetricNavigationType } from '../instrumentation/performanceObserver';\nimport {\n addClsInstrumentationHandler,\n addInpInstrumentationHandler,\n addLcpInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport type { LargestContentfulPaint, LayoutShift } from './emitSpan';\nimport { BROWSER_NAVIGATION_TYPE } from '@sentry/conventions/attributes';\nimport { _emitWebVitalSpan } from './emitSpan';\nimport { isValidLcpMetric } from './lcp';\nimport type { WebVitalReportEvent } from './reportEvents';\nimport { listenForWebVitalReportEvents } from './reportEvents';\nimport { getNavigationSpanForMetric } from './softNavs';\nimport { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';\nimport type { PerformanceEventTiming } from '../instrumentation/performanceObserver';\nimport {\n NAVIGATION,\n UI_INTERACTION_CLICK,\n UI_INTERACTION_DRAG,\n UI_INTERACTION_HOVER,\n UI_INTERACTION_PRESS,\n UI_WEBVITAL_CLS,\n UI_WEBVITAL_LCP,\n} from '@sentry/conventions/op';\n\nconst INTERACTION_TYPE_TO_SPAN_OP: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK,\n hover: UI_INTERACTION_HOVER,\n drag: UI_INTERACTION_DRAG,\n press: UI_INTERACTION_PRESS,\n};\n\ntype WebVitalMetric = Parameters<Parameters<typeof addLcpInstrumentationHandler>[0]>[0]['metric'];\ntype InpMetric = Parameters<InstrumentationHandlerCallback>[0]['metric'];\n\n/**\n * Reports a web vital once per navigation, rather than once per page load.\n *\n * web-vitals restarts the metric on every soft navigation and force-reports the previous one just\n * before it does (and again on pagehide), and re-reports every metric after a bfcache restore.\n * Since `reportAllChanges` is off in this mode, every value we're handed is already the final one\n * for its navigation, so there is nothing to accumulate: each report is a span.\n */\nfunction trackWebVitalPerNavigation<M extends WebVitalMetric>(\n client: Client,\n addInstrumentationHandler: (callback: (data: { metric: M }) => void) => unknown,\n send: (metric: M, parentSpan: Span | undefined, softNavigationId: number | undefined) => void,\n): void {\n let pageloadSpan: Span | undefined;\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n });\n\n // Remembered when the restore happens rather than read back at report time: the restore\n // navigation span is an idle span, and CLS and INP are only finalized on pagehide, by which point\n // it has long ended and is no longer what is active.\n let bfcacheNavigationSpan: Span | undefined;\n client.on('spanStart', span => {\n // The op has to be checked too: the web vital spans emitted for a restore carry the same\n // `bfcache` navigation type, so matching on that alone lets the first of them replace the\n // navigation span, and every later vital then hangs off a sibling vital instead.\n const attributes = spanToJSON(span).attributes;\n if (\n attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION &&\n attributes[BROWSER_NAVIGATION_TYPE] === 'bfcache'\n ) {\n bfcacheNavigationSpan = span;\n }\n });\n\n addInstrumentationHandler(({ metric }) => {\n const navigationSpan = getNavigationSpanForMetric(metric);\n if (metric.navigationType === 'soft-navigation') {\n // Reporting an uncorrelated soft navigation vital would attribute it to the wrong route, so\n // it's dropped instead.\n if (navigationSpan) {\n send(metric, navigationSpan, metric.navigationId);\n } else {\n DEBUG_BUILD &&\n debug.log(`[SoftNav] Dropping ${metric.name} for uncorrelated soft navigation ${metric.navigationId}`);\n }\n return;\n }\n\n if (metric.navigationType === 'back-forward-cache') {\n // A restore reuses the frozen document, so the pageload span above belongs to the page view\n // from before the freeze. The navigation span started for the restore is the page view these\n // values were actually measured on.\n send(metric, bfcacheNavigationSpan, undefined);\n return;\n }\n\n send(metric, pageloadSpan, undefined);\n });\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addLcpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n _sendLcpSpan(\n metric.value,\n entry,\n parentSpan,\n undefined,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n let lcpNavigationType: MetricNavigationType | undefined;\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n // The navigation type describes the page, not the entry, so it is worth keeping even for a\n // report we otherwise discard.\n lcpNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n lcpValue = metric.value;\n lcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, reportEvent, undefined, lcpNavigationType);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin() || 0;\n // A soft navigation's LCP is measured from the triggering interaction, not the document time\n // origin. Starting the span there too keeps it inside the navigation span it is parented to and\n // keeps its duration equal to the value it reports.\n const startTime = msToSec(performanceTimeOrigin + (navigationStartTime || 0));\n // Without an entry there is no render time to end at, so the span lasts the value it reports,\n // like an entry-less INP does. Ending at the time origin instead would invert the span.\n const endTime = entry ? msToSec(performanceTimeOrigin + entry.startTime) : startTime + msToSec(lcpValue);\n const name = entry ? htmlTreeAsString(entry.element) : 'Largest contentful paint';\n\n const attributes: SpanAttributes = {};\n\n entry?.element && (attributes['browser.web_vital.lcp.element'] = htmlTreeAsString(entry.element));\n entry?.id && (attributes['browser.web_vital.lcp.id'] = entry.id);\n entry?.url && (attributes['browser.web_vital.lcp.url'] = entry.url);\n entry?.loadTime != null && (attributes['browser.web_vital.lcp.load_time'] = entry.loadTime);\n entry?.renderTime != null && (attributes['browser.web_vital.lcp.render_time'] = entry.renderTime);\n entry?.size != null && (attributes['browser.web_vital.lcp.size'] = entry.size);\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_LCP,\n origin: 'auto.http.browser.lcp',\n metricName: 'lcp',\n value: lcpValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime,\n endTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addClsInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n _sendClsSpan(\n metric.value,\n entry,\n parentSpan,\n undefined,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n let clsNavigationType: MetricNavigationType | undefined;\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n // A CLS of 0 is reported with no entries and still emits a span, so the navigation type has to\n // be captured before the entry check rather than alongside the value.\n clsNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n clsValue = metric.value;\n clsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, reportEvent, undefined, clsNavigationType);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin();\n // A CLS of 0 has no shift to place the span at. It is reported when the navigation it was\n // measured on is already over - the next soft navigation, or pagehide - so the current time would\n // land it outside that navigation, on the route that follows it.\n const offset = entry?.startTime ?? navigationStartTime ?? 0;\n const startTime = performanceTimeOrigin ? msToSec(performanceTimeOrigin + offset) : timestampInSeconds();\n const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';\n\n const attributes: SpanAttributes = {};\n\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`browser.web_vital.cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_CLS,\n origin: 'auto.http.browser.cls',\n metricName: 'cls',\n value: clsValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks INP and emits it as a web vital span, as a child of the interaction's root span.\n * Requires `registerInpInteractionListener()` to be called separately for cached element names and\n * root spans per interaction.\n */\nexport function trackInpAsSpan(client: Client, perNavigation = false): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n // INP reports late (on pagehide, after the pageload span has ended). With span streaming enabled\n // it rides the streaming pipeline. With streaming disabled it would be dropped as a late span, so\n // it is emitted as its own standalone v2 span instead (see `_emitWebVitalSpan`), overriding the\n // static trace lifecycle for INP only.\n // TODO(standalone): once the static trace lifecycle is dropped, INP always streams; drop this flag.\n const standalone = !hasSpanStreamingEnabled(client);\n\n if (perNavigation) {\n // INP restarts per navigation and reports once that navigation is over, by which point the\n // navigation span has ended and the interaction cache no longer knows about it. The metric\n // says which navigation it belongs to, so INP is attributed exactly like LCP and CLS.\n trackWebVitalPerNavigation(client, addInpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, parentSpan, softNavigationId, metric);\n }\n });\n return;\n }\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, undefined, undefined, metric);\n }\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\nfunction isPlausibleInp(metric: InpMetric): boolean {\n return metric.value != null && msToSec(metric.value) <= MAX_PLAUSIBLE_INP_DURATION;\n}\n\n/**\n * The entry an INP span is built from: the one whose duration the reported value came from.\n *\n * There isn't always one. When every interaction of a soft navigation stayed below the Event Timing\n * threshold, web-vitals reports a synthetic value with no entries at all - see\n * `_estimateP98LongestInteraction`. The span still gets reported in that case, just without the\n * element and interaction type an entry would have supplied.\n */\nfunction findInpEntry(metric: InpMetric): PerformanceEventTiming | undefined {\n return metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(\n inpValue: number,\n entry: PerformanceEventTiming | undefined,\n standalone = false,\n attributedSpan?: Span,\n softNavigationId?: number,\n metric?: InpMetric,\n): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n // A web vital span carries the metric, not a real interaction timing, so an INP without an entry\n // is still worth reporting. It just has no element or interaction type to describe, and is placed\n // at the start of the navigation it belongs to rather than at the interaction.\n const startTime = msToSec(\n (browserPerformanceTimeOrigin() as number) + (entry?.startTime ?? metric?.navigationStartTime ?? 0),\n );\n const duration = msToSec(inpValue);\n // An INP without an entry has no interaction type to report. It still has to land inside the\n // `ui.interaction.*` family, because falling outside it would hide exactly the fast navigations\n // that web-vitals synthesizes these values for (GoogleChrome/web-vitals#724), reintroducing the\n // reporting bias they were added to remove.\n const interactionType = (entry && INP_ENTRY_MAP[entry.name]) || 'click';\n\n const cachedContext = entry && getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // With soft navigations the caller knows exactly which navigation the metric belongs to. Without\n // them we fall back to the span that was active when the interaction was observed.\n const spanToUse = attributedSpan || cachedContext?.span || rootSpan;\n const name = cachedContext?.elementName || (entry ? htmlTreeAsString(entry.target) : 'Interaction to next paint');\n\n _emitWebVitalSpan({\n name,\n op: INTERACTION_TYPE_TO_SPAN_OP[interactionType],\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes: {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue,\n },\n startTime,\n endTime: startTime + duration,\n navigationType: metric?.navigationType,\n parentSpan: spanToUse,\n standalone,\n softNavigationId,\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spans.js","sources":["../../../src/web-vitals/spans.ts"],"sourcesContent":["import type { Client, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n timestampInSeconds,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport type { InteractionType } from './inp';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION } from './inp';\nimport type { InstrumentationHandlerCallback, MetricNavigationType } from '../instrumentation/performanceObserver';\nimport {\n addClsInstrumentationHandler,\n addInpInstrumentationHandler,\n addLcpInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport type { LargestContentfulPaint, LayoutShift } from './emitSpan';\nimport { BROWSER_NAVIGATION_TYPE } from '@sentry/conventions/attributes';\nimport { _emitWebVitalSpan } from './emitSpan';\nimport { isValidLcpMetric } from './lcp';\nimport type { WebVitalReportEvent } from './reportEvents';\nimport { listenForWebVitalReportEvents } from './reportEvents';\nimport { getNavigationSpanForMetric } from './softNavs';\nimport { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';\nimport type { PerformanceEventTiming } from '../instrumentation/performanceObserver';\nimport {\n NAVIGATION,\n UI_INTERACTION_CLICK,\n UI_INTERACTION_DRAG,\n UI_INTERACTION_HOVER,\n UI_INTERACTION_PRESS,\n UI_WEBVITAL_CLS,\n UI_WEBVITAL_LCP,\n} from '@sentry/conventions/op';\n\nconst INTERACTION_TYPE_TO_SPAN_OP: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK,\n hover: UI_INTERACTION_HOVER,\n drag: UI_INTERACTION_DRAG,\n press: UI_INTERACTION_PRESS,\n};\n\ntype WebVitalMetric = Parameters<Parameters<typeof addLcpInstrumentationHandler>[0]>[0]['metric'];\ntype InpMetric = Parameters<InstrumentationHandlerCallback>[0]['metric'];\n\n/**\n * Reports a web vital once per navigation, rather than once per page load.\n *\n * web-vitals restarts the metric on every soft navigation and force-reports the previous one just\n * before it does (and again on pagehide), and re-reports every metric after a bfcache restore.\n * Since `reportAllChanges` is off in this mode, every value we're handed is already the final one\n * for its navigation, so there is nothing to accumulate: each report is a span.\n */\nfunction trackWebVitalPerNavigation<M extends WebVitalMetric>(\n client: Client,\n addInstrumentationHandler: (callback: (data: { metric: M }) => void) => unknown,\n send: (metric: M, parentSpan: Span | undefined, softNavigationId: number | undefined) => void,\n): void {\n let pageloadSpan: Span | undefined;\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n });\n\n // Remembered when the restore happens rather than read back at report time: the restore\n // navigation span is an idle span, and CLS and INP are only finalized on pagehide, by which point\n // it has long ended and is no longer what is active.\n let bfcacheNavigationSpan: Span | undefined;\n client.on('spanStart', span => {\n // The op has to be checked too: the web vital spans emitted for a restore carry the same\n // `back-forward-cache` navigation type, so matching on that alone lets the first of them replace the\n // navigation span, and every later vital then hangs off a sibling vital instead.\n const attributes = spanToJSON(span).attributes;\n if (\n attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION &&\n attributes[BROWSER_NAVIGATION_TYPE] === 'back-forward-cache'\n ) {\n bfcacheNavigationSpan = span;\n }\n });\n\n addInstrumentationHandler(({ metric }) => {\n const navigationSpan = getNavigationSpanForMetric(metric);\n if (metric.navigationType === 'soft-navigation') {\n // Reporting an uncorrelated soft navigation vital would attribute it to the wrong route, so\n // it's dropped instead.\n if (navigationSpan) {\n send(metric, navigationSpan, metric.navigationId);\n } else {\n DEBUG_BUILD &&\n debug.log(`[SoftNav] Dropping ${metric.name} for uncorrelated soft navigation ${metric.navigationId}`);\n }\n return;\n }\n\n if (metric.navigationType === 'back-forward-cache') {\n // A restore reuses the frozen document, so the pageload span above belongs to the page view\n // from before the freeze. The navigation span started for the restore is the page view these\n // values were actually measured on.\n send(metric, bfcacheNavigationSpan, undefined);\n return;\n }\n\n send(metric, pageloadSpan, undefined);\n });\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addLcpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n _sendLcpSpan(\n metric.value,\n entry,\n parentSpan,\n undefined,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n let lcpNavigationType: MetricNavigationType | undefined;\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n // The navigation type describes the page, not the entry, so it is worth keeping even for a\n // report we otherwise discard.\n lcpNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n lcpValue = metric.value;\n lcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, reportEvent, undefined, lcpNavigationType);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin() || 0;\n // A soft navigation's LCP is measured from the triggering interaction, not the document time\n // origin. Starting the span there too keeps it inside the navigation span it is parented to and\n // keeps its duration equal to the value it reports.\n const startTime = msToSec(performanceTimeOrigin + (navigationStartTime || 0));\n // Without an entry there is no render time to end at, so the span lasts the value it reports,\n // like an entry-less INP does. Ending at the time origin instead would invert the span.\n const endTime = entry ? msToSec(performanceTimeOrigin + entry.startTime) : startTime + msToSec(lcpValue);\n const name = entry ? htmlTreeAsString(entry.element) : 'Largest contentful paint';\n\n const attributes: SpanAttributes = {};\n\n entry?.element && (attributes['browser.web_vital.lcp.element'] = htmlTreeAsString(entry.element));\n entry?.id && (attributes['browser.web_vital.lcp.id'] = entry.id);\n entry?.url && (attributes['browser.web_vital.lcp.url'] = entry.url);\n entry?.loadTime != null && (attributes['browser.web_vital.lcp.load_time'] = entry.loadTime);\n entry?.renderTime != null && (attributes['browser.web_vital.lcp.render_time'] = entry.renderTime);\n entry?.size != null && (attributes['browser.web_vital.lcp.size'] = entry.size);\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_LCP,\n origin: 'auto.http.browser.lcp',\n metricName: 'lcp',\n value: lcpValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime,\n endTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addClsInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n _sendClsSpan(\n metric.value,\n entry,\n parentSpan,\n undefined,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n let clsNavigationType: MetricNavigationType | undefined;\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n // A CLS of 0 is reported with no entries and still emits a span, so the navigation type has to\n // be captured before the entry check rather than alongside the value.\n clsNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n clsValue = metric.value;\n clsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, reportEvent, undefined, clsNavigationType);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpan?: Span,\n reportEvent?: WebVitalReportEvent,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin();\n // A CLS of 0 has no shift to place the span at. It is reported when the navigation it was\n // measured on is already over - the next soft navigation, or pagehide - so the current time would\n // land it outside that navigation, on the route that follows it.\n const offset = entry?.startTime ?? navigationStartTime ?? 0;\n const startTime = performanceTimeOrigin ? msToSec(performanceTimeOrigin + offset) : timestampInSeconds();\n const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';\n\n const attributes: SpanAttributes = {};\n\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`browser.web_vital.cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_CLS,\n origin: 'auto.http.browser.cls',\n metricName: 'cls',\n value: clsValue,\n attributes,\n parentSpan: pageloadSpan,\n reportEvent,\n startTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks INP and emits it as a web vital span, as a child of the interaction's root span.\n * Requires `registerInpInteractionListener()` to be called separately for cached element names and\n * root spans per interaction.\n */\nexport function trackInpAsSpan(client: Client, perNavigation = false): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n // INP reports late (on pagehide, after the pageload span has ended). With span streaming enabled\n // it rides the streaming pipeline. With streaming disabled it would be dropped as a late span, so\n // it is emitted as its own standalone v2 span instead (see `_emitWebVitalSpan`), overriding the\n // static trace lifecycle for INP only.\n // TODO(standalone): once the static trace lifecycle is dropped, INP always streams; drop this flag.\n const standalone = !hasSpanStreamingEnabled(client);\n\n if (perNavigation) {\n // INP restarts per navigation and reports once that navigation is over, by which point the\n // navigation span has ended and the interaction cache no longer knows about it. The metric\n // says which navigation it belongs to, so INP is attributed exactly like LCP and CLS.\n trackWebVitalPerNavigation(client, addInpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, parentSpan, softNavigationId, metric);\n }\n });\n return;\n }\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, undefined, undefined, metric);\n }\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\nfunction isPlausibleInp(metric: InpMetric): boolean {\n return metric.value != null && msToSec(metric.value) <= MAX_PLAUSIBLE_INP_DURATION;\n}\n\n/**\n * The entry an INP span is built from: the one whose duration the reported value came from.\n *\n * There isn't always one. When every interaction of a soft navigation stayed below the Event Timing\n * threshold, web-vitals reports a synthetic value with no entries at all - see\n * `_estimateP98LongestInteraction`. The span still gets reported in that case, just without the\n * element and interaction type an entry would have supplied.\n */\nfunction findInpEntry(metric: InpMetric): PerformanceEventTiming | undefined {\n return metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(\n inpValue: number,\n entry: PerformanceEventTiming | undefined,\n standalone = false,\n attributedSpan?: Span,\n softNavigationId?: number,\n metric?: InpMetric,\n): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n // A web vital span carries the metric, not a real interaction timing, so an INP without an entry\n // is still worth reporting. It just has no element or interaction type to describe, and is placed\n // at the start of the navigation it belongs to rather than at the interaction.\n const startTime = msToSec(\n (browserPerformanceTimeOrigin() as number) + (entry?.startTime ?? metric?.navigationStartTime ?? 0),\n );\n const duration = msToSec(inpValue);\n // An INP without an entry has no interaction type to report. It still has to land inside the\n // `ui.interaction.*` family, because falling outside it would hide exactly the fast navigations\n // that web-vitals synthesizes these values for (GoogleChrome/web-vitals#724), reintroducing the\n // reporting bias they were added to remove.\n const interactionType = (entry && INP_ENTRY_MAP[entry.name]) || 'click';\n\n const cachedContext = entry && getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // With soft navigations the caller knows exactly which navigation the metric belongs to. Without\n // them we fall back to the span that was active when the interaction was observed.\n const spanToUse = attributedSpan || cachedContext?.span || rootSpan;\n const name = cachedContext?.elementName || (entry ? htmlTreeAsString(entry.target) : 'Interaction to next paint');\n\n _emitWebVitalSpan({\n name,\n op: INTERACTION_TYPE_TO_SPAN_OP[interactionType],\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes: {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue,\n },\n startTime,\n endTime: startTime + duration,\n navigationType: metric?.navigationType,\n parentSpan: spanToUse,\n standalone,\n softNavigationId,\n });\n}\n"],"names":[],"mappings":"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"}
@@ -34,8 +34,7 @@ export interface PerformanceLongAnimationFrameTiming extends PerformanceEntry {
34
34
  scripts: PerformanceScriptTiming[];
35
35
  }
36
36
  /**
37
- * The navigation types web-vitals reports a metric for. Wider than the set the
38
- * `browser.navigation.type` attribute uses - see `toBrowserNavigationType`.
37
+ * The navigation types web-vitals reports a metric for, reported as-is on `browser.navigation.type`.
39
38
  */
40
39
  export type MetricNavigationType = 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'restore' | 'soft-navigation';
41
40
  interface Metric {
@@ -1 +1 @@
1
- {"version":3,"file":"performanceObserver.d.ts","sourceRoot":"","sources":["../../../src/instrumentation/performanceObserver.ts"],"names":[],"mappings":"AAIA,KAAK,wCAAwC,GACzC,UAAU,GACV,OAAO,GACP,YAAY,GACZ,OAAO,GACP,UAAU,GACV,SAAS,GACT,iBAAiB,GAEjB,aAAa,CAAC;AAMlB,UAAU,gBAAgB;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AACD,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IACjE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,UAAU,uBAAwB,SAAQ,gBAAgB;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,mCAAoC,SAAQ,gBAAgB;IAC3E,OAAO,EAAE,uBAAuB,EAAE,CAAC;CACpC;AAMD;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAC5B,UAAU,GACV,QAAQ,GACR,cAAc,GACd,oBAAoB,GACpB,WAAW,GACX,SAAS,GACT,iBAAiB,CAAC;AAEtB,UAAU,MAAM;IACd;;OAEG;IACH,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAE7C;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,mBAAmB,GAAG,MAAM,CAAC;IAE9C;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;;;;OAQG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;OAIG;IACH,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAE5B;;;;;;OAMG;IACH,cAAc,EAAE,oBAAoB,CAAC;IAErC;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AASD,KAAK,sBAAsB,GAAG,MAAM,IAAI,CAAC;AAgBzC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,EAC5C,cAAc,UAAQ,GACrB,sBAAsB,CAExB;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,EAC5C,cAAc,UAAQ,GACrB,sBAAsB,CAExB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,GAAG,sBAAsB,CAElH;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,GAAG,sBAAsB,CAEjH;AAED,MAAM,MAAM,8BAA8B,GAAG,CAAC,IAAI,EAAE;IAClD,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG;QAChC,OAAO,EAAE,sBAAsB,EAAE,CAAC;KACnC,CAAC;CACH,KAAK,IAAI,CAAC;AAEX;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,8BAA8B,GAAG,sBAAsB,CAE7G;AAED,wBAAgB,oCAAoC,CAClD,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,CAAC,CAAC,gBAAgB,GAAG;QAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE,CAAC,GAAG,sBAAsB,CAAC,EAAE,CAAA;CAAE,KAAK,IAAI,GACnH,sBAAsB,CAAC;AAC1B,wBAAgB,oCAAoC,CAClD,IAAI,EAAE,wCAAwC,EAC9C,QAAQ,EAAE,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,gBAAgB,EAAE,CAAA;CAAE,KAAK,IAAI,GACxD,sBAAsB,CAAC;AA0M1B;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,GAAG,KAAK,IAAI,sBAAsB,CAEjG"}
1
+ {"version":3,"file":"performanceObserver.d.ts","sourceRoot":"","sources":["../../../src/instrumentation/performanceObserver.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"emitSpan.d.ts","sourceRoot":"","sources":["../../../src/web-vitals/emitSpan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,IAAI,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAoBtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAoB1D,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IACtC,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAClC;AAED,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CA2EpE"}
1
+ {"version":3,"file":"emitSpan.d.ts","sourceRoot":"","sources":["../../../src/web-vitals/emitSpan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,IAAI,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAoBtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAM1D,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IACtC,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAClC;AAED,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CA2EpE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/browser-utils",
3
- "version": "11.0.0-rc.0",
3
+ "version": "11.0.0-rc.1",
4
4
  "description": "Browser Utilities for all Sentry JavaScript SDKs",
5
5
  "repository": "git://github.com/getsentry/sentry-javascript.git",
6
6
  "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/browser-utils",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@sentry/core": "11.0.0-rc.0",
36
+ "@sentry/core": "11.0.0-rc.1",
37
37
  "@sentry/conventions": "^0.23.0",
38
38
  "web-vitals": "^6.1.1"
39
39
  },