{"version":3,"file":"WebVitalsInstrumentation.cjs","names":["KEY_EMB_WEB_VITAL_ATTRIBUTION_PREFIX","MAX_LOAF_SCRIPT_URL_LENGTH","EmbraceInstrumentationBase","WEB_VITALS_ID_TO_LISTENER","page","KEY_EMB_TYPE","ATTR_URL_FULL","KEY_BROWSER_URL_FULL","KEY_EMB_WEB_VITAL_NAVIGATION_TYPE","KEY_EMB_WEB_VITAL_NAME","KEY_EMB_WEB_VITAL_RATING","KEY_EMB_WEB_VITAL_ID","KEY_EMB_WEB_VITAL_DELTA","KEY_EMB_WEB_VITAL_VALUE","KEY_EMB_PAGE_PATH","KEY_EMB_PAGE_ID","KEY_APP_SURFACE_LABEL","EMB_WEB_VITALS_PREFIX"],"sources":["../../../../src/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.ts"],"sourcesContent":["import type {\n  Attributes,\n  AttributeValue,\n  DiagLogger,\n} from '@opentelemetry/api';\nimport { ATTR_URL_FULL } from '@opentelemetry/semantic-conventions';\nimport type {\n  CLSMetricWithAttribution,\n  INPAttribution,\n  Metric,\n  MetricWithAttribution,\n  TTFBAttribution,\n} from 'web-vitals/attribution';\nimport type { PageManager } from '../../../api-page/index.ts';\nimport { page } from '../../../api-page/index.ts';\nimport type { URLDocument } from '../../../common/index.ts';\nimport {\n  EMB_TYPES,\n  KEY_APP_SURFACE_LABEL,\n  KEY_BROWSER_URL_FULL,\n  KEY_EMB_PAGE_ID,\n  KEY_EMB_PAGE_PATH,\n  KEY_EMB_TYPE,\n} from '../../../constants/index.ts';\nimport { EmbraceInstrumentationBase } from '../../EmbraceInstrumentationBase/index.ts';\nimport {\n  KEY_EMB_WEB_VITAL_ATTRIBUTION_PREFIX,\n  KEY_EMB_WEB_VITAL_DELTA,\n  KEY_EMB_WEB_VITAL_ID,\n  KEY_EMB_WEB_VITAL_NAME,\n  KEY_EMB_WEB_VITAL_NAVIGATION_TYPE,\n  KEY_EMB_WEB_VITAL_RATING,\n  KEY_EMB_WEB_VITAL_VALUE,\n} from './attributes.ts';\nimport {\n  ALL_WEB_VITALS,\n  EMB_WEB_VITALS_PREFIX,\n  MAX_LOAF_SCRIPT_ENTRIES,\n  MAX_LOAF_SCRIPT_URL_LENGTH,\n  WEB_VITALS_ID_TO_LISTENER,\n} from './constants.ts';\nimport type {\n  WebVitalListeners,\n  WebVitalsInstrumentationArgs,\n} from './types.ts';\n\ntype AttributedPage = {\n  fullURL: string;\n  path?: string;\n  pageID?: string;\n  label?: string;\n};\n\nconst isPrimitiveValue = (value: unknown): value is AttributeValue => {\n  const type = typeof value;\n  return type === 'number' || type === 'string' || type === 'boolean';\n};\n\nconst roundClamp = (value: number): number => Math.round(Math.max(0, value));\n\nconst webVitalAttributionToReport = (\n  metric: MetricWithAttribution,\n): Attributes => {\n  const attributes: Attributes = {};\n  const attribution = metric.attribution;\n\n  if (!attribution || typeof attribution !== 'object') {\n    return attributes;\n  }\n\n  for (const [key, value] of Object.entries(attribution)) {\n    if (isPrimitiveValue(value)) {\n      attributes[`${KEY_EMB_WEB_VITAL_ATTRIBUTION_PREFIX}${key}`] = value;\n    }\n  }\n\n  return attributes;\n};\n\nconst loafScriptsAttribution = (\n  metric: MetricWithAttribution,\n  diag: DiagLogger,\n): Attributes => {\n  const attributes: Attributes = {};\n  const attribution = metric.attribution as INPAttribution;\n\n  try {\n    // suppress LoAF baseline errors\n    /* eslint-disable baseline-js/use-baseline */\n    if (attribution.longAnimationFrameEntries.length > 0) {\n      const scripts = new Map<\n        string,\n        {\n          totalDuration: number;\n          styleAndLayoutDuration: number;\n          count: number;\n        }\n      >();\n      for (const entry of attribution.longAnimationFrameEntries) {\n        for (const script of entry.scripts) {\n          let url = script.sourceURL || '(inline)';\n          if (url.length > MAX_LOAF_SCRIPT_URL_LENGTH) {\n            url = `${url.substring(0, MAX_LOAF_SCRIPT_URL_LENGTH)}...`;\n          }\n          const existing = scripts.get(url);\n          if (existing) {\n            existing.totalDuration += script.duration;\n            existing.styleAndLayoutDuration +=\n              script.forcedStyleAndLayoutDuration;\n            existing.count++;\n          } else {\n            scripts.set(url, {\n              totalDuration: script.duration,\n              styleAndLayoutDuration: script.forcedStyleAndLayoutDuration,\n              count: 1,\n            });\n          }\n        }\n      }\n      if (scripts.size > 0) {\n        attributes[`${KEY_EMB_WEB_VITAL_ATTRIBUTION_PREFIX}loaf_scripts`] =\n          JSON.stringify(\n            Object.fromEntries(\n              [...scripts]\n                .sort((a, b) => b[1].totalDuration - a[1].totalDuration)\n                .slice(0, MAX_LOAF_SCRIPT_ENTRIES)\n                .map(([url, script]) => [\n                  url,\n                  {\n                    total_duration: Math.round(script.totalDuration),\n                    style_and_layout_duration: Math.round(\n                      script.styleAndLayoutDuration,\n                    ),\n                    count: script.count,\n                  },\n                ]),\n            ),\n          );\n      }\n    }\n    /* eslint-enable baseline-js/use-baseline */\n  } catch (e) {\n    diag.error('error building loaf scripts for INP', e);\n  }\n\n  return attributes;\n};\n\nconst ttfbSubPartsAttribution = (\n  metric: MetricWithAttribution,\n  diag: DiagLogger,\n): Attributes => {\n  const attributes: Attributes = {};\n  const attribution = metric.attribution as TTFBAttribution;\n  const entry = attribution.navigationEntry as\n    | PerformanceNavigationTiming\n    | undefined;\n\n  if (entry) {\n    try {\n      const redirect = roundClamp(entry.redirectEnd - entry.redirectStart);\n      const domainLookup = roundClamp(\n        entry.domainLookupEnd - entry.domainLookupStart,\n      );\n      const tcpConnection = roundClamp(\n        entry.secureConnectionStart > 0\n          ? entry.secureConnectionStart - entry.connectStart\n          : entry.connectEnd - entry.connectStart,\n      );\n      const tlsNegotiation = roundClamp(\n        entry.secureConnectionStart > 0\n          ? entry.connectEnd - entry.secureConnectionStart\n          : 0,\n      );\n      const effectiveResponseStart = Math.max(\n        // @ts-expect-error 103 Early hints are not supported in all browsers\n        // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/finalResponseHeadersStart\n        entry.finalResponseHeadersStart ?? 0,\n        entry.responseStart,\n      );\n      const serverResponse = roundClamp(\n        effectiveResponseStart - entry.requestStart,\n      );\n      const total = Math.round(entry.responseEnd - entry.startTime);\n      const unattributed = roundClamp(\n        total -\n          redirect -\n          domainLookup -\n          tcpConnection -\n          tlsNegotiation -\n          serverResponse,\n      );\n      const prefix = KEY_EMB_WEB_VITAL_ATTRIBUTION_PREFIX;\n      attributes[`${prefix}redirect`] = redirect;\n      attributes[`${prefix}domainLookup`] = domainLookup;\n      attributes[`${prefix}tcpConnection`] = tcpConnection;\n      attributes[`${prefix}tlsNegotiation`] = tlsNegotiation;\n      attributes[`${prefix}serverResponse`] = serverResponse;\n      attributes[`${prefix}unattributed`] = unattributed;\n    } catch (e) {\n      diag.error('error computing TTFB timing breakdown', e);\n    }\n  } else {\n    diag.debug('TTFB navigationEntry unavailable, skipping timing breakdown');\n  }\n\n  return attributes;\n};\n\nexport class WebVitalsInstrumentation extends EmbraceInstrumentationBase {\n  private readonly _listeners: WebVitalListeners;\n  private readonly _urlDocument: URLDocument;\n  private readonly _urlAttribution: boolean;\n  private readonly _pageManager: PageManager;\n  private readonly _attributedPage: Record<\n    Metric['name'],\n    AttributedPage | undefined\n  > = {\n    INP: undefined,\n    LCP: undefined,\n    CLS: undefined,\n    FCP: undefined,\n    TTFB: undefined,\n  };\n  private _largestShiftTargetForCLS: string | undefined;\n  private _listenersRegistered = false;\n  private _isEnabled = false;\n\n  // instrumentation that adds an event to the session span for each web vital report\n  public constructor({\n    diag,\n    perf,\n    listeners = WEB_VITALS_ID_TO_LISTENER,\n    urlDocument = window.document,\n    urlAttribution = true,\n    pageManager,\n  }: WebVitalsInstrumentationArgs = {}) {\n    super({\n      instrumentationName: 'WebVitalsInstrumentation',\n      instrumentationVersion: '1.0.0',\n      diag,\n      perf,\n      config: {},\n    });\n    this._listeners = listeners;\n    this._urlDocument = urlDocument;\n    this._urlAttribution = urlAttribution;\n    this._pageManager = pageManager ?? page.getPageManager();\n\n    if (this._config.enabled) {\n      this.enable();\n    }\n  }\n\n  public override disable(): void {\n    // web-vitals library doesn't support removing listeners, so we just pause emission\n    // https://github.com/GoogleChrome/web-vitals/issues/357#issuecomment-1593439036\n    this._isEnabled = false;\n    this._diag.debug('WebVitalsInstrumentation disabled, pausing emission');\n  }\n\n  public enable(): void {\n    this._isEnabled = true;\n\n    // web-vitals library doesn't support removing listeners, so only register once\n    if (this._listenersRegistered) {\n      this._diag.debug(\n        'WebVitalsInstrumentation listeners already registered, resuming emission',\n      );\n      return;\n    }\n    this._listenersRegistered = true;\n\n    ALL_WEB_VITALS.forEach((name) => {\n      this._listeners[name]?.((metric) => {\n        if (!this._isEnabled) {\n          return;\n        }\n\n        const currentSessionSpan = this.sessionManager.getSessionSpan();\n\n        if (!currentSessionSpan) {\n          return;\n        }\n\n        // first thing record the time when this cb was invoked\n        const metricTime = this._getTimeForMetric(metric);\n\n        const attributedPage = this._getAttributedPageForMetric(metric);\n\n        const attrs: Attributes = {\n          [KEY_EMB_TYPE]: EMB_TYPES.WebVital,\n          [ATTR_URL_FULL]: attributedPage.fullURL,\n          [KEY_BROWSER_URL_FULL]: attributedPage.fullURL,\n          [KEY_EMB_WEB_VITAL_NAVIGATION_TYPE]: metric.navigationType,\n          [KEY_EMB_WEB_VITAL_NAME]: metric.name,\n          [KEY_EMB_WEB_VITAL_RATING]: metric.rating,\n          [KEY_EMB_WEB_VITAL_ID]: metric.id,\n          [KEY_EMB_WEB_VITAL_DELTA]: metric.delta,\n          [KEY_EMB_WEB_VITAL_VALUE]: metric.value,\n          ...webVitalAttributionToReport(metric),\n          ...(name === 'INP' ? loafScriptsAttribution(metric, this._diag) : {}),\n          ...(name === 'TTFB'\n            ? ttfbSubPartsAttribution(metric, this._diag)\n            : {}),\n        };\n\n        // Add page attributes if route and page ID exist\n        if (attributedPage.path && attributedPage.pageID) {\n          attrs[KEY_EMB_PAGE_PATH] = attributedPage.path;\n          attrs[KEY_EMB_PAGE_ID] = attributedPage.pageID;\n        }\n\n        if (attributedPage.label) {\n          attrs[KEY_APP_SURFACE_LABEL] = attributedPage.label;\n        }\n\n        currentSessionSpan.addEvent(\n          `${EMB_WEB_VITALS_PREFIX}-report-${name}`,\n          attrs,\n          metricTime,\n        );\n      });\n    });\n\n    if (this._urlAttribution) {\n      // When these web vitals make their final report (e.g. when the listeners w/ reportAllChanges=false trigger) the\n      // document's URL at that time may not match what it was at the time the scores were last updated. Instead, listen\n      // for updates to the scores and keep track of the Page information to attribute for each\n      this._listeners.TTFB?.(\n        () => {\n          this._attributedPage.TTFB = this._currentAttributedPage();\n        },\n        {\n          reportAllChanges: true,\n        },\n      );\n      this._listeners.FCP?.(\n        () => {\n          this._attributedPage.FCP = this._currentAttributedPage();\n        },\n        {\n          reportAllChanges: true,\n        },\n      );\n      this._listeners.INP?.(\n        () => {\n          this._attributedPage.INP = this._currentAttributedPage();\n        },\n        {\n          reportAllChanges: true,\n        },\n      );\n      this._listeners.LCP?.(\n        () => {\n          this._attributedPage.LCP = this._currentAttributedPage();\n        },\n        {\n          reportAllChanges: true,\n        },\n      );\n      this._listeners.CLS?.(\n        (metric: MetricWithAttribution) => {\n          const clsMetric = metric as CLSMetricWithAttribution;\n          // A layout shift could cause CLS to change its rating but because the score is cumulative this might not\n          // correspond with an updated `largestShiftTarget`. Since we want to tie the attributed URL to the page that\n          // the `largestShiftTarget` was on we only update the attributed URL if that target has changed\n          if (\n            this._largestShiftTargetForCLS !==\n            clsMetric.attribution.largestShiftTarget\n          ) {\n            this._largestShiftTargetForCLS =\n              clsMetric.attribution.largestShiftTarget;\n            this._attributedPage.CLS = this._currentAttributedPage();\n          }\n        },\n        {\n          reportAllChanges: true,\n        },\n      );\n    }\n  }\n\n  private _getTimeForMetric(metric: MetricWithAttribution): number {\n    if (metric.name === 'CLS' && metric.attribution.largestShiftTime) {\n      return this.perf.epochMillisFromOriginOffset(\n        metric.attribution.largestShiftTime,\n      );\n    }\n\n    if (metric.name === 'INP' && metric.attribution.interactionTime) {\n      return this.perf.epochMillisFromOriginOffset(\n        metric.attribution.interactionTime,\n      );\n    }\n\n    return this.perf.getNowMillis();\n  }\n\n  private _currentAttributedPage(): AttributedPage {\n    const attributed: AttributedPage = {\n      fullURL: this._urlDocument.URL,\n    };\n\n    const currentRoute = this._pageManager.getCurrentRoute();\n    const currentPageId = this._pageManager.getCurrentPageId();\n    if (currentRoute && currentPageId) {\n      attributed.path = currentRoute.path;\n      attributed.pageID = currentPageId;\n    }\n\n    const pageLabel = this._pageManager.getPageLabel();\n    if (pageLabel) {\n      attributed.label = pageLabel;\n    }\n\n    return attributed;\n  }\n\n  private _getAttributedPageForMetric(\n    metric: MetricWithAttribution,\n  ): AttributedPage {\n    if (metric.name === 'FCP' && this._attributedPage.FCP) {\n      return this._attributedPage.FCP;\n    }\n\n    if (metric.name === 'TTFB' && this._attributedPage.TTFB) {\n      return this._attributedPage.TTFB;\n    }\n\n    if (metric.name === 'INP' && this._attributedPage.INP) {\n      return this._attributedPage.INP;\n    }\n\n    if (metric.name === 'LCP' && this._attributedPage.LCP) {\n      return this._attributedPage.LCP;\n    }\n\n    if (\n      metric.name === 'CLS' &&\n      this._attributedPage.CLS &&\n      metric.attribution.largestShiftTarget === this._largestShiftTargetForCLS\n    ) {\n      return this._attributedPage.CLS;\n    }\n\n    return this._currentAttributedPage();\n  }\n}\n"],"mappings":"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"}