{"version":3,"sources":["../src/modules/webvitals.ts"],"sourcesContent":["import { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals/attribution'\n\nimport type { FeedbackApi, FeedbackApiInternal, WebVitalEntry } from '../types'\nimport { scrubCredentials } from '../capture/scrub'\n\nexport interface WebVitalsOptions {\n  reportAllChanges?: boolean\n}\n\n// web-vitals/attribution returns DOM-pointer fields like `lcpElement`,\n// `largestShiftTarget`, `eventTarget` — selectors derived from real DOM\n// content. Hosts commonly bake PII into element ids (\"#user-bob-row\",\n// \"[data-email='bob@x.com']\") so we scrub the same patterns the\n// console/error capture paths scrub, before the payload leaves the page.\n//\n// Audit R6/F2: attribution objects nest. `lcpResourceEntry.name`,\n// `lcpEntry.name`, `processedEventEntries[].name`, `largestShiftSources`\n// all carry URLs (often with OAuth tokens / email querystrings) one or\n// more levels down. Recurse so nested string leaves get the same scrub\n// as top-level fields.\nfunction _sanitizeAttribution(value: unknown, depth = 0): unknown {\n  if (depth > 4) return undefined  // bound recursion against pathological inputs\n  if (value == null) return value\n  if (typeof value === 'string') return scrubCredentials(value).slice(0, 200)\n  if (typeof value !== 'object') return value\n  if (Array.isArray(value)) return value.map((item) => _sanitizeAttribution(item, depth + 1))\n  // Strip PerformanceEntry instances down to their useful fields so we don't\n  // serialize a huge object graph (and don't leak `responseHeaders` etc.).\n  const out: Record<string, unknown> = {}\n  for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n    out[k] = _sanitizeAttribution(v, depth + 1)\n  }\n  return out\n}\n\nexport function withWebVitals(fb: FeedbackApi, options: WebVitalsOptions = {}): FeedbackApi {\n  const internal = fb as FeedbackApiInternal\n  if (typeof internal._registerTransformer !== 'function') return fb\n\n  const entries = new Map<string, WebVitalEntry>()\n  const record = (metric: { name: string; value: number; rating: string; attribution?: unknown }) => {\n    const attribution = metric.attribution !== undefined\n      ? _sanitizeAttribution(metric.attribution)\n      : undefined\n    entries.set(metric.name, {\n      name: metric.name as WebVitalEntry['name'],\n      value: metric.value,\n      rating: metric.rating as WebVitalEntry['rating'],\n      ...(attribution !== undefined && { attribution }),\n    })\n  }\n\n  const opts = { reportAllChanges: options.reportAllChanges ?? false }\n  try {\n    onCLS(record, opts)\n    onINP(record, opts)\n    onLCP(record, opts)\n    onFCP(record, opts)\n    onTTFB(record, opts)\n  } catch { /* unsupported env */ }\n\n  internal._registerTransformer((payload) => ({\n    ...payload,\n    technical_context: {\n      ...payload.technical_context,\n      webVitals: Array.from(entries.values()),\n    },\n  }))\n\n  return fb\n}\n"],"mappings":";;;;;AAAA,SAAS,OAAO,OAAO,OAAO,OAAO,cAAc;AAoBnD,SAAS,qBAAqB,OAAgB,QAAQ,GAAY;AAChE,MAAI,QAAQ,EAAG,QAAO;AACtB,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,OAAO,UAAU,SAAU,QAAO,iBAAiB,KAAK,EAAE,MAAM,GAAG,GAAG;AAC1E,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,CAAC,SAAS,qBAAqB,MAAM,QAAQ,CAAC,CAAC;AAG1F,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAgC,GAAG;AACrE,QAAI,CAAC,IAAI,qBAAqB,GAAG,QAAQ,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAEO,SAAS,cAAc,IAAiB,UAA4B,CAAC,GAAgB;AAC1F,QAAM,WAAW;AACjB,MAAI,OAAO,SAAS,yBAAyB,WAAY,QAAO;AAEhE,QAAM,UAAU,oBAAI,IAA2B;AAC/C,QAAM,SAAS,CAAC,WAAmF;AACjG,UAAM,cAAc,OAAO,gBAAgB,SACvC,qBAAqB,OAAO,WAAW,IACvC;AACJ,YAAQ,IAAI,OAAO,MAAM;AAAA,MACvB,MAAM,OAAO;AAAA,MACb,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,GAAI,gBAAgB,UAAa,EAAE,YAAY;AAAA,IACjD,CAAC;AAAA,EACH;AAEA,QAAM,OAAO,EAAE,kBAAkB,QAAQ,oBAAoB,MAAM;AACnE,MAAI;AACF,UAAM,QAAQ,IAAI;AAClB,UAAM,QAAQ,IAAI;AAClB,UAAM,QAAQ,IAAI;AAClB,UAAM,QAAQ,IAAI;AAClB,WAAO,QAAQ,IAAI;AAAA,EACrB,QAAQ;AAAA,EAAwB;AAEhC,WAAS,qBAAqB,CAAC,aAAa;AAAA,IAC1C,GAAG;AAAA,IACH,mBAAmB;AAAA,MACjB,GAAG,QAAQ;AAAA,MACX,WAAW,MAAM,KAAK,QAAQ,OAAO,CAAC;AAAA,IACxC;AAAA,EACF,EAAE;AAEF,SAAO;AACT;","names":[]}