{"version":3,"file":"static/js/main-221ea48c-9bf22c27e23a8b7e1b53.js","mappings":"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","sources":["webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/debug-build.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/getNativeImplementation.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/instrument/dom.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/instrument/xhr.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/cls.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/browserMetrics.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/inp.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/bindReporter.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/initMetric.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/generateUniqueID.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/observe.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/runOnce.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/whenActivated.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/onFCP.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/getCLS.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/getFID.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/interactions.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/whenIdle.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/getINP.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/getLCP.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/onTTFB.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/instrument.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/getActivationStart.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/getNavigationEntry.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/getVisibilityWatcher.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/metrics/web-vitals/lib/onHidden.ts","webpack://leadsbridge/./node_modules/@sentry-internal/browser-utils/src/types.ts"],"sourcesContent":["declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n","import { isNativeFunction, logger } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport { WINDOW } from './types';\n\n/**\n * We generally want to use window.fetch / window.setTimeout.\n * However, in some cases this may be wrapped (e.g. by Zone.js for Angular),\n * so we try to get an unpatched version of this from a sandboxed iframe.\n */\n\ninterface CacheableImplementations {\n setTimeout: typeof WINDOW.setTimeout;\n fetch: typeof WINDOW.fetch;\n}\n\nconst cachedImplementations: Partial = {};\n\n/**\n * Get the native implementation of a browser function.\n *\n * This can be used to ensure we get an unwrapped version of a function, in cases where a wrapped function can lead to problems.\n *\n * The following methods can be retrieved:\n * - `setTimeout`: This can be wrapped by e.g. Angular, causing change detection to be triggered.\n * - `fetch`: This can be wrapped by e.g. ad-blockers, causing an infinite loop when a request is blocked.\n */\nexport function getNativeImplementation(\n name: T,\n): CacheableImplementations[T] {\n const cached = cachedImplementations[name];\n if (cached) {\n return cached;\n }\n\n let impl = WINDOW[name] as CacheableImplementations[T];\n\n // Fast path to avoid DOM I/O\n if (isNativeFunction(impl)) {\n return (cachedImplementations[name] = impl.bind(WINDOW) as CacheableImplementations[T]);\n }\n\n const document = WINDOW.document;\n // eslint-disable-next-line deprecation/deprecation\n if (document && typeof document.createElement === 'function') {\n try {\n const sandbox = document.createElement('iframe');\n sandbox.hidden = true;\n document.head.appendChild(sandbox);\n const contentWindow = sandbox.contentWindow;\n if (contentWindow && contentWindow[name]) {\n impl = contentWindow[name] as CacheableImplementations[T];\n }\n document.head.removeChild(sandbox);\n } catch (e) {\n // Could not create sandbox iframe, just use window.xxx\n DEBUG_BUILD && logger.warn(`Could not create sandbox iframe for ${name} check, bailing to window.${name}: `, e);\n }\n }\n\n // Sanity check: This _should_ not happen, but if it does, we just skip caching...\n // This can happen e.g. in tests where fetch may not be available in the env, or similar.\n if (!impl) {\n return impl;\n }\n\n return (cachedImplementations[name] = impl.bind(WINDOW) as CacheableImplementations[T]);\n}\n\n/** Clear a cached implementation. */\nexport function clearCachedImplementation(name: keyof CacheableImplementations): void {\n cachedImplementations[name] = undefined;\n}\n\n/**\n * A special usecase for incorrectly wrapped Fetch APIs in conjunction with ad-blockers.\n * Whenever someone wraps the Fetch API and returns the wrong promise chain,\n * this chain becomes orphaned and there is no possible way to capture it's rejections\n * other than allowing it bubble up to this very handler. eg.\n *\n * const f = window.fetch;\n * window.fetch = function () {\n * const p = f.apply(this, arguments);\n *\n * p.then(function() {\n * console.log('hi.');\n * });\n *\n * return p;\n * }\n *\n * `p.then(function () { ... })` is producing a completely separate promise chain,\n * however, what's returned is `p` - the result of original `fetch` call.\n *\n * This mean, that whenever we use the Fetch API to send our own requests, _and_\n * some ad-blocker blocks it, this orphaned chain will _always_ reject,\n * effectively causing another event to be captured.\n * This makes a whole process become an infinite loop, which we need to somehow\n * deal with, and break it in one way or another.\n *\n * To deal with this issue, we are making sure that we _always_ use the real\n * browser Fetch API, instead of relying on what `window.fetch` exposes.\n * The only downside to this would be missing our own requests as breadcrumbs,\n * but because we are already not doing this, it should be just fine.\n *\n * Possible failed fetch error messages per-browser:\n *\n * Chrome: Failed to fetch\n * Edge: Failed to Fetch\n * Firefox: NetworkError when attempting to fetch resource\n * Safari: resource blocked by content blocker\n */\nexport function fetch(...rest: Parameters): ReturnType {\n return getNativeImplementation('fetch')(...rest);\n}\n\n/**\n * Get an unwrapped `setTimeout` method.\n * This ensures that even if e.g. Angular wraps `setTimeout`, we get the native implementation,\n * avoiding triggering change detection.\n */\nexport function setTimeout(...rest: Parameters): ReturnType {\n return getNativeImplementation('setTimeout')(...rest);\n}\n","import type { HandlerDataDom } from '@sentry/core';\nimport { addHandler, addNonEnumerableProperty, fill, maybeInstrument, triggerHandlers, uuid4 } from '@sentry/core';\nimport { WINDOW } from '../types';\n\ntype SentryWrappedTarget = HTMLElement & { _sentryId?: string };\n\ntype AddEventListener = (\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n) => void;\ntype RemoveEventListener = (\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n) => void;\n\ntype InstrumentedElement = Element & {\n __sentry_instrumentation_handlers__?: {\n [key in 'click' | 'keypress']?: {\n handler?: unknown;\n /** The number of custom listeners attached to this element */\n refCount: number;\n };\n };\n};\n\nconst DEBOUNCE_DURATION = 1000;\n\nlet debounceTimerID: number | undefined;\nlet lastCapturedEventType: string | undefined;\nlet lastCapturedEventTargetId: string | undefined;\n\n/**\n * Add an instrumentation handler for when a click or a keypress happens.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addClickKeypressInstrumentationHandler(handler: (data: HandlerDataDom) => void): void {\n const type = 'dom';\n addHandler(type, handler);\n maybeInstrument(type, instrumentDOM);\n}\n\n/** Exported for tests only. */\nexport function instrumentDOM(): void {\n if (!WINDOW.document) {\n return;\n }\n\n // Make it so that any click or keypress that is unhandled / bubbled up all the way to the document triggers our dom\n // handlers. (Normally we have only one, which captures a breadcrumb for each click or keypress.) Do this before\n // we instrument `addEventListener` so that we don't end up attaching this handler twice.\n const triggerDOMHandler = triggerHandlers.bind(null, 'dom');\n const globalDOMEventHandler = makeDOMEventHandler(triggerDOMHandler, true);\n WINDOW.document.addEventListener('click', globalDOMEventHandler, false);\n WINDOW.document.addEventListener('keypress', globalDOMEventHandler, false);\n\n // After hooking into click and keypress events bubbled up to `document`, we also hook into user-handled\n // clicks & keypresses, by adding an event listener of our own to any element to which they add a listener. That\n // way, whenever one of their handlers is triggered, ours will be, too. (This is needed because their handler\n // could potentially prevent the event from bubbling up to our global listeners. This way, our handler are still\n // guaranteed to fire at least once.)\n ['EventTarget', 'Node'].forEach((target: string) => {\n const globalObject = WINDOW as unknown as Record;\n const targetObj = globalObject[target];\n const proto = targetObj && targetObj.prototype;\n\n // eslint-disable-next-line no-prototype-builtins\n if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {\n return;\n }\n\n fill(proto, 'addEventListener', function (originalAddEventListener: AddEventListener): AddEventListener {\n return function (this: InstrumentedElement, type, listener, options): AddEventListener {\n if (type === 'click' || type == 'keypress') {\n try {\n const handlers = (this.__sentry_instrumentation_handlers__ =\n this.__sentry_instrumentation_handlers__ || {});\n const handlerForType = (handlers[type] = handlers[type] || { refCount: 0 });\n\n if (!handlerForType.handler) {\n const handler = makeDOMEventHandler(triggerDOMHandler);\n handlerForType.handler = handler;\n originalAddEventListener.call(this, type, handler, options);\n }\n\n handlerForType.refCount++;\n } catch (e) {\n // Accessing dom properties is always fragile.\n // Also allows us to skip `addEventListeners` calls with no proper `this` context.\n }\n }\n\n return originalAddEventListener.call(this, type, listener, options);\n };\n });\n\n fill(\n proto,\n 'removeEventListener',\n function (originalRemoveEventListener: RemoveEventListener): RemoveEventListener {\n return function (this: InstrumentedElement, type, listener, options): () => void {\n if (type === 'click' || type == 'keypress') {\n try {\n const handlers = this.__sentry_instrumentation_handlers__ || {};\n const handlerForType = handlers[type];\n\n if (handlerForType) {\n handlerForType.refCount--;\n // If there are no longer any custom handlers of the current type on this element, we can remove ours, too.\n if (handlerForType.refCount <= 0) {\n originalRemoveEventListener.call(this, type, handlerForType.handler, options);\n handlerForType.handler = undefined;\n delete handlers[type]; // eslint-disable-line @typescript-eslint/no-dynamic-delete\n }\n\n // If there are no longer any custom handlers of any type on this element, cleanup everything.\n if (Object.keys(handlers).length === 0) {\n delete this.__sentry_instrumentation_handlers__;\n }\n }\n } catch (e) {\n // Accessing dom properties is always fragile.\n // Also allows us to skip `addEventListeners` calls with no proper `this` context.\n }\n }\n\n return originalRemoveEventListener.call(this, type, listener, options);\n };\n },\n );\n });\n}\n\n/**\n * Check whether the event is similar to the last captured one. For example, two click events on the same button.\n */\nfunction isSimilarToLastCapturedEvent(event: Event): boolean {\n // If both events have different type, then user definitely performed two separate actions. e.g. click + keypress.\n if (event.type !== lastCapturedEventType) {\n return false;\n }\n\n try {\n // If both events have the same type, it's still possible that actions were performed on different targets.\n // e.g. 2 clicks on different buttons.\n if (!event.target || (event.target as SentryWrappedTarget)._sentryId !== lastCapturedEventTargetId) {\n return false;\n }\n } catch (e) {\n // just accessing `target` property can throw an exception in some rare circumstances\n // see: https://github.com/getsentry/sentry-javascript/issues/838\n }\n\n // If both events have the same type _and_ same `target` (an element which triggered an event, _not necessarily_\n // to which an event listener was attached), we treat them as the same action, as we want to capture\n // only one breadcrumb. e.g. multiple clicks on the same button, or typing inside a user input box.\n return true;\n}\n\n/**\n * Decide whether an event should be captured.\n * @param event event to be captured\n */\nfunction shouldSkipDOMEvent(eventType: string, target: SentryWrappedTarget | null): boolean {\n // We are only interested in filtering `keypress` events for now.\n if (eventType !== 'keypress') {\n return false;\n }\n\n if (!target || !target.tagName) {\n return true;\n }\n\n // Only consider keypress events on actual input elements. This will disregard keypresses targeting body\n // e.g.tabbing through elements, hotkeys, etc.\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Wraps addEventListener to capture UI breadcrumbs\n */\nfunction makeDOMEventHandler(\n handler: (data: HandlerDataDom) => void,\n globalListener: boolean = false,\n): (event: Event) => void {\n return (event: Event & { _sentryCaptured?: true }): void => {\n // It's possible this handler might trigger multiple times for the same\n // event (e.g. event propagation through node ancestors).\n // Ignore if we've already captured that event.\n if (!event || event['_sentryCaptured']) {\n return;\n }\n\n const target = getEventTarget(event);\n\n // We always want to skip _some_ events.\n if (shouldSkipDOMEvent(event.type, target)) {\n return;\n }\n\n // Mark event as \"seen\"\n addNonEnumerableProperty(event, '_sentryCaptured', true);\n\n if (target && !target._sentryId) {\n // Add UUID to event target so we can identify if\n addNonEnumerableProperty(target, '_sentryId', uuid4());\n }\n\n const name = event.type === 'keypress' ? 'input' : event.type;\n\n // If there is no last captured event, it means that we can safely capture the new event and store it for future comparisons.\n // If there is a last captured event, see if the new event is different enough to treat it as a unique one.\n // If that's the case, emit the previous event and store locally the newly-captured DOM event.\n if (!isSimilarToLastCapturedEvent(event)) {\n const handlerData: HandlerDataDom = { event, name, global: globalListener };\n handler(handlerData);\n lastCapturedEventType = event.type;\n lastCapturedEventTargetId = target ? target._sentryId : undefined;\n }\n\n // Start a new debounce timer that will prevent us from capturing multiple events that should be grouped together.\n clearTimeout(debounceTimerID);\n debounceTimerID = WINDOW.setTimeout(() => {\n lastCapturedEventTargetId = undefined;\n lastCapturedEventType = undefined;\n }, DEBOUNCE_DURATION);\n };\n}\n\nfunction getEventTarget(event: Event): SentryWrappedTarget | null {\n try {\n return event.target as SentryWrappedTarget | null;\n } catch (e) {\n // just accessing `target` property can throw an exception in some rare circumstances\n // see: https://github.com/getsentry/sentry-javascript/issues/838\n return null;\n }\n}\n","import type { HandlerDataXhr, SentryWrappedXMLHttpRequest } from '@sentry/core';\nimport { addHandler, isString, maybeInstrument, timestampInSeconds, triggerHandlers } from '@sentry/core';\nimport { WINDOW } from '../types';\n\nexport const SENTRY_XHR_DATA_KEY = '__sentry_xhr_v3__';\n\ntype WindowWithXhr = Window & { XMLHttpRequest?: typeof XMLHttpRequest };\n\n/**\n * Add an instrumentation handler for when an XHR request happens.\n * The handler function is called once when the request starts and once when it ends,\n * which can be identified by checking if it has an `endTimestamp`.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addXhrInstrumentationHandler(handler: (data: HandlerDataXhr) => void): void {\n const type = 'xhr';\n addHandler(type, handler);\n maybeInstrument(type, instrumentXHR);\n}\n\n/** Exported only for tests. */\nexport function instrumentXHR(): void {\n if (!(WINDOW as WindowWithXhr).XMLHttpRequest) {\n return;\n }\n\n const xhrproto = XMLHttpRequest.prototype;\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n xhrproto.open = new Proxy(xhrproto.open, {\n apply(originalOpen, xhrOpenThisArg: XMLHttpRequest & SentryWrappedXMLHttpRequest, xhrOpenArgArray) {\n const startTimestamp = timestampInSeconds() * 1000;\n\n // open() should always be called with two or more arguments\n // But to be on the safe side, we actually validate this and bail out if we don't have a method & url\n const method = isString(xhrOpenArgArray[0]) ? xhrOpenArgArray[0].toUpperCase() : undefined;\n const url = parseUrl(xhrOpenArgArray[1]);\n\n if (!method || !url) {\n return originalOpen.apply(xhrOpenThisArg, xhrOpenArgArray);\n }\n\n xhrOpenThisArg[SENTRY_XHR_DATA_KEY] = {\n method,\n url,\n request_headers: {},\n };\n\n // if Sentry key appears in URL, don't capture it as a request\n if (method === 'POST' && url.match(/sentry_key/)) {\n xhrOpenThisArg.__sentry_own_request__ = true;\n }\n\n const onreadystatechangeHandler: () => void = () => {\n // For whatever reason, this is not the same instance here as from the outer method\n const xhrInfo = xhrOpenThisArg[SENTRY_XHR_DATA_KEY];\n\n if (!xhrInfo) {\n return;\n }\n\n if (xhrOpenThisArg.readyState === 4) {\n try {\n // touching statusCode in some platforms throws\n // an exception\n xhrInfo.status_code = xhrOpenThisArg.status;\n } catch (e) {\n /* do nothing */\n }\n\n const handlerData: HandlerDataXhr = {\n endTimestamp: timestampInSeconds() * 1000,\n startTimestamp,\n xhr: xhrOpenThisArg,\n };\n triggerHandlers('xhr', handlerData);\n }\n };\n\n if ('onreadystatechange' in xhrOpenThisArg && typeof xhrOpenThisArg.onreadystatechange === 'function') {\n xhrOpenThisArg.onreadystatechange = new Proxy(xhrOpenThisArg.onreadystatechange, {\n apply(originalOnreadystatechange, onreadystatechangeThisArg, onreadystatechangeArgArray: unknown[]) {\n onreadystatechangeHandler();\n return originalOnreadystatechange.apply(onreadystatechangeThisArg, onreadystatechangeArgArray);\n },\n });\n } else {\n xhrOpenThisArg.addEventListener('readystatechange', onreadystatechangeHandler);\n }\n\n // Intercepting `setRequestHeader` to access the request headers of XHR instance.\n // This will only work for user/library defined headers, not for the default/browser-assigned headers.\n // Request cookies are also unavailable for XHR, as `Cookie` header can't be defined by `setRequestHeader`.\n xhrOpenThisArg.setRequestHeader = new Proxy(xhrOpenThisArg.setRequestHeader, {\n apply(\n originalSetRequestHeader,\n setRequestHeaderThisArg: SentryWrappedXMLHttpRequest,\n setRequestHeaderArgArray: unknown[],\n ) {\n const [header, value] = setRequestHeaderArgArray;\n\n const xhrInfo = setRequestHeaderThisArg[SENTRY_XHR_DATA_KEY];\n\n if (xhrInfo && isString(header) && isString(value)) {\n xhrInfo.request_headers[header.toLowerCase()] = value;\n }\n\n return originalSetRequestHeader.apply(setRequestHeaderThisArg, setRequestHeaderArgArray);\n },\n });\n\n return originalOpen.apply(xhrOpenThisArg, xhrOpenArgArray);\n },\n });\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n xhrproto.send = new Proxy(xhrproto.send, {\n apply(originalSend, sendThisArg: XMLHttpRequest & SentryWrappedXMLHttpRequest, sendArgArray: unknown[]) {\n const sentryXhrData = sendThisArg[SENTRY_XHR_DATA_KEY];\n\n if (!sentryXhrData) {\n return originalSend.apply(sendThisArg, sendArgArray);\n }\n\n if (sendArgArray[0] !== undefined) {\n sentryXhrData.body = sendArgArray[0];\n }\n\n const handlerData: HandlerDataXhr = {\n startTimestamp: timestampInSeconds() * 1000,\n xhr: sendThisArg,\n };\n triggerHandlers('xhr', handlerData);\n\n return originalSend.apply(sendThisArg, sendArgArray);\n },\n });\n}\n\nfunction parseUrl(url: string | unknown): string | undefined {\n if (isString(url)) {\n return url;\n }\n\n try {\n // url can be a string or URL\n // but since URL is not available in IE11, we do not check for it,\n // but simply assume it is an URL and return `toString()` from it (which returns the full URL)\n // If that fails, we just return undefined\n return (url as URL).toString();\n } catch {} // eslint-disable-line no-empty\n\n return undefined;\n}\n","import {\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n getActiveSpan,\n getClient,\n getCurrentScope,\n getRootSpan,\n spanToJSON,\n} from '@sentry/core';\nimport { browserPerformanceTimeOrigin, dropUndefinedKeys, htmlTreeAsString, logger } from '@sentry/core';\nimport type { SpanAttributes } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { addClsInstrumentationHandler } from './instrument';\nimport { msToSec, startStandaloneWebVitalSpan } from './utils';\nimport { onHidden } from './web-vitals/lib/onHidden';\n\n/**\n * Starts tracking the Cumulative Layout Shift on the current page and collects the value once\n *\n * - the page visibility is hidden\n * - a navigation span is started (to stop CLS measurement for SPA soft navigations)\n *\n * Once either of these events triggers, the CLS value is sent as a standalone span and we stop\n * measuring CLS.\n */\nexport function trackClsAsStandaloneSpan(): void {\n let standaloneCLsValue = 0;\n let standaloneClsEntry: LayoutShift | undefined;\n let pageloadSpanId: string | undefined;\n\n if (!supportsLayoutShift()) {\n return;\n }\n\n let sentSpan = false;\n function _collectClsOnce() {\n if (sentSpan) {\n return;\n }\n sentSpan = true;\n if (pageloadSpanId) {\n sendStandaloneClsSpan(standaloneCLsValue, standaloneClsEntry, pageloadSpanId);\n }\n cleanupClsHandler();\n }\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n standaloneCLsValue = metric.value;\n standaloneClsEntry = entry;\n }, true);\n\n // use pagehide event from web-vitals\n onHidden(() => {\n _collectClsOnce();\n });\n\n // Since the call chain of this function is synchronous and evaluates before the SDK client is created,\n // we need to wait with subscribing to a client hook until the client is created. Therefore, we defer\n // to the next tick after the SDK setup.\n setTimeout(() => {\n const client = getClient();\n\n if (!client) {\n return;\n }\n\n const unsubscribeStartNavigation = client.on('startNavigationSpan', () => {\n _collectClsOnce();\n unsubscribeStartNavigation && unsubscribeStartNavigation();\n });\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n const spanJSON = rootSpan && spanToJSON(rootSpan);\n if (spanJSON && spanJSON.op === 'pageload') {\n pageloadSpanId = rootSpan.spanContext().spanId;\n }\n }, 0);\n}\n\nfunction sendStandaloneClsSpan(clsValue: number, entry: LayoutShift | undefined, pageloadSpanId: string) {\n DEBUG_BUILD && logger.log(`Sending CLS span (${clsValue})`);\n\n const startTime = msToSec((browserPerformanceTimeOrigin || 0) + ((entry && entry.startTime) || 0));\n const routeName = getCurrentScope().getScopeData().transactionName;\n\n const name = entry ? htmlTreeAsString(entry.sources[0] && entry.sources[0].node) : 'Layout shift';\n\n const attributes: SpanAttributes = dropUndefinedKeys({\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.cls',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'ui.webvital.cls',\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: (entry && entry.duration) || 0,\n // attach the pageload span id to the CLS span so that we can link them in the UI\n 'sentry.pageload.span_id': pageloadSpanId,\n });\n\n const span = startStandaloneWebVitalSpan({\n name,\n transaction: routeName,\n attributes,\n startTime,\n });\n\n if (span) {\n span.addEvent('cls', {\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: '',\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: clsValue,\n });\n\n // LayoutShift performance entries always have a duration of 0, so we don't need to add `entry.duration` here\n // see: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry/duration\n span.end(startTime);\n }\n}\n\nfunction supportsLayoutShift(): boolean {\n try {\n return PerformanceObserver.supportedEntryTypes.includes('layout-shift');\n } catch {\n return false;\n }\n}\n","/* eslint-disable max-lines */\nimport type { Measurements, Span, SpanAttributes, StartSpanOptions } from '@sentry/core';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n browserPerformanceTimeOrigin,\n getActiveSpan,\n getComponentName,\n htmlTreeAsString,\n parseUrl,\n setMeasurement,\n spanToJSON,\n} from '@sentry/core';\nimport { WINDOW } from '../types';\nimport { trackClsAsStandaloneSpan } from './cls';\nimport {\n type PerformanceLongAnimationFrameTiming,\n addClsInstrumentationHandler,\n addFidInstrumentationHandler,\n addLcpInstrumentationHandler,\n addPerformanceInstrumentationHandler,\n addTtfbInstrumentationHandler,\n} from './instrument';\nimport { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan } from './utils';\nimport { getActivationStart } from './web-vitals/lib/getActivationStart';\nimport { getNavigationEntry } from './web-vitals/lib/getNavigationEntry';\nimport { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher';\n\ninterface NavigatorNetworkInformation {\n readonly connection?: NetworkInformation;\n}\n\n// http://wicg.github.io/netinfo/#connection-types\ntype ConnectionType = 'bluetooth' | 'cellular' | 'ethernet' | 'mixed' | 'none' | 'other' | 'unknown' | 'wifi' | 'wimax';\n\n// http://wicg.github.io/netinfo/#effectiveconnectiontype-enum\ntype EffectiveConnectionType = '2g' | '3g' | '4g' | 'slow-2g';\n\n// http://wicg.github.io/netinfo/#dom-megabit\ntype Megabit = number;\n// http://wicg.github.io/netinfo/#dom-millisecond\ntype Millisecond = number;\n\n// http://wicg.github.io/netinfo/#networkinformation-interface\ninterface NetworkInformation extends EventTarget {\n // http://wicg.github.io/netinfo/#type-attribute\n readonly type?: ConnectionType;\n // http://wicg.github.io/netinfo/#effectivetype-attribute\n readonly effectiveType?: EffectiveConnectionType;\n // http://wicg.github.io/netinfo/#downlinkmax-attribute\n readonly downlinkMax?: Megabit;\n // http://wicg.github.io/netinfo/#downlink-attribute\n readonly downlink?: Megabit;\n // http://wicg.github.io/netinfo/#rtt-attribute\n readonly rtt?: Millisecond;\n // http://wicg.github.io/netinfo/#savedata-attribute\n readonly saveData?: boolean;\n // http://wicg.github.io/netinfo/#handling-changes-to-the-underlying-connection\n onchange?: EventListener;\n}\n\n// https://w3c.github.io/device-memory/#sec-device-memory-js-api\ninterface NavigatorDeviceMemory {\n readonly deviceMemory?: number;\n}\n\nconst MAX_INT_AS_BYTES = 2147483647;\n\nlet _performanceCursor: number = 0;\n\nlet _measurements: Measurements = {};\nlet _lcpEntry: LargestContentfulPaint | undefined;\nlet _clsEntry: LayoutShift | undefined;\n\ninterface StartTrackingWebVitalsOptions {\n recordClsStandaloneSpans: boolean;\n}\n\n/**\n * Start tracking web vitals.\n * The callback returned by this function can be used to stop tracking & ensure all measurements are final & captured.\n *\n * @returns A function that forces web vitals collection\n */\nexport function startTrackingWebVitals({ recordClsStandaloneSpans }: StartTrackingWebVitalsOptions): () => void {\n const performance = getBrowserPerformanceAPI();\n if (performance && browserPerformanceTimeOrigin) {\n // @ts-expect-error we want to make sure all of these are available, even if TS is sure they are\n if (performance.mark) {\n WINDOW.performance.mark('sentry-tracing-init');\n }\n const fidCleanupCallback = _trackFID();\n const lcpCleanupCallback = _trackLCP();\n const ttfbCleanupCallback = _trackTtfb();\n const clsCleanupCallback = recordClsStandaloneSpans ? trackClsAsStandaloneSpan() : _trackCLS();\n\n return (): void => {\n fidCleanupCallback();\n lcpCleanupCallback();\n ttfbCleanupCallback();\n clsCleanupCallback && clsCleanupCallback();\n };\n }\n\n return () => undefined;\n}\n\n/**\n * Start tracking long tasks.\n */\nexport function startTrackingLongTasks(): void {\n addPerformanceInstrumentationHandler('longtask', ({ entries }) => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n\n const { op: parentOp, start_timestamp: parentStartTimestamp } = spanToJSON(parent);\n\n for (const entry of entries) {\n const startTime = msToSec((browserPerformanceTimeOrigin as number) + entry.startTime);\n const duration = msToSec(entry.duration);\n\n if (parentOp === 'navigation' && parentStartTimestamp && startTime < parentStartTimestamp) {\n // Skip adding a span if the long task started before the navigation started.\n // `startAndEndSpan` will otherwise adjust the parent's start time to the span's start\n // time, potentially skewing the duration of the actual navigation as reported via our\n // routing instrumentations\n continue;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, {\n name: 'Main UI thread blocked',\n op: 'ui.long-task',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n }\n });\n}\n\n/**\n * Start tracking long animation frames.\n */\nexport function startTrackingLongAnimationFrames(): void {\n // NOTE: the current web-vitals version (3.5.2) does not support long-animation-frame, so\n // we directly observe `long-animation-frame` events instead of through the web-vitals\n // `observe` helper function.\n const observer = new PerformanceObserver(list => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n for (const entry of list.getEntries() as PerformanceLongAnimationFrameTiming[]) {\n if (!entry.scripts[0]) {\n continue;\n }\n\n const startTime = msToSec((browserPerformanceTimeOrigin as number) + entry.startTime);\n\n const { start_timestamp: parentStartTimestamp, op: parentOp } = spanToJSON(parent);\n\n if (parentOp === 'navigation' && parentStartTimestamp && startTime < parentStartTimestamp) {\n // Skip adding the span if the long animation frame started before the navigation started.\n // `startAndEndSpan` will otherwise adjust the parent's start time to the span's start\n // time, potentially skewing the duration of the actual navigation as reported via our\n // routing instrumentations\n continue;\n }\n\n const duration = msToSec(entry.duration);\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n };\n\n const initialScript = entry.scripts[0];\n const { invoker, invokerType, sourceURL, sourceFunctionName, sourceCharPosition } = initialScript;\n attributes['browser.script.invoker'] = invoker;\n attributes['browser.script.invoker_type'] = invokerType;\n if (sourceURL) {\n attributes['code.filepath'] = sourceURL;\n }\n if (sourceFunctionName) {\n attributes['code.function'] = sourceFunctionName;\n }\n if (sourceCharPosition !== -1) {\n attributes['browser.script.source_char_position'] = sourceCharPosition;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, {\n name: 'Main UI thread blocked',\n op: 'ui.long-animation-frame',\n attributes,\n });\n }\n });\n\n observer.observe({ type: 'long-animation-frame', buffered: true });\n}\n\n/**\n * Start tracking interaction events.\n */\nexport function startTrackingInteractions(): void {\n addPerformanceInstrumentationHandler('event', ({ entries }) => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n for (const entry of entries) {\n if (entry.name === 'click') {\n const startTime = msToSec((browserPerformanceTimeOrigin as number) + entry.startTime);\n const duration = msToSec(entry.duration);\n\n const spanOptions: StartSpanOptions & Required> = {\n name: htmlTreeAsString(entry.target),\n op: `ui.interaction.${entry.name}`,\n startTime: startTime,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n };\n\n const componentName = getComponentName(entry.target);\n if (componentName) {\n spanOptions.attributes['ui.component_name'] = componentName;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, spanOptions);\n }\n }\n });\n}\n\nexport { registerInpInteractionListener, startTrackingINP } from './inp';\n\n/**\n * Starts tracking the Cumulative Layout Shift on the current page and collects the value and last entry\n * to the `_measurements` object which ultimately is applied to the pageload span's measurements.\n */\nfunction _trackCLS(): () => void {\n return addClsInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n _measurements['cls'] = { value: metric.value, unit: '' };\n _clsEntry = entry;\n }, true);\n}\n\n/** Starts tracking the Largest Contentful Paint on the current page. */\nfunction _trackLCP(): () => void {\n return addLcpInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1];\n if (!entry) {\n return;\n }\n\n _measurements['lcp'] = { value: metric.value, unit: 'millisecond' };\n _lcpEntry = entry as LargestContentfulPaint;\n }, true);\n}\n\n/** Starts tracking the First Input Delay on the current page. */\nfunction _trackFID(): () => void {\n return addFidInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1];\n if (!entry) {\n return;\n }\n\n const timeOrigin = msToSec(browserPerformanceTimeOrigin as number);\n const startTime = msToSec(entry.startTime);\n _measurements['fid'] = { value: metric.value, unit: 'millisecond' };\n _measurements['mark.fid'] = { value: timeOrigin + startTime, unit: 'second' };\n });\n}\n\nfunction _trackTtfb(): () => void {\n return addTtfbInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1];\n if (!entry) {\n return;\n }\n\n _measurements['ttfb'] = { value: metric.value, unit: 'millisecond' };\n });\n}\n\ninterface AddPerformanceEntriesOptions {\n /**\n * Flag to determine if CLS should be recorded as a measurement on the span or\n * sent as a standalone span instead.\n */\n recordClsOnPageloadSpan: boolean;\n}\n\n/** Add performance related spans to a transaction */\nexport function addPerformanceEntries(span: Span, options: AddPerformanceEntriesOptions): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !WINDOW.performance.getEntries || !browserPerformanceTimeOrigin) {\n // Gatekeeper if performance API not available\n return;\n }\n\n const timeOrigin = msToSec(browserPerformanceTimeOrigin);\n\n const performanceEntries = performance.getEntries();\n\n const { op, start_timestamp: transactionStartTime } = spanToJSON(span);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n performanceEntries.slice(_performanceCursor).forEach((entry: Record) => {\n const startTime = msToSec(entry.startTime);\n const duration = msToSec(\n // Inexplicably, Chrome sometimes emits a negative duration. We need to work around this.\n // There is a SO post attempting to explain this, but it leaves one with open questions: https://stackoverflow.com/questions/23191918/peformance-getentries-and-negative-duration-display\n // The way we clamp the value is probably not accurate, since we have observed this happen for things that may take a while to load, like for example the replay worker.\n // TODO: Investigate why this happens and how to properly mitigate. For now, this is a workaround to prevent transactions being dropped due to negative duration spans.\n Math.max(0, entry.duration),\n );\n\n if (op === 'navigation' && transactionStartTime && timeOrigin + startTime < transactionStartTime) {\n return;\n }\n\n switch (entry.entryType) {\n case 'navigation': {\n _addNavigationSpans(span, entry, timeOrigin);\n break;\n }\n case 'mark':\n case 'paint':\n case 'measure': {\n _addMeasureSpans(span, entry, startTime, duration, timeOrigin);\n\n // capture web vitals\n const firstHidden = getVisibilityWatcher();\n // Only report if the page wasn't hidden prior to the web vital.\n const shouldRecord = entry.startTime < firstHidden.firstHiddenTime;\n\n if (entry.name === 'first-paint' && shouldRecord) {\n _measurements['fp'] = { value: entry.startTime, unit: 'millisecond' };\n }\n if (entry.name === 'first-contentful-paint' && shouldRecord) {\n _measurements['fcp'] = { value: entry.startTime, unit: 'millisecond' };\n }\n break;\n }\n case 'resource': {\n _addResourceSpans(span, entry, entry.name as string, startTime, duration, timeOrigin);\n break;\n }\n default:\n // Ignore other entry types.\n }\n });\n\n _performanceCursor = Math.max(performanceEntries.length - 1, 0);\n\n _trackNavigator(span);\n\n // Measurements are only available for pageload transactions\n if (op === 'pageload') {\n _addTtfbRequestTimeToMeasurements(_measurements);\n\n const fidMark = _measurements['mark.fid'];\n if (fidMark && _measurements['fid']) {\n // create span for FID\n startAndEndSpan(span, fidMark.value, fidMark.value + msToSec(_measurements['fid'].value), {\n name: 'first input delay',\n op: 'ui.action',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n\n // Delete mark.fid as we don't want it to be part of final payload\n delete _measurements['mark.fid'];\n }\n\n // If FCP is not recorded we should not record the cls value\n // according to the new definition of CLS.\n // TODO: Check if the first condition is still necessary: `onCLS` already only fires once `onFCP` was called.\n if (!('fcp' in _measurements) || !options.recordClsOnPageloadSpan) {\n delete _measurements.cls;\n }\n\n Object.entries(_measurements).forEach(([measurementName, measurement]) => {\n setMeasurement(measurementName, measurement.value, measurement.unit);\n });\n\n // Set timeOrigin which denotes the timestamp which to base the LCP/FCP/FP/TTFB measurements on\n span.setAttribute('performance.timeOrigin', timeOrigin);\n\n // In prerendering scenarios, where a page might be prefetched and pre-rendered before the user clicks the link,\n // the navigation starts earlier than when the user clicks it. Web Vitals should always be based on the\n // user-perceived time, so they are not reported from the actual start of the navigation, but rather from the\n // time where the user actively started the navigation, for example by clicking a link.\n // This is user action is called \"activation\" and the time between navigation and activation is stored in\n // the `activationStart` attribute of the \"navigation\" PerformanceEntry.\n span.setAttribute('performance.activationStart', getActivationStart());\n\n _setWebVitalAttributes(span);\n }\n\n _lcpEntry = undefined;\n _clsEntry = undefined;\n _measurements = {};\n}\n\n/** Create measure related spans */\nexport function _addMeasureSpans(\n span: Span,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n entry: Record,\n startTime: number,\n duration: number,\n timeOrigin: number,\n): number {\n const navEntry = getNavigationEntry(false);\n const requestTime = msToSec(navEntry ? navEntry.requestStart : 0);\n // Because performance.measure accepts arbitrary timestamps it can produce\n // spans that happen before the browser even makes a request for the page.\n //\n // An example of this is the automatically generated Next.js-before-hydration\n // spans created by the Next.js framework.\n //\n // To prevent this we will pin the start timestamp to the request start time\n // This does make duration inaccurate, so if this does happen, we will add\n // an attribute to the span\n const measureStartTimestamp = timeOrigin + Math.max(startTime, requestTime);\n const startTimeStamp = timeOrigin + startTime;\n const measureEndTimestamp = startTimeStamp + duration;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',\n };\n\n if (measureStartTimestamp !== startTimeStamp) {\n attributes['sentry.browser.measure_happened_before_request'] = true;\n attributes['sentry.browser.measure_start_time'] = measureStartTimestamp;\n }\n\n startAndEndSpan(span, measureStartTimestamp, measureEndTimestamp, {\n name: entry.name as string,\n op: entry.entryType as string,\n attributes,\n });\n\n return measureStartTimestamp;\n}\n\n/** Instrument navigation entries */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction _addNavigationSpans(span: Span, entry: Record, timeOrigin: number): void {\n ['unloadEvent', 'redirect', 'domContentLoadedEvent', 'loadEvent', 'connect'].forEach(event => {\n _addPerformanceNavigationTiming(span, entry, event, timeOrigin);\n });\n _addPerformanceNavigationTiming(span, entry, 'secureConnection', timeOrigin, 'TLS/SSL', 'connectEnd');\n _addPerformanceNavigationTiming(span, entry, 'fetch', timeOrigin, 'cache', 'domainLookupStart');\n _addPerformanceNavigationTiming(span, entry, 'domainLookup', timeOrigin, 'DNS');\n _addRequest(span, entry, timeOrigin);\n}\n\n/** Create performance navigation related spans */\nfunction _addPerformanceNavigationTiming(\n span: Span,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n entry: Record,\n event: string,\n timeOrigin: number,\n name?: string,\n eventEnd?: string,\n): void {\n const end = eventEnd ? (entry[eventEnd] as number | undefined) : (entry[`${event}End`] as number | undefined);\n const start = entry[`${event}Start`] as number | undefined;\n if (!start || !end) {\n return;\n }\n startAndEndSpan(span, timeOrigin + msToSec(start), timeOrigin + msToSec(end), {\n op: `browser.${name || event}`,\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n}\n\n/** Create request and response related spans */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction _addRequest(span: Span, entry: Record, timeOrigin: number): void {\n const requestStartTimestamp = timeOrigin + msToSec(entry.requestStart as number);\n const responseEndTimestamp = timeOrigin + msToSec(entry.responseEnd as number);\n const responseStartTimestamp = timeOrigin + msToSec(entry.responseStart as number);\n if (entry.responseEnd) {\n // It is possible that we are collecting these metrics when the page hasn't finished loading yet, for example when the HTML slowly streams in.\n // In this case, ie. when the document request hasn't finished yet, `entry.responseEnd` will be 0.\n // In order not to produce faulty spans, where the end timestamp is before the start timestamp, we will only collect\n // these spans when the responseEnd value is available. The backend (Relay) would drop the entire span if it contained faulty spans.\n startAndEndSpan(span, requestStartTimestamp, responseEndTimestamp, {\n op: 'browser.request',\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n\n startAndEndSpan(span, responseStartTimestamp, responseEndTimestamp, {\n op: 'browser.response',\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n }\n}\n\nexport interface ResourceEntry extends Record {\n initiatorType?: string;\n transferSize?: number;\n encodedBodySize?: number;\n decodedBodySize?: number;\n renderBlockingStatus?: string;\n deliveryType?: string;\n}\n\n/** Create resource-related spans */\nexport function _addResourceSpans(\n span: Span,\n entry: ResourceEntry,\n resourceUrl: string,\n startTime: number,\n duration: number,\n timeOrigin: number,\n): void {\n // we already instrument based on fetch and xhr, so we don't need to\n // duplicate spans here.\n if (entry.initiatorType === 'xmlhttprequest' || entry.initiatorType === 'fetch') {\n return;\n }\n\n const parsedUrl = parseUrl(resourceUrl);\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',\n };\n setResourceEntrySizeData(attributes, entry, 'transferSize', 'http.response_transfer_size');\n setResourceEntrySizeData(attributes, entry, 'encodedBodySize', 'http.response_content_length');\n setResourceEntrySizeData(attributes, entry, 'decodedBodySize', 'http.decoded_response_content_length');\n\n if (entry.deliveryType != null) {\n attributes['http.response_delivery_type'] = entry.deliveryType;\n }\n\n if ('renderBlockingStatus' in entry) {\n attributes['resource.render_blocking_status'] = entry.renderBlockingStatus;\n }\n if (parsedUrl.protocol) {\n attributes['url.scheme'] = parsedUrl.protocol.split(':').pop(); // the protocol returned by parseUrl includes a :, but OTEL spec does not, so we remove it.\n }\n\n if (parsedUrl.host) {\n attributes['server.address'] = parsedUrl.host;\n }\n\n attributes['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin);\n\n const startTimestamp = timeOrigin + startTime;\n const endTimestamp = startTimestamp + duration;\n\n startAndEndSpan(span, startTimestamp, endTimestamp, {\n name: resourceUrl.replace(WINDOW.location.origin, ''),\n op: entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other',\n attributes,\n });\n}\n\n/**\n * Capture the information of the user agent.\n */\nfunction _trackNavigator(span: Span): void {\n const navigator = WINDOW.navigator as null | (Navigator & NavigatorNetworkInformation & NavigatorDeviceMemory);\n if (!navigator) {\n return;\n }\n\n // track network connectivity\n const connection = navigator.connection;\n if (connection) {\n if (connection.effectiveType) {\n span.setAttribute('effectiveConnectionType', connection.effectiveType);\n }\n\n if (connection.type) {\n span.setAttribute('connectionType', connection.type);\n }\n\n if (isMeasurementValue(connection.rtt)) {\n _measurements['connection.rtt'] = { value: connection.rtt, unit: 'millisecond' };\n }\n }\n\n if (isMeasurementValue(navigator.deviceMemory)) {\n span.setAttribute('deviceMemory', `${navigator.deviceMemory} GB`);\n }\n\n if (isMeasurementValue(navigator.hardwareConcurrency)) {\n span.setAttribute('hardwareConcurrency', String(navigator.hardwareConcurrency));\n }\n}\n\n/** Add LCP / CLS data to span to allow debugging */\nfunction _setWebVitalAttributes(span: Span): void {\n if (_lcpEntry) {\n // Capture Properties of the LCP element that contributes to the LCP.\n\n if (_lcpEntry.element) {\n span.setAttribute('lcp.element', htmlTreeAsString(_lcpEntry.element));\n }\n\n if (_lcpEntry.id) {\n span.setAttribute('lcp.id', _lcpEntry.id);\n }\n\n if (_lcpEntry.url) {\n // Trim URL to the first 200 characters.\n span.setAttribute('lcp.url', _lcpEntry.url.trim().slice(0, 200));\n }\n\n if (_lcpEntry.loadTime != null) {\n // loadTime is the time of LCP that's related to receiving the LCP element response..\n span.setAttribute('lcp.loadTime', _lcpEntry.loadTime);\n }\n\n if (_lcpEntry.renderTime != null) {\n // renderTime is loadTime + rendering time\n // it's 0 if the LCP element is loaded from a 3rd party origin that doesn't send the\n // `Timing-Allow-Origin` header.\n span.setAttribute('lcp.renderTime', _lcpEntry.renderTime);\n }\n\n span.setAttribute('lcp.size', _lcpEntry.size);\n }\n\n // See: https://developer.mozilla.org/en-US/docs/Web/API/LayoutShift\n if (_clsEntry && _clsEntry.sources) {\n _clsEntry.sources.forEach((source, index) =>\n span.setAttribute(`cls.source.${index + 1}`, htmlTreeAsString(source.node)),\n );\n }\n}\n\nfunction setResourceEntrySizeData(\n attributes: SpanAttributes,\n entry: ResourceEntry,\n key: keyof Pick,\n dataKey: 'http.response_transfer_size' | 'http.response_content_length' | 'http.decoded_response_content_length',\n): void {\n const entryVal = entry[key];\n if (entryVal != null && entryVal < MAX_INT_AS_BYTES) {\n attributes[dataKey] = entryVal;\n }\n}\n\n/**\n * Add ttfb request time information to measurements.\n *\n * ttfb information is added via vendored web vitals library.\n */\nfunction _addTtfbRequestTimeToMeasurements(_measurements: Measurements): void {\n const navEntry = getNavigationEntry(false);\n if (!navEntry) {\n return;\n }\n\n const { responseStart, requestStart } = navEntry;\n\n if (requestStart <= responseStart) {\n _measurements['ttfb.requestTime'] = {\n value: responseStart - requestStart,\n unit: 'millisecond',\n };\n }\n}\n","import type { Span, SpanAttributes } from '@sentry/core';\nimport {\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT,\n SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n browserPerformanceTimeOrigin,\n dropUndefinedKeys,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n htmlTreeAsString,\n spanToJSON,\n} from '@sentry/core';\nimport {\n addInpInstrumentationHandler,\n addPerformanceInstrumentationHandler,\n isPerformanceEventTiming,\n} from './instrument';\nimport { getBrowserPerformanceAPI, msToSec, startStandaloneWebVitalSpan } from './utils';\n\nconst LAST_INTERACTIONS: number[] = [];\nconst INTERACTIONS_SPAN_MAP = new Map();\n\n/**\n * Start tracking INP webvital events.\n */\nexport function startTrackingINP(): () => void {\n const performance = getBrowserPerformanceAPI();\n if (performance && browserPerformanceTimeOrigin) {\n const inpCallback = _trackINP();\n\n return (): void => {\n inpCallback();\n };\n }\n\n return () => undefined;\n}\n\nconst INP_ENTRY_MAP: Record = {\n click: 'click',\n pointerdown: 'click',\n pointerup: 'click',\n mousedown: 'click',\n mouseup: 'click',\n touchstart: 'click',\n touchend: 'click',\n mouseover: 'hover',\n mouseout: 'hover',\n mouseenter: 'hover',\n mouseleave: 'hover',\n pointerover: 'hover',\n pointerout: 'hover',\n pointerenter: 'hover',\n pointerleave: 'hover',\n dragstart: 'drag',\n dragend: 'drag',\n drag: 'drag',\n dragenter: 'drag',\n dragleave: 'drag',\n dragover: 'drag',\n drop: 'drag',\n keydown: 'press',\n keyup: 'press',\n keypress: 'press',\n input: 'press',\n};\n\n/** Starts tracking the Interaction to Next Paint on the current page. */\nfunction _trackINP(): () => void {\n return addInpInstrumentationHandler(({ metric }) => {\n if (metric.value == undefined) {\n return;\n }\n\n const entry = metric.entries.find(entry => entry.duration === metric.value && INP_ENTRY_MAP[entry.name]);\n\n if (!entry) {\n return;\n }\n\n const { interactionId } = entry;\n const interactionType = INP_ENTRY_MAP[entry.name];\n\n /** Build the INP span, create an envelope from the span, and then send the envelope */\n const startTime = msToSec((browserPerformanceTimeOrigin as number) + entry.startTime);\n const duration = msToSec(metric.value);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // We first try to lookup the span from our INTERACTIONS_SPAN_MAP,\n // where we cache the route per interactionId\n const cachedSpan = interactionId != null ? INTERACTIONS_SPAN_MAP.get(interactionId) : undefined;\n\n const spanToUse = cachedSpan || rootSpan;\n\n // Else, we try to use the active span.\n // Finally, we fall back to look at the transactionName on the scope\n const routeName = spanToUse ? spanToJSON(spanToUse).description : getCurrentScope().getScopeData().transactionName;\n\n const name = htmlTreeAsString(entry.target);\n const attributes: SpanAttributes = dropUndefinedKeys({\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.inp',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `ui.interaction.${interactionType}`,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry.duration,\n });\n\n const span = startStandaloneWebVitalSpan({\n name,\n transaction: routeName,\n attributes,\n startTime,\n });\n\n if (span) {\n span.addEvent('inp', {\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: 'millisecond',\n [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: metric.value,\n });\n\n span.end(startTime + duration);\n }\n });\n}\n\n/**\n * Register a listener to cache route information for INP interactions.\n * TODO(v9): `latestRoute` no longer needs to be passed in and will be removed in v9.\n */\nexport function registerInpInteractionListener(_latestRoute?: unknown): void {\n const handleEntries = ({ entries }: { entries: PerformanceEntry[] }): void => {\n const activeSpan = getActiveSpan();\n const activeRootSpan = activeSpan && getRootSpan(activeSpan);\n\n entries.forEach(entry => {\n if (!isPerformanceEventTiming(entry) || !activeRootSpan) {\n return;\n }\n\n const interactionId = entry.interactionId;\n if (interactionId == null) {\n return;\n }\n\n // If the interaction was already recorded before, nothing more to do\n if (INTERACTIONS_SPAN_MAP.has(interactionId)) {\n return;\n }\n\n // We keep max. 10 interactions in the list, then remove the oldest one & clean up\n if (LAST_INTERACTIONS.length > 10) {\n const last = LAST_INTERACTIONS.shift() as number;\n INTERACTIONS_SPAN_MAP.delete(last);\n }\n\n // We add the interaction to the list of recorded interactions\n // and store the span for this interaction\n LAST_INTERACTIONS.push(interactionId);\n INTERACTIONS_SPAN_MAP.set(interactionId, activeRootSpan);\n });\n };\n\n addPerformanceInstrumentationHandler('event', handleEntries);\n addPerformanceInstrumentationHandler('first-input', handleEntries);\n}\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { MetricRatingThresholds, MetricType } from '../types';\n\nconst getRating = (value: number, thresholds: MetricRatingThresholds): MetricType['rating'] => {\n if (value > thresholds[1]) {\n return 'poor';\n }\n if (value > thresholds[0]) {\n return 'needs-improvement';\n }\n return 'good';\n};\n\nexport const bindReporter = (\n callback: (metric: Extract) => void,\n metric: Extract,\n thresholds: MetricRatingThresholds,\n reportAllChanges?: boolean,\n) => {\n let prevValue: number;\n let delta: number;\n return (forceReport?: boolean) => {\n if (metric.value >= 0) {\n if (forceReport || reportAllChanges) {\n delta = metric.value - (prevValue || 0);\n\n // Report the metric if there's a non-zero delta or if no previous\n // value exists (which can happen in the case of the document becoming\n // hidden when the metric value is 0).\n // See: https://github.com/GoogleChrome/web-vitals/issues/14\n if (delta || prevValue === undefined) {\n prevValue = metric.value;\n metric.delta = delta;\n metric.rating = getRating(metric.value, thresholds);\n callback(metric);\n }\n }\n }\n };\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../../types';\nimport type { MetricType } from '../types';\nimport { generateUniqueID } from './generateUniqueID';\nimport { getActivationStart } from './getActivationStart';\nimport { getNavigationEntry } from './getNavigationEntry';\n\nexport const initMetric = (name: MetricName, value?: number) => {\n const navEntry = getNavigationEntry();\n let navigationType: MetricType['navigationType'] = 'navigate';\n\n if (navEntry) {\n if ((WINDOW.document && WINDOW.document.prerendering) || getActivationStart() > 0) {\n navigationType = 'prerender';\n } else if (WINDOW.document && WINDOW.document.wasDiscarded) {\n navigationType = 'restore';\n } else if (navEntry.type) {\n navigationType = navEntry.type.replace(/_/g, '-') as MetricType['navigationType'];\n }\n }\n\n // Use `entries` type specific for the metric.\n const entries: Extract['entries'] = [];\n\n return {\n name,\n value: typeof value === 'undefined' ? -1 : value,\n rating: 'good' as const, // If needed, will be updated when reported. `const` to keep the type from widening to `string`.\n delta: 0,\n entries,\n id: generateUniqueID(),\n navigationType,\n };\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Performantly generate a unique, 30-char string by combining a version\n * number, the current timestamp with a 13-digit number integer.\n * @return {string}\n */\nexport const generateUniqueID = () => {\n return `v4-${Date.now()}-${Math.floor(Math.random() * (9e12 - 1)) + 1e12}`;\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ninterface PerformanceEntryMap {\n event: PerformanceEventTiming[];\n 'first-input': PerformanceEventTiming[];\n 'layout-shift': LayoutShift[];\n 'largest-contentful-paint': LargestContentfulPaint[];\n 'long-animation-frame': PerformanceLongAnimationFrameTiming[];\n paint: PerformancePaintTiming[];\n navigation: PerformanceNavigationTiming[];\n resource: PerformanceResourceTiming[];\n // Sentry-specific change:\n // We add longtask as a supported entry type as we use this in\n // our `instrumentPerformanceObserver` function also observes 'longtask'\n // entries.\n longtask: PerformanceEntry[];\n}\n\n/**\n * Takes a performance entry type and a callback function, and creates a\n * `PerformanceObserver` instance that will observe the specified entry type\n * with buffering enabled and call the callback _for each entry_.\n *\n * This function also feature-detects entry support and wraps the logic in a\n * try/catch to avoid errors in unsupporting browsers.\n */\nexport const observe = (\n type: K,\n callback: (entries: PerformanceEntryMap[K]) => void,\n opts?: PerformanceObserverInit,\n): PerformanceObserver | undefined => {\n try {\n if (PerformanceObserver.supportedEntryTypes.includes(type)) {\n const po = new PerformanceObserver(list => {\n // Delay by a microtask to workaround a bug in Safari where the\n // callback is invoked immediately, rather than in a separate task.\n // See: https://github.com/GoogleChrome/web-vitals/issues/277\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n Promise.resolve().then(() => {\n callback(list.getEntries() as PerformanceEntryMap[K]);\n });\n });\n po.observe(\n Object.assign(\n {\n type,\n buffered: true,\n },\n opts || {},\n ) as PerformanceObserverInit,\n );\n return po;\n }\n } catch (e) {\n // Do nothing.\n }\n return;\n};\n","/*\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const runOnce = (cb: () => void) => {\n let called = false;\n return () => {\n if (!called) {\n cb();\n called = true;\n }\n };\n};\n","/*\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../../types';\n\nexport const whenActivated = (callback: () => void) => {\n if (WINDOW.document && WINDOW.document.prerendering) {\n addEventListener('prerenderingchange', () => callback(), true);\n } else {\n callback();\n }\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { bindReporter } from './lib/bindReporter';\nimport { getActivationStart } from './lib/getActivationStart';\nimport { getVisibilityWatcher } from './lib/getVisibilityWatcher';\nimport { initMetric } from './lib/initMetric';\nimport { observe } from './lib/observe';\nimport { whenActivated } from './lib/whenActivated';\nimport type { FCPMetric, MetricRatingThresholds, ReportOpts } from './types';\n\n/** Thresholds for FCP. See https://web.dev/articles/fcp#what_is_a_good_fcp_score */\nexport const FCPThresholds: MetricRatingThresholds = [1800, 3000];\n\n/**\n * Calculates the [FCP](https://web.dev/articles/fcp) value for the current page and\n * calls the `callback` function once the value is ready, along with the\n * relevant `paint` performance entry used to determine the value. The reported\n * value is a `DOMHighResTimeStamp`.\n */\nexport const onFCP = (onReport: (metric: FCPMetric) => void, opts: ReportOpts = {}) => {\n whenActivated(() => {\n const visibilityWatcher = getVisibilityWatcher();\n const metric = initMetric('FCP');\n let report: ReturnType;\n\n const handleEntries = (entries: FCPMetric['entries']) => {\n entries.forEach(entry => {\n if (entry.name === 'first-contentful-paint') {\n po!.disconnect();\n\n // Only report if the page wasn't hidden prior to the first paint.\n if (entry.startTime < visibilityWatcher.firstHiddenTime) {\n // The activationStart reference is used because FCP should be\n // relative to page activation rather than navigation start if the\n // page was prerendered. But in cases where `activationStart` occurs\n // after the FCP, this time should be clamped at 0.\n metric.value = Math.max(entry.startTime - getActivationStart(), 0);\n metric.entries.push(entry);\n report(true);\n }\n }\n });\n };\n\n const po = observe('paint', handleEntries);\n\n if (po) {\n report = bindReporter(onReport, metric, FCPThresholds, opts.reportAllChanges);\n }\n });\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { bindReporter } from './lib/bindReporter';\nimport { initMetric } from './lib/initMetric';\nimport { observe } from './lib/observe';\nimport { onHidden } from './lib/onHidden';\nimport { runOnce } from './lib/runOnce';\nimport { onFCP } from './onFCP';\nimport type { CLSMetric, MetricRatingThresholds, ReportOpts } from './types';\n\n/** Thresholds for CLS. See https://web.dev/articles/cls#what_is_a_good_cls_score */\nexport const CLSThresholds: MetricRatingThresholds = [0.1, 0.25];\n\n/**\n * Calculates the [CLS](https://web.dev/articles/cls) value for the current page and\n * calls the `callback` function once the value is ready to be reported, along\n * with all `layout-shift` performance entries that were used in the metric\n * value calculation. The reported value is a `double` (corresponding to a\n * [layout shift score](https://web.dev/articles/cls#layout_shift_score)).\n *\n * If the `reportAllChanges` configuration option is set to `true`, the\n * `callback` function will be called as soon as the value is initially\n * determined as well as any time the value changes throughout the page\n * lifespan.\n *\n * _**Important:** CLS should be continually monitored for changes throughout\n * the entire lifespan of a page—including if the user returns to the page after\n * it's been hidden/backgrounded. However, since browsers often [will not fire\n * additional callbacks once the user has backgrounded a\n * page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden),\n * `callback` is always called when the page's visibility state changes to\n * hidden. As a result, the `callback` function might be called multiple times\n * during the same page load._\n */\nexport const onCLS = (onReport: (metric: CLSMetric) => void, opts: ReportOpts = {}) => {\n // Start monitoring FCP so we can only report CLS if FCP is also reported.\n // Note: this is done to match the current behavior of CrUX.\n onFCP(\n runOnce(() => {\n const metric = initMetric('CLS', 0);\n let report: ReturnType;\n\n let sessionValue = 0;\n let sessionEntries: LayoutShift[] = [];\n\n const handleEntries = (entries: LayoutShift[]) => {\n entries.forEach(entry => {\n // Only count layout shifts without recent user input.\n if (!entry.hadRecentInput) {\n const firstSessionEntry = sessionEntries[0];\n const lastSessionEntry = sessionEntries[sessionEntries.length - 1];\n\n // If the entry occurred less than 1 second after the previous entry\n // and less than 5 seconds after the first entry in the session,\n // include the entry in the current session. Otherwise, start a new\n // session.\n if (\n sessionValue &&\n firstSessionEntry &&\n lastSessionEntry &&\n entry.startTime - lastSessionEntry.startTime < 1000 &&\n entry.startTime - firstSessionEntry.startTime < 5000\n ) {\n sessionValue += entry.value;\n sessionEntries.push(entry);\n } else {\n sessionValue = entry.value;\n sessionEntries = [entry];\n }\n }\n });\n\n // If the current session value is larger than the current CLS value,\n // update CLS and the entries contributing to it.\n if (sessionValue > metric.value) {\n metric.value = sessionValue;\n metric.entries = sessionEntries;\n report();\n }\n };\n\n const po = observe('layout-shift', handleEntries);\n if (po) {\n report = bindReporter(onReport, metric, CLSThresholds, opts.reportAllChanges);\n\n onHidden(() => {\n handleEntries(po.takeRecords() as CLSMetric['entries']);\n report(true);\n });\n\n // Queue a task to report (if nothing else triggers a report first).\n // This allows CLS to be reported as soon as FCP fires when\n // `reportAllChanges` is true.\n setTimeout(report, 0);\n }\n }),\n );\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { bindReporter } from './lib/bindReporter';\nimport { getVisibilityWatcher } from './lib/getVisibilityWatcher';\nimport { initMetric } from './lib/initMetric';\nimport { observe } from './lib/observe';\nimport { onHidden } from './lib/onHidden';\nimport { runOnce } from './lib/runOnce';\nimport { whenActivated } from './lib/whenActivated';\nimport type { FIDMetric, MetricRatingThresholds, ReportOpts } from './types';\n\n/** Thresholds for FID. See https://web.dev/articles/fid#what_is_a_good_fid_score */\nexport const FIDThresholds: MetricRatingThresholds = [100, 300];\n\n/**\n * Calculates the [FID](https://web.dev/articles/fid) value for the current page and\n * calls the `callback` function once the value is ready, along with the\n * relevant `first-input` performance entry used to determine the value. The\n * reported value is a `DOMHighResTimeStamp`.\n *\n * _**Important:** since FID is only reported after the user interacts with the\n * page, it's possible that it will not be reported for some page loads._\n */\nexport const onFID = (onReport: (metric: FIDMetric) => void, opts: ReportOpts = {}) => {\n whenActivated(() => {\n const visibilityWatcher = getVisibilityWatcher();\n const metric = initMetric('FID');\n // eslint-disable-next-line prefer-const\n let report: ReturnType;\n\n const handleEntry = (entry: PerformanceEventTiming): void => {\n // Only report if the page wasn't hidden prior to the first input.\n if (entry.startTime < visibilityWatcher.firstHiddenTime) {\n metric.value = entry.processingStart - entry.startTime;\n metric.entries.push(entry);\n report(true);\n }\n };\n\n const handleEntries = (entries: FIDMetric['entries']) => {\n (entries as PerformanceEventTiming[]).forEach(handleEntry);\n };\n\n const po = observe('first-input', handleEntries);\n\n report = bindReporter(onReport, metric, FIDThresholds, opts.reportAllChanges);\n\n if (po) {\n onHidden(\n runOnce(() => {\n handleEntries(po.takeRecords() as FIDMetric['entries']);\n po.disconnect();\n }),\n );\n }\n });\n};\n","/*\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { observe } from '../observe';\n\ndeclare global {\n interface Performance {\n interactionCount: number;\n }\n}\n\nlet interactionCountEstimate = 0;\nlet minKnownInteractionId = Infinity;\nlet maxKnownInteractionId = 0;\n\nconst updateEstimate = (entries: PerformanceEventTiming[]) => {\n entries.forEach(e => {\n if (e.interactionId) {\n minKnownInteractionId = Math.min(minKnownInteractionId, e.interactionId);\n maxKnownInteractionId = Math.max(maxKnownInteractionId, e.interactionId);\n\n interactionCountEstimate = maxKnownInteractionId ? (maxKnownInteractionId - minKnownInteractionId) / 7 + 1 : 0;\n }\n });\n};\n\nlet po: PerformanceObserver | undefined;\n\n/**\n * Returns the `interactionCount` value using the native API (if available)\n * or the polyfill estimate in this module.\n */\nexport const getInteractionCount = (): number => {\n return po ? interactionCountEstimate : performance.interactionCount || 0;\n};\n\n/**\n * Feature detects native support or initializes the polyfill if needed.\n */\nexport const initInteractionCountPolyfill = (): void => {\n if ('interactionCount' in performance || po) return;\n\n po = observe('event', updateEstimate, {\n type: 'event',\n buffered: true,\n durationThreshold: 0,\n } as PerformanceObserverInit);\n};\n","/*\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getInteractionCount } from './polyfills/interactionCountPolyfill';\n\ninterface Interaction {\n id: number;\n latency: number;\n entries: PerformanceEventTiming[];\n}\n\ninterface EntryPreProcessingHook {\n (entry: PerformanceEventTiming): void;\n}\n\n// A list of longest interactions on the page (by latency) sorted so the\n// longest one is first. The list is at most MAX_INTERACTIONS_TO_CONSIDER long.\nexport const longestInteractionList: Interaction[] = [];\n\n// A mapping of longest interactions by their interaction ID.\n// This is used for faster lookup.\nexport const longestInteractionMap: Map = new Map();\n\n// The default `durationThreshold` used across this library for observing\n// `event` entries via PerformanceObserver.\nexport const DEFAULT_DURATION_THRESHOLD = 40;\n\n// Used to store the interaction count after a bfcache restore, since p98\n// interaction latencies should only consider the current navigation.\nlet prevInteractionCount = 0;\n\n/**\n * Returns the interaction count since the last bfcache restore (or for the\n * full page lifecycle if there were no bfcache restores).\n */\nconst getInteractionCountForNavigation = () => {\n return getInteractionCount() - prevInteractionCount;\n};\n\nexport const resetInteractions = () => {\n prevInteractionCount = getInteractionCount();\n longestInteractionList.length = 0;\n longestInteractionMap.clear();\n};\n\n/**\n * Returns the estimated p98 longest interaction based on the stored\n * interaction candidates and the interaction count for the current page.\n */\nexport const estimateP98LongestInteraction = () => {\n const candidateInteractionIndex = Math.min(\n longestInteractionList.length - 1,\n Math.floor(getInteractionCountForNavigation() / 50),\n );\n\n return longestInteractionList[candidateInteractionIndex];\n};\n\n// To prevent unnecessary memory usage on pages with lots of interactions,\n// store at most 10 of the longest interactions to consider as INP candidates.\nconst MAX_INTERACTIONS_TO_CONSIDER = 10;\n\n/**\n * A list of callback functions to run before each entry is processed.\n * Exposing this list allows the attribution build to hook into the\n * entry processing pipeline.\n */\nexport const entryPreProcessingCallbacks: EntryPreProcessingHook[] = [];\n\n/**\n * Takes a performance entry and adds it to the list of worst interactions\n * if its duration is long enough to make it among the worst. If the\n * entry is part of an existing interaction, it is merged and the latency\n * and entries list is updated as needed.\n */\nexport const processInteractionEntry = (entry: PerformanceEventTiming) => {\n entryPreProcessingCallbacks.forEach(cb => cb(entry));\n\n // Skip further processing for entries that cannot be INP candidates.\n if (!(entry.interactionId || entry.entryType === 'first-input')) return;\n\n // The least-long of the 10 longest interactions.\n const minLongestInteraction = longestInteractionList[longestInteractionList.length - 1];\n\n const existingInteraction = longestInteractionMap.get(entry.interactionId!);\n\n // Only process the entry if it's possibly one of the ten longest,\n // or if it's part of an existing interaction.\n if (\n existingInteraction ||\n longestInteractionList.length < MAX_INTERACTIONS_TO_CONSIDER ||\n (minLongestInteraction && entry.duration > minLongestInteraction.latency)\n ) {\n // If the interaction already exists, update it. Otherwise create one.\n if (existingInteraction) {\n // If the new entry has a longer duration, replace the old entries,\n // otherwise add to the array.\n if (entry.duration > existingInteraction.latency) {\n existingInteraction.entries = [entry];\n existingInteraction.latency = entry.duration;\n } else if (\n entry.duration === existingInteraction.latency &&\n entry.startTime === (existingInteraction.entries[0] && existingInteraction.entries[0].startTime)\n ) {\n existingInteraction.entries.push(entry);\n }\n } else {\n const interaction = {\n id: entry.interactionId!,\n latency: entry.duration,\n entries: [entry],\n };\n longestInteractionMap.set(interaction.id, interaction);\n longestInteractionList.push(interaction);\n }\n\n // Sort the entries by latency (descending) and keep only the top ten.\n longestInteractionList.sort((a, b) => b.latency - a.latency);\n if (longestInteractionList.length > MAX_INTERACTIONS_TO_CONSIDER) {\n longestInteractionList.splice(MAX_INTERACTIONS_TO_CONSIDER).forEach(i => longestInteractionMap.delete(i.id));\n }\n }\n};\n","/*\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../../types';\nimport { onHidden } from './onHidden';\nimport { runOnce } from './runOnce';\n\n/**\n * Runs the passed callback during the next idle period, or immediately\n * if the browser's visibility state is (or becomes) hidden.\n */\nexport const whenIdle = (cb: () => void): number => {\n const rIC = WINDOW.requestIdleCallback || WINDOW.setTimeout;\n\n let handle = -1;\n // eslint-disable-next-line no-param-reassign\n cb = runOnce(cb) as () => void;\n // If the document is hidden, run the callback immediately, otherwise\n // race an idle callback with the next `visibilitychange` event.\n if (WINDOW.document && WINDOW.document.visibilityState === 'hidden') {\n cb();\n } else {\n handle = rIC(cb);\n onHidden(cb);\n }\n return handle;\n};\n","/*\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../types';\nimport { bindReporter } from './lib/bindReporter';\nimport { initMetric } from './lib/initMetric';\nimport { DEFAULT_DURATION_THRESHOLD, estimateP98LongestInteraction, processInteractionEntry } from './lib/interactions';\nimport { observe } from './lib/observe';\nimport { onHidden } from './lib/onHidden';\nimport { initInteractionCountPolyfill } from './lib/polyfills/interactionCountPolyfill';\nimport { whenActivated } from './lib/whenActivated';\nimport { whenIdle } from './lib/whenIdle';\n\nimport type { INPMetric, MetricRatingThresholds, ReportOpts } from './types';\n\n/** Thresholds for INP. See https://web.dev/articles/inp#what_is_a_good_inp_score */\nexport const INPThresholds: MetricRatingThresholds = [200, 500];\n\n/**\n * Calculates the [INP](https://web.dev/articles/inp) value for the current\n * page and calls the `callback` function once the value is ready, along with\n * the `event` performance entries reported for that interaction. The reported\n * value is a `DOMHighResTimeStamp`.\n *\n * A custom `durationThreshold` configuration option can optionally be passed to\n * control what `event-timing` entries are considered for INP reporting. The\n * default threshold is `40`, which means INP scores of less than 40 are\n * reported as 0. Note that this will not affect your 75th percentile INP value\n * unless that value is also less than 40 (well below the recommended\n * [good](https://web.dev/articles/inp#what_is_a_good_inp_score) threshold).\n *\n * If the `reportAllChanges` configuration option is set to `true`, the\n * `callback` function will be called as soon as the value is initially\n * determined as well as any time the value changes throughout the page\n * lifespan.\n *\n * _**Important:** INP should be continually monitored for changes throughout\n * the entire lifespan of a page—including if the user returns to the page after\n * it's been hidden/backgrounded. However, since browsers often [will not fire\n * additional callbacks once the user has backgrounded a\n * page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden),\n * `callback` is always called when the page's visibility state changes to\n * hidden. As a result, the `callback` function might be called multiple times\n * during the same page load._\n */\nexport const onINP = (onReport: (metric: INPMetric) => void, opts: ReportOpts = {}) => {\n // Return if the browser doesn't support all APIs needed to measure INP.\n if (!('PerformanceEventTiming' in WINDOW && 'interactionId' in PerformanceEventTiming.prototype)) {\n return;\n }\n\n whenActivated(() => {\n // TODO(philipwalton): remove once the polyfill is no longer needed.\n initInteractionCountPolyfill();\n\n const metric = initMetric('INP');\n // eslint-disable-next-line prefer-const\n let report: ReturnType;\n\n const handleEntries = (entries: INPMetric['entries']) => {\n // Queue the `handleEntries()` callback in the next idle task.\n // This is needed to increase the chances that all event entries that\n // occurred between the user interaction and the next paint\n // have been dispatched. Note: there is currently an experiment\n // running in Chrome (EventTimingKeypressAndCompositionInteractionId)\n // 123+ that if rolled out fully may make this no longer necessary.\n whenIdle(() => {\n entries.forEach(processInteractionEntry);\n\n const inp = estimateP98LongestInteraction();\n\n if (inp && inp.latency !== metric.value) {\n metric.value = inp.latency;\n metric.entries = inp.entries;\n report();\n }\n });\n };\n\n const po = observe('event', handleEntries, {\n // Event Timing entries have their durations rounded to the nearest 8ms,\n // so a duration of 40ms would be any event that spans 2.5 or more frames\n // at 60Hz. This threshold is chosen to strike a balance between usefulness\n // and performance. Running this callback for any interaction that spans\n // just one or two frames is likely not worth the insight that could be\n // gained.\n durationThreshold: opts.durationThreshold != null ? opts.durationThreshold : DEFAULT_DURATION_THRESHOLD,\n });\n\n report = bindReporter(onReport, metric, INPThresholds, opts.reportAllChanges);\n\n if (po) {\n // Also observe entries of type `first-input`. This is useful in cases\n // where the first interaction is less than the `durationThreshold`.\n po.observe({ type: 'first-input', buffered: true });\n\n onHidden(() => {\n handleEntries(po.takeRecords() as INPMetric['entries']);\n report(true);\n });\n }\n });\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../types';\nimport { bindReporter } from './lib/bindReporter';\nimport { getActivationStart } from './lib/getActivationStart';\nimport { getVisibilityWatcher } from './lib/getVisibilityWatcher';\nimport { initMetric } from './lib/initMetric';\nimport { observe } from './lib/observe';\nimport { onHidden } from './lib/onHidden';\nimport { runOnce } from './lib/runOnce';\nimport { whenActivated } from './lib/whenActivated';\nimport { whenIdle } from './lib/whenIdle';\nimport type { LCPMetric, MetricRatingThresholds, ReportOpts } from './types';\n\n/** Thresholds for LCP. See https://web.dev/articles/lcp#what_is_a_good_lcp_score */\nexport const LCPThresholds: MetricRatingThresholds = [2500, 4000];\n\nconst reportedMetricIDs: Record = {};\n\n/**\n * Calculates the [LCP](https://web.dev/articles/lcp) value for the current page and\n * calls the `callback` function once the value is ready (along with the\n * relevant `largest-contentful-paint` performance entry used to determine the\n * value). The reported value is a `DOMHighResTimeStamp`.\n *\n * If the `reportAllChanges` configuration option is set to `true`, the\n * `callback` function will be called any time a new `largest-contentful-paint`\n * performance entry is dispatched, or once the final value of the metric has\n * been determined.\n */\nexport const onLCP = (onReport: (metric: LCPMetric) => void, opts: ReportOpts = {}) => {\n whenActivated(() => {\n const visibilityWatcher = getVisibilityWatcher();\n const metric = initMetric('LCP');\n let report: ReturnType;\n\n const handleEntries = (entries: LCPMetric['entries']) => {\n // If reportAllChanges is set then call this function for each entry,\n // otherwise only consider the last one.\n if (!opts.reportAllChanges) {\n // eslint-disable-next-line no-param-reassign\n entries = entries.slice(-1);\n }\n\n entries.forEach(entry => {\n // Only report if the page wasn't hidden prior to LCP.\n if (entry.startTime < visibilityWatcher.firstHiddenTime) {\n // The startTime attribute returns the value of the renderTime if it is\n // not 0, and the value of the loadTime otherwise. The activationStart\n // reference is used because LCP should be relative to page activation\n // rather than navigation start if the page was pre-rendered. But in cases\n // where `activationStart` occurs after the LCP, this time should be\n // clamped at 0.\n metric.value = Math.max(entry.startTime - getActivationStart(), 0);\n metric.entries = [entry];\n report();\n }\n });\n };\n\n const po = observe('largest-contentful-paint', handleEntries);\n\n if (po) {\n report = bindReporter(onReport, metric, LCPThresholds, opts.reportAllChanges);\n\n const stopListening = runOnce(() => {\n if (!reportedMetricIDs[metric.id]) {\n handleEntries(po.takeRecords() as LCPMetric['entries']);\n po.disconnect();\n reportedMetricIDs[metric.id] = true;\n report(true);\n }\n });\n\n // Stop listening after input. Note: while scrolling is an input that\n // stops LCP observation, it's unreliable since it can be programmatically\n // generated. See: https://github.com/GoogleChrome/web-vitals/issues/75\n ['keydown', 'click'].forEach(type => {\n // Wrap in a setTimeout so the callback is run in a separate task\n // to avoid extending the keyboard/click handler to reduce INP impact\n // https://github.com/GoogleChrome/web-vitals/issues/383\n if (WINDOW.document) {\n addEventListener(type, () => whenIdle(stopListening as () => void), {\n once: true,\n capture: true,\n });\n }\n });\n\n onHidden(stopListening);\n }\n });\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../types';\nimport { bindReporter } from './lib/bindReporter';\nimport { getActivationStart } from './lib/getActivationStart';\nimport { getNavigationEntry } from './lib/getNavigationEntry';\nimport { initMetric } from './lib/initMetric';\nimport { whenActivated } from './lib/whenActivated';\nimport type { MetricRatingThresholds, ReportOpts, TTFBMetric } from './types';\n\n/** Thresholds for TTFB. See https://web.dev/articles/ttfb#what_is_a_good_ttfb_score */\nexport const TTFBThresholds: MetricRatingThresholds = [800, 1800];\n\n/**\n * Runs in the next task after the page is done loading and/or prerendering.\n * @param callback\n */\nconst whenReady = (callback: () => void) => {\n if (WINDOW.document && WINDOW.document.prerendering) {\n whenActivated(() => whenReady(callback));\n } else if (WINDOW.document && WINDOW.document.readyState !== 'complete') {\n addEventListener('load', () => whenReady(callback), true);\n } else {\n // Queue a task so the callback runs after `loadEventEnd`.\n setTimeout(callback, 0);\n }\n};\n\n/**\n * Calculates the [TTFB](https://web.dev/articles/ttfb) value for the\n * current page and calls the `callback` function once the page has loaded,\n * along with the relevant `navigation` performance entry used to determine the\n * value. The reported value is a `DOMHighResTimeStamp`.\n *\n * Note, this function waits until after the page is loaded to call `callback`\n * in order to ensure all properties of the `navigation` entry are populated.\n * This is useful if you want to report on other metrics exposed by the\n * [Navigation Timing API](https://w3c.github.io/navigation-timing/). For\n * example, the TTFB metric starts from the page's [time\n * origin](https://www.w3.org/TR/hr-time-2/#sec-time-origin), which means it\n * includes time spent on DNS lookup, connection negotiation, network latency,\n * and server processing time.\n */\nexport const onTTFB = (onReport: (metric: TTFBMetric) => void, opts: ReportOpts = {}) => {\n const metric = initMetric('TTFB');\n const report = bindReporter(onReport, metric, TTFBThresholds, opts.reportAllChanges);\n\n whenReady(() => {\n const navigationEntry = getNavigationEntry();\n\n if (navigationEntry) {\n // The activationStart reference is used because TTFB should be\n // relative to page activation rather than navigation start if the\n // page was prerendered. But in cases where `activationStart` occurs\n // after the first byte is received, this time should be clamped at 0.\n metric.value = Math.max(navigationEntry.responseStart - getActivationStart(), 0);\n\n metric.entries = [navigationEntry];\n report(true);\n }\n });\n};\n","import { getFunctionName, logger } from '@sentry/core';\n\nimport { DEBUG_BUILD } from '../debug-build';\nimport { onCLS } from './web-vitals/getCLS';\nimport { onFID } from './web-vitals/getFID';\nimport { onINP } from './web-vitals/getINP';\nimport { onLCP } from './web-vitals/getLCP';\nimport { observe } from './web-vitals/lib/observe';\nimport { onTTFB } from './web-vitals/onTTFB';\n\ntype InstrumentHandlerTypePerformanceObserver =\n | 'longtask'\n | 'event'\n | 'navigation'\n | 'paint'\n | 'resource'\n | 'first-input';\n\ntype InstrumentHandlerTypeMetric = 'cls' | 'lcp' | 'fid' | 'ttfb' | 'inp';\n\n// We provide this here manually instead of relying on a global, as this is not available in non-browser environements\n// And we do not want to expose such types\ninterface PerformanceEntry {\n readonly duration: number;\n readonly entryType: string;\n readonly name: string;\n readonly startTime: number;\n toJSON(): Record;\n}\ninterface PerformanceEventTiming extends PerformanceEntry {\n processingStart: number;\n processingEnd: number;\n duration: number;\n cancelable?: boolean;\n target?: unknown | null;\n interactionId?: number;\n}\n\ninterface PerformanceScriptTiming extends PerformanceEntry {\n sourceURL: string;\n sourceFunctionName: string;\n sourceCharPosition: number;\n invoker: string;\n invokerType: string;\n}\nexport interface PerformanceLongAnimationFrameTiming extends PerformanceEntry {\n scripts: PerformanceScriptTiming[];\n}\n\ninterface Metric {\n /**\n * The name of the metric (in acronym form).\n */\n name: 'CLS' | 'FCP' | 'FID' | 'INP' | 'LCP' | 'TTFB';\n\n /**\n * The current value of the metric.\n */\n value: number;\n\n /**\n * The rating as to whether the metric value is within the \"good\",\n * \"needs improvement\", or \"poor\" thresholds of the metric.\n */\n rating: 'good' | 'needs-improvement' | 'poor';\n\n /**\n * The delta between the current value and the last-reported value.\n * On the first report, `delta` and `value` will always be the same.\n */\n delta: number;\n\n /**\n * A unique ID representing this particular metric instance. This ID can\n * be used by an analytics tool to dedupe multiple values sent for the same\n * metric instance, or to group multiple deltas together and calculate a\n * total. It can also be used to differentiate multiple different metric\n * instances sent from the same page, which can happen if the page is\n * restored from the back/forward cache (in that case new metrics object\n * get created).\n */\n id: string;\n\n /**\n * Any performance entries relevant to the metric value calculation.\n * The array may also be empty if the metric value was not based on any\n * entries (e.g. a CLS value of 0 given no layout shifts).\n */\n entries: PerformanceEntry[];\n\n /**\n * The type of navigation\n *\n * Navigation Timing API (or `undefined` if the browser doesn't\n * support that API). For pages that are restored from the bfcache, this\n * value will be 'back-forward-cache'.\n */\n navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'restore';\n}\n\ntype InstrumentHandlerType = InstrumentHandlerTypeMetric | InstrumentHandlerTypePerformanceObserver;\n\ntype StopListening = undefined | void | (() => void);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InstrumentHandlerCallback = (data: any) => void;\n\ntype CleanupHandlerCallback = () => void;\n\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\nlet _previousCls: Metric | undefined;\nlet _previousFid: Metric | undefined;\nlet _previousLcp: Metric | undefined;\nlet _previousTtfb: Metric | undefined;\nlet _previousInp: Metric | undefined;\n\n/**\n * Add a callback that will be triggered when a CLS metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called.\n * This will lead to the CLS being finalized and frozen.\n */\nexport function addClsInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a LCP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called.\n * This will lead to the LCP being finalized and frozen.\n */\nexport function addLcpInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a FID metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addFidInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('fid', callback, instrumentFid, _previousFid);\n}\n\n/**\n * Add a callback that will be triggered when a FID 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 INP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addInpInstrumentationHandler(\n callback: (data: { metric: Omit & { entries: PerformanceEventTiming[] } }) => void,\n): 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 || !typeHandlers.length) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n logger.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n\nfunction instrumentCls(): StopListening {\n return onCLS(\n metric => {\n triggerHandlers('cls', {\n metric,\n });\n _previousCls = metric;\n },\n // We want the callback to be called whenever the CLS value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: true },\n );\n}\n\nfunction instrumentFid(): void {\n return onFID(metric => {\n triggerHandlers('fid', {\n metric,\n });\n _previousFid = metric;\n });\n}\n\nfunction instrumentLcp(): StopListening {\n return onLCP(\n metric => {\n triggerHandlers('lcp', {\n metric,\n });\n _previousLcp = metric;\n },\n // We want the callback to be called whenever the LCP value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: true },\n );\n}\n\nfunction instrumentTtfb(): StopListening {\n return onTTFB(metric => {\n triggerHandlers('ttfb', {\n metric,\n });\n _previousTtfb = metric;\n });\n}\n\nfunction instrumentInp(): void {\n return onINP(metric => {\n triggerHandlers('inp', {\n metric,\n });\n _previousInp = metric;\n });\n}\n\nfunction addMetricObserver(\n type: InstrumentHandlerTypeMetric,\n callback: InstrumentHandlerCallback,\n instrumentFn: () => StopListening,\n previousValue: Metric | undefined,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n let stopListening: StopListening | undefined;\n\n if (!instrumented[type]) {\n stopListening = instrumentFn();\n instrumented[type] = true;\n }\n\n if (previousValue) {\n callback({ metric: previousValue });\n }\n\n return getCleanupCallback(type, callback, stopOnCallback ? stopListening : undefined);\n}\n\nfunction instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObserver): void {\n const options: PerformanceObserverInit = {};\n\n // Special per-type options we want to use\n if (type === 'event') {\n options.durationThreshold = 0;\n }\n\n observe(\n type,\n entries => {\n triggerHandlers(type, { entries });\n },\n options,\n );\n}\n\nfunction addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n (handlers[type] as InstrumentHandlerCallback[]).push(handler);\n}\n\n// Get a callback which can be called to remove the instrumentation handler\nfunction getCleanupCallback(\n type: InstrumentHandlerType,\n callback: InstrumentHandlerCallback,\n stopListening: StopListening,\n): CleanupHandlerCallback {\n return () => {\n if (stopListening) {\n stopListening();\n }\n\n const typeHandlers = handlers[type];\n\n if (!typeHandlers) {\n return;\n }\n\n const index = typeHandlers.indexOf(callback);\n if (index !== -1) {\n typeHandlers.splice(index, 1);\n }\n };\n}\n\n/**\n * Check if a PerformanceEntry is a PerformanceEventTiming by checking for the `duration` property.\n */\nexport function isPerformanceEventTiming(entry: PerformanceEntry): entry is PerformanceEventTiming {\n return 'duration' in entry;\n}\n","/*\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getNavigationEntry } from './getNavigationEntry';\n\nexport const getActivationStart = (): number => {\n const navEntry = getNavigationEntry();\n return (navEntry && navEntry.activationStart) || 0;\n};\n","/*\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../../types';\n\n// sentry-specific change:\n// add optional param to not check for responseStart (see comment below)\nexport const getNavigationEntry = (checkResponseStart = true): PerformanceNavigationTiming | void => {\n const navigationEntry =\n WINDOW.performance && WINDOW.performance.getEntriesByType && WINDOW.performance.getEntriesByType('navigation')[0];\n // Check to ensure the `responseStart` property is present and valid.\n // In some cases no value is reported by the browser (for\n // privacy/security reasons), and in other cases (bugs) the value is\n // negative or is larger than the current page time. Ignore these cases:\n // https://github.com/GoogleChrome/web-vitals/issues/137\n // https://github.com/GoogleChrome/web-vitals/issues/162\n // https://github.com/GoogleChrome/web-vitals/issues/275\n if (\n // sentry-specific change:\n // We don't want to check for responseStart for our own use of `getNavigationEntry`\n !checkResponseStart ||\n (navigationEntry && navigationEntry.responseStart > 0 && navigationEntry.responseStart < performance.now())\n ) {\n return navigationEntry;\n }\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../../types';\n\nlet firstHiddenTime = -1;\n\nconst initHiddenTime = () => {\n // If the document is hidden when this code runs, assume it was always\n // hidden and the page was loaded in the background, with the one exception\n // that visibility state is always 'hidden' during prerendering, so we have\n // to ignore that case until prerendering finishes (see: `prerenderingchange`\n // event logic below).\n return WINDOW.document!.visibilityState === 'hidden' && !WINDOW.document!.prerendering ? 0 : Infinity;\n};\n\nconst onVisibilityUpdate = (event: Event) => {\n // If the document is 'hidden' and no previous hidden timestamp has been\n // set, update it based on the current event data.\n if (WINDOW.document!.visibilityState === 'hidden' && firstHiddenTime > -1) {\n // If the event is a 'visibilitychange' event, it means the page was\n // visible prior to this change, so the event timestamp is the first\n // hidden time.\n // However, if the event is not a 'visibilitychange' event, then it must\n // be a 'prerenderingchange' event, and the fact that the document is\n // still 'hidden' from the above check means the tab was activated\n // in a background state and so has always been hidden.\n firstHiddenTime = event.type === 'visibilitychange' ? event.timeStamp : 0;\n\n // Remove all listeners now that a `firstHiddenTime` value has been set.\n removeChangeListeners();\n }\n};\n\nconst addChangeListeners = () => {\n addEventListener('visibilitychange', onVisibilityUpdate, true);\n // IMPORTANT: when a page is prerendering, its `visibilityState` is\n // 'hidden', so in order to account for cases where this module checks for\n // visibility during prerendering, an additional check after prerendering\n // completes is also required.\n addEventListener('prerenderingchange', onVisibilityUpdate, true);\n};\n\nconst removeChangeListeners = () => {\n removeEventListener('visibilitychange', onVisibilityUpdate, true);\n removeEventListener('prerenderingchange', onVisibilityUpdate, true);\n};\n\nexport const getVisibilityWatcher = () => {\n if (WINDOW.document && firstHiddenTime < 0) {\n // If the document is hidden when this code runs, assume it was hidden\n // since navigation start. This isn't a perfect heuristic, but it's the\n // best we can do until an API is available to support querying past\n // visibilityState.\n firstHiddenTime = initHiddenTime();\n addChangeListeners();\n }\n return {\n get firstHiddenTime() {\n return firstHiddenTime;\n },\n };\n};\n","/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../../types';\n\nexport interface OnHiddenCallback {\n (event: Event): void;\n}\n\n// Sentry-specific change:\n// This function's logic was NOT updated to web-vitals 4.2.4 but we continue\n// to use the web-vitals 3.5.2 due to us having stricter browser support.\n// PR with context that made the changes: https://github.com/GoogleChrome/web-vitals/pull/442/files#r1530492402\n// The PR removed listening to the `pagehide` event, in favour of only listening to `visibilitychange` event.\n// This is \"more correct\" but some browsers we still support (Safari 12.1-14.0) don't fully support `visibilitychange`\n// or have known bugs w.r.t the `visibilitychange` event.\n// TODO (v9): If we decide to drop support for Safari 12.1-14.0, we can use the logic from web-vitals 4.2.4\n// In this case, we also need to update the integration tests that currently trigger the `pagehide` event to\n// simulate the page being hidden.\nexport const onHidden = (cb: OnHiddenCallback) => {\n const onHiddenOrPageHide = (event: Event) => {\n if (event.type === 'pagehide' || (WINDOW.document && WINDOW.document.visibilityState === 'hidden')) {\n cb(event);\n }\n };\n\n if (WINDOW.document) {\n addEventListener('visibilitychange', onHiddenOrPageHide, true);\n // Some browsers have buggy implementations of visibilitychange,\n // so we use pagehide in addition, just to be safe.\n addEventListener('pagehide', onHiddenOrPageHide, true);\n }\n};\n","import { GLOBAL_OBJ } from '@sentry/core';\n\nexport const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ &\n // document is not available in all browser environments (webworkers). We make it optional so you have to explicitly check for it\n Omit &\n Partial>;\n"],"names":["DEBUG_BUILD","cachedImplementations","getNativeImplementation","name","cached","impl","bind","document","createElement","sandbox","hidden","head","appendChild","contentWindow","removeChild","e","clearCachedImplementation","undefined","setTimeout","rest","debounceTimerID","lastCapturedEventType","lastCapturedEventTargetId","addClickKeypressInstrumentationHandler","handler","instrumentDOM","triggerDOMHandler","globalDOMEventHandler","makeDOMEventHandler","forEach","target","targetObj","proto","prototype","hasOwnProperty","originalAddEventListener","type","listener","options","handlers","this","__sentry_instrumentation_handlers__","handlerForType","refCount","call","originalRemoveEventListener","Object","keys","length","globalListener","event","getEventTarget","eventType","tagName","isContentEditable","shouldSkipDOMEvent","_sentryId","isSimilarToLastCapturedEvent","global","clearTimeout","SENTRY_XHR_DATA_KEY","addXhrInstrumentationHandler","instrumentXHR","xhrproto","XMLHttpRequest","open","Proxy","apply","originalOpen","xhrOpenThisArg","xhrOpenArgArray","startTimestamp","method","toUpperCase","url","toString","parseUrl","request_headers","match","__sentry_own_request__","onreadystatechangeHandler","xhrInfo","readyState","status_code","status","handlerData","endTimestamp","xhr","onreadystatechange","originalOnreadystatechange","onreadystatechangeThisArg","onreadystatechangeArgArray","addEventListener","setRequestHeader","originalSetRequestHeader","setRequestHeaderThisArg","setRequestHeaderArgArray","header","value","toLowerCase","send","originalSend","sendThisArg","sendArgArray","sentryXhrData","body","trackClsAsStandaloneSpan","standaloneClsEntry","pageloadSpanId","standaloneCLsValue","PerformanceObserver","supportedEntryTypes","includes","supportsLayoutShift","sentSpan","_collectClsOnce","clsValue","entry","logger","log","startTime","routeName","getScopeData","transactionName","sources","node","attributes","duration","span","transaction","addEvent","end","sendStandaloneClsSpan","cleanupClsHandler","metric","entries","onHidden","client","unsubscribeStartNavigation","on","activeSpan","rootSpan","spanJSON","op","spanContext","spanId","_lcpEntry","_clsEntry","_performanceCursor","_measurements","startTrackingWebVitals","recordClsStandaloneSpans","performance","mark","fidCleanupCallback","lcpCleanupCallback","ttfbCleanupCallback","clsCleanupCallback","startTrackingLongTasks","parent","parentOp","start_timestamp","parentStartTimestamp","startTrackingLongAnimationFrames","list","getEntries","scripts","initialScript","invoker","invokerType","sourceURL","sourceFunctionName","sourceCharPosition","observe","buffered","startTrackingInteractions","spanOptions","fidMark","LAST_INTERACTIONS","INTERACTIONS_SPAN_MAP","Map","startTrackingINP","inpCallback","find","INP_ENTRY_MAP","interactionId","interactionType","spanToUse","get","description","click","pointerdown","pointerup","mousedown","mouseup","touchstart","touchend","mouseover","mouseout","mouseenter","mouseleave","pointerover","pointerout","pointerenter","pointerleave","dragstart","dragend","drag","dragenter","dragleave","dragover","drop","keydown","keyup","keypress","input","bindReporter","callback","thresholds","reportAllChanges","prevValue","delta","forceReport","rating","getRating","initMetric","navEntry","getNavigationEntry","navigationType","getActivationStart","replace","id","Date","now","Math","floor","random","opts","po","Promise","resolve","then","assign","runOnce","cb","called","whenActivated","FCPThresholds","CLSThresholds","onCLS","onReport","visibilityWatcher","getVisibilityWatcher","report","disconnect","firstHiddenTime","max","push","onFCP","sessionValue","sessionEntries","handleEntries","hadRecentInput","firstSessionEntry","lastSessionEntry","takeRecords","FIDThresholds","interactionCountEstimate","minKnownInteractionId","Infinity","maxKnownInteractionId","updateEstimate","min","initInteractionCountPolyfill","durationThreshold","longestInteractionList","longestInteractionMap","getInteractionCountForNavigation","interactionCount","entryPreProcessingCallbacks","processInteractionEntry","entryType","minLongestInteraction","existingInteraction","latency","interaction","set","sort","a","b","splice","i","delete","whenIdle","rIC","handle","INPThresholds","onINP","PerformanceEventTiming","inp","candidateInteractionIndex","estimateP98LongestInteraction","LCPThresholds","reportedMetricIDs","TTFBThresholds","whenReady","instrumented","_previousCls","_previousFid","_previousLcp","_previousTtfb","_previousInp","addClsInstrumentationHandler","stopOnCallback","addMetricObserver","instrumentCls","addLcpInstrumentationHandler","instrumentLcp","addFidInstrumentationHandler","instrumentFid","addTtfbInstrumentationHandler","instrumentTtfb","addInpInstrumentationHandler","instrumentInp","addPerformanceInstrumentationHandler","addHandler","triggerHandlers","instrumentPerformanceObserver","getCleanupCallback","data","typeHandlers","handleEntry","processingStart","onFID","slice","stopListening","once","capture","onLCP","navigationEntry","responseStart","onTTFB","instrumentFn","previousValue","index","indexOf","isPerformanceEventTiming","activationStart","checkResponseStart","onVisibilityUpdate","timeStamp","removeChangeListeners","removeEventListener","onHiddenOrPageHide","WINDOW"],"sourceRoot":""}