Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
1 line
14 KiB
Plaintext
1 line
14 KiB
Plaintext
{"version":3,"file":"instrument.js","sources":["../../../src/metrics/instrument.ts"],"sourcesContent":["import { debug, getFunctionName } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { onCLS } from './web-vitals/getCLS';\nimport { onINP } from './web-vitals/getINP';\nimport { onLCP } from './web-vitals/getLCP';\nimport { observe } from './web-vitals/lib/observe';\nimport { onTTFB } from './web-vitals/onTTFB';\n\ntype InstrumentHandlerTypePerformanceObserver =\n | 'longtask'\n | 'event'\n | 'navigation'\n | 'paint'\n | 'resource'\n | 'element'\n // fist-input is still needed for INP\n | 'first-input';\n\ntype InstrumentHandlerTypeMetric = 'cls' | 'lcp' | 'ttfb' | 'inp';\n\n// We provide this here manually instead of relying on a global, as this is not available in non-browser environements\n// And we do not want to expose such types\ninterface PerformanceEntry {\n readonly duration: number;\n readonly entryType: string;\n readonly name: string;\n readonly startTime: number;\n toJSON(): Record<string, unknown>;\n}\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' | 'INP' | 'LCP' | 'TTFB';\n\n /**\n * The current value of the metric.\n */\n value: number;\n\n /**\n * The rating as to whether the metric value is within the \"good\",\n * \"needs improvement\", or \"poor\" thresholds of the metric.\n */\n rating: 'good' | 'needs-improvement' | 'poor';\n\n /**\n * The delta between the current value and the last-reported value.\n * On the first report, `delta` and `value` will always be the same.\n */\n delta: number;\n\n /**\n * A unique ID representing this particular metric instance. This ID can\n * be used by an analytics tool to dedupe multiple values sent for the same\n * metric instance, or to group multiple deltas together and calculate a\n * total. It can also be used to differentiate multiple different metric\n * instances sent from the same page, which can happen if the page is\n * restored from the back/forward cache (in that case new metrics object\n * get created).\n */\n id: string;\n\n /**\n * Any performance entries relevant to the metric value calculation.\n * The array may also be empty if the metric value was not based on any\n * entries (e.g. a CLS value of 0 given no layout shifts).\n */\n entries: PerformanceEntry[];\n\n /**\n * The type of navigation\n *\n * Navigation Timing API (or `undefined` if the browser doesn't\n * support that API). For pages that are restored from the bfcache, this\n * value will be 'back-forward-cache'.\n */\n navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'restore';\n}\n\ntype InstrumentHandlerType = InstrumentHandlerTypeMetric | InstrumentHandlerTypePerformanceObserver;\n\ntype StopListening = undefined | void | (() => void);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InstrumentHandlerCallback = (data: any) => void;\n\ntype CleanupHandlerCallback = () => void;\n\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\nlet _previousCls: Metric | undefined;\nlet _previousLcp: Metric | undefined;\nlet _previousTtfb: Metric | undefined;\nlet _previousInp: Metric | undefined;\n\n/**\n * Add a callback that will be triggered when a CLS metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called.\n * This will lead to the CLS being finalized and frozen.\n */\nexport function addClsInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a LCP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n *\n * Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called.\n * This will lead to the LCP being finalized and frozen.\n */\nexport function addLcpInstrumentationHandler(\n callback: (data: { metric: Metric }) => void,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback);\n}\n\n/**\n * Add a callback that will be triggered when a TTFD metric is available.\n */\nexport function addTtfbInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {\n return addMetricObserver('ttfb', callback, instrumentTtfb, _previousTtfb);\n}\n\nexport type InstrumentationHandlerCallback = (data: {\n metric: Omit<Metric, 'entries'> & {\n entries: PerformanceEventTiming[];\n };\n}) => void;\n\n/**\n * Add a callback that will be triggered when a INP metric is available.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addInpInstrumentationHandler(callback: InstrumentationHandlerCallback): CleanupHandlerCallback {\n return addMetricObserver('inp', callback, instrumentInp, _previousInp);\n}\n\nexport function addPerformanceInstrumentationHandler(\n type: 'event',\n callback: (data: { entries: ((PerformanceEntry & { target?: unknown | null }) | PerformanceEventTiming)[] }) => void,\n): CleanupHandlerCallback;\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback;\n\n/**\n * Add a callback that will be triggered when a performance observer is triggered,\n * and receives the entries of the observer.\n * Returns a cleanup callback which can be called to remove the instrumentation handler.\n */\nexport function addPerformanceInstrumentationHandler(\n type: InstrumentHandlerTypePerformanceObserver,\n callback: (data: { entries: PerformanceEntry[] }) => void,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n if (!instrumented[type]) {\n instrumentPerformanceObserver(type);\n instrumented[type] = true;\n }\n\n return getCleanupCallback(type, callback);\n}\n\n/** Trigger all handlers of a given type. */\nfunction triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = handlers[type];\n\n if (!typeHandlers?.length) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n debug.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n\nfunction instrumentCls(): StopListening {\n return onCLS(\n metric => {\n triggerHandlers('cls', {\n metric,\n });\n _previousCls = metric;\n },\n // We want the callback to be called whenever the CLS value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: true },\n );\n}\n\nfunction instrumentLcp(): StopListening {\n return onLCP(\n metric => {\n triggerHandlers('lcp', {\n metric,\n });\n _previousLcp = metric;\n },\n // We want the callback to be called whenever the LCP value updates.\n // By default, the callback is only called when the tab goes to the background.\n { reportAllChanges: true },\n );\n}\n\nfunction instrumentTtfb(): StopListening {\n return onTTFB(metric => {\n triggerHandlers('ttfb', {\n metric,\n });\n _previousTtfb = metric;\n });\n}\n\nfunction instrumentInp(): void {\n return onINP(metric => {\n triggerHandlers('inp', {\n metric,\n });\n _previousInp = metric;\n });\n}\n\nfunction addMetricObserver(\n type: InstrumentHandlerTypeMetric,\n callback: InstrumentHandlerCallback,\n instrumentFn: () => StopListening,\n previousValue: Metric | undefined,\n stopOnCallback = false,\n): CleanupHandlerCallback {\n addHandler(type, callback);\n\n let stopListening: StopListening | undefined;\n\n if (!instrumented[type]) {\n stopListening = instrumentFn();\n instrumented[type] = true;\n }\n\n if (previousValue) {\n callback({ metric: previousValue });\n }\n\n return getCleanupCallback(type, callback, stopOnCallback ? stopListening : undefined);\n}\n\nfunction instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObserver): void {\n const options: PerformanceObserverInit = {};\n\n // Special per-type options we want to use\n if (type === 'event') {\n options.durationThreshold = 0;\n }\n\n observe(\n type,\n entries => {\n triggerHandlers(type, { entries });\n },\n options,\n );\n}\n\nfunction addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n handlers[type].push(handler);\n}\n\n// Get a callback which can be called to remove the instrumentation handler\nfunction getCleanupCallback(\n type: InstrumentHandlerType,\n callback: InstrumentHandlerCallback,\n stopListening: StopListening,\n): CleanupHandlerCallback {\n return () => {\n if (stopListening) {\n stopListening();\n }\n\n const typeHandlers = handlers[type];\n\n if (!typeHandlers) {\n return;\n }\n\n const index = typeHandlers.indexOf(callback);\n if (index !== -1) {\n typeHandlers.splice(index, 1);\n }\n };\n}\n\n/**\n * Check if a PerformanceEntry is a PerformanceEventTiming by checking for the `duration` property.\n */\nexport function isPerformanceEventTiming(entry: PerformanceEntry): entry is PerformanceEventTiming {\n return 'duration' in entry;\n}\n"],"names":["DEBUG_BUILD","debug","getFunctionName","onCLS","onLCP","onTTFB","onINP","observe"],"mappings":"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"} |