@diegotsi/flint-core 1.3.0 → 1.3.2
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.
- package/dist/index.cjs +76 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +76 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -620,6 +620,76 @@ function createFrustrationCollector(opts) {
|
|
|
620
620
|
|
|
621
621
|
// src/collectors/network.ts
|
|
622
622
|
var MAX_ENTRIES3 = 50;
|
|
623
|
+
var DEFAULT_BLOCKED_HOSTS = [
|
|
624
|
+
"browser-intake-datadoghq.com",
|
|
625
|
+
"datadoghq.com",
|
|
626
|
+
"datadoghq.eu",
|
|
627
|
+
"google.com",
|
|
628
|
+
"googleapis.com",
|
|
629
|
+
"google-analytics.com",
|
|
630
|
+
"googletagmanager.com",
|
|
631
|
+
"gstatic.com",
|
|
632
|
+
"doubleclick.net",
|
|
633
|
+
"facebook.com",
|
|
634
|
+
"facebook.net",
|
|
635
|
+
"hotjar.com",
|
|
636
|
+
"hotjar.io",
|
|
637
|
+
"intercom.io",
|
|
638
|
+
"intercomcdn.com",
|
|
639
|
+
"segment.io",
|
|
640
|
+
"segment.com",
|
|
641
|
+
"mixpanel.com",
|
|
642
|
+
"amplitude.com",
|
|
643
|
+
"sentry.io",
|
|
644
|
+
"fullstory.com",
|
|
645
|
+
"clarity.ms",
|
|
646
|
+
"newrelic.com",
|
|
647
|
+
"nr-data.net",
|
|
648
|
+
"cloudflareinsights.com",
|
|
649
|
+
"heapanalytics.com",
|
|
650
|
+
"posthog.com",
|
|
651
|
+
"logrocket.io",
|
|
652
|
+
"lr-in-prod.com",
|
|
653
|
+
"crowdin.net",
|
|
654
|
+
"crowdin.com"
|
|
655
|
+
];
|
|
656
|
+
var ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
657
|
+
".woff",
|
|
658
|
+
".woff2",
|
|
659
|
+
".ttf",
|
|
660
|
+
".otf",
|
|
661
|
+
".eot",
|
|
662
|
+
// fonts
|
|
663
|
+
".png",
|
|
664
|
+
".jpg",
|
|
665
|
+
".jpeg",
|
|
666
|
+
".gif",
|
|
667
|
+
".svg",
|
|
668
|
+
".webp",
|
|
669
|
+
".ico",
|
|
670
|
+
".avif",
|
|
671
|
+
// images
|
|
672
|
+
".css",
|
|
673
|
+
".map",
|
|
674
|
+
// styles & source maps
|
|
675
|
+
".js",
|
|
676
|
+
".mjs",
|
|
677
|
+
// scripts (usually loaded by browser, not app logic)
|
|
678
|
+
".mp3",
|
|
679
|
+
".mp4",
|
|
680
|
+
".webm",
|
|
681
|
+
".ogg"
|
|
682
|
+
// media
|
|
683
|
+
]);
|
|
684
|
+
function isAssetUrl(url) {
|
|
685
|
+
try {
|
|
686
|
+
const pathname = new URL(url, location.href).pathname;
|
|
687
|
+
const ext = pathname.slice(pathname.lastIndexOf(".")).toLowerCase();
|
|
688
|
+
return ASSET_EXTENSIONS.has(ext);
|
|
689
|
+
} catch {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
623
693
|
function isBlockedUrl(url, blocked) {
|
|
624
694
|
try {
|
|
625
695
|
const host = new URL(url, location.href).hostname;
|
|
@@ -628,6 +698,9 @@ function isBlockedUrl(url, blocked) {
|
|
|
628
698
|
return false;
|
|
629
699
|
}
|
|
630
700
|
}
|
|
701
|
+
function shouldIgnore(url, blocked) {
|
|
702
|
+
return isBlockedUrl(url, blocked) || isAssetUrl(url);
|
|
703
|
+
}
|
|
631
704
|
function truncateUrl(url) {
|
|
632
705
|
try {
|
|
633
706
|
const u = new URL(url, location.href);
|
|
@@ -639,7 +712,7 @@ function truncateUrl(url) {
|
|
|
639
712
|
}
|
|
640
713
|
function createNetworkCollector(extraBlockedHosts = []) {
|
|
641
714
|
const entries = [];
|
|
642
|
-
const blocked = new Set(extraBlockedHosts);
|
|
715
|
+
const blocked = /* @__PURE__ */ new Set([...DEFAULT_BLOCKED_HOSTS, ...extraBlockedHosts]);
|
|
643
716
|
let origFetch = null;
|
|
644
717
|
let origXHROpen = null;
|
|
645
718
|
let active = false;
|
|
@@ -657,7 +730,7 @@ function createNetworkCollector(extraBlockedHosts = []) {
|
|
|
657
730
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
658
731
|
const startTime = Date.now();
|
|
659
732
|
const res = await origFetch.call(window, input, init2);
|
|
660
|
-
if (!
|
|
733
|
+
if (!shouldIgnore(url, blocked)) {
|
|
661
734
|
push({
|
|
662
735
|
method,
|
|
663
736
|
url: truncateUrl(url),
|
|
@@ -673,7 +746,7 @@ function createNetworkCollector(extraBlockedHosts = []) {
|
|
|
673
746
|
const startTime = Date.now();
|
|
674
747
|
const urlStr = typeof url === "string" ? url : url.href;
|
|
675
748
|
this.addEventListener("load", () => {
|
|
676
|
-
if (!
|
|
749
|
+
if (!shouldIgnore(urlStr, blocked)) {
|
|
677
750
|
push({
|
|
678
751
|
method: method.toUpperCase(),
|
|
679
752
|
url: truncateUrl(urlStr),
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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"]}
|
|
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\n// Well-known third-party domains to always ignore\nconst DEFAULT_BLOCKED_HOSTS = [\n \"browser-intake-datadoghq.com\",\n \"datadoghq.com\",\n \"datadoghq.eu\",\n \"google.com\",\n \"googleapis.com\",\n \"google-analytics.com\",\n \"googletagmanager.com\",\n \"gstatic.com\",\n \"doubleclick.net\",\n \"facebook.com\",\n \"facebook.net\",\n \"hotjar.com\",\n \"hotjar.io\",\n \"intercom.io\",\n \"intercomcdn.com\",\n \"segment.io\",\n \"segment.com\",\n \"mixpanel.com\",\n \"amplitude.com\",\n \"sentry.io\",\n \"fullstory.com\",\n \"clarity.ms\",\n \"newrelic.com\",\n \"nr-data.net\",\n \"cloudflareinsights.com\",\n \"heapanalytics.com\",\n \"posthog.com\",\n \"logrocket.io\",\n \"lr-in-prod.com\",\n \"crowdin.net\",\n \"crowdin.com\",\n];\n\n// Static asset extensions to ignore\nconst ASSET_EXTENSIONS = new Set([\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".otf\",\n \".eot\", // fonts\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".svg\",\n \".webp\",\n \".ico\",\n \".avif\", // images\n \".css\",\n \".map\", // styles & source maps\n \".js\",\n \".mjs\", // scripts (usually loaded by browser, not app logic)\n \".mp3\",\n \".mp4\",\n \".webm\",\n \".ogg\", // media\n]);\n\nfunction isAssetUrl(url: string): boolean {\n try {\n const pathname = new URL(url, location.href).pathname;\n const ext = pathname.slice(pathname.lastIndexOf(\".\")).toLowerCase();\n return ASSET_EXTENSIONS.has(ext);\n } catch {\n return false;\n }\n}\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\nfunction shouldIgnore(url: string, blocked: Set<string>): boolean {\n return isBlockedUrl(url, blocked) || isAssetUrl(url);\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([...DEFAULT_BLOCKED_HOSTS, ...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 (!shouldIgnore(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 (!shouldIgnore(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"]}
|
package/dist/index.js
CHANGED
|
@@ -548,6 +548,76 @@ function createFrustrationCollector(opts) {
|
|
|
548
548
|
|
|
549
549
|
// src/collectors/network.ts
|
|
550
550
|
var MAX_ENTRIES3 = 50;
|
|
551
|
+
var DEFAULT_BLOCKED_HOSTS = [
|
|
552
|
+
"browser-intake-datadoghq.com",
|
|
553
|
+
"datadoghq.com",
|
|
554
|
+
"datadoghq.eu",
|
|
555
|
+
"google.com",
|
|
556
|
+
"googleapis.com",
|
|
557
|
+
"google-analytics.com",
|
|
558
|
+
"googletagmanager.com",
|
|
559
|
+
"gstatic.com",
|
|
560
|
+
"doubleclick.net",
|
|
561
|
+
"facebook.com",
|
|
562
|
+
"facebook.net",
|
|
563
|
+
"hotjar.com",
|
|
564
|
+
"hotjar.io",
|
|
565
|
+
"intercom.io",
|
|
566
|
+
"intercomcdn.com",
|
|
567
|
+
"segment.io",
|
|
568
|
+
"segment.com",
|
|
569
|
+
"mixpanel.com",
|
|
570
|
+
"amplitude.com",
|
|
571
|
+
"sentry.io",
|
|
572
|
+
"fullstory.com",
|
|
573
|
+
"clarity.ms",
|
|
574
|
+
"newrelic.com",
|
|
575
|
+
"nr-data.net",
|
|
576
|
+
"cloudflareinsights.com",
|
|
577
|
+
"heapanalytics.com",
|
|
578
|
+
"posthog.com",
|
|
579
|
+
"logrocket.io",
|
|
580
|
+
"lr-in-prod.com",
|
|
581
|
+
"crowdin.net",
|
|
582
|
+
"crowdin.com"
|
|
583
|
+
];
|
|
584
|
+
var ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
585
|
+
".woff",
|
|
586
|
+
".woff2",
|
|
587
|
+
".ttf",
|
|
588
|
+
".otf",
|
|
589
|
+
".eot",
|
|
590
|
+
// fonts
|
|
591
|
+
".png",
|
|
592
|
+
".jpg",
|
|
593
|
+
".jpeg",
|
|
594
|
+
".gif",
|
|
595
|
+
".svg",
|
|
596
|
+
".webp",
|
|
597
|
+
".ico",
|
|
598
|
+
".avif",
|
|
599
|
+
// images
|
|
600
|
+
".css",
|
|
601
|
+
".map",
|
|
602
|
+
// styles & source maps
|
|
603
|
+
".js",
|
|
604
|
+
".mjs",
|
|
605
|
+
// scripts (usually loaded by browser, not app logic)
|
|
606
|
+
".mp3",
|
|
607
|
+
".mp4",
|
|
608
|
+
".webm",
|
|
609
|
+
".ogg"
|
|
610
|
+
// media
|
|
611
|
+
]);
|
|
612
|
+
function isAssetUrl(url) {
|
|
613
|
+
try {
|
|
614
|
+
const pathname = new URL(url, location.href).pathname;
|
|
615
|
+
const ext = pathname.slice(pathname.lastIndexOf(".")).toLowerCase();
|
|
616
|
+
return ASSET_EXTENSIONS.has(ext);
|
|
617
|
+
} catch {
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
551
621
|
function isBlockedUrl(url, blocked) {
|
|
552
622
|
try {
|
|
553
623
|
const host = new URL(url, location.href).hostname;
|
|
@@ -556,6 +626,9 @@ function isBlockedUrl(url, blocked) {
|
|
|
556
626
|
return false;
|
|
557
627
|
}
|
|
558
628
|
}
|
|
629
|
+
function shouldIgnore(url, blocked) {
|
|
630
|
+
return isBlockedUrl(url, blocked) || isAssetUrl(url);
|
|
631
|
+
}
|
|
559
632
|
function truncateUrl(url) {
|
|
560
633
|
try {
|
|
561
634
|
const u = new URL(url, location.href);
|
|
@@ -567,7 +640,7 @@ function truncateUrl(url) {
|
|
|
567
640
|
}
|
|
568
641
|
function createNetworkCollector(extraBlockedHosts = []) {
|
|
569
642
|
const entries = [];
|
|
570
|
-
const blocked = new Set(extraBlockedHosts);
|
|
643
|
+
const blocked = /* @__PURE__ */ new Set([...DEFAULT_BLOCKED_HOSTS, ...extraBlockedHosts]);
|
|
571
644
|
let origFetch = null;
|
|
572
645
|
let origXHROpen = null;
|
|
573
646
|
let active = false;
|
|
@@ -585,7 +658,7 @@ function createNetworkCollector(extraBlockedHosts = []) {
|
|
|
585
658
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
586
659
|
const startTime = Date.now();
|
|
587
660
|
const res = await origFetch.call(window, input, init2);
|
|
588
|
-
if (!
|
|
661
|
+
if (!shouldIgnore(url, blocked)) {
|
|
589
662
|
push({
|
|
590
663
|
method,
|
|
591
664
|
url: truncateUrl(url),
|
|
@@ -601,7 +674,7 @@ function createNetworkCollector(extraBlockedHosts = []) {
|
|
|
601
674
|
const startTime = Date.now();
|
|
602
675
|
const urlStr = typeof url === "string" ? url : url.href;
|
|
603
676
|
this.addEventListener("load", () => {
|
|
604
|
-
if (!
|
|
677
|
+
if (!shouldIgnore(urlStr, blocked)) {
|
|
605
678
|
push({
|
|
606
679
|
method: method.toUpperCase(),
|
|
607
680
|
url: truncateUrl(urlStr),
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../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":["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"]}
|
|
1
|
+
{"version":3,"sources":["../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":["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\n// Well-known third-party domains to always ignore\nconst DEFAULT_BLOCKED_HOSTS = [\n \"browser-intake-datadoghq.com\",\n \"datadoghq.com\",\n \"datadoghq.eu\",\n \"google.com\",\n \"googleapis.com\",\n \"google-analytics.com\",\n \"googletagmanager.com\",\n \"gstatic.com\",\n \"doubleclick.net\",\n \"facebook.com\",\n \"facebook.net\",\n \"hotjar.com\",\n \"hotjar.io\",\n \"intercom.io\",\n \"intercomcdn.com\",\n \"segment.io\",\n \"segment.com\",\n \"mixpanel.com\",\n \"amplitude.com\",\n \"sentry.io\",\n \"fullstory.com\",\n \"clarity.ms\",\n \"newrelic.com\",\n \"nr-data.net\",\n \"cloudflareinsights.com\",\n \"heapanalytics.com\",\n \"posthog.com\",\n \"logrocket.io\",\n \"lr-in-prod.com\",\n \"crowdin.net\",\n \"crowdin.com\",\n];\n\n// Static asset extensions to ignore\nconst ASSET_EXTENSIONS = new Set([\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".otf\",\n \".eot\", // fonts\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".svg\",\n \".webp\",\n \".ico\",\n \".avif\", // images\n \".css\",\n \".map\", // styles & source maps\n \".js\",\n \".mjs\", // scripts (usually loaded by browser, not app logic)\n \".mp3\",\n \".mp4\",\n \".webm\",\n \".ogg\", // media\n]);\n\nfunction isAssetUrl(url: string): boolean {\n try {\n const pathname = new URL(url, location.href).pathname;\n const ext = pathname.slice(pathname.lastIndexOf(\".\")).toLowerCase();\n return ASSET_EXTENSIONS.has(ext);\n } catch {\n return false;\n }\n}\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\nfunction shouldIgnore(url: string, blocked: Set<string>): boolean {\n return isBlockedUrl(url, blocked) || isAssetUrl(url);\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([...DEFAULT_BLOCKED_HOSTS, ...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 (!shouldIgnore(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 (!shouldIgnore(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":";;;;;;AAAA,SAAS,gBAAgB;AAGzB,eAAe,eAAe,KAAaA,OAAmB,UAAU,GAAG,YAAY,KAAyB;AAC9G,WAAS,UAAU,GAAG,WAAW,SAAS,WAAW;AACnD,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,KAAKA,KAAI;AACjC,UAAI,IAAI,MAAM,YAAY,QAAS,QAAO;AAE1C,UAAI,IAAI,UAAU,OAAO,IAAI,SAAS,OAAO,IAAI,WAAW,IAAK,QAAO;AAAA,IAC1E,SAAS,KAAK;AACZ,UAAI,YAAY,QAAS,OAAM;AAAA,IACjC;AACA,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,YAAY,KAAK,OAAO,CAAC;AAAA,EAClE;AACA,QAAM,IAAI,MAAM,sBAAsB;AACxC;AAEA,eAAsB,aACpB,WACA,YACA,SACA,YACuB;AACvB,QAAM,MAAM,GAAG,UAAU,QAAQ,OAAO,EAAE,CAAC;AAE3C,MAAI;AACJ,QAAM,UAAkC;AAAA,IACtC,iBAAiB;AAAA,EACnB;AAEA,MAAI,YAAY;AACd,UAAM,OAAO,IAAI,SAAS;AAC1B,SAAK,OAAO,cAAc,QAAQ,UAAU;AAC5C,SAAK,OAAO,gBAAgB,QAAQ,YAAY;AAChD,QAAI,QAAQ,cAAe,MAAK,OAAO,iBAAiB,QAAQ,aAAa;AAC7E,SAAK,OAAO,eAAe,QAAQ,WAAW;AAC9C,QAAI,QAAQ,iBAAkB,MAAK,OAAO,oBAAoB,QAAQ,gBAAgB;AACtF,QAAI,QAAQ,iBAAkB,MAAK,OAAO,oBAAoB,KAAK,UAAU,QAAQ,gBAAgB,CAAC;AACtG,QAAI,QAAQ,kBAAmB,MAAK,OAAO,qBAAqB,QAAQ,iBAAiB;AACzF,QAAI,QAAQ,kBAAmB,MAAK,OAAO,qBAAqB,QAAQ,iBAAiB;AACzF,SAAK,OAAO,YAAY,QAAQ,QAAQ;AACxC,QAAI,QAAQ,IAAK,MAAK,OAAO,OAAO,QAAQ,GAAG;AAC/C,QAAI,QAAQ,KAAM,MAAK,OAAO,QAAQ,KAAK,UAAU,QAAQ,IAAI,CAAC;AAClE,SAAK,OAAO,cAAc,UAAU;AACpC,WAAO;AAAA,EACT,OAAO;AACL,WAAO,KAAK,UAAU,OAAO;AAC7B,YAAQ,cAAc,IAAI;AAAA,EAC5B;AAEA,QAAM,MAAM,MAAM,eAAe,KAAK,EAAE,QAAQ,QAAQ,SAAS,KAAK,CAAC;AAEvE,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,MAAM,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,OAAO,gBAAgB,EAAE;AACrE,UAAM,IAAI,MAAO,IAA2B,SAAS,QAAQ,IAAI,MAAM,EAAE;AAAA,EAC3E;AAEA,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,aACpB,WACA,YACA,UACA,QACe;AACf,QAAM,OAAO,KAAK,UAAU,MAAM;AAClC,QAAM,UAAU,IAAI,YAAY,EAAE,OAAO,IAAI;AAC7C,QAAM,aAAa,SAAS,OAAO;AAEnC,QAAM,MAAM,GAAG,UAAU,QAAQ,OAAO,EAAE,CAAC,uBAAuB,QAAQ;AAC1E,QAAM,MAAM,KAAK;AAAA,IACf,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,WAAW;AAAA,EACnB,CAAC;AACH;;;AC9EA,IAAM,cAAc;AAGpB,IAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;AAEA,SAAS,SAAS,KAAqB;AACrC,MAAI,SAAS;AACb,aAAW,WAAW,oBAAoB;AACxC,aAAS,OAAO,QAAQ,SAAS,YAAY;AAAA,EAC/C;AACA,SAAO;AACT;AAQO,SAAS,yBAA2C;AACzD,QAAM,UAA0B,CAAC;AACjC,MAAI,SAAS;AAEb,QAAM,YAAY;AAAA,IAChB,KAAK,QAAQ,IAAI,KAAK,OAAO;AAAA,IAC7B,MAAM,QAAQ,KAAK,KAAK,OAAO;AAAA,IAC/B,OAAO,QAAQ,MAAM,KAAK,OAAO;AAAA,EACnC;AAEA,MAAI,cAAqC;AACzC,MAAI,gBAAoD;AAExD,WAAS,KAAK,OAA8B,MAAiB;AAC3D,QAAI;AACJ,QAAI;AACF,YAAM,KAAK,IAAI,CAAC,MAAO,OAAO,MAAM,WAAW,IAAI,KAAK,UAAU,CAAC,CAAE,EAAE,KAAK,GAAG;AAAA,IACjF,QAAQ;AACN,YAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACtB;AACA,QAAI,IAAI,SAAS,IAAK,OAAM,IAAI,MAAM,GAAG,GAAG,IAAI;AAChD,UAAM,SAAS,GAAG;AAClB,YAAQ,KAAK,EAAE,OAAO,MAAM,KAAK,WAAW,KAAK,IAAI,EAAE,CAAC;AACxD,QAAI,QAAQ,SAAS,YAAa,SAAQ,MAAM;AAAA,EAClD;AAEA,SAAO;AAAA,IACL,QAAQ;AACN,UAAI,OAAQ;AACZ,eAAS;AAET,cAAQ,MAAM,IAAI,SAAoB;AACpC,aAAK,OAAO,IAAI;AAChB,kBAAU,IAAI,GAAG,IAAI;AAAA,MACvB;AACA,cAAQ,OAAO,IAAI,SAAoB;AACrC,aAAK,QAAQ,IAAI;AACjB,kBAAU,KAAK,GAAG,IAAI;AAAA,MACxB;AACA,cAAQ,QAAQ,IAAI,SAAoB;AACtC,aAAK,SAAS,IAAI;AAClB,kBAAU,MAAM,GAAG,IAAI;AAAA,MACzB;AAEA,oBAAc,OAAO;AACrB,aAAO,UAAU,CAAC,KAAK,KAAK,MAAM,KAAK,QAAQ;AAC7C,aAAK,SAAS,CAAC,KAAK,WAAW,OAAO,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;AACpE,YAAI,OAAO,gBAAgB,WAAY,QAAO,YAAY,KAAK,KAAK,MAAM,KAAK,GAAG;AAClF,eAAO;AAAA,MACT;AAEA,sBAAgB,OAAO;AACvB,aAAO,uBAAuB,CAAC,UAAU;AACvC,cAAM,SAAS,MAAM,kBAAkB,QAAQ,MAAM,OAAO,UAAU,KAAK,UAAU,MAAM,MAAM;AACjG,aAAK,SAAS,CAAC,uBAAuB,MAAM,CAAC;AAC7C,YAAI,OAAO,kBAAkB,WAAY,eAAc,KAAK,QAAQ,KAAK;AAAA,MAC3E;AAAA,IACF;AAAA,IAEA,OAAO;AACL,UAAI,CAAC,OAAQ;AACb,eAAS;AACT,cAAQ,MAAM,UAAU;AACxB,cAAQ,OAAO,UAAU;AACzB,cAAQ,QAAQ,UAAU;AAC1B,aAAO,UAAU;AACjB,aAAO,uBAAuB;AAAA,IAChC;AAAA,IAEA,aAAa;AACX,aAAO,CAAC,GAAG,OAAO;AAAA,IACpB;AAAA,EACF;AACF;;;AClGO,SAAS,qBAAsC;AACpD,QAAM,KAAK,UAAU;AAGrB,MAAI,UAAU;AACd,QAAM,UAAU,GAAG,MAAM,eAAe;AACxC,QAAM,WAAW,GAAG,MAAM,gBAAgB;AAC1C,QAAM,QAAQ,GAAG,MAAM,YAAY;AACnC,QAAM,UAAU,GAAG,MAAM,gBAAgB;AACzC,QAAM,SAAS,GAAG,MAAM,YAAY;AAEpC,MAAI,QAAQ;AACV,cAAU,SAAS,OAAO,CAAC,CAAC;AAAA,EAC9B,WAAW,OAAO;AAChB,cAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,EAC5B,WAAW,WAAW,CAAC,UAAU,KAAK,EAAE,GAAG;AACzC,cAAU,UAAU,QAAQ,CAAC,CAAC;AAAA,EAChC,WAAW,UAAU;AACnB,cAAU,WAAW,SAAS,CAAC,CAAC;AAAA,EAClC,WAAW,WAAW,WAAW,KAAK,EAAE,GAAG;AACzC,cAAU,UAAU,QAAQ,CAAC,CAAC;AAAA,EAChC;AAGA,MAAI,KAAK;AACT,QAAM,OAAO,GAAG,MAAM,uBAAuB;AAC7C,QAAM,OAAO,GAAG,MAAM,uBAAuB;AAC7C,QAAM,WAAW,GAAG,MAAM,eAAe;AACzC,QAAM,OAAO,GAAG,MAAM,wBAAwB;AAE9C,MAAI,MAAM;AACR,SAAK,SAAS,KAAK,CAAC,EAAE,QAAQ,KAAK,GAAG,CAAC;AAAA,EACzC,WAAW,MAAM;AACf,UAAM,SAAiC;AAAA,MACrC,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AACA,SAAK,WAAW,OAAO,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;AAAA,EAC5C,WAAW,UAAU;AACnB,SAAK,WAAW,SAAS,CAAC,CAAC;AAAA,EAC7B,WAAW,MAAM;AACf,SAAK,OAAO,KAAK,CAAC,EAAE,QAAQ,MAAM,GAAG,CAAC;AAAA,EACxC,WAAW,QAAQ,KAAK,EAAE,GAAG;AAC3B,SAAK;AAAA,EACP;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,GAAG,OAAO,UAAU,IAAI,OAAO,WAAW;AAAA,IACpD,QAAQ,GAAG,OAAO,KAAK,IAAI,OAAO,MAAM;AAAA,IACxC,UAAU,UAAU;AAAA,IACpB,UAAU,KAAK,eAAe,EAAE,gBAAgB,EAAE;AAAA,IAClD,QAAQ,UAAU;AAAA,EACpB;AACF;;;ACzDA,IAAMC,eAAc;AAOpB,IAAM,uBAAuB;AAS7B,IAAM,0BAA0B;AAqBhC,SAAS,UAAU,MAA+B;AAChD,MAAI,KAAK,GAAI,QAAO,IAAI,KAAK,EAAE;AAC/B,MAAI,KAAK,aAAa,MAAM,EAAG,QAAO,cAAc,KAAK,aAAa,MAAM,CAAC;AAC7E,MAAI,KAAK,UAAU,KAAK,WAAW,SAAS,KAAM,QAAO,KAAK;AAC9D,SAAO,QAAQ,MAAM,KAAK,SAAS,KAAK,EAAE,QAAQ,IAAI,CAAC;AACzD;AAEA,SAAS,cAAc,OAAoB,MAA2B;AACpE,QAAM,YAAY,MAAM,aAAa,YAAY;AACjD,MAAI,UAAW,QAAO;AAEtB,QAAM,KAAK,MAAM;AACjB,MAAI,IAAI;AACN,UAAM,QAAQ,KAAK,cAAgC,cAAc,EAAE,IAAI;AACvE,QAAI,OAAO,YAAa,QAAO,MAAM,YAAY,KAAK;AAAA,EACxD;AAEA,QAAM,cAAc,MAAM,QAAQ,OAAO;AACzC,MAAI,aAAa,aAAa;AAC5B,UAAM,OAAO,YAAY,YAAY,KAAK;AAC1C,QAAI,KAAK,SAAS,GAAI,QAAO;AAAA,EAC/B;AAEA,SAAQ,MAA2B,QAAS,MAA2B,eAAe,MAAM,QAAQ,YAAY;AAClH;AAEA,SAAS,gBAAgB,OAAwC;AAE/D,QAAM,QAAQ,MAAM,aAAa,mBAAmB;AACpD,MAAI,OAAO;AACT,UAAM,KAAK,SAAS,eAAe,KAAK;AACxC,QAAI,IAAI,YAAa,QAAO,GAAG,YAAY,KAAK;AAAA,EAClD;AAGA,QAAM,SAAS,MAAM,aAAa,kBAAkB;AACpD,MAAI,QAAQ;AACV,eAAW,MAAM,OAAO,MAAM,KAAK,GAAG;AACpC,YAAM,KAAK,SAAS,eAAe,EAAE;AACrC,UAAI,IAAI,aAAa,KAAK,EAAG,QAAO,GAAG,YAAY,KAAK;AAAA,IAC1D;AAAA,EACF;AAGA,MAAI,iBAAiB,oBAAoB,iBAAiB,uBAAuB,iBAAiB,mBAAmB;AACnH,QAAI,MAAM,kBAAmB,QAAO,MAAM;AAAA,EAC5C;AAGA,QAAM,OAAO,MAAM;AACnB,MAAI,MAAM,aAAa,MAAM,MAAM,WAAW,KAAK,aAAa;AAC9D,WAAO,KAAK,YAAY,KAAK;AAAA,EAC/B;AAEA,SAAO;AACT;AAMA,SAAS,qBAAqB,MAAqC;AACjE,QAAM,SAA2B,CAAC;AAClC,QAAM,aAAa,KAAK,iBAA8B,iCAAiC;AAEvF,aAAW,MAAM,YAAY;AAC3B,QAAI,cAAc,gBAAiB;AACnC,QAAI,GAAG,YAAY,WAAY;AAE/B,WAAO,KAAK;AAAA,MACV,MAAM,cAAc,IAAI,IAAI;AAAA,MAC5B,SAAS,gBAAgB,EAAE;AAAA,IAC7B,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AASA,SAAS,qBAAqB,MAAqC;AACjE,QAAM,SAA2B,CAAC;AAClC,QAAM,OAAO,oBAAI,IAAY;AAG7B,QAAM,SAAS,KAAK,iBAA8B,gBAAgB;AAClE,aAAW,MAAM,QAAQ;AACvB,UAAM,OAAO,GAAG,aAAa,KAAK;AAClC,QAAI,CAAC,QAAQ,KAAK,SAAS,IAAK;AAChC,QAAI,KAAK,IAAI,IAAI,EAAG;AACpB,SAAK,IAAI,IAAI;AACb,WAAO,KAAK,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,EAC9C;AAGA,QAAM,WAAW,KAAK;AAAA,IACpB;AAAA,EACF;AACA,aAAW,MAAM,UAAU;AACzB,UAAM,OAAO,GAAG,aAAa,KAAK;AAClC,QAAI,CAAC,QAAQ,KAAK,SAAS,IAAK;AAChC,QAAI,KAAK,IAAI,IAAI,EAAG;AACpB,SAAK,IAAI,IAAI;AACb,WAAO,KAAK,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,EAC9C;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,IAA0C;AAChE,MAAI,GAAG,YAAY,UAAU;AAC3B,UAAM,OAAO,GAAG,aAAa,MAAM;AAEnC,WAAO,SAAS,YAAY,SAAS,QAAQ,SAAS;AAAA,EACxD;AACA,MAAI,GAAG,YAAY,SAAS;AAC1B,WAAQ,GAAwB,SAAS;AAAA,EAC3C;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,IAAyC;AAEhE,MAAI,UAAU,MAAO,GAAyB,MAAM;AAClD,WAAQ,GAAyB;AAAA,EACnC;AACA,SAAO,GAAG,QAAQ,MAAM;AAC1B;AAIO,SAAS,2BAA+C;AAC7D,QAAM,UAA4B,CAAC;AACnC,QAAM,gBAAgB,oBAAI,IAAoB;AAC9C,MAAI,SAAS;AAGb,MAAI,gBAA6C;AACjD,MAAI,iBAA8C;AAClD,MAAI,eAAiD;AAGrD,MAAI,iBAAiB;AAGrB,QAAM,gBAAgB,oBAAI,IAAoB;AAC9C,QAAM,WAAW;AAEjB,WAAS,KAAK,OAAuB;AAEnC,UAAM,OAAO,GAAG,MAAM,MAAM,IAAI,MAAM,SAAS;AAC/C,UAAM,OAAO,cAAc,IAAI,MAAM,MAAM;AAC3C,QAAI,QAAQ,MAAM,YAAY,OAAO,SAAU;AAC/C,kBAAc,IAAI,MAAM,QAAQ,MAAM,SAAS;AAE/C,YAAQ,KAAK,KAAK;AAClB,QAAI,QAAQ,SAASA,aAAa,SAAQ,MAAM;AAAA,EAClD;AAEA,WAAS,iBAAiB,MAAuB,MAA8B;AAC7E,UAAM,SAAS,UAAU,IAAI;AAG7B,QAAI,SAAS,qBAAqB,IAAI;AAGtC,QAAI,OAAO,WAAW,GAAG;AACvB,eAAS,qBAAqB,IAAI;AAAA,IACpC;AAEA,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,SAAS,cAAc,IAAI,MAAM,KAAK,KAAK;AACjD,kBAAc,IAAI,QAAQ,KAAK;AAE/B,SAAK;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe;AAAA,MACf,KAAK,SAAS;AAAA,MACd,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAAA,EACH;AAOA,WAAS,wBAAwB,QAAqB;AACpD,UAAM,OAAO,gBAAgB,MAAM;AAEnC,eAAW,MAAM;AACf,UAAI,CAAC,OAAQ;AAEb,UAAI,KAAK,IAAI,IAAI,iBAAiB,wBAAyB;AAG3D,YAAM,OAAO,QAAS,SAAS;AAC/B,YAAM,SAAS,OAAO,UAAU,IAAI,IAAI,QAAQ,SAAS,QAAQ;AAEjE,UAAI,SAAS,OAAO,qBAAqB,IAAI,IAAI,CAAC;AAClD,UAAI,OAAO,WAAW,GAAG;AACvB,iBAAS,qBAAqB,IAAI;AAAA,MACpC;AAGA,UAAI,OAAO,WAAW,KAAK,MAAM;AAC/B,iBAAS,qBAAqB,SAAS,IAAI;AAAA,MAC7C;AAEA,UAAI,OAAO,WAAW,EAAG;AAEzB,YAAM,SAAS,cAAc,IAAI,MAAM,KAAK,KAAK;AACjD,oBAAc,IAAI,QAAQ,KAAK;AAE/B,WAAK;AAAA,QACH,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,eAAe;AAAA,QACf,KAAK,SAAS;AAAA,QACd,WAAW,KAAK,IAAI;AAAA,MACtB,CAAC;AAAA,IACH,GAAG,uBAAuB;AAAA,EAC5B;AAEA,SAAO;AAAA,IACL,QAAQ;AACN,UAAI,OAAQ;AACZ,eAAS;AAGT,sBAAgB,CAAC,MAAa;AAC5B,yBAAiB,KAAK,IAAI;AAC1B,cAAM,OAAO,EAAE;AACf,YAAI,EAAE,gBAAgB,iBAAkB;AAExC,mBAAW,MAAM;AACf,cAAI,CAAC,OAAQ;AACb,2BAAiB,MAAM,mBAAmB;AAAA,QAC5C,GAAG,oBAAoB;AAAA,MACzB;AACA,eAAS,iBAAiB,UAAU,eAAe,IAAI;AAGvD,uBAAiB,CAAC,MAAa;AAC7B,yBAAiB,KAAK,IAAI;AAC1B,cAAM,QAAQ,EAAE;AAChB,cAAM,OAAO,MAAM,QAAQ,MAAM;AACjC,YAAI,CAAC,KAAM;AAEX,mBAAW,MAAM;AACf,cAAI,CAAC,OAAQ;AACb,2BAAiB,MAAM,mBAAmB;AAAA,QAC5C,GAAG,oBAAoB;AAAA,MACzB;AACA,eAAS,iBAAiB,WAAW,gBAAgB,IAAI;AAIzD,qBAAe,CAAC,MAAkB;AAChC,cAAM,SAAS,EAAE;AACjB,YAAI,CAAC,OAAQ;AAGb,cAAM,SAAS,OAAO,QAAQ,4BAA4B;AAC1D,YAAI,CAAC,OAAQ;AACb,YAAI,CAAC,eAAe,MAAM,EAAG;AAE7B,gCAAwB,MAAM;AAAA,MAChC;AACA,eAAS,iBAAiB,SAAS,cAAc,IAAI;AAAA,IACvD;AAAA,IAEA,OAAO;AACL,UAAI,CAAC,OAAQ;AACb,eAAS;AACT,UAAI,cAAe,UAAS,oBAAoB,UAAU,eAAe,IAAI;AAC7E,UAAI,eAAgB,UAAS,oBAAoB,WAAW,gBAAgB,IAAI;AAChF,UAAI,aAAc,UAAS,oBAAoB,SAAS,cAAc,IAAI;AAC1E,oBAAc,MAAM;AACpB,oBAAc,MAAM;AAAA,IACtB;AAAA,IAEA,aAAa;AACX,aAAO,CAAC,GAAG,OAAO;AAAA,IACpB;AAAA,IAEA,OAAO,QAAgB,QAA0D;AAC/E,YAAM,SAA2B,CAAC;AAClC,iBAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,MAAM,GAAG;AAChD,YAAI,CAAC,IAAK;AACV,eAAO,KAAK,EAAE,MAAM,SAAS,IAAI,QAAQ,CAAC;AAAA,MAC5C;AACA,UAAI,OAAO,WAAW,EAAG;AAEzB,YAAM,SAAS,cAAc,IAAI,MAAM,KAAK,KAAK;AACjD,oBAAc,IAAI,QAAQ,KAAK;AAE/B,WAAK;AAAA,QACH,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,eAAe;AAAA,QACf,KAAK,SAAS;AAAA,QACd,WAAW,KAAK,IAAI;AAAA,MACtB,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;ACpVO,SAAS,2BAA2B,MAMlB;AACvB,QAAM,YAAY,MAAM,sBAAsB;AAC9C,QAAMC,UAAS,MAAM,mBAAmB;AACxC,QAAM,iBAAiB,MAAM,sBAAsB;AACnD,QAAM,cAAc,MAAM,mBAAmB;AAC7C,QAAM,oBAAoB,MAAM,oBAAoB;AAEpD,QAAM,SAA6B,CAAC;AACpC,QAAMC,aAAY,oBAAI,IAAuC;AAC7D,QAAM,eAA+D,CAAC;AACtE,QAAM,cAAc,oBAAI,IAAkD;AAC1E,MAAI,eAAiD;AACrD,MAAI,mBAAgD;AAEpD,WAASC,MAAK,OAAyB;AACrC,WAAO,KAAK,KAAK;AACjB,QAAI,OAAO,SAAS,GAAI,QAAO,MAAM;AACrC,eAAW,MAAMD,WAAW,IAAG,KAAK;AAAA,EACtC;AAEA,WAAS,eAAe,IAAqB;AAC3C,QAAI,GAAG,GAAI,QAAO,IAAI,GAAG,EAAE;AAC3B,UAAM,MAAM,GAAG,QAAQ,YAAY;AACnC,UAAM,MAAM,CAAC,GAAG,GAAG,SAAS,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG;AAClD,QAAI,IAAK,QAAO,GAAG,GAAG,IAAI,GAAG;AAC7B,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,IAA0B;AAC/C,UAAM,MAAM,GAAG,QAAQ,YAAY;AACnC,QAAI,CAAC,KAAK,UAAU,SAAS,UAAU,YAAY,SAAS,SAAS,EAAE,SAAS,GAAG,EAAG,QAAO;AAC7F,QAAI,GAAG,aAAa,MAAM,MAAM,YAAY,GAAG,aAAa,UAAU,EAAG,QAAO;AAChF,QAAI,GAAG,WAAW,GAAG,aAAa,SAAS,EAAG,QAAO;AACrD,QAAI,GAAG,QAAQ,qCAAqC,EAAG,QAAO;AAC9D,QAAI;AACF,UAAI,iBAAiB,EAAE,EAAE,WAAW,UAAW,QAAO;AAAA,IACxD,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AAEA,WAAS,YAAY,GAAe;AAClC,UAAM,SAAS,EAAE;AACjB,QAAI,CAAC,OAAQ;AACb,UAAM,MAAM,KAAK,IAAI;AAGrB,iBAAa,KAAK,EAAE,QAAQ,MAAM,IAAI,CAAC;AAEvC,WAAO,aAAa,SAAS,KAAK,MAAM,aAAa,CAAC,EAAE,OAAO,KAAM;AACnE,mBAAa,MAAM;AAAA,IACrB;AACA,UAAM,eAAe,aAAa,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,MAAM,EAAE,OAAOD,OAAM;AAC5F,QAAI,aAAa,UAAU,WAAW;AACpC,MAAAE,MAAK;AAAA,QACH,MAAM;AAAA,QACN,WAAW;AAAA,QACX,QAAQ,eAAe,MAAM;AAAA,QAC7B,SAAS,GAAG,aAAa,MAAM,cAAc,MAAM,aAAa,CAAC,EAAE,IAAI;AAAA,QACvE,KAAK,WAAW,UAAU,QAAQ;AAAA,MACpC,CAAC;AACD,mBAAa,SAAS;AAAA,IACxB;AAGA,QAAI,qBAAqB,CAAC,cAAc,MAAM,GAAG;AAC/C,MAAAA,MAAK;AAAA,QACH,MAAM;AAAA,QACN,WAAW;AAAA,QACX,QAAQ,eAAe,MAAM;AAAA,QAC7B,SAAS,6BAA6B,OAAO,QAAQ,YAAY,CAAC;AAAA,QAClE,KAAK,WAAW,UAAU,QAAQ;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,WAAS,oBAAoB;AAC3B,uBAAmB,QAAQ;AAC3B,YAAQ,QAAQ,IAAI,SAAoB;AACtC,wBAAkB,MAAM,SAAS,IAAI;AAErC,YAAM,MAAM,OAAO,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG;AACxC,YAAM,MAAM,KAAK,IAAI;AACrB,YAAM,WAAW,YAAY,IAAI,GAAG;AACpC,UAAI,YAAY,MAAM,SAAS,YAAY,aAAa;AACtD,iBAAS;AACT,YAAI,SAAS,SAAS,gBAAgB;AACpC,UAAAA,MAAK;AAAA,YACH,MAAM;AAAA,YACN,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,SAAS,cAAc,SAAS,KAAK,QAAQ,KAAK,OAAO,MAAM,SAAS,aAAa,GAAI,CAAC,MAAM,GAAG;AAAA,YACnG,KAAK,WAAW,UAAU,QAAQ;AAAA,UACpC,CAAC;AACD,sBAAY,OAAO,GAAG;AAAA,QACxB;AAAA,MACF,OAAO;AACL,oBAAY,IAAI,KAAK,EAAE,OAAO,GAAG,WAAW,IAAI,CAAC;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ;AACN,qBAAe;AACf,eAAS,iBAAiB,SAAS,cAAc,IAAI;AACrD,wBAAkB;AAAA,IACpB;AAAA,IACA,OAAO;AACL,UAAI,aAAc,UAAS,oBAAoB,SAAS,cAAc,IAAI;AAC1E,UAAI,iBAAkB,SAAQ,QAAQ;AACtC,mBAAa,SAAS;AACtB,kBAAY,MAAM;AAAA,IACpB;AAAA,IACA,YAAY;AACV,aAAO,CAAC,GAAG,MAAM;AAAA,IACnB;AAAA,IACA,cAAc,UAAU;AACtB,MAAAD,WAAU,IAAI,QAAQ;AACtB,aAAO,MAAMA,WAAU,OAAO,QAAQ;AAAA,IACxC;AAAA,EACF;AACF;;;AC9IA,IAAME,eAAc;AAGpB,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AACF,CAAC;AAED,SAAS,WAAW,KAAsB;AACxC,MAAI;AACF,UAAM,WAAW,IAAI,IAAI,KAAK,SAAS,IAAI,EAAE;AAC7C,UAAM,MAAM,SAAS,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,YAAY;AAClE,WAAO,iBAAiB,IAAI,GAAG;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,aAAa,KAAa,SAA+B;AAChE,MAAI;AACF,UAAM,OAAO,IAAI,IAAI,KAAK,SAAS,IAAI,EAAE;AACzC,WAAO,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,MAAM,SAAS,KAAK,KAAK,SAAS,MAAM,CAAC,CAAC;AAAA,EACtE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,aAAa,KAAa,SAA+B;AAChE,SAAO,aAAa,KAAK,OAAO,KAAK,WAAW,GAAG;AACrD;AAQA,SAAS,YAAY,KAAqB;AACxC,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,KAAK,SAAS,IAAI;AACpC,UAAM,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,QAAQ;AACrC,WAAO,KAAK,SAAS,MAAM,KAAK,MAAM,GAAG,GAAG,IAAI,WAAW;AAAA,EAC7D,QAAQ;AACN,WAAO,IAAI,SAAS,MAAM,IAAI,MAAM,GAAG,GAAG,IAAI,WAAW;AAAA,EAC3D;AACF;AAEO,SAAS,uBAAuB,oBAA8B,CAAC,GAAqB;AACzF,QAAM,UAA0B,CAAC;AACjC,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,uBAAuB,GAAG,iBAAiB,CAAC;AACxE,MAAI,YAAwC;AAC5C,MAAI,cAA2D;AAC/D,MAAI,SAAS;AAEb,WAAS,KAAK,OAAqB;AACjC,YAAQ,KAAK,KAAK;AAClB,QAAI,QAAQ,SAASA,aAAa,SAAQ,MAAM;AAAA,EAClD;AAEA,SAAO;AAAA,IACL,QAAQ;AACN,UAAI,OAAQ;AACZ,eAAS;AAGT,kBAAY,OAAO;AACnB,aAAO,QAAQ,OAAO,OAA0BC,UAA0C;AACxF,cAAM,UAAWA,OAAM,UAAU,OAAkB,YAAY;AAC/D,cAAM,MAAM,OAAO,UAAU,WAAW,QAAQ,iBAAiB,MAAM,MAAM,OAAQ,MAAkB;AACvG,cAAM,YAAY,KAAK,IAAI;AAC3B,cAAM,MAAM,MAAM,UAAW,KAAK,QAAQ,OAAOA,KAAI;AACrD,YAAI,CAAC,aAAa,KAAK,OAAO,GAAG;AAC/B,eAAK;AAAA,YACH;AAAA,YACA,KAAK,YAAY,GAAG;AAAA,YACpB,QAAQ,IAAI;AAAA,YACZ,UAAU,KAAK,IAAI,IAAI;AAAA,YACvB,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA,eAAO;AAAA,MACT;AAGA,oBAAc,eAAe,UAAU;AACvC,qBAAe,UAAU,OAAO,SAC9B,QACA,KACA,OACA,UACA,UACA;AACA,cAAM,YAAY,KAAK,IAAI;AAC3B,cAAM,SAAS,OAAO,QAAQ,WAAW,MAAO,IAAY;AAE5D,aAAK,iBAAiB,QAAQ,MAAM;AAClC,cAAI,CAAC,aAAa,QAAQ,OAAO,GAAG;AAClC,iBAAK;AAAA,cACH,QAAQ,OAAO,YAAY;AAAA,cAC3B,KAAK,YAAY,MAAM;AAAA,cACvB,QAAQ,KAAK;AAAA,cACb,UAAU,KAAK,IAAI,IAAI;AAAA,cACvB,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAED,eAAO,YAAa,MAAM,MAAM,CAAC,QAAQ,KAAK,SAAS,MAAM,UAAU,QAAQ,CAE9E;AAAA,MACH;AAAA,IACF;AAAA,IAEA,OAAO;AACL,UAAI,CAAC,OAAQ;AACb,eAAS;AACT,UAAI,UAAW,QAAO,QAAQ;AAC9B,UAAI,YAAa,gBAAe,UAAU,OAAO;AAAA,IACnD;AAAA,IAEA,aAAa;AACX,aAAO,CAAC,GAAG,OAAO;AAAA,IACpB;AAAA,EACF;AACF;;;AC1KA,IAAI,wBAAmD;AAEhD,SAAS,uBAAuB,WAAsC;AAC3E,0BAAwB;AAC1B;AAEA,IAAI,QAAoB,EAAE,MAAM,QAAW,eAAe,OAAU;AACpE,IAAM,YAAY,oBAAI,IAAgB;AAEtC,SAAS,OAAO;AACd,aAAW,KAAK,UAAW,GAAE;AAC/B;AAEO,SAAS,UAAU,UAAsB;AAC9C,YAAU,IAAI,QAAQ;AACtB,SAAO,MAAM,UAAU,OAAO,QAAQ;AACxC;AAEO,SAAS,cAA0B;AACxC,SAAO;AACT;AAGO,IAAM,QAAQ;AAAA,EACnB,QAAQ,MAAwB;AAC9B,YAAQ,EAAE,GAAG,OAAO,MAAM,QAAQ,OAAU;AAC5C,SAAK;AAAA,EACP;AAAA,EACA,iBAAiB,KAAqC;AACpD,YAAQ,EAAE,GAAG,OAAO,eAAe,OAAO,OAAU;AACpD,SAAK;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,gBAAgB,QAAgB,QAA0D;AACxF,2BAAuB,OAAO,QAAQ,MAAM;AAAA,EAC9C;AACF;;;AC1CA,IAAM,2BAA2B;AAYjC,IAAI,WAAiC;AAErC,SAAS,SAAS,WAAwB,MAAiB;AACzD,MAAI,OAAO,MAAO,SAAQ,IAAI,WAAW,GAAG,IAAI;AAClD;AAEA,SAAS,KAAK,QAA2B;AACvC,MAAI,UAAU;AACZ,YAAQ,KAAK,4EAA4E;AACzF;AAAA,EACF;AAEA,QAAM;AAAA,IACJ,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe,CAAC;AAAA,IAChB,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,WAAS,QAAQ,gBAAgB;AAAA,IAC/B,WAAW,OAAO;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,QAAM,aAAa,MAAM;AACvB,QAAI;AACF,aAAO,IAAI,IAAI,OAAO,SAAS,EAAE;AAAA,IACnC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,GAAG;AAEH,QAAM,kBAAkB,CAAC,GAAG,cAAc,GAAI,YAAY,CAAC,SAAS,IAAI,CAAC,CAAE;AAG3E,QAAM,aAAa,gBAAiB,aAAa,UAAU,KAAK,uBAAuB,IAAK;AAC5F,cAAY,MAAM;AAElB,QAAM,aAAa,gBACd,aAAa,UAAU,eAAe,KAAK,uBAAuB,eAAe,IAClF;AACJ,cAAY,MAAM;AAElB,QAAM,gBAAgB,mBAAmB,yBAAyB,IAAI;AACtE,MAAI,eAAe;AACjB,kBAAc,MAAM;AACpB,2BAAuB,aAAa;AAAA,EACtC;AAEA,QAAM,iBAAiB,oBAAoB,2BAA2B,eAAe,IAAI;AACzF,kBAAgB,MAAM;AAGtB,MAAI,OAAO,MAAM;AACf,UAAM,QAAQ,OAAO,IAAI;AAAA,EAC3B;AAEA,QAAM,eAA0B,CAAC;AACjC,MAAI,aAAkC;AAEtC,WAAS,QAAQ,sBAAsB;AAAA,IACrC,SAAS,CAAC,CAAC;AAAA,IACX,SAAS,CAAC,CAAC;AAAA,IACX,YAAY,CAAC,CAAC;AAAA,IACd,aAAa,CAAC,CAAC;AAAA,EACjB,CAAC;AAED,aAAW;AAAA,IACT;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb;AAAA,IACA,YAAY;AAAA,EACd;AAGA,MAAI,gBAAgB,iBAAiB;AACnC,oBAAgB,CAAC,UAAmB;AAClC,mBAAa,KAAK,KAAK;AACvB,YAAM,SAAS,KAAK,IAAI,IAAI;AAC5B,aAAO,aAAa,SAAS,KAAM,aAAa,CAAC,EAA4B,YAAY,QAAQ;AAC/F,qBAAa,MAAM;AAAA,MACrB;AAAA,IACF,CAAC,EAAE,KAAK,CAAC,SAAS;AAChB,mBAAa,QAAQ;AACrB,UAAI,SAAU,UAAS,aAAa;AAAA,IACtC,CAAC;AAAA,EACH;AAGA,QAAM,iBAAiB,aAAa,eAAe;AACnD,MAAI,kBAAkB,uBAAuB;AAC3C,mBAAe,cAAc,OAAO,UAAU;AAC5C,eAAS,QAAQ,yCAAyC,MAAM,MAAM,MAAM,OAAO;AACnF,sBAAgB,KAAK;AACrB,YAAM,OAAO,YAAY,EAAE,QAAQ,OAAO;AAC1C,YAAM,aAAa,OAAO,WAAW,OAAO,YAAY;AAAA,QACtD,YAAY,MAAM,MAAM;AAAA,QACxB,cAAc,MAAM,QAAQ;AAAA,QAC5B,eAAe,MAAM;AAAA,QACrB,aAAa,mBAAmB,MAAM,KAAK,QAAQ,MAAM,GAAG,CAAC,KAAK,MAAM,OAAO;AAAA,QAC/E,UAAU,MAAM,SAAS,eAAe,OAAO,MAAM,SAAS,eAAe,OAAO;AAAA,QACpF,KAAK,MAAM;AAAA,QACX,QAAQ;AAAA,QACR,MAAM;AAAA,UACJ,GAAG,OAAO;AAAA,UACV,aAAa,eAAe;AAAA,UAC5B,aAAa,YAAY,WAAW,KAAK,CAAC;AAAA,UAC1C,eAAe,YAAY,WAAW,KAAK,CAAC;AAAA,UAC5C,YAAY,eAAe,WAAW,KAAK,CAAC;AAAA,UAC5C,kBAAkB;AAAA,QACpB;AAAA,MACF,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACnB,CAAC;AAAA,EACH,WAAW,kBAAkB,eAAe;AAC1C,mBAAe,cAAc,aAAa;AAAA,EAC5C;AAGA,MAAI,CAAC,OAAO,wBAAwB;AAClC,uBAAmB,OAAO,WAAW,OAAO,UAAU,EACnD,KAAK,CAAC,WAAW;AAChB,UAAI,CAAC,YAAY,CAAC,QAAQ,aAAc;AACxC,YAAM,KAAK,OAAO,aAAa;AAC/B,UAAI,IAAI,WAAW,GAAG,MAAM;AAE1B,eAAO,uBAA2B,EAAE,KAAK,CAAC,EAAE,6BAAAC,6BAA4B,MAAM;AAC5E,cAAI,CAAC,SAAU;AACf,mBAAS,SAAS;AAAA,YAChB,GAAG,SAAS;AAAA,YACZ,wBAAwBA,6BAA4B,GAAG,IAAc;AAAA,UACvE;AACA,mBAAS,QAAQ,sCAAsC,GAAG,IAAI;AAAA,QAChE,CAAC;AAAA,MACH;AAAA,IACF,CAAC,EACA,MAAM,MAAM;AAAA,IAEb,CAAC;AAAA,EACL;AACF;AAGA,eAAe,mBACb,WACA,YAC8F;AAC9F,MAAI;AACF,UAAM,MAAM,GAAG,UAAU,QAAQ,OAAO,EAAE,CAAC;AAC3C,UAAM,MAAM,MAAM,MAAM,KAAK,EAAE,SAAS,EAAE,iBAAiB,WAAW,EAAE,CAAC;AACzE,QAAI,CAAC,IAAI,GAAI,QAAO;AACpB,WAAO,IAAI,KAAK;AAAA,EAClB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WAAiB;AACxB,MAAI,CAAC,SAAU;AAEf,WAAS,SAAS,KAAK;AACvB,WAAS,SAAS,KAAK;AACvB,WAAS,YAAY,KAAK;AAC1B,yBAAuB,IAAI;AAC3B,WAAS,aAAa,KAAK;AAC3B,WAAS,aAAa;AACtB,aAAW;AACb;AAEA,SAAS,gBAAyB;AAChC,SAAO,aAAa;AACtB;AAEA,SAAS,cAAoC;AAC3C,SAAO;AACT;AAEA,SAAS,QAAQ,WAAoD;AACnE,QAAM,iBAAiB,UAAU,OAAO,aAAa,eAAe;AACpE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,aAAa,eAAe;AAAA,IAC5B,aAAa,UAAU,SAAS,WAAW,KAAK,CAAC;AAAA,IACjD,eAAe,UAAU,SAAS,WAAW,KAAK,CAAC;AAAA,IACnD,YAAY,UAAU,YAAY,WAAW,KAAK,CAAC;AAAA,EACrD;AACF;AAEA,SAAS,kBAA6B;AACpC,SAAO,WAAW,CAAC,GAAG,SAAS,YAAY,IAAI,CAAC;AAClD;AAEA,SAAS,YAAgC;AACvC,SAAO,UAAU,UAAU;AAC7B;AAEA,SAAS,uBAA2C;AAElD,QAAM,cAAc,YAAY,EAAE;AAClC,QAAM,YAAY,OAAO,gBAAgB,aAAa,YAAY,IAAI;AACtE,MAAI,UAAW,QAAO;AAEtB,SAAO,UAAU,OAAO,yBAAyB;AACnD;AAEO,IAAM,QAAQ;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,MAAM;AAAA,EACf,kBAAkB,MAAM;AAAA,EACxB,iBAAiB,MAAM;AACzB;;;ACnPA,IAAM,QAAuB;AAAA,EAC3B,YAAY;AAAA,EACZ,qBAAqB;AAAA,EACrB,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,MAAM;AAAA,EACN,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAEA,IAAM,OAAsB;AAAA,EAC1B,YAAY;AAAA,EACZ,qBAAqB;AAAA,EACrB,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,MAAM;AAAA,EACN,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAEO,SAAS,aAAa,OAA6B;AACxD,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,UAAU,QAAS,QAAO;AAE9B,QAAM,WAAW;AACjB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY,SAAS,cAAc,MAAM;AAAA,IACzC,QAAQ,SAAS,UAAU,MAAM;AAAA,IACjC,aAAa,SAAS,UAAU,MAAM;AAAA,IACtC,MAAM,SAAS,QAAQ,MAAM;AAAA,IAC7B,QAAQ,SAAS,UAAU,MAAM;AAAA,EACnC;AACF;","names":["init","MAX_ENTRIES","window","listeners","emit","MAX_ENTRIES","init","createDatadogReplayProvider"]}
|