@diegotsi/flint-core 1.1.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ // src/integrations/datadog.ts
2
+ var DATADOG_BLOCKED_HOSTS = [
3
+ "browser-intake-datadoghq.com",
4
+ "rum.browser-intake-datadoghq.com",
5
+ "logs.browser-intake-datadoghq.com",
6
+ "session-replay.browser-intake-datadoghq.com"
7
+ ];
8
+ function createDatadogReplayProvider(site) {
9
+ return () => {
10
+ try {
11
+ const ddRum = window.DD_RUM;
12
+ const ctx = ddRum?.getInternalContext?.();
13
+ if (ctx?.session_id) {
14
+ const ts = Date.now();
15
+ const fromTs = ts - 3e4;
16
+ const toTs = ts + 5e3;
17
+ return `https://${site}/rum/replay/sessions/${ctx.session_id}?from_ts=${fromTs}&to_ts=${toTs}&tab=replay&live=false`;
18
+ }
19
+ } catch {
20
+ }
21
+ return void 0;
22
+ };
23
+ }
24
+
25
+ export {
26
+ DATADOG_BLOCKED_HOSTS,
27
+ createDatadogReplayProvider
28
+ };
29
+ //# sourceMappingURL=chunk-HVSD45YR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/integrations/datadog.ts"],"sourcesContent":["/**\n * Datadog RUM integration — opt-in helper.\n *\n * Usage:\n * import { Flint } from \"@diegotsi/flint-core\";\n * import { createDatadogReplayProvider, DATADOG_BLOCKED_HOSTS } from \"@diegotsi/flint-core\";\n *\n * Flint.init({\n * projectKey: \"...\",\n * serverUrl: \"...\",\n * externalReplayProvider: createDatadogReplayProvider(\"app.datadoghq.com\"),\n * blockedHosts: DATADOG_BLOCKED_HOSTS,\n * });\n */\n\n/** Datadog intake hosts to exclude from network capture. */\nexport const DATADOG_BLOCKED_HOSTS = [\n \"browser-intake-datadoghq.com\",\n \"rum.browser-intake-datadoghq.com\",\n \"logs.browser-intake-datadoghq.com\",\n \"session-replay.browser-intake-datadoghq.com\",\n];\n\n/**\n * Creates an `externalReplayProvider` that reads the current Datadog RUM\n * session and returns a deep link to the Session Replay viewer.\n */\nexport function createDatadogReplayProvider(site: string): () => string | undefined {\n return () => {\n try {\n const ddRum = (window as unknown as Record<string, unknown>).DD_RUM as\n | { getInternalContext?: () => { session_id?: string } | undefined }\n | undefined;\n const ctx = ddRum?.getInternalContext?.();\n if (ctx?.session_id) {\n const ts = Date.now();\n const fromTs = ts - 30_000;\n const toTs = ts + 5_000;\n return `https://${site}/rum/replay/sessions/${ctx.session_id}?from_ts=${fromTs}&to_ts=${toTs}&tab=replay&live=false`;\n }\n } catch {\n // DD_RUM not available — silently skip\n }\n return undefined;\n };\n}\n"],"mappings":";AAgBO,IAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,SAAS,4BAA4B,MAAwC;AAClF,SAAO,MAAM;AACX,QAAI;AACF,YAAM,QAAS,OAA8C;AAG7D,YAAM,MAAM,OAAO,qBAAqB;AACxC,UAAI,KAAK,YAAY;AACnB,cAAM,KAAK,KAAK,IAAI;AACpB,cAAM,SAAS,KAAK;AACpB,cAAM,OAAO,KAAK;AAClB,eAAO,WAAW,IAAI,wBAAwB,IAAI,UAAU,YAAY,MAAM,UAAU,IAAI;AAAA,MAC9F;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -0,0 +1,9 @@
1
+ import {
2
+ DATADOG_BLOCKED_HOSTS,
3
+ createDatadogReplayProvider
4
+ } from "./chunk-HVSD45YR.js";
5
+ export {
6
+ DATADOG_BLOCKED_HOSTS,
7
+ createDatadogReplayProvider
8
+ };
9
+ //# sourceMappingURL=datadog-I3QKI6Q3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/index.cjs CHANGED
@@ -3,6 +3,9 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __esm = (fn, res) => function __init() {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ };
6
9
  var __export = (target, all) => {
7
10
  for (var name in all)
8
11
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -17,17 +20,53 @@ var __copyProps = (to, from, except, desc) => {
17
20
  };
18
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
22
 
23
+ // src/integrations/datadog.ts
24
+ var datadog_exports = {};
25
+ __export(datadog_exports, {
26
+ DATADOG_BLOCKED_HOSTS: () => DATADOG_BLOCKED_HOSTS,
27
+ createDatadogReplayProvider: () => createDatadogReplayProvider
28
+ });
29
+ function createDatadogReplayProvider(site) {
30
+ return () => {
31
+ try {
32
+ const ddRum = window.DD_RUM;
33
+ const ctx = ddRum?.getInternalContext?.();
34
+ if (ctx?.session_id) {
35
+ const ts = Date.now();
36
+ const fromTs = ts - 3e4;
37
+ const toTs = ts + 5e3;
38
+ return `https://${site}/rum/replay/sessions/${ctx.session_id}?from_ts=${fromTs}&to_ts=${toTs}&tab=replay&live=false`;
39
+ }
40
+ } catch {
41
+ }
42
+ return void 0;
43
+ };
44
+ }
45
+ var DATADOG_BLOCKED_HOSTS;
46
+ var init_datadog = __esm({
47
+ "src/integrations/datadog.ts"() {
48
+ "use strict";
49
+ DATADOG_BLOCKED_HOSTS = [
50
+ "browser-intake-datadoghq.com",
51
+ "rum.browser-intake-datadoghq.com",
52
+ "logs.browser-intake-datadoghq.com",
53
+ "session-replay.browser-intake-datadoghq.com"
54
+ ];
55
+ }
56
+ });
57
+
20
58
  // src/index.ts
21
59
  var index_exports = {};
22
60
  __export(index_exports, {
61
+ DATADOG_BLOCKED_HOSTS: () => DATADOG_BLOCKED_HOSTS,
23
62
  Flint: () => Flint,
24
63
  _setFormErrorCollector: () => _setFormErrorCollector,
25
64
  collectEnvironment: () => collectEnvironment,
26
65
  createConsoleCollector: () => createConsoleCollector,
66
+ createDatadogReplayProvider: () => createDatadogReplayProvider,
27
67
  createFormErrorCollector: () => createFormErrorCollector,
28
68
  createFrustrationCollector: () => createFrustrationCollector,
29
69
  createNetworkCollector: () => createNetworkCollector,
30
- flint: () => flint,
31
70
  getSnapshot: () => getSnapshot,
32
71
  resolveTheme: () => resolveTheme,
33
72
  submitReplay: () => submitReplay,
@@ -581,17 +620,10 @@ function createFrustrationCollector(opts) {
581
620
 
582
621
  // src/collectors/network.ts
583
622
  var MAX_ENTRIES3 = 50;
584
- var BLOCKED_HOSTS = /* @__PURE__ */ new Set([
585
- "browser-intake-datadoghq.com",
586
- "rum.browser-intake-datadoghq.com",
587
- "logs.browser-intake-datadoghq.com",
588
- "session-replay.browser-intake-datadoghq.com"
589
- ]);
590
- function isBlockedUrl(url, extra) {
623
+ function isBlockedUrl(url, blocked) {
591
624
  try {
592
625
  const host = new URL(url, location.href).hostname;
593
- const all = [...BLOCKED_HOSTS, ...extra];
594
- return all.some((b) => host === b || host.endsWith("." + b));
626
+ return [...blocked].some((b) => host === b || host.endsWith("." + b));
595
627
  } catch {
596
628
  return false;
597
629
  }
@@ -666,6 +698,9 @@ function createNetworkCollector(extraBlockedHosts = []) {
666
698
  };
667
699
  }
668
700
 
701
+ // src/index.ts
702
+ init_datadog();
703
+
669
704
  // src/store.ts
670
705
  var formErrorCollectorRef = null;
671
706
  function _setFormErrorCollector(collector) {
@@ -710,6 +745,9 @@ var flint = {
710
745
  // src/singleton.ts
711
746
  var DEFAULT_REPLAY_BUFFER_MS = 6e4;
712
747
  var instance = null;
748
+ function debugLog(config, ...args) {
749
+ if (config.debug) console.log("[Flint]", ...args);
750
+ }
713
751
  function init(config) {
714
752
  if (instance) {
715
753
  console.warn("[Flint] Already initialized. Call Flint.shutdown() first to re-initialize.");
@@ -726,8 +764,17 @@ function init(config) {
726
764
  blockedHosts = [],
727
765
  frustration: frustrationOpts,
728
766
  onFrustration,
729
- _replayRecorder
767
+ _replayRecorder,
768
+ _collectors
730
769
  } = config;
770
+ debugLog(config, "Initializing", {
771
+ serverUrl: config.serverUrl,
772
+ enableConsole,
773
+ enableNetwork,
774
+ enableFormErrors,
775
+ enableFrustration,
776
+ enableReplay
777
+ });
731
778
  const flintHost = (() => {
732
779
  try {
733
780
  return new URL(config.serverUrl).hostname;
@@ -735,9 +782,10 @@ function init(config) {
735
782
  return "";
736
783
  }
737
784
  })();
738
- const consoleCol = enableConsole ? createConsoleCollector() : null;
785
+ const allBlockedHosts = [...blockedHosts, ...flintHost ? [flintHost] : []];
786
+ const consoleCol = enableConsole ? _collectors?.console?.() ?? createConsoleCollector() : null;
739
787
  consoleCol?.start();
740
- const networkCol = enableNetwork ? createNetworkCollector([...blockedHosts, ...flintHost ? [flintHost] : []]) : null;
788
+ const networkCol = enableNetwork ? _collectors?.network?.(allBlockedHosts) ?? createNetworkCollector(allBlockedHosts) : null;
741
789
  networkCol?.start();
742
790
  const formErrorsCol = enableFormErrors ? createFormErrorCollector() : null;
743
791
  if (formErrorsCol) {
@@ -751,6 +799,12 @@ function init(config) {
751
799
  }
752
800
  const replayEvents = [];
753
801
  let stopReplay = null;
802
+ debugLog(config, "Collectors started", {
803
+ console: !!consoleCol,
804
+ network: !!networkCol,
805
+ formErrors: !!formErrorsCol,
806
+ frustration: !!frustrationCol
807
+ });
754
808
  instance = {
755
809
  config,
756
810
  console: consoleCol,
@@ -772,8 +826,10 @@ function init(config) {
772
826
  if (instance) instance.stopReplay = stopReplay;
773
827
  });
774
828
  }
829
+ const getEnvironment = _collectors?.environment ?? collectEnvironment;
775
830
  if (frustrationCol && autoReportFrustration) {
776
831
  frustrationCol.onFrustration(async (event) => {
832
+ debugLog(config, "Frustration detected, auto-reporting:", event.type, event.details);
777
833
  onFrustration?.(event);
778
834
  const user = getSnapshot().user ?? config.user;
779
835
  await submitReport(config.serverUrl, config.projectKey, {
@@ -783,9 +839,10 @@ function init(config) {
783
839
  description: `[Auto-detected] ${event.type.replace(/_/g, " ")}: ${event.details}`,
784
840
  severity: event.type === "error_loop" ? "P1" : event.type === "rage_click" ? "P2" : "P3",
785
841
  url: event.url,
842
+ source: "auto_capture",
786
843
  meta: {
787
844
  ...config.meta,
788
- environment: collectEnvironment(),
845
+ environment: getEnvironment(),
789
846
  consoleLogs: consoleCol?.getEntries() ?? [],
790
847
  networkErrors: networkCol?.getEntries() ?? [],
791
848
  formErrors: formErrorsCol?.getEntries() ?? [],
@@ -797,6 +854,33 @@ function init(config) {
797
854
  } else if (frustrationCol && onFrustration) {
798
855
  frustrationCol.onFrustration(onFrustration);
799
856
  }
857
+ if (!config.externalReplayProvider) {
858
+ fetchProjectConfig(config.serverUrl, config.projectKey).then((remote) => {
859
+ if (!instance || !remote?.integrations) return;
860
+ const dd = remote.integrations.datadog;
861
+ if (dd?.enabled && dd.site) {
862
+ Promise.resolve().then(() => (init_datadog(), datadog_exports)).then(({ createDatadogReplayProvider: createDatadogReplayProvider2 }) => {
863
+ if (!instance) return;
864
+ instance.config = {
865
+ ...instance.config,
866
+ externalReplayProvider: createDatadogReplayProvider2(dd.site)
867
+ };
868
+ debugLog(config, "Remote Datadog integration loaded:", dd.site);
869
+ });
870
+ }
871
+ }).catch(() => {
872
+ });
873
+ }
874
+ }
875
+ async function fetchProjectConfig(serverUrl, projectKey) {
876
+ try {
877
+ const url = `${serverUrl.replace(/\/$/, "")}/api/v1/project-config`;
878
+ const res = await fetch(url, { headers: { "x-project-key": projectKey } });
879
+ if (!res.ok) return null;
880
+ return res.json();
881
+ } catch {
882
+ return null;
883
+ }
800
884
  }
801
885
  function shutdown() {
802
886
  if (!instance) return;
@@ -815,9 +899,10 @@ function getInstance() {
815
899
  return instance;
816
900
  }
817
901
  function getMeta(extraMeta) {
902
+ const getEnvironment = instance?.config._collectors?.environment ?? collectEnvironment;
818
903
  return {
819
904
  ...extraMeta,
820
- environment: collectEnvironment(),
905
+ environment: getEnvironment(),
821
906
  consoleLogs: instance?.console?.getEntries() ?? [],
822
907
  networkErrors: instance?.network?.getEntries() ?? [],
823
908
  formErrors: instance?.formErrors?.getEntries() ?? []
@@ -829,6 +914,12 @@ function getReplayEvents() {
829
914
  function getConfig() {
830
915
  return instance?.config ?? null;
831
916
  }
917
+ function getExternalReplayUrl() {
918
+ const storeReplay = getSnapshot().sessionReplay;
919
+ const fromStore = typeof storeReplay === "function" ? storeReplay() : storeReplay;
920
+ if (fromStore) return fromStore;
921
+ return instance?.config.externalReplayProvider?.();
922
+ }
832
923
  var Flint = {
833
924
  init,
834
925
  shutdown,
@@ -837,6 +928,7 @@ var Flint = {
837
928
  getMeta,
838
929
  getReplayEvents,
839
930
  getConfig,
931
+ getExternalReplayUrl,
840
932
  setUser: flint.setUser,
841
933
  setSessionReplay: flint.setSessionReplay,
842
934
  reportFormError: flint.reportFormError
@@ -882,14 +974,15 @@ function resolveTheme(theme) {
882
974
  }
883
975
  // Annotate the CommonJS export names for ESM import in node:
884
976
  0 && (module.exports = {
977
+ DATADOG_BLOCKED_HOSTS,
885
978
  Flint,
886
979
  _setFormErrorCollector,
887
980
  collectEnvironment,
888
981
  createConsoleCollector,
982
+ createDatadogReplayProvider,
889
983
  createFormErrorCollector,
890
984
  createFrustrationCollector,
891
985
  createNetworkCollector,
892
- flint,
893
986
  getSnapshot,
894
987
  resolveTheme,
895
988
  submitReplay,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/api.ts","../src/collectors/console.ts","../src/collectors/environment.ts","../src/collectors/formErrors.ts","../src/collectors/frustration.ts","../src/collectors/network.ts","../src/store.ts","../src/singleton.ts","../src/theme.ts"],"sourcesContent":["// Collectors\n\n// API\nexport { submitReplay, submitReport } from \"./api.js\";\n// Collector types\nexport type { ConsoleCollector } from \"./collectors/console.js\";\nexport { createConsoleCollector } from \"./collectors/console.js\";\nexport { collectEnvironment } from \"./collectors/environment.js\";\nexport type { FormErrorCollector } from \"./collectors/formErrors.js\";\nexport { createFormErrorCollector } from \"./collectors/formErrors.js\";\nexport type { FrustrationCollector, FrustrationEvent } from \"./collectors/frustration.js\";\nexport { createFrustrationCollector } from \"./collectors/frustration.js\";\nexport type { NetworkCollector } from \"./collectors/network.js\";\nexport { createNetworkCollector } from \"./collectors/network.js\";\n// Singleton\nexport { Flint } from \"./singleton.js\";\nexport type { FlintState } from \"./store.js\";\n// State\nexport { _setFormErrorCollector, flint, getSnapshot, subscribe } from \"./store.js\";\nexport type { ResolvedTheme } from \"./theme.js\";\n// Theme\nexport { resolveTheme } from \"./theme.js\";\n// Types (re-export)\nexport type {\n CollectedMeta,\n ConsoleEntry,\n EnvironmentInfo,\n FlintConfig,\n FlintExtraFields,\n FlintUser,\n FlintWidgetProps,\n FormErrorEntry,\n Locale,\n NetworkEntry,\n ReportPayload,\n ReportResult,\n Severity,\n Theme,\n ThemeOverride,\n} from \"./types.js\";\n","import { gzipSync } from \"fflate\";\nimport type { ReportPayload, ReportResult } from \"./types.js\";\n\nasync function fetchWithRetry(url: string, init: RequestInit, retries = 3, baseDelay = 1000): Promise<Response> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n const res = await fetch(url, init);\n if (res.ok || attempt === retries) return res;\n // Don't retry client errors (4xx) except 429\n if (res.status >= 400 && res.status < 500 && res.status !== 429) return res;\n } catch (err) {\n if (attempt === retries) throw err;\n }\n await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));\n }\n throw new Error(\"Max retries exceeded\");\n}\n\nexport async function submitReport(\n serverUrl: string,\n projectKey: string,\n payload: ReportPayload,\n screenshot?: File,\n): Promise<ReportResult> {\n const url = `${serverUrl.replace(/\\/$/, \"\")}/api/v1/bug-reports`;\n\n let body: BodyInit;\n const headers: Record<string, string> = {\n \"x-project-key\": projectKey,\n };\n\n if (screenshot) {\n const form = new FormData();\n form.append(\"reporterId\", payload.reporterId);\n form.append(\"reporterName\", payload.reporterName);\n if (payload.reporterEmail) form.append(\"reporterEmail\", payload.reporterEmail);\n form.append(\"description\", payload.description);\n if (payload.expectedBehavior) form.append(\"expectedBehavior\", payload.expectedBehavior);\n if (payload.stepsToReproduce) form.append(\"stepsToReproduce\", JSON.stringify(payload.stepsToReproduce));\n if (payload.externalReplayUrl) form.append(\"externalReplayUrl\", payload.externalReplayUrl);\n if (payload.additionalContext) form.append(\"additionalContext\", payload.additionalContext);\n form.append(\"severity\", payload.severity);\n if (payload.url) form.append(\"url\", payload.url);\n if (payload.meta) form.append(\"meta\", JSON.stringify(payload.meta));\n form.append(\"screenshot\", screenshot);\n body = form;\n } else {\n body = JSON.stringify(payload);\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const res = await fetchWithRetry(url, { method: \"POST\", headers, body });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: \"Unknown error\" }));\n throw new Error((err as { error?: string }).error ?? `HTTP ${res.status}`);\n }\n\n return res.json() as Promise<ReportResult>;\n}\n\nexport async function submitReplay(\n serverUrl: string,\n projectKey: string,\n reportId: string,\n events: unknown[],\n): Promise<void> {\n const json = JSON.stringify(events);\n const encoded = new TextEncoder().encode(json);\n const compressed = gzipSync(encoded);\n\n const url = `${serverUrl.replace(/\\/$/, \"\")}/api/v1/bug-reports/${reportId}/replay`;\n await fetch(url, {\n method: \"POST\",\n headers: {\n \"x-project-key\": projectKey,\n \"Content-Type\": \"application/octet-stream\",\n },\n body: compressed.buffer as ArrayBuffer,\n });\n}\n","import type { ConsoleEntry } from \"../types.js\";\n\nconst MAX_ENTRIES = 50;\n\n// Redact values that look like tokens, passwords, secrets, or API keys\nconst SENSITIVE_PATTERNS = [\n /(?:password|passwd|pwd|secret|token|api[_-]?key|access[_-]?key|authorization|bearer)\\s*[:=]\\s*[\"']?[^\\s\"',]{4,}/gi,\n /\\b(sk-[a-zA-Z0-9_-]{20,})\\b/g, // API keys (e.g. sk-ant-...)\n /\\b(ghp_[a-zA-Z0-9]{36,})\\b/g, // GitHub tokens\n /\\b(xoxb-[a-zA-Z0-9-]+)\\b/g, // Slack tokens\n /\\b(eyJ[a-zA-Z0-9_-]{10,}\\.[a-zA-Z0-9_-]{10,})\\b/g, // JWTs\n];\n\nfunction sanitize(str: string): string {\n let result = str;\n for (const pattern of SENSITIVE_PATTERNS) {\n result = result.replace(pattern, \"[REDACTED]\");\n }\n return result;\n}\n\nexport interface ConsoleCollector {\n start(): void;\n stop(): void;\n getEntries(): ConsoleEntry[];\n}\n\nexport function createConsoleCollector(): ConsoleCollector {\n const entries: ConsoleEntry[] = [];\n let active = false;\n\n const originals = {\n log: console.log.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n };\n\n let origOnerror: typeof window.onerror = null;\n let origUnhandled: typeof window.onunhandledrejection = null;\n\n function push(level: ConsoleEntry[\"level\"], args: unknown[]) {\n let str: string;\n try {\n str = args.map((a) => (typeof a === \"string\" ? a : JSON.stringify(a))).join(\" \");\n } catch {\n str = String(args[0]);\n }\n if (str.length > 500) str = str.slice(0, 500) + \"\\u2026\";\n str = sanitize(str);\n entries.push({ level, args: str, timestamp: Date.now() });\n if (entries.length > MAX_ENTRIES) entries.shift();\n }\n\n return {\n start() {\n if (active) return;\n active = true;\n\n console.log = (...args: unknown[]) => {\n push(\"log\", args);\n originals.log(...args);\n };\n console.warn = (...args: unknown[]) => {\n push(\"warn\", args);\n originals.warn(...args);\n };\n console.error = (...args: unknown[]) => {\n push(\"error\", args);\n originals.error(...args);\n };\n\n origOnerror = window.onerror;\n window.onerror = (msg, src, line, col, err) => {\n push(\"error\", [err?.message ?? String(msg), `${src}:${line}:${col}`]);\n if (typeof origOnerror === \"function\") return origOnerror(msg, src, line, col, err);\n return false;\n };\n\n origUnhandled = window.onunhandledrejection;\n window.onunhandledrejection = (event) => {\n const reason = event.reason instanceof Error ? event.reason.message : JSON.stringify(event.reason);\n push(\"error\", [\"UnhandledRejection:\", reason]);\n if (typeof origUnhandled === \"function\") origUnhandled.call(window, event);\n };\n },\n\n stop() {\n if (!active) return;\n active = false;\n console.log = originals.log;\n console.warn = originals.warn;\n console.error = originals.error;\n window.onerror = origOnerror;\n window.onunhandledrejection = origUnhandled;\n },\n\n getEntries() {\n return [...entries];\n },\n };\n}\n","import type { EnvironmentInfo } from \"../types.js\";\n\nexport function collectEnvironment(): EnvironmentInfo {\n const ua = navigator.userAgent;\n\n // -- Browser --\n let browser = \"Unknown\";\n const chromeM = ua.match(/Chrome\\/(\\d+)/);\n const firefoxM = ua.match(/Firefox\\/(\\d+)/);\n const edgeM = ua.match(/Edg\\/(\\d+)/);\n const safariM = ua.match(/Version\\/(\\d+)/);\n const operaM = ua.match(/OPR\\/(\\d+)/);\n\n if (operaM) {\n browser = `Opera ${operaM[1]}`;\n } else if (edgeM) {\n browser = `Edge ${edgeM[1]}`;\n } else if (chromeM && !/Edg|OPR/.test(ua)) {\n browser = `Chrome ${chromeM[1]}`;\n } else if (firefoxM) {\n browser = `Firefox ${firefoxM[1]}`;\n } else if (safariM && /Safari\\//.test(ua)) {\n browser = `Safari ${safariM[1]}`;\n }\n\n // -- OS --\n let os = \"Unknown\";\n const macM = ua.match(/Mac OS X (\\d+[._]\\d+)/);\n const winM = ua.match(/Windows NT (\\d+\\.\\d+)/);\n const androidM = ua.match(/Android (\\d+)/);\n const iosM = ua.match(/iPhone OS (\\d+[._]\\d+)/);\n\n if (macM) {\n os = `macOS ${macM[1].replace(\"_\", \".\")}`;\n } else if (winM) {\n const winMap: Record<string, string> = {\n \"10.0\": \"10/11\",\n \"6.3\": \"8.1\",\n \"6.2\": \"8\",\n \"6.1\": \"7\",\n };\n os = `Windows ${winMap[winM[1]] ?? winM[1]}`;\n } else if (androidM) {\n os = `Android ${androidM[1]}`;\n } else if (iosM) {\n os = `iOS ${iosM[1].replace(/_/g, \".\")}`;\n } else if (/Linux/.test(ua)) {\n os = \"Linux\";\n }\n\n return {\n browser,\n os,\n viewport: `${window.innerWidth}x${window.innerHeight}`,\n screen: `${screen.width}x${screen.height}`,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n online: navigator.onLine,\n };\n}\n","import type { FormErrorEntry, FormErrorField } from \"../types.js\";\n\nconst MAX_ENTRIES = 30;\n\n/**\n * Time to wait after a submit event before checking the DOM for error\n * indicators. RHF/zod validate asynchronously — 300ms covers most cases\n * while keeping the detection snappy.\n */\nconst POST_SUBMIT_CHECK_MS = 300;\n\n/**\n * After a submit button click, if no submit event fires within this window\n * it means the form library swallowed the submit entirely (e.g. RHF's\n * handleSubmit called preventDefault before the native event propagated,\n * or the button isn't even inside a <form>). We treat this as a potential\n * silent failure and scan the page for error indicators.\n */\nconst SILENT_SUBMIT_WINDOW_MS = 400;\n\nexport interface FormErrorCollector {\n start(): void;\n stop(): void;\n getEntries(): FormErrorEntry[];\n /**\n * Manually report a form validation failure. Call this from your form\n * library's error handler to capture exact field-level errors.\n *\n * @example\n * // React Hook Form + Zod\n * <form onSubmit={handleSubmit(onValid, (errors) => {\n * flint.reportFormError('checkout-form', errors);\n * })}>\n */\n report(formId: string, errors: Record<string, { message?: string } | undefined>): void;\n}\n\n// ── DOM helpers ────────────────────────────────────────────────────────────────\n\nfunction getFormId(form: HTMLFormElement): string {\n if (form.id) return `#${form.id}`;\n if (form.getAttribute(\"name\")) return `form[name=\"${form.getAttribute(\"name\")}\"]`;\n if (form.action && form.action !== location.href) return form.action;\n return `form:${Array.from(document.forms).indexOf(form)}`;\n}\n\nfunction getFieldLabel(field: HTMLElement, root: HTMLElement): string {\n const ariaLabel = field.getAttribute(\"aria-label\");\n if (ariaLabel) return ariaLabel;\n\n const id = field.id;\n if (id) {\n const label = root.querySelector<HTMLLabelElement>(`label[for=\"${id}\"]`);\n if (label?.textContent) return label.textContent.trim();\n }\n\n const parentLabel = field.closest(\"label\");\n if (parentLabel?.textContent) {\n const text = parentLabel.textContent.trim();\n if (text.length < 60) return text;\n }\n\n return (field as HTMLInputElement).name || (field as HTMLInputElement).placeholder || field.tagName.toLowerCase();\n}\n\nfunction getErrorMessage(field: HTMLElement): string | undefined {\n // aria-errormessage\n const errId = field.getAttribute(\"aria-errormessage\");\n if (errId) {\n const el = document.getElementById(errId);\n if (el?.textContent) return el.textContent.trim();\n }\n\n // aria-describedby (RHF wires error messages here)\n const descId = field.getAttribute(\"aria-describedby\");\n if (descId) {\n for (const id of descId.split(/\\s+/)) {\n const el = document.getElementById(id);\n if (el?.textContent?.trim()) return el.textContent.trim();\n }\n }\n\n // native validationMessage\n if (field instanceof HTMLInputElement || field instanceof HTMLTextAreaElement || field instanceof HTMLSelectElement) {\n if (field.validationMessage) return field.validationMessage;\n }\n\n // adjacent role=\"alert\"\n const next = field.nextElementSibling;\n if (next?.getAttribute(\"role\") === \"alert\" && next.textContent) {\n return next.textContent.trim();\n }\n\n return undefined;\n}\n\n/**\n * Collect fields with `aria-invalid=\"true\"` or native `:invalid` inside a\n * root element (a <form> or the whole document).\n */\nfunction collectInvalidFields(root: HTMLElement): FormErrorField[] {\n const fields: FormErrorField[] = [];\n const invalidEls = root.querySelectorAll<HTMLElement>('[aria-invalid=\"true\"], :invalid');\n\n for (const el of invalidEls) {\n if (el instanceof HTMLFormElement) continue;\n if (el.tagName === \"FIELDSET\") continue;\n\n fields.push({\n name: getFieldLabel(el, root),\n message: getErrorMessage(el),\n });\n }\n\n return fields;\n}\n\n/**\n * Scan the page for visible error indicators that appeared after a submit\n * attempt. This catches errors even when:\n * - The errored field is in another tab/step of a multi-step form\n * - The form doesn't use aria-invalid at all\n * - Errors are rendered as standalone alert divs\n */\nfunction collectVisibleErrors(root: HTMLElement): FormErrorField[] {\n const fields: FormErrorField[] = [];\n const seen = new Set<string>();\n\n // 1. role=\"alert\" elements that appeared (error toasts, inline messages)\n const alerts = root.querySelectorAll<HTMLElement>('[role=\"alert\"]');\n for (const el of alerts) {\n const text = el.textContent?.trim();\n if (!text || text.length > 200) continue;\n if (seen.has(text)) continue;\n seen.add(text);\n fields.push({ name: \"alert\", message: text });\n }\n\n // 2. Common error class patterns (data-error, .error, .field-error, etc.)\n const errorEls = root.querySelectorAll<HTMLElement>(\n \"[data-error], [data-field-error], .error-message, .field-error, .form-error\",\n );\n for (const el of errorEls) {\n const text = el.textContent?.trim();\n if (!text || text.length > 200) continue;\n if (seen.has(text)) continue;\n seen.add(text);\n fields.push({ name: \"error\", message: text });\n }\n\n return fields;\n}\n\nfunction isSubmitButton(el: HTMLElement): el is HTMLButtonElement {\n if (el.tagName === \"BUTTON\") {\n const type = el.getAttribute(\"type\");\n // Buttons default to type=\"submit\" inside forms when no type is set\n return type === \"submit\" || type === null || type === \"\";\n }\n if (el.tagName === \"INPUT\") {\n return (el as HTMLInputElement).type === \"submit\";\n }\n return false;\n}\n\nfunction findClosestForm(el: HTMLElement): HTMLFormElement | null {\n // Direct form association\n if (\"form\" in el && (el as HTMLButtonElement).form) {\n return (el as HTMLButtonElement).form;\n }\n return el.closest(\"form\");\n}\n\n// ── Collector ──────────────────────────────────────────────────────────────────\n\nexport function createFormErrorCollector(): FormErrorCollector {\n const entries: FormErrorEntry[] = [];\n const attemptCounts = new Map<string, number>();\n let active = false;\n\n // Handlers we need to clean up\n let submitHandler: ((e: Event) => void) | null = null;\n let invalidHandler: ((e: Event) => void) | null = null;\n let clickHandler: ((e: MouseEvent) => void) | null = null;\n\n // Track whether a real submit event followed a button click\n let lastSubmitTime = 0;\n\n // Dedup: avoid recording the same form twice within a short window\n const recentRecords = new Map<string, number>();\n const DEDUP_MS = 500;\n\n function push(entry: FormErrorEntry) {\n // Dedup check\n const _key = `${entry.formId}:${entry.timestamp}`;\n const last = recentRecords.get(entry.formId);\n if (last && entry.timestamp - last < DEDUP_MS) return;\n recentRecords.set(entry.formId, entry.timestamp);\n\n entries.push(entry);\n if (entries.length > MAX_ENTRIES) entries.shift();\n }\n\n function recordFormErrors(form: HTMLFormElement, type: FormErrorEntry[\"type\"]) {\n const formId = getFormId(form);\n\n // Strategy 1: aria-invalid / :invalid fields\n let fields = collectInvalidFields(form);\n\n // Strategy 2: if no aria-invalid fields found, look for visible error messages\n if (fields.length === 0) {\n fields = collectVisibleErrors(form);\n }\n\n if (fields.length === 0) return;\n\n const count = (attemptCounts.get(formId) ?? 0) + 1;\n attemptCounts.set(formId, count);\n\n push({\n type,\n formId,\n fields,\n attemptNumber: count,\n url: location.href,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Handle clicks on submit buttons. If no submit event follows within\n * SILENT_SUBMIT_WINDOW_MS, it means the form library blocked the submit\n * entirely — scan for errors.\n */\n function handleSubmitButtonClick(button: HTMLElement) {\n const form = findClosestForm(button);\n\n setTimeout(() => {\n if (!active) return;\n // A real submit event fired — the submitHandler already took care of it\n if (Date.now() - lastSubmitTime < SILENT_SUBMIT_WINDOW_MS) return;\n\n // No submit event → silent failure\n const root = form ?? (document.body as HTMLElement);\n const formId = form ? getFormId(form) : `page:${location.pathname}`;\n\n let fields = form ? collectInvalidFields(form) : [];\n if (fields.length === 0) {\n fields = collectVisibleErrors(root);\n }\n\n // Also scan full page — the error might be in a toast or outside the form\n if (fields.length === 0 && form) {\n fields = collectVisibleErrors(document.body);\n }\n\n if (fields.length === 0) return;\n\n const count = (attemptCounts.get(formId) ?? 0) + 1;\n attemptCounts.set(formId, count);\n\n push({\n type: \"silent_submit\",\n formId,\n fields,\n attemptNumber: count,\n url: location.href,\n timestamp: Date.now(),\n });\n }, SILENT_SUBMIT_WINDOW_MS);\n }\n\n return {\n start() {\n if (active) return;\n active = true;\n\n // 1. Capture submit events (fires even with e.preventDefault())\n submitHandler = (e: Event) => {\n lastSubmitTime = Date.now();\n const form = e.target as HTMLFormElement;\n if (!(form instanceof HTMLFormElement)) return;\n\n setTimeout(() => {\n if (!active) return;\n recordFormErrors(form, \"validation_failed\");\n }, POST_SUBMIT_CHECK_MS);\n };\n document.addEventListener(\"submit\", submitHandler, true);\n\n // 2. Capture native invalid events (HTML5 constraint validation)\n invalidHandler = (e: Event) => {\n lastSubmitTime = Date.now();\n const field = e.target as HTMLElement;\n const form = field.closest(\"form\");\n if (!form) return;\n\n setTimeout(() => {\n if (!active) return;\n recordFormErrors(form, \"validation_failed\");\n }, POST_SUBMIT_CHECK_MS);\n };\n document.addEventListener(\"invalid\", invalidHandler, true);\n\n // 3. Capture clicks on submit buttons — catches silent failures\n // where the form lib eats the submit and shows nothing\n clickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target) return;\n\n // Walk up to find the actual button (click might be on an icon/span inside)\n const button = target.closest(\"button, input[type=submit]\") as HTMLElement | null;\n if (!button) return;\n if (!isSubmitButton(button)) return;\n\n handleSubmitButtonClick(button);\n };\n document.addEventListener(\"click\", clickHandler, true);\n },\n\n stop() {\n if (!active) return;\n active = false;\n if (submitHandler) document.removeEventListener(\"submit\", submitHandler, true);\n if (invalidHandler) document.removeEventListener(\"invalid\", invalidHandler, true);\n if (clickHandler) document.removeEventListener(\"click\", clickHandler, true);\n attemptCounts.clear();\n recentRecords.clear();\n },\n\n getEntries() {\n return [...entries];\n },\n\n report(formId: string, errors: Record<string, { message?: string } | undefined>) {\n const fields: FormErrorField[] = [];\n for (const [name, err] of Object.entries(errors)) {\n if (!err) continue;\n fields.push({ name, message: err.message });\n }\n if (fields.length === 0) return;\n\n const count = (attemptCounts.get(formId) ?? 0) + 1;\n attemptCounts.set(formId, count);\n\n push({\n type: \"validation_failed\",\n formId,\n fields,\n attemptNumber: count,\n url: location.href,\n timestamp: Date.now(),\n });\n },\n };\n}\n","export interface FrustrationEvent {\n type: \"rage_click\" | \"dead_click\" | \"error_loop\";\n timestamp: number;\n target: string;\n details: string;\n url: string;\n}\n\nexport interface FrustrationCollector {\n start(): void;\n stop(): void;\n getEvents(): FrustrationEvent[];\n onFrustration(callback: (event: FrustrationEvent) => void): () => void;\n}\n\nexport function createFrustrationCollector(opts?: {\n rageClickThreshold?: number;\n rageClickWindow?: number;\n errorLoopThreshold?: number;\n errorLoopWindow?: number;\n enableDeadClicks?: boolean;\n}): FrustrationCollector {\n const threshold = opts?.rageClickThreshold ?? 3;\n const window = opts?.rageClickWindow ?? 500;\n const errorThreshold = opts?.errorLoopThreshold ?? 3;\n const errorWindow = opts?.errorLoopWindow ?? 30_000;\n const deadClicksEnabled = opts?.enableDeadClicks ?? true;\n\n const events: FrustrationEvent[] = [];\n const listeners = new Set<(event: FrustrationEvent) => void>();\n const clickHistory: { target: EventTarget | null; time: number }[] = [];\n const errorCounts = new Map<string, { count: number; firstSeen: number }>();\n let clickHandler: ((e: MouseEvent) => void) | null = null;\n let origConsoleError: typeof console.error | null = null;\n\n function emit(event: FrustrationEvent) {\n events.push(event);\n if (events.length > 50) events.shift();\n for (const cb of listeners) cb(event);\n }\n\n function getCSSSelector(el: Element): string {\n if (el.id) return `#${el.id}`;\n const tag = el.tagName.toLowerCase();\n const cls = [...el.classList].slice(0, 3).join(\".\");\n if (cls) return `${tag}.${cls}`;\n return tag;\n }\n\n function isInteractive(el: HTMLElement): boolean {\n const tag = el.tagName.toLowerCase();\n if ([\"a\", \"button\", \"input\", \"select\", \"textarea\", \"label\", \"summary\"].includes(tag)) return true;\n if (el.getAttribute(\"role\") === \"button\" || el.getAttribute(\"tabindex\")) return true;\n if (el.onclick || el.getAttribute(\"onclick\")) return true;\n if (el.closest(\"a, button, [role=button], [onclick]\")) return true;\n try {\n if (getComputedStyle(el).cursor === \"pointer\") return true;\n } catch {\n /* getComputedStyle may throw */\n }\n return false;\n }\n\n function handleClick(e: MouseEvent) {\n const target = e.target as HTMLElement;\n if (!target) return;\n const now = Date.now();\n\n // --- Rage click detection ---\n clickHistory.push({ target, time: now });\n // Remove old clicks\n while (clickHistory.length > 0 && now - clickHistory[0].time > 1000) {\n clickHistory.shift();\n }\n const recentOnSame = clickHistory.filter((c) => c.target === target && now - c.time < window);\n if (recentOnSame.length >= threshold) {\n emit({\n type: \"rage_click\",\n timestamp: now,\n target: getCSSSelector(target),\n details: `${recentOnSame.length} clicks in ${now - recentOnSame[0].time}ms`,\n url: globalThis.location?.href ?? \"\",\n });\n clickHistory.length = 0;\n }\n\n // --- Dead click detection ---\n if (deadClicksEnabled && !isInteractive(target)) {\n emit({\n type: \"dead_click\",\n timestamp: now,\n target: getCSSSelector(target),\n details: `Click on non-interactive <${target.tagName.toLowerCase()}>`,\n url: globalThis.location?.href ?? \"\",\n });\n }\n }\n\n function patchConsoleError() {\n origConsoleError = console.error;\n console.error = (...args: unknown[]) => {\n origConsoleError?.apply(console, args);\n // Check for error loop\n const key = String(args[0]).slice(0, 100);\n const now = Date.now();\n const existing = errorCounts.get(key);\n if (existing && now - existing.firstSeen < errorWindow) {\n existing.count++;\n if (existing.count >= errorThreshold) {\n emit({\n type: \"error_loop\",\n timestamp: now,\n target: \"console\",\n details: `Same error ${existing.count}x in ${Math.round((now - existing.firstSeen) / 1000)}s: ${key}`,\n url: globalThis.location?.href ?? \"\",\n });\n errorCounts.delete(key);\n }\n } else {\n errorCounts.set(key, { count: 1, firstSeen: now });\n }\n };\n }\n\n return {\n start() {\n clickHandler = handleClick;\n document.addEventListener(\"click\", clickHandler, true);\n patchConsoleError();\n },\n stop() {\n if (clickHandler) document.removeEventListener(\"click\", clickHandler, true);\n if (origConsoleError) console.error = origConsoleError;\n clickHistory.length = 0;\n errorCounts.clear();\n },\n getEvents() {\n return [...events];\n },\n onFrustration(callback) {\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n };\n}\n","import type { NetworkEntry } from \"../types.js\";\n\nconst MAX_ENTRIES = 50;\n\nconst BLOCKED_HOSTS = new Set([\n \"browser-intake-datadoghq.com\",\n \"rum.browser-intake-datadoghq.com\",\n \"logs.browser-intake-datadoghq.com\",\n \"session-replay.browser-intake-datadoghq.com\",\n]);\n\nfunction isBlockedUrl(url: string, extra: Set<string>): boolean {\n try {\n const host = new URL(url, location.href).hostname;\n const all = [...BLOCKED_HOSTS, ...extra];\n return all.some((b) => host === b || host.endsWith(\".\" + b));\n } catch {\n return false;\n }\n}\n\nexport interface NetworkCollector {\n start(): void;\n stop(): void;\n getEntries(): NetworkEntry[];\n}\n\nfunction truncateUrl(url: string): string {\n try {\n const u = new URL(url, location.href);\n const base = `${u.origin}${u.pathname}`;\n return base.length > 200 ? base.slice(0, 200) + \"\\u2026\" : base;\n } catch {\n return url.length > 200 ? url.slice(0, 200) + \"\\u2026\" : url;\n }\n}\n\nexport function createNetworkCollector(extraBlockedHosts: string[] = []): NetworkCollector {\n const entries: NetworkEntry[] = [];\n const blocked = new Set(extraBlockedHosts);\n let origFetch: typeof window.fetch | null = null;\n let origXHROpen: typeof XMLHttpRequest.prototype.open | null = null;\n let active = false;\n\n function push(entry: NetworkEntry) {\n entries.push(entry);\n if (entries.length > MAX_ENTRIES) entries.shift();\n }\n\n return {\n start() {\n if (active) return;\n active = true;\n\n // -- Patch fetch --\n origFetch = window.fetch;\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const method = ((init?.method ?? \"GET\") as string).toUpperCase();\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : (input as Request).url;\n const startTime = Date.now();\n const res = await origFetch!.call(window, input, init);\n if (!isBlockedUrl(url, blocked)) {\n push({\n method,\n url: truncateUrl(url),\n status: res.status,\n duration: Date.now() - startTime,\n timestamp: startTime,\n });\n }\n return res;\n };\n\n // -- Patch XHR --\n origXHROpen = XMLHttpRequest.prototype.open;\n XMLHttpRequest.prototype.open = function (\n method: string,\n url: string | URL,\n async?: boolean,\n username?: string | null,\n password?: string | null,\n ) {\n const startTime = Date.now();\n const urlStr = typeof url === \"string\" ? url : (url as URL).href;\n\n this.addEventListener(\"load\", () => {\n if (!isBlockedUrl(urlStr, blocked)) {\n push({\n method: method.toUpperCase(),\n url: truncateUrl(urlStr),\n status: this.status,\n duration: Date.now() - startTime,\n timestamp: startTime,\n });\n }\n });\n\n return origXHROpen!.apply(this, [method, url, async ?? true, username, password] as Parameters<\n typeof XMLHttpRequest.prototype.open\n >);\n };\n },\n\n stop() {\n if (!active) return;\n active = false;\n if (origFetch) window.fetch = origFetch;\n if (origXHROpen) XMLHttpRequest.prototype.open = origXHROpen;\n },\n\n getEntries() {\n return [...entries];\n },\n };\n}\n","import type { FormErrorCollector } from \"./collectors/formErrors.js\";\nimport type { FlintUser } from \"./types.js\";\n\nexport interface FlintState {\n user: FlintUser | undefined;\n sessionReplay: string | (() => string) | undefined;\n}\n\n// Holds a reference to the active form error collector so flint.reportFormError\n// can forward calls without the consumer needing to manage the collector.\nlet formErrorCollectorRef: FormErrorCollector | null = null;\n\nexport function _setFormErrorCollector(collector: FormErrorCollector | null) {\n formErrorCollectorRef = collector;\n}\n\nlet state: FlintState = { user: undefined, sessionReplay: undefined };\nconst listeners = new Set<() => void>();\n\nfunction emit() {\n for (const l of listeners) l();\n}\n\nexport function subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nexport function getSnapshot(): FlintState {\n return state;\n}\n\nexport const flint = {\n setUser(user: FlintUser | null) {\n state = { ...state, user: user ?? undefined };\n emit();\n },\n setSessionReplay(url: string | (() => string) | null) {\n state = { ...state, sessionReplay: url ?? undefined };\n emit();\n },\n\n /**\n * Report a form validation failure with exact field-level errors.\n * Call this from your form library's error callback.\n *\n * @example\n * // React Hook Form + Zod\n * const onSubmit = handleSubmit(onValid, (errors) => {\n * flint.reportFormError('checkout-form', errors);\n * });\n */\n reportFormError(formId: string, errors: Record<string, { message?: string } | undefined>) {\n formErrorCollectorRef?.report(formId, errors);\n },\n};\n","// Flint singleton — manages global collector lifecycle\nimport { submitReport } from \"./api.js\";\nimport type { ConsoleCollector } from \"./collectors/console.js\";\nimport { createConsoleCollector } from \"./collectors/console.js\";\nimport { collectEnvironment } from \"./collectors/environment.js\";\nimport type { FormErrorCollector } from \"./collectors/formErrors.js\";\nimport { createFormErrorCollector } from \"./collectors/formErrors.js\";\nimport type { FrustrationCollector } from \"./collectors/frustration.js\";\nimport { createFrustrationCollector } from \"./collectors/frustration.js\";\nimport type { NetworkCollector } from \"./collectors/network.js\";\nimport { createNetworkCollector } from \"./collectors/network.js\";\nimport { _setFormErrorCollector, flint, getSnapshot } from \"./store.js\";\nimport type { CollectedMeta, FlintConfig } from \"./types.js\";\n\nconst DEFAULT_REPLAY_BUFFER_MS = 60_000;\n\ninterface FlintInstance {\n config: Readonly<FlintConfig>;\n console: ConsoleCollector | null;\n network: NetworkCollector | null;\n formErrors: FormErrorCollector | null;\n frustration: FrustrationCollector | null;\n replayEvents: unknown[];\n stopReplay: (() => void) | null;\n}\n\nlet instance: FlintInstance | null = null;\n\nfunction init(config: FlintConfig): void {\n if (instance) {\n console.warn(\"[Flint] Already initialized. Call Flint.shutdown() first to re-initialize.\");\n return;\n }\n\n const {\n enableConsole = true,\n enableNetwork = true,\n enableFormErrors = true,\n enableFrustration = false,\n autoReportFrustration = false,\n enableReplay = false,\n replayBufferMs = DEFAULT_REPLAY_BUFFER_MS,\n blockedHosts = [],\n frustration: frustrationOpts,\n onFrustration,\n _replayRecorder,\n } = config;\n\n // Determine Flint server host to block from network capture\n const flintHost = (() => {\n try {\n return new URL(config.serverUrl).hostname;\n } catch {\n return \"\";\n }\n })();\n\n // Create and start collectors\n const consoleCol = enableConsole ? createConsoleCollector() : null;\n consoleCol?.start();\n\n const networkCol = enableNetwork\n ? createNetworkCollector([...blockedHosts, ...(flintHost ? [flintHost] : [])])\n : null;\n networkCol?.start();\n\n const formErrorsCol = enableFormErrors ? createFormErrorCollector() : null;\n if (formErrorsCol) {\n formErrorsCol.start();\n _setFormErrorCollector(formErrorsCol);\n }\n\n const frustrationCol = enableFrustration ? createFrustrationCollector(frustrationOpts) : null;\n frustrationCol?.start();\n\n // Set user if provided\n if (config.user) {\n flint.setUser(config.user);\n }\n\n const replayEvents: unknown[] = [];\n let stopReplay: (() => void) | null = null;\n\n instance = {\n config,\n console: consoleCol,\n network: networkCol,\n formErrors: formErrorsCol,\n frustration: frustrationCol,\n replayEvents,\n stopReplay: null,\n };\n\n // Start replay recording (async, via injected recorder)\n if (enableReplay && _replayRecorder) {\n _replayRecorder((event: unknown) => {\n replayEvents.push(event);\n const cutoff = Date.now() - replayBufferMs;\n while (replayEvents.length > 0 && (replayEvents[0] as { timestamp: number }).timestamp < cutoff) {\n replayEvents.shift();\n }\n }).then((stop) => {\n stopReplay = stop ?? null;\n if (instance) instance.stopReplay = stopReplay;\n });\n }\n\n // Wire frustration auto-report\n if (frustrationCol && autoReportFrustration) {\n frustrationCol.onFrustration(async (event) => {\n onFrustration?.(event);\n const user = getSnapshot().user ?? config.user;\n await submitReport(config.serverUrl, config.projectKey, {\n reporterId: user?.id ?? \"anonymous\",\n reporterName: user?.name ?? \"Anonymous\",\n reporterEmail: user?.email,\n description: `[Auto-detected] ${event.type.replace(/_/g, \" \")}: ${event.details}`,\n severity: event.type === \"error_loop\" ? \"P1\" : event.type === \"rage_click\" ? \"P2\" : \"P3\",\n url: event.url,\n meta: {\n ...config.meta,\n environment: collectEnvironment(),\n consoleLogs: consoleCol?.getEntries() ?? [],\n networkErrors: networkCol?.getEntries() ?? [],\n formErrors: formErrorsCol?.getEntries() ?? [],\n frustrationEvent: event,\n },\n }).catch(() => {});\n });\n } else if (frustrationCol && onFrustration) {\n frustrationCol.onFrustration(onFrustration);\n }\n}\n\nfunction shutdown(): void {\n if (!instance) return;\n\n instance.console?.stop();\n instance.network?.stop();\n instance.formErrors?.stop();\n _setFormErrorCollector(null);\n instance.frustration?.stop();\n instance.stopReplay?.();\n instance = null;\n}\n\nfunction isInitialized(): boolean {\n return instance !== null;\n}\n\nfunction getInstance(): FlintInstance | null {\n return instance;\n}\n\nfunction getMeta(extraMeta?: Record<string, unknown>): CollectedMeta {\n return {\n ...extraMeta,\n environment: collectEnvironment(),\n consoleLogs: instance?.console?.getEntries() ?? [],\n networkErrors: instance?.network?.getEntries() ?? [],\n formErrors: instance?.formErrors?.getEntries() ?? [],\n };\n}\n\nfunction getReplayEvents(): unknown[] {\n return instance ? [...instance.replayEvents] : [];\n}\n\nfunction getConfig(): Readonly<FlintConfig> | null {\n return instance?.config ?? null;\n}\n\nexport const Flint = {\n init,\n shutdown,\n isInitialized,\n getInstance,\n getMeta,\n getReplayEvents,\n getConfig,\n setUser: flint.setUser,\n setSessionReplay: flint.setSessionReplay,\n reportFormError: flint.reportFormError,\n};\n","import type { Theme, ThemeOverride } from \"./types.js\";\n\nexport interface ResolvedTheme {\n background: string;\n backgroundSecondary: string;\n accent: string;\n accentHover: string;\n text: string;\n textMuted: string;\n border: string;\n shadow: string;\n buttonText: string;\n backdropFilter: string;\n}\n\nconst light: ResolvedTheme = {\n background: \"rgba(255,255,255,0.90)\",\n backgroundSecondary: \"rgba(249,250,251,0.75)\",\n accent: \"#2563eb\",\n accentHover: \"#1d4ed8\",\n text: \"#111827\",\n textMuted: \"#6b7280\",\n border: \"rgba(255,255,255,0.9)\",\n shadow: \"0 32px 80px rgba(0,0,0,0.18), 0 8px 32px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.04)\",\n buttonText: \"#ffffff\",\n backdropFilter: \"blur(32px) saturate(1.8)\",\n};\n\nconst dark: ResolvedTheme = {\n background: \"rgba(15,20,35,0.88)\",\n backgroundSecondary: \"rgba(5,8,18,0.65)\",\n accent: \"#4d8aff\",\n accentHover: \"#3b6fdb\",\n text: \"#dde3ef\",\n textMuted: \"#6b7a93\",\n border: \"rgba(255,255,255,0.08)\",\n shadow: \"0 24px 60px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04)\",\n buttonText: \"#ffffff\",\n backdropFilter: \"blur(32px) saturate(1.6)\",\n};\n\nexport function resolveTheme(theme: Theme): ResolvedTheme {\n if (theme === \"dark\") return dark;\n if (theme === \"light\") return light;\n // ThemeOverride — merge over light base\n const override = theme as ThemeOverride;\n return {\n ...light,\n background: override.background ?? light.background,\n accent: override.accent ?? light.accent,\n accentHover: override.accent ?? light.accentHover,\n text: override.text ?? light.text,\n border: override.border ?? light.border,\n };\n}\n"],"mappings":"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","names":["init","MAX_ENTRIES","window","listeners","emit","MAX_ENTRIES","init"]}
1
+ {"version":3,"sources":["../src/integrations/datadog.ts","../src/index.ts","../src/api.ts","../src/collectors/console.ts","../src/collectors/environment.ts","../src/collectors/formErrors.ts","../src/collectors/frustration.ts","../src/collectors/network.ts","../src/store.ts","../src/singleton.ts","../src/theme.ts"],"sourcesContent":["/**\n * Datadog RUM integration — opt-in helper.\n *\n * Usage:\n * import { Flint } from \"@diegotsi/flint-core\";\n * import { createDatadogReplayProvider, DATADOG_BLOCKED_HOSTS } from \"@diegotsi/flint-core\";\n *\n * Flint.init({\n * projectKey: \"...\",\n * serverUrl: \"...\",\n * externalReplayProvider: createDatadogReplayProvider(\"app.datadoghq.com\"),\n * blockedHosts: DATADOG_BLOCKED_HOSTS,\n * });\n */\n\n/** Datadog intake hosts to exclude from network capture. */\nexport const DATADOG_BLOCKED_HOSTS = [\n \"browser-intake-datadoghq.com\",\n \"rum.browser-intake-datadoghq.com\",\n \"logs.browser-intake-datadoghq.com\",\n \"session-replay.browser-intake-datadoghq.com\",\n];\n\n/**\n * Creates an `externalReplayProvider` that reads the current Datadog RUM\n * session and returns a deep link to the Session Replay viewer.\n */\nexport function createDatadogReplayProvider(site: string): () => string | undefined {\n return () => {\n try {\n const ddRum = (window as unknown as Record<string, unknown>).DD_RUM as\n | { getInternalContext?: () => { session_id?: string } | undefined }\n | undefined;\n const ctx = ddRum?.getInternalContext?.();\n if (ctx?.session_id) {\n const ts = Date.now();\n const fromTs = ts - 30_000;\n const toTs = ts + 5_000;\n return `https://${site}/rum/replay/sessions/${ctx.session_id}?from_ts=${fromTs}&to_ts=${toTs}&tab=replay&live=false`;\n }\n } catch {\n // DD_RUM not available — silently skip\n }\n return undefined;\n };\n}\n","// API\nexport { submitReplay, submitReport } from \"./api.js\";\n// Collector types\nexport type { ConsoleCollector } from \"./collectors/console.js\";\nexport { createConsoleCollector } from \"./collectors/console.js\";\nexport { collectEnvironment } from \"./collectors/environment.js\";\nexport type { FormErrorCollector } from \"./collectors/formErrors.js\";\nexport { createFormErrorCollector } from \"./collectors/formErrors.js\";\nexport type { FrustrationCollector, FrustrationEvent } from \"./collectors/frustration.js\";\nexport { createFrustrationCollector } from \"./collectors/frustration.js\";\nexport type { NetworkCollector } from \"./collectors/network.js\";\nexport { createNetworkCollector } from \"./collectors/network.js\";\n// Integrations\nexport { createDatadogReplayProvider, DATADOG_BLOCKED_HOSTS } from \"./integrations/datadog.js\";\n// Singleton\nexport { Flint } from \"./singleton.js\";\nexport type { FlintState } from \"./store.js\";\n// State (flint lowercase removed from public API — use Flint.setUser() etc.)\nexport { _setFormErrorCollector, getSnapshot, subscribe } from \"./store.js\";\nexport type { ResolvedTheme } from \"./theme.js\";\n// Theme\nexport { resolveTheme } from \"./theme.js\";\n// Types (re-export)\nexport type {\n CollectedMeta,\n ConsoleEntry,\n EnvironmentInfo,\n FlintConfig,\n FlintUser,\n FlintWidgetProps,\n FormErrorEntry,\n Locale,\n NetworkEntry,\n ReportPayload,\n ReportResult,\n Severity,\n Theme,\n ThemeOverride,\n} from \"./types.js\";\n","import { gzipSync } from \"fflate\";\nimport type { ReportPayload, ReportResult } from \"./types.js\";\n\nasync function fetchWithRetry(url: string, init: RequestInit, retries = 3, baseDelay = 1000): Promise<Response> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n const res = await fetch(url, init);\n if (res.ok || attempt === retries) return res;\n // Don't retry client errors (4xx) except 429\n if (res.status >= 400 && res.status < 500 && res.status !== 429) return res;\n } catch (err) {\n if (attempt === retries) throw err;\n }\n await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));\n }\n throw new Error(\"Max retries exceeded\");\n}\n\nexport async function submitReport(\n serverUrl: string,\n projectKey: string,\n payload: ReportPayload,\n screenshot?: File,\n): Promise<ReportResult> {\n const url = `${serverUrl.replace(/\\/$/, \"\")}/api/v1/bug-reports`;\n\n let body: BodyInit;\n const headers: Record<string, string> = {\n \"x-project-key\": projectKey,\n };\n\n if (screenshot) {\n const form = new FormData();\n form.append(\"reporterId\", payload.reporterId);\n form.append(\"reporterName\", payload.reporterName);\n if (payload.reporterEmail) form.append(\"reporterEmail\", payload.reporterEmail);\n form.append(\"description\", payload.description);\n if (payload.expectedBehavior) form.append(\"expectedBehavior\", payload.expectedBehavior);\n if (payload.stepsToReproduce) form.append(\"stepsToReproduce\", JSON.stringify(payload.stepsToReproduce));\n if (payload.externalReplayUrl) form.append(\"externalReplayUrl\", payload.externalReplayUrl);\n if (payload.additionalContext) form.append(\"additionalContext\", payload.additionalContext);\n form.append(\"severity\", payload.severity);\n if (payload.url) form.append(\"url\", payload.url);\n if (payload.meta) form.append(\"meta\", JSON.stringify(payload.meta));\n form.append(\"screenshot\", screenshot);\n body = form;\n } else {\n body = JSON.stringify(payload);\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const res = await fetchWithRetry(url, { method: \"POST\", headers, body });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: \"Unknown error\" }));\n throw new Error((err as { error?: string }).error ?? `HTTP ${res.status}`);\n }\n\n return res.json() as Promise<ReportResult>;\n}\n\nexport async function submitReplay(\n serverUrl: string,\n projectKey: string,\n reportId: string,\n events: unknown[],\n): Promise<void> {\n const json = JSON.stringify(events);\n const encoded = new TextEncoder().encode(json);\n const compressed = gzipSync(encoded);\n\n const url = `${serverUrl.replace(/\\/$/, \"\")}/api/v1/bug-reports/${reportId}/replay`;\n await fetch(url, {\n method: \"POST\",\n headers: {\n \"x-project-key\": projectKey,\n \"Content-Type\": \"application/octet-stream\",\n },\n body: compressed.buffer as ArrayBuffer,\n });\n}\n","import type { ConsoleEntry } from \"../types.js\";\n\nconst MAX_ENTRIES = 50;\n\n// Redact values that look like tokens, passwords, secrets, or API keys\nconst SENSITIVE_PATTERNS = [\n /(?:password|passwd|pwd|secret|token|api[_-]?key|access[_-]?key|authorization|bearer)\\s*[:=]\\s*[\"']?[^\\s\"',]{4,}/gi,\n /\\b(sk-[a-zA-Z0-9_-]{20,})\\b/g, // API keys (e.g. sk-ant-...)\n /\\b(ghp_[a-zA-Z0-9]{36,})\\b/g, // GitHub tokens\n /\\b(xoxb-[a-zA-Z0-9-]+)\\b/g, // Slack tokens\n /\\b(eyJ[a-zA-Z0-9_-]{10,}\\.[a-zA-Z0-9_-]{10,})\\b/g, // JWTs\n];\n\nfunction sanitize(str: string): string {\n let result = str;\n for (const pattern of SENSITIVE_PATTERNS) {\n result = result.replace(pattern, \"[REDACTED]\");\n }\n return result;\n}\n\nexport interface ConsoleCollector {\n start(): void;\n stop(): void;\n getEntries(): ConsoleEntry[];\n}\n\nexport function createConsoleCollector(): ConsoleCollector {\n const entries: ConsoleEntry[] = [];\n let active = false;\n\n const originals = {\n log: console.log.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n };\n\n let origOnerror: typeof window.onerror = null;\n let origUnhandled: typeof window.onunhandledrejection = null;\n\n function push(level: ConsoleEntry[\"level\"], args: unknown[]) {\n let str: string;\n try {\n str = args.map((a) => (typeof a === \"string\" ? a : JSON.stringify(a))).join(\" \");\n } catch {\n str = String(args[0]);\n }\n if (str.length > 500) str = str.slice(0, 500) + \"\\u2026\";\n str = sanitize(str);\n entries.push({ level, args: str, timestamp: Date.now() });\n if (entries.length > MAX_ENTRIES) entries.shift();\n }\n\n return {\n start() {\n if (active) return;\n active = true;\n\n console.log = (...args: unknown[]) => {\n push(\"log\", args);\n originals.log(...args);\n };\n console.warn = (...args: unknown[]) => {\n push(\"warn\", args);\n originals.warn(...args);\n };\n console.error = (...args: unknown[]) => {\n push(\"error\", args);\n originals.error(...args);\n };\n\n origOnerror = window.onerror;\n window.onerror = (msg, src, line, col, err) => {\n push(\"error\", [err?.message ?? String(msg), `${src}:${line}:${col}`]);\n if (typeof origOnerror === \"function\") return origOnerror(msg, src, line, col, err);\n return false;\n };\n\n origUnhandled = window.onunhandledrejection;\n window.onunhandledrejection = (event) => {\n const reason = event.reason instanceof Error ? event.reason.message : JSON.stringify(event.reason);\n push(\"error\", [\"UnhandledRejection:\", reason]);\n if (typeof origUnhandled === \"function\") origUnhandled.call(window, event);\n };\n },\n\n stop() {\n if (!active) return;\n active = false;\n console.log = originals.log;\n console.warn = originals.warn;\n console.error = originals.error;\n window.onerror = origOnerror;\n window.onunhandledrejection = origUnhandled;\n },\n\n getEntries() {\n return [...entries];\n },\n };\n}\n","import type { EnvironmentInfo } from \"../types.js\";\n\nexport function collectEnvironment(): EnvironmentInfo {\n const ua = navigator.userAgent;\n\n // -- Browser --\n let browser = \"Unknown\";\n const chromeM = ua.match(/Chrome\\/(\\d+)/);\n const firefoxM = ua.match(/Firefox\\/(\\d+)/);\n const edgeM = ua.match(/Edg\\/(\\d+)/);\n const safariM = ua.match(/Version\\/(\\d+)/);\n const operaM = ua.match(/OPR\\/(\\d+)/);\n\n if (operaM) {\n browser = `Opera ${operaM[1]}`;\n } else if (edgeM) {\n browser = `Edge ${edgeM[1]}`;\n } else if (chromeM && !/Edg|OPR/.test(ua)) {\n browser = `Chrome ${chromeM[1]}`;\n } else if (firefoxM) {\n browser = `Firefox ${firefoxM[1]}`;\n } else if (safariM && /Safari\\//.test(ua)) {\n browser = `Safari ${safariM[1]}`;\n }\n\n // -- OS --\n let os = \"Unknown\";\n const macM = ua.match(/Mac OS X (\\d+[._]\\d+)/);\n const winM = ua.match(/Windows NT (\\d+\\.\\d+)/);\n const androidM = ua.match(/Android (\\d+)/);\n const iosM = ua.match(/iPhone OS (\\d+[._]\\d+)/);\n\n if (macM) {\n os = `macOS ${macM[1].replace(\"_\", \".\")}`;\n } else if (winM) {\n const winMap: Record<string, string> = {\n \"10.0\": \"10/11\",\n \"6.3\": \"8.1\",\n \"6.2\": \"8\",\n \"6.1\": \"7\",\n };\n os = `Windows ${winMap[winM[1]] ?? winM[1]}`;\n } else if (androidM) {\n os = `Android ${androidM[1]}`;\n } else if (iosM) {\n os = `iOS ${iosM[1].replace(/_/g, \".\")}`;\n } else if (/Linux/.test(ua)) {\n os = \"Linux\";\n }\n\n return {\n browser,\n os,\n viewport: `${window.innerWidth}x${window.innerHeight}`,\n screen: `${screen.width}x${screen.height}`,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n online: navigator.onLine,\n };\n}\n","import type { FormErrorEntry, FormErrorField } from \"../types.js\";\n\nconst MAX_ENTRIES = 30;\n\n/**\n * Time to wait after a submit event before checking the DOM for error\n * indicators. RHF/zod validate asynchronously — 300ms covers most cases\n * while keeping the detection snappy.\n */\nconst POST_SUBMIT_CHECK_MS = 300;\n\n/**\n * After a submit button click, if no submit event fires within this window\n * it means the form library swallowed the submit entirely (e.g. RHF's\n * handleSubmit called preventDefault before the native event propagated,\n * or the button isn't even inside a <form>). We treat this as a potential\n * silent failure and scan the page for error indicators.\n */\nconst SILENT_SUBMIT_WINDOW_MS = 400;\n\nexport interface FormErrorCollector {\n start(): void;\n stop(): void;\n getEntries(): FormErrorEntry[];\n /**\n * Manually report a form validation failure. Call this from your form\n * library's error handler to capture exact field-level errors.\n *\n * @example\n * // React Hook Form + Zod\n * <form onSubmit={handleSubmit(onValid, (errors) => {\n * flint.reportFormError('checkout-form', errors);\n * })}>\n */\n report(formId: string, errors: Record<string, { message?: string } | undefined>): void;\n}\n\n// ── DOM helpers ────────────────────────────────────────────────────────────────\n\nfunction getFormId(form: HTMLFormElement): string {\n if (form.id) return `#${form.id}`;\n if (form.getAttribute(\"name\")) return `form[name=\"${form.getAttribute(\"name\")}\"]`;\n if (form.action && form.action !== location.href) return form.action;\n return `form:${Array.from(document.forms).indexOf(form)}`;\n}\n\nfunction getFieldLabel(field: HTMLElement, root: HTMLElement): string {\n const ariaLabel = field.getAttribute(\"aria-label\");\n if (ariaLabel) return ariaLabel;\n\n const id = field.id;\n if (id) {\n const label = root.querySelector<HTMLLabelElement>(`label[for=\"${id}\"]`);\n if (label?.textContent) return label.textContent.trim();\n }\n\n const parentLabel = field.closest(\"label\");\n if (parentLabel?.textContent) {\n const text = parentLabel.textContent.trim();\n if (text.length < 60) return text;\n }\n\n return (field as HTMLInputElement).name || (field as HTMLInputElement).placeholder || field.tagName.toLowerCase();\n}\n\nfunction getErrorMessage(field: HTMLElement): string | undefined {\n // aria-errormessage\n const errId = field.getAttribute(\"aria-errormessage\");\n if (errId) {\n const el = document.getElementById(errId);\n if (el?.textContent) return el.textContent.trim();\n }\n\n // aria-describedby (RHF wires error messages here)\n const descId = field.getAttribute(\"aria-describedby\");\n if (descId) {\n for (const id of descId.split(/\\s+/)) {\n const el = document.getElementById(id);\n if (el?.textContent?.trim()) return el.textContent.trim();\n }\n }\n\n // native validationMessage\n if (field instanceof HTMLInputElement || field instanceof HTMLTextAreaElement || field instanceof HTMLSelectElement) {\n if (field.validationMessage) return field.validationMessage;\n }\n\n // adjacent role=\"alert\"\n const next = field.nextElementSibling;\n if (next?.getAttribute(\"role\") === \"alert\" && next.textContent) {\n return next.textContent.trim();\n }\n\n return undefined;\n}\n\n/**\n * Collect fields with `aria-invalid=\"true\"` or native `:invalid` inside a\n * root element (a <form> or the whole document).\n */\nfunction collectInvalidFields(root: HTMLElement): FormErrorField[] {\n const fields: FormErrorField[] = [];\n const invalidEls = root.querySelectorAll<HTMLElement>('[aria-invalid=\"true\"], :invalid');\n\n for (const el of invalidEls) {\n if (el instanceof HTMLFormElement) continue;\n if (el.tagName === \"FIELDSET\") continue;\n\n fields.push({\n name: getFieldLabel(el, root),\n message: getErrorMessage(el),\n });\n }\n\n return fields;\n}\n\n/**\n * Scan the page for visible error indicators that appeared after a submit\n * attempt. This catches errors even when:\n * - The errored field is in another tab/step of a multi-step form\n * - The form doesn't use aria-invalid at all\n * - Errors are rendered as standalone alert divs\n */\nfunction collectVisibleErrors(root: HTMLElement): FormErrorField[] {\n const fields: FormErrorField[] = [];\n const seen = new Set<string>();\n\n // 1. role=\"alert\" elements that appeared (error toasts, inline messages)\n const alerts = root.querySelectorAll<HTMLElement>('[role=\"alert\"]');\n for (const el of alerts) {\n const text = el.textContent?.trim();\n if (!text || text.length > 200) continue;\n if (seen.has(text)) continue;\n seen.add(text);\n fields.push({ name: \"alert\", message: text });\n }\n\n // 2. Common error class patterns (data-error, .error, .field-error, etc.)\n const errorEls = root.querySelectorAll<HTMLElement>(\n \"[data-error], [data-field-error], .error-message, .field-error, .form-error\",\n );\n for (const el of errorEls) {\n const text = el.textContent?.trim();\n if (!text || text.length > 200) continue;\n if (seen.has(text)) continue;\n seen.add(text);\n fields.push({ name: \"error\", message: text });\n }\n\n return fields;\n}\n\nfunction isSubmitButton(el: HTMLElement): el is HTMLButtonElement {\n if (el.tagName === \"BUTTON\") {\n const type = el.getAttribute(\"type\");\n // Buttons default to type=\"submit\" inside forms when no type is set\n return type === \"submit\" || type === null || type === \"\";\n }\n if (el.tagName === \"INPUT\") {\n return (el as HTMLInputElement).type === \"submit\";\n }\n return false;\n}\n\nfunction findClosestForm(el: HTMLElement): HTMLFormElement | null {\n // Direct form association\n if (\"form\" in el && (el as HTMLButtonElement).form) {\n return (el as HTMLButtonElement).form;\n }\n return el.closest(\"form\");\n}\n\n// ── Collector ──────────────────────────────────────────────────────────────────\n\nexport function createFormErrorCollector(): FormErrorCollector {\n const entries: FormErrorEntry[] = [];\n const attemptCounts = new Map<string, number>();\n let active = false;\n\n // Handlers we need to clean up\n let submitHandler: ((e: Event) => void) | null = null;\n let invalidHandler: ((e: Event) => void) | null = null;\n let clickHandler: ((e: MouseEvent) => void) | null = null;\n\n // Track whether a real submit event followed a button click\n let lastSubmitTime = 0;\n\n // Dedup: avoid recording the same form twice within a short window\n const recentRecords = new Map<string, number>();\n const DEDUP_MS = 500;\n\n function push(entry: FormErrorEntry) {\n // Dedup check\n const _key = `${entry.formId}:${entry.timestamp}`;\n const last = recentRecords.get(entry.formId);\n if (last && entry.timestamp - last < DEDUP_MS) return;\n recentRecords.set(entry.formId, entry.timestamp);\n\n entries.push(entry);\n if (entries.length > MAX_ENTRIES) entries.shift();\n }\n\n function recordFormErrors(form: HTMLFormElement, type: FormErrorEntry[\"type\"]) {\n const formId = getFormId(form);\n\n // Strategy 1: aria-invalid / :invalid fields\n let fields = collectInvalidFields(form);\n\n // Strategy 2: if no aria-invalid fields found, look for visible error messages\n if (fields.length === 0) {\n fields = collectVisibleErrors(form);\n }\n\n if (fields.length === 0) return;\n\n const count = (attemptCounts.get(formId) ?? 0) + 1;\n attemptCounts.set(formId, count);\n\n push({\n type,\n formId,\n fields,\n attemptNumber: count,\n url: location.href,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Handle clicks on submit buttons. If no submit event follows within\n * SILENT_SUBMIT_WINDOW_MS, it means the form library blocked the submit\n * entirely — scan for errors.\n */\n function handleSubmitButtonClick(button: HTMLElement) {\n const form = findClosestForm(button);\n\n setTimeout(() => {\n if (!active) return;\n // A real submit event fired — the submitHandler already took care of it\n if (Date.now() - lastSubmitTime < SILENT_SUBMIT_WINDOW_MS) return;\n\n // No submit event → silent failure\n const root = form ?? (document.body as HTMLElement);\n const formId = form ? getFormId(form) : `page:${location.pathname}`;\n\n let fields = form ? collectInvalidFields(form) : [];\n if (fields.length === 0) {\n fields = collectVisibleErrors(root);\n }\n\n // Also scan full page — the error might be in a toast or outside the form\n if (fields.length === 0 && form) {\n fields = collectVisibleErrors(document.body);\n }\n\n if (fields.length === 0) return;\n\n const count = (attemptCounts.get(formId) ?? 0) + 1;\n attemptCounts.set(formId, count);\n\n push({\n type: \"silent_submit\",\n formId,\n fields,\n attemptNumber: count,\n url: location.href,\n timestamp: Date.now(),\n });\n }, SILENT_SUBMIT_WINDOW_MS);\n }\n\n return {\n start() {\n if (active) return;\n active = true;\n\n // 1. Capture submit events (fires even with e.preventDefault())\n submitHandler = (e: Event) => {\n lastSubmitTime = Date.now();\n const form = e.target as HTMLFormElement;\n if (!(form instanceof HTMLFormElement)) return;\n\n setTimeout(() => {\n if (!active) return;\n recordFormErrors(form, \"validation_failed\");\n }, POST_SUBMIT_CHECK_MS);\n };\n document.addEventListener(\"submit\", submitHandler, true);\n\n // 2. Capture native invalid events (HTML5 constraint validation)\n invalidHandler = (e: Event) => {\n lastSubmitTime = Date.now();\n const field = e.target as HTMLElement;\n const form = field.closest(\"form\");\n if (!form) return;\n\n setTimeout(() => {\n if (!active) return;\n recordFormErrors(form, \"validation_failed\");\n }, POST_SUBMIT_CHECK_MS);\n };\n document.addEventListener(\"invalid\", invalidHandler, true);\n\n // 3. Capture clicks on submit buttons — catches silent failures\n // where the form lib eats the submit and shows nothing\n clickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target) return;\n\n // Walk up to find the actual button (click might be on an icon/span inside)\n const button = target.closest(\"button, input[type=submit]\") as HTMLElement | null;\n if (!button) return;\n if (!isSubmitButton(button)) return;\n\n handleSubmitButtonClick(button);\n };\n document.addEventListener(\"click\", clickHandler, true);\n },\n\n stop() {\n if (!active) return;\n active = false;\n if (submitHandler) document.removeEventListener(\"submit\", submitHandler, true);\n if (invalidHandler) document.removeEventListener(\"invalid\", invalidHandler, true);\n if (clickHandler) document.removeEventListener(\"click\", clickHandler, true);\n attemptCounts.clear();\n recentRecords.clear();\n },\n\n getEntries() {\n return [...entries];\n },\n\n report(formId: string, errors: Record<string, { message?: string } | undefined>) {\n const fields: FormErrorField[] = [];\n for (const [name, err] of Object.entries(errors)) {\n if (!err) continue;\n fields.push({ name, message: err.message });\n }\n if (fields.length === 0) return;\n\n const count = (attemptCounts.get(formId) ?? 0) + 1;\n attemptCounts.set(formId, count);\n\n push({\n type: \"validation_failed\",\n formId,\n fields,\n attemptNumber: count,\n url: location.href,\n timestamp: Date.now(),\n });\n },\n };\n}\n","export interface FrustrationEvent {\n type: \"rage_click\" | \"dead_click\" | \"error_loop\";\n timestamp: number;\n target: string;\n details: string;\n url: string;\n}\n\nexport interface FrustrationCollector {\n start(): void;\n stop(): void;\n getEvents(): FrustrationEvent[];\n onFrustration(callback: (event: FrustrationEvent) => void): () => void;\n}\n\nexport function createFrustrationCollector(opts?: {\n rageClickThreshold?: number;\n rageClickWindow?: number;\n errorLoopThreshold?: number;\n errorLoopWindow?: number;\n enableDeadClicks?: boolean;\n}): FrustrationCollector {\n const threshold = opts?.rageClickThreshold ?? 3;\n const window = opts?.rageClickWindow ?? 500;\n const errorThreshold = opts?.errorLoopThreshold ?? 3;\n const errorWindow = opts?.errorLoopWindow ?? 30_000;\n const deadClicksEnabled = opts?.enableDeadClicks ?? true;\n\n const events: FrustrationEvent[] = [];\n const listeners = new Set<(event: FrustrationEvent) => void>();\n const clickHistory: { target: EventTarget | null; time: number }[] = [];\n const errorCounts = new Map<string, { count: number; firstSeen: number }>();\n let clickHandler: ((e: MouseEvent) => void) | null = null;\n let origConsoleError: typeof console.error | null = null;\n\n function emit(event: FrustrationEvent) {\n events.push(event);\n if (events.length > 50) events.shift();\n for (const cb of listeners) cb(event);\n }\n\n function getCSSSelector(el: Element): string {\n if (el.id) return `#${el.id}`;\n const tag = el.tagName.toLowerCase();\n const cls = [...el.classList].slice(0, 3).join(\".\");\n if (cls) return `${tag}.${cls}`;\n return tag;\n }\n\n function isInteractive(el: HTMLElement): boolean {\n const tag = el.tagName.toLowerCase();\n if ([\"a\", \"button\", \"input\", \"select\", \"textarea\", \"label\", \"summary\"].includes(tag)) return true;\n if (el.getAttribute(\"role\") === \"button\" || el.getAttribute(\"tabindex\")) return true;\n if (el.onclick || el.getAttribute(\"onclick\")) return true;\n if (el.closest(\"a, button, [role=button], [onclick]\")) return true;\n try {\n if (getComputedStyle(el).cursor === \"pointer\") return true;\n } catch {\n /* getComputedStyle may throw */\n }\n return false;\n }\n\n function handleClick(e: MouseEvent) {\n const target = e.target as HTMLElement;\n if (!target) return;\n const now = Date.now();\n\n // --- Rage click detection ---\n clickHistory.push({ target, time: now });\n // Remove old clicks\n while (clickHistory.length > 0 && now - clickHistory[0].time > 1000) {\n clickHistory.shift();\n }\n const recentOnSame = clickHistory.filter((c) => c.target === target && now - c.time < window);\n if (recentOnSame.length >= threshold) {\n emit({\n type: \"rage_click\",\n timestamp: now,\n target: getCSSSelector(target),\n details: `${recentOnSame.length} clicks in ${now - recentOnSame[0].time}ms`,\n url: globalThis.location?.href ?? \"\",\n });\n clickHistory.length = 0;\n }\n\n // --- Dead click detection ---\n if (deadClicksEnabled && !isInteractive(target)) {\n emit({\n type: \"dead_click\",\n timestamp: now,\n target: getCSSSelector(target),\n details: `Click on non-interactive <${target.tagName.toLowerCase()}>`,\n url: globalThis.location?.href ?? \"\",\n });\n }\n }\n\n function patchConsoleError() {\n origConsoleError = console.error;\n console.error = (...args: unknown[]) => {\n origConsoleError?.apply(console, args);\n // Check for error loop\n const key = String(args[0]).slice(0, 100);\n const now = Date.now();\n const existing = errorCounts.get(key);\n if (existing && now - existing.firstSeen < errorWindow) {\n existing.count++;\n if (existing.count >= errorThreshold) {\n emit({\n type: \"error_loop\",\n timestamp: now,\n target: \"console\",\n details: `Same error ${existing.count}x in ${Math.round((now - existing.firstSeen) / 1000)}s: ${key}`,\n url: globalThis.location?.href ?? \"\",\n });\n errorCounts.delete(key);\n }\n } else {\n errorCounts.set(key, { count: 1, firstSeen: now });\n }\n };\n }\n\n return {\n start() {\n clickHandler = handleClick;\n document.addEventListener(\"click\", clickHandler, true);\n patchConsoleError();\n },\n stop() {\n if (clickHandler) document.removeEventListener(\"click\", clickHandler, true);\n if (origConsoleError) console.error = origConsoleError;\n clickHistory.length = 0;\n errorCounts.clear();\n },\n getEvents() {\n return [...events];\n },\n onFrustration(callback) {\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n };\n}\n","import type { NetworkEntry } from \"../types.js\";\n\nconst MAX_ENTRIES = 50;\n\nfunction isBlockedUrl(url: string, blocked: Set<string>): boolean {\n try {\n const host = new URL(url, location.href).hostname;\n return [...blocked].some((b) => host === b || host.endsWith(\".\" + b));\n } catch {\n return false;\n }\n}\n\nexport interface NetworkCollector {\n start(): void;\n stop(): void;\n getEntries(): NetworkEntry[];\n}\n\nfunction truncateUrl(url: string): string {\n try {\n const u = new URL(url, location.href);\n const base = `${u.origin}${u.pathname}`;\n return base.length > 200 ? base.slice(0, 200) + \"\\u2026\" : base;\n } catch {\n return url.length > 200 ? url.slice(0, 200) + \"\\u2026\" : url;\n }\n}\n\nexport function createNetworkCollector(extraBlockedHosts: string[] = []): NetworkCollector {\n const entries: NetworkEntry[] = [];\n const blocked = new Set(extraBlockedHosts);\n let origFetch: typeof window.fetch | null = null;\n let origXHROpen: typeof XMLHttpRequest.prototype.open | null = null;\n let active = false;\n\n function push(entry: NetworkEntry) {\n entries.push(entry);\n if (entries.length > MAX_ENTRIES) entries.shift();\n }\n\n return {\n start() {\n if (active) return;\n active = true;\n\n // -- Patch fetch --\n origFetch = window.fetch;\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const method = ((init?.method ?? \"GET\") as string).toUpperCase();\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : (input as Request).url;\n const startTime = Date.now();\n const res = await origFetch!.call(window, input, init);\n if (!isBlockedUrl(url, blocked)) {\n push({\n method,\n url: truncateUrl(url),\n status: res.status,\n duration: Date.now() - startTime,\n timestamp: startTime,\n });\n }\n return res;\n };\n\n // -- Patch XHR --\n origXHROpen = XMLHttpRequest.prototype.open;\n XMLHttpRequest.prototype.open = function (\n method: string,\n url: string | URL,\n async?: boolean,\n username?: string | null,\n password?: string | null,\n ) {\n const startTime = Date.now();\n const urlStr = typeof url === \"string\" ? url : (url as URL).href;\n\n this.addEventListener(\"load\", () => {\n if (!isBlockedUrl(urlStr, blocked)) {\n push({\n method: method.toUpperCase(),\n url: truncateUrl(urlStr),\n status: this.status,\n duration: Date.now() - startTime,\n timestamp: startTime,\n });\n }\n });\n\n return origXHROpen!.apply(this, [method, url, async ?? true, username, password] as Parameters<\n typeof XMLHttpRequest.prototype.open\n >);\n };\n },\n\n stop() {\n if (!active) return;\n active = false;\n if (origFetch) window.fetch = origFetch;\n if (origXHROpen) XMLHttpRequest.prototype.open = origXHROpen;\n },\n\n getEntries() {\n return [...entries];\n },\n };\n}\n","import type { FormErrorCollector } from \"./collectors/formErrors.js\";\nimport type { FlintUser } from \"./types.js\";\n\nexport interface FlintState {\n user: FlintUser | undefined;\n sessionReplay: string | (() => string) | undefined;\n}\n\n// Holds a reference to the active form error collector so flint.reportFormError\n// can forward calls without the consumer needing to manage the collector.\nlet formErrorCollectorRef: FormErrorCollector | null = null;\n\nexport function _setFormErrorCollector(collector: FormErrorCollector | null) {\n formErrorCollectorRef = collector;\n}\n\nlet state: FlintState = { user: undefined, sessionReplay: undefined };\nconst listeners = new Set<() => void>();\n\nfunction emit() {\n for (const l of listeners) l();\n}\n\nexport function subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nexport function getSnapshot(): FlintState {\n return state;\n}\n\n/** @internal Use Flint.setUser() / Flint.setSessionReplay() / Flint.reportFormError() instead */\nexport const flint = {\n setUser(user: FlintUser | null) {\n state = { ...state, user: user ?? undefined };\n emit();\n },\n setSessionReplay(url: string | (() => string) | null) {\n state = { ...state, sessionReplay: url ?? undefined };\n emit();\n },\n\n /**\n * Report a form validation failure with exact field-level errors.\n * Call this from your form library's error callback.\n *\n * @example\n * // React Hook Form + Zod\n * const onSubmit = handleSubmit(onValid, (errors) => {\n * flint.reportFormError('checkout-form', errors);\n * });\n */\n reportFormError(formId: string, errors: Record<string, { message?: string } | undefined>) {\n formErrorCollectorRef?.report(formId, errors);\n },\n};\n","// Flint singleton — manages global collector lifecycle\nimport { submitReport } from \"./api.js\";\nimport type { ConsoleCollector } from \"./collectors/console.js\";\nimport { createConsoleCollector } from \"./collectors/console.js\";\nimport { collectEnvironment } from \"./collectors/environment.js\";\nimport type { FormErrorCollector } from \"./collectors/formErrors.js\";\nimport { createFormErrorCollector } from \"./collectors/formErrors.js\";\nimport type { FrustrationCollector } from \"./collectors/frustration.js\";\nimport { createFrustrationCollector } from \"./collectors/frustration.js\";\nimport type { NetworkCollector } from \"./collectors/network.js\";\nimport { createNetworkCollector } from \"./collectors/network.js\";\nimport { _setFormErrorCollector, flint, getSnapshot } from \"./store.js\";\nimport type { CollectedMeta, FlintConfig } from \"./types.js\";\n\nconst DEFAULT_REPLAY_BUFFER_MS = 60_000;\n\ninterface FlintInstance {\n config: FlintConfig;\n console: ConsoleCollector | null;\n network: NetworkCollector | null;\n formErrors: FormErrorCollector | null;\n frustration: FrustrationCollector | null;\n replayEvents: unknown[];\n stopReplay: (() => void) | null;\n}\n\nlet instance: FlintInstance | null = null;\n\nfunction debugLog(config: FlintConfig, ...args: unknown[]) {\n if (config.debug) console.log(\"[Flint]\", ...args);\n}\n\nfunction init(config: FlintConfig): void {\n if (instance) {\n console.warn(\"[Flint] Already initialized. Call Flint.shutdown() first to re-initialize.\");\n return;\n }\n\n const {\n enableConsole = true,\n enableNetwork = true,\n enableFormErrors = true,\n enableFrustration = false,\n autoReportFrustration = false,\n enableReplay = false,\n replayBufferMs = DEFAULT_REPLAY_BUFFER_MS,\n blockedHosts = [],\n frustration: frustrationOpts,\n onFrustration,\n _replayRecorder,\n _collectors,\n } = config;\n\n debugLog(config, \"Initializing\", {\n serverUrl: config.serverUrl,\n enableConsole,\n enableNetwork,\n enableFormErrors,\n enableFrustration,\n enableReplay,\n });\n\n // Determine Flint server host to block from network capture\n const flintHost = (() => {\n try {\n return new URL(config.serverUrl).hostname;\n } catch {\n return \"\";\n }\n })();\n\n const allBlockedHosts = [...blockedHosts, ...(flintHost ? [flintHost] : [])];\n\n // Create and start collectors (use injected factories if provided, e.g. React Native)\n const consoleCol = enableConsole ? (_collectors?.console?.() ?? createConsoleCollector()) : null;\n consoleCol?.start();\n\n const networkCol = enableNetwork\n ? (_collectors?.network?.(allBlockedHosts) ?? createNetworkCollector(allBlockedHosts))\n : null;\n networkCol?.start();\n\n const formErrorsCol = enableFormErrors ? createFormErrorCollector() : null;\n if (formErrorsCol) {\n formErrorsCol.start();\n _setFormErrorCollector(formErrorsCol);\n }\n\n const frustrationCol = enableFrustration ? createFrustrationCollector(frustrationOpts) : null;\n frustrationCol?.start();\n\n // Set user if provided\n if (config.user) {\n flint.setUser(config.user);\n }\n\n const replayEvents: unknown[] = [];\n let stopReplay: (() => void) | null = null;\n\n debugLog(config, \"Collectors started\", {\n console: !!consoleCol,\n network: !!networkCol,\n formErrors: !!formErrorsCol,\n frustration: !!frustrationCol,\n });\n\n instance = {\n config,\n console: consoleCol,\n network: networkCol,\n formErrors: formErrorsCol,\n frustration: frustrationCol,\n replayEvents,\n stopReplay: null,\n };\n\n // Start replay recording (async, via injected recorder)\n if (enableReplay && _replayRecorder) {\n _replayRecorder((event: unknown) => {\n replayEvents.push(event);\n const cutoff = Date.now() - replayBufferMs;\n while (replayEvents.length > 0 && (replayEvents[0] as { timestamp: number }).timestamp < cutoff) {\n replayEvents.shift();\n }\n }).then((stop) => {\n stopReplay = stop ?? null;\n if (instance) instance.stopReplay = stopReplay;\n });\n }\n\n // Wire frustration auto-report\n const getEnvironment = _collectors?.environment ?? collectEnvironment;\n if (frustrationCol && autoReportFrustration) {\n frustrationCol.onFrustration(async (event) => {\n debugLog(config, \"Frustration detected, auto-reporting:\", event.type, event.details);\n onFrustration?.(event);\n const user = getSnapshot().user ?? config.user;\n await submitReport(config.serverUrl, config.projectKey, {\n reporterId: user?.id ?? \"anonymous\",\n reporterName: user?.name ?? \"Anonymous\",\n reporterEmail: user?.email,\n description: `[Auto-detected] ${event.type.replace(/_/g, \" \")}: ${event.details}`,\n severity: event.type === \"error_loop\" ? \"P1\" : event.type === \"rage_click\" ? \"P2\" : \"P3\",\n url: event.url,\n source: \"auto_capture\",\n meta: {\n ...config.meta,\n environment: getEnvironment(),\n consoleLogs: consoleCol?.getEntries() ?? [],\n networkErrors: networkCol?.getEntries() ?? [],\n formErrors: formErrorsCol?.getEntries() ?? [],\n frustrationEvent: event,\n },\n }).catch(() => {});\n });\n } else if (frustrationCol && onFrustration) {\n frustrationCol.onFrustration(onFrustration);\n }\n\n // Auto-fetch remote integrations config if no externalReplayProvider was set\n if (!config.externalReplayProvider) {\n fetchProjectConfig(config.serverUrl, config.projectKey)\n .then((remote) => {\n if (!instance || !remote?.integrations) return;\n const dd = remote.integrations.datadog;\n if (dd?.enabled && dd.site) {\n // Lazy-import to avoid bundling datadog helper when not needed\n import(\"./integrations/datadog.js\").then(({ createDatadogReplayProvider }) => {\n if (!instance) return;\n instance.config = {\n ...instance.config,\n externalReplayProvider: createDatadogReplayProvider(dd.site as string),\n };\n debugLog(config, \"Remote Datadog integration loaded:\", dd.site);\n });\n }\n })\n .catch(() => {\n // Fail silently — remote config is optional\n });\n }\n}\n\n/** Fetch project integrations config from the server. */\nasync function fetchProjectConfig(\n serverUrl: string,\n projectKey: string,\n): Promise<{ integrations: Record<string, { enabled: boolean; [k: string]: unknown }> } | null> {\n try {\n const url = `${serverUrl.replace(/\\/$/, \"\")}/api/v1/project-config`;\n const res = await fetch(url, { headers: { \"x-project-key\": projectKey } });\n if (!res.ok) return null;\n return res.json();\n } catch {\n return null;\n }\n}\n\nfunction shutdown(): void {\n if (!instance) return;\n\n instance.console?.stop();\n instance.network?.stop();\n instance.formErrors?.stop();\n _setFormErrorCollector(null);\n instance.frustration?.stop();\n instance.stopReplay?.();\n instance = null;\n}\n\nfunction isInitialized(): boolean {\n return instance !== null;\n}\n\nfunction getInstance(): FlintInstance | null {\n return instance;\n}\n\nfunction getMeta(extraMeta?: Record<string, unknown>): CollectedMeta {\n const getEnvironment = instance?.config._collectors?.environment ?? collectEnvironment;\n return {\n ...extraMeta,\n environment: getEnvironment(),\n consoleLogs: instance?.console?.getEntries() ?? [],\n networkErrors: instance?.network?.getEntries() ?? [],\n formErrors: instance?.formErrors?.getEntries() ?? [],\n };\n}\n\nfunction getReplayEvents(): unknown[] {\n return instance ? [...instance.replayEvents] : [];\n}\n\nfunction getConfig(): FlintConfig | null {\n return instance?.config ?? null;\n}\n\nfunction getExternalReplayUrl(): string | undefined {\n // 1. Store value (set via Flint.setSessionReplay)\n const storeReplay = getSnapshot().sessionReplay;\n const fromStore = typeof storeReplay === \"function\" ? storeReplay() : storeReplay;\n if (fromStore) return fromStore;\n // 2. Config provider (e.g. createDatadogReplayProvider)\n return instance?.config.externalReplayProvider?.();\n}\n\nexport const Flint = {\n init,\n shutdown,\n isInitialized,\n getInstance,\n getMeta,\n getReplayEvents,\n getConfig,\n getExternalReplayUrl,\n setUser: flint.setUser,\n setSessionReplay: flint.setSessionReplay,\n reportFormError: flint.reportFormError,\n};\n","import type { Theme, ThemeOverride } from \"./types.js\";\n\nexport interface ResolvedTheme {\n background: string;\n backgroundSecondary: string;\n accent: string;\n accentHover: string;\n text: string;\n textMuted: string;\n border: string;\n shadow: string;\n buttonText: string;\n backdropFilter: string;\n}\n\nconst light: ResolvedTheme = {\n background: \"rgba(255,255,255,0.90)\",\n backgroundSecondary: \"rgba(249,250,251,0.75)\",\n accent: \"#2563eb\",\n accentHover: \"#1d4ed8\",\n text: \"#111827\",\n textMuted: \"#6b7280\",\n border: \"rgba(255,255,255,0.9)\",\n shadow: \"0 32px 80px rgba(0,0,0,0.18), 0 8px 32px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.04)\",\n buttonText: \"#ffffff\",\n backdropFilter: \"blur(32px) saturate(1.8)\",\n};\n\nconst dark: ResolvedTheme = {\n background: \"rgba(15,20,35,0.88)\",\n backgroundSecondary: \"rgba(5,8,18,0.65)\",\n accent: \"#4d8aff\",\n accentHover: \"#3b6fdb\",\n text: \"#dde3ef\",\n textMuted: \"#6b7a93\",\n border: \"rgba(255,255,255,0.08)\",\n shadow: \"0 24px 60px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04)\",\n buttonText: \"#ffffff\",\n backdropFilter: \"blur(32px) saturate(1.6)\",\n};\n\nexport function resolveTheme(theme: Theme): ResolvedTheme {\n if (theme === \"dark\") return dark;\n if (theme === \"light\") return light;\n // ThemeOverride — merge over light base\n const override = theme as ThemeOverride;\n return {\n ...light,\n background: override.background ?? light.background,\n accent: override.accent ?? light.accent,\n accentHover: override.accent ?? light.accentHover,\n text: override.text ?? light.text,\n border: override.border ?? light.border,\n };\n}\n"],"mappings":"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","names":["init","MAX_ENTRIES","window","listeners","emit","MAX_ENTRIES","init","createDatadogReplayProvider"]}