@ga-components/logger 1.0.58 → 1.0.59

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.d.mts CHANGED
@@ -56,6 +56,7 @@ declare class Logger {
56
56
  private rageClickFired;
57
57
  private domObserverInitialized;
58
58
  constructor();
59
+ private recentDomChanges;
59
60
  private initDomActivityObserver;
60
61
  init(config: LoggerConfig): void;
61
62
  setUserId(userId: string | null): void;
package/dist/index.d.ts CHANGED
@@ -56,6 +56,7 @@ declare class Logger {
56
56
  private rageClickFired;
57
57
  private domObserverInitialized;
58
58
  constructor();
59
+ private recentDomChanges;
59
60
  private initDomActivityObserver;
60
61
  init(config: LoggerConfig): void;
61
62
  setUserId(userId: string | null): void;
package/dist/index.js CHANGED
@@ -93,6 +93,7 @@ var Logger = class {
93
93
  this.clickHistory = /* @__PURE__ */ new Map();
94
94
  this.rageClickFired = /* @__PURE__ */ new Map();
95
95
  this.domObserverInitialized = false;
96
+ this.recentDomChanges = [];
96
97
  // Global error capture — hanya aktif di non-development
97
98
  this.loggedErrorKeys = /* @__PURE__ */ new Set();
98
99
  if (typeof window !== "undefined") {
@@ -102,16 +103,28 @@ var Logger = class {
102
103
  initDomActivityObserver() {
103
104
  if (this.domObserverInitialized) return;
104
105
  this.domObserverInitialized = true;
105
- const markActivity = () => {
106
+ const markActivity = (addedText) => {
106
107
  this.lastDomActivity = Date.now();
108
+ if (addedText) {
109
+ this.recentDomChanges.push(addedText);
110
+ setTimeout(() => {
111
+ this.recentDomChanges = this.recentDomChanges.filter((t) => t !== addedText);
112
+ }, 1e3);
113
+ }
107
114
  };
108
- const observer = new MutationObserver(markActivity);
109
- observer.observe(document.body, {
110
- childList: true,
111
- subtree: true,
112
- attributes: true
115
+ const observer = new MutationObserver((mutations) => {
116
+ markActivity();
117
+ for (const m of mutations) {
118
+ m.addedNodes.forEach((node) => {
119
+ if (node.nodeType === Node.ELEMENT_NODE) {
120
+ const text = node.innerText?.trim();
121
+ if (text && text.length < 200) markActivity(text);
122
+ }
123
+ });
124
+ }
113
125
  });
114
- window.addEventListener("scroll", markActivity, { passive: true, capture: true });
126
+ observer.observe(document.body, { childList: true, subtree: true, attributes: true });
127
+ window.addEventListener("scroll", () => markActivity(), { passive: true, capture: true });
115
128
  }
116
129
  init(config) {
117
130
  this.config = config;
@@ -538,10 +551,16 @@ var Logger = class {
538
551
  if (["button", "a", "input"].includes(tagName)) {
539
552
  setTimeout(() => {
540
553
  if (this.lastDomActivity <= domActivityAtClick) {
554
+ const reason = "no DOM/scroll activity within 7s";
541
555
  this.addBreadcrumb("click", `Dead click: ${message}`, {
542
556
  tagName,
543
557
  ...id ? { id } : {},
544
- reason: "no DOM/scroll activity within 7s"
558
+ reason
559
+ });
560
+ void this.warn({
561
+ fnName: "interceptClick.deadClick",
562
+ messageError: new Error(`Dead click: ${message}`),
563
+ payload: { tagName, ...id ? { id } : {}, reason }
545
564
  });
546
565
  }
547
566
  }, 7e3);
@@ -553,11 +572,17 @@ var Logger = class {
553
572
  const lastFired = this.rageClickFired.get(historyKey) ?? 0;
554
573
  if (timestamps.length >= 3 && clickTime - lastFired > 7e3) {
555
574
  this.rageClickFired.set(historyKey, clickTime);
575
+ const possibleReason = this.recentDomChanges.length ? this.recentDomChanges.slice(-1)[0] : "no visible UI feedback detected";
556
576
  this.addBreadcrumb("click", `Rage click: ${message}`, {
557
577
  tagName,
558
- ...id ? { id } : {},
559
578
  clickCount: timestamps.length,
560
- windowMs: 7e3
579
+ windowMs: 7e3,
580
+ possibleReason
581
+ });
582
+ void this.warn({
583
+ fnName: "interceptClick.rageClick",
584
+ messageError: new Error(`Rage click: ${message}`),
585
+ payload: { tagName, clickCount: timestamps.length, windowMs: 7e3, possibleReason }
561
586
  });
562
587
  }
563
588
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/logger.ts","../src/config/firebase.ts","../src/core/environment.ts","../src/components/LoggerErrorBoundary.tsx"],"sourcesContent":["export { logger } from \"./core/logger\";\nexport { LoggerErrorBoundary } from \"./components/LoggerErrorBoundary\";\nexport type { LogEntry, LoggerConfig, LogLevel, LogEnv, Breadcrumb, BreadcrumbType } from \"./types\";\n","import { collection, addDoc, Timestamp } from \"firebase/firestore\";\nimport { initFirebase, getDb } from \"../config/firebase\";\nimport type { Breadcrumb, BreadcrumbType, LogEntry, LogLevel, LogParams, LoggerConfig } from \"../types\";\nimport { initEnvironment } from \"./environment\";\nimport { getEnvironmentPayload } from \"./environment\";\n\nconst sessionId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\nconst MAX_BREADCRUMBS = 50;\n\nconst CLICK_SKIP_PATTERNS = [/^:r[a-z0-9]+:$/, /^\\[object/, /^#/];\n\n// Sanitize PII sebelum masuk Firestore\nconst sanitizeClickText = (text: string): string => {\n return text\n .replace(/\\b[\\w.-]+@[\\w.-]+\\.\\w+\\b/g, \"[email]\")\n .replace(/\\b\\d{10,}\\b/g, \"[number]\")\n .replace(/Rp[\\s]?\\d[\\d.,]*/gi, \"[amount]\")\n .trim();\n};\n\nclass Logger {\n private config: LoggerConfig | null = null;\n private initialized = false;\n private breadcrumbs: Breadcrumb[] = [];\n\n private lastDomActivity = Date.now();\n private clickHistory = new Map<string, number[]>();\n private rageClickFired = new Map<string, number>();\n private domObserverInitialized = false;\n\n constructor() {\n if (typeof window !== \"undefined\") {\n (window as any).__ga_debug_breadcrumbs = () => this.breadcrumbs;\n }\n }\n\n private initDomActivityObserver(): void {\n if (this.domObserverInitialized) return;\n this.domObserverInitialized = true;\n\n const markActivity = () => {\n this.lastDomActivity = Date.now();\n };\n\n const observer = new MutationObserver(markActivity);\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n });\n\n window.addEventListener(\"scroll\", markActivity, { passive: true, capture: true });\n }\n\n init(config: LoggerConfig) {\n this.config = config;\n initFirebase(config);\n initEnvironment();\n this.initialized = true;\n console.info(\"[ga-logger] initialized —\", config.env);\n }\n setUserId(userId: string | null) {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n this.config.userId = userId;\n }\n\n initAnonymousUser(): void {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n const STORAGE_KEY = \"ga_anon_id\";\n\n try {\n let anonId = localStorage.getItem(STORAGE_KEY);\n\n if (!anonId) {\n anonId =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? crypto.randomUUID()\n : \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n\n localStorage.setItem(STORAGE_KEY, anonId);\n }\n\n const shortId = anonId.slice(-8);\n this.setUserId(`Anonymous #${shortId}`);\n } catch (e) {\n // localStorage blocked (private mode / HTTP restriction)\n console.warn(\"[ga-logger] initAnonymousUser failed:\", e);\n this.setUserId(\"Anonymous\");\n }\n }\n\n // Add breadcrumb ke in-memory array\n addBreadcrumb(type: BreadcrumbType, message: string, data?: Record<string, unknown>) {\n const breadcrumb: Breadcrumb = {\n timestamp: new Date(),\n type,\n message,\n data,\n };\n\n this.breadcrumbs.push(breadcrumb);\n\n // Jaga memory — max 50 breadcrumbs, buang yang paling lama\n if (this.breadcrumbs.length > MAX_BREADCRUMBS) {\n this.breadcrumbs.shift();\n }\n }\n\n // Global error capture — hanya aktif di non-development\n private loggedErrorKeys = new Set<string>();\n\n // Helper: trim URL jadi domain/filename\n private trimUrl(url: string): string {\n try {\n const u = new URL(url);\n const filename = u.pathname.split(\"/\").filter(Boolean).pop() ?? u.pathname;\n return `${u.hostname}/${filename}`;\n } catch {\n // bukan valid URL, potong saja jika terlalu panjang\n return url.length > 80 ? url.slice(0, 80) + \"...\" : url;\n }\n }\n\n // Helper: build dedup key\n private buildErrorKey(type: string, message: string): string {\n return `${type}::${message}`;\n }\n\n // Helper: should skip resource error\n private shouldSkipResourceError(src: string, tagName: string): boolean {\n // Skip IMG — tidak sebabkan blank page\n if (tagName === \"IMG\") return true;\n\n // Skip base64 URL\n if (src.startsWith(\"data:\")) return true;\n\n // Skip known 3rd party trackers\n const THIRD_PARTY = [\n \"omguk.com\",\n \"track.\",\n \"doubleclick\",\n \"adservice\",\n \"googletagmanager\",\n \"google-analytics\",\n \"hotjar\",\n \"facebook.net\",\n \"analytics\",\n \"magnolia\",\n \"gtm.js\",\n ];\n if (THIRD_PARTY.some((p) => src.includes(p))) return true;\n\n return false;\n }\n\n private shouldSkipGlobalError(message: string): boolean {\n const NOISE = [\n \"CORS\",\n \"cross-origin\",\n \"ERR_FAILED\",\n \"Failed to load resource\",\n \"NetworkError\",\n \"ResizeObserver loop\",\n \"Script error\",\n \"ServiceWorker\",\n \"sw.js\",\n \"dev-sw.js\",\n \"Warning:\",\n ];\n const THIRD_PARTY = [\n \"magnolia\",\n \"gtm.js\",\n \"analytics\",\n \"googletagmanager\",\n \"facebook\",\n \"hotjar\",\n \"omguk.com\",\n \"track.\",\n \"doubleclick\",\n \"adservice\",\n ];\n return NOISE.some((p) => message.includes(p)) || THIRD_PARTY.some((p) => message.includes(p));\n }\n\n initGlobalCapture(): void {\n const isLocalhost = window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n if (isLocalhost) return;\n\n window.onerror = (message, source, lineno, colno) => {\n const msg = typeof message === \"string\" ? message : \"Unknown error\";\n if (this.shouldSkipGlobalError(msg)) return false;\n\n const trimmedSource = source ? this.trimUrl(source) : \"unknown source\";\n const finalMessage = `${msg} at ${trimmedSource}:${lineno ?? 0}`;\n const key = this.buildErrorKey(\"onerror\", finalMessage);\n if (this.loggedErrorKeys.has(key)) return false;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"window.onerror\",\n messageError: new Error(finalMessage),\n payload: { source: trimmedSource, lineno, colno },\n });\n\n return false;\n };\n\n // unhandledrejection\n window.addEventListener(\"unhandledrejection\", (event) => {\n const msg =\n event.reason instanceof Error\n ? event.reason.message\n : String(event.reason ?? \"Unhandled Promise rejection\");\n\n if (this.shouldSkipGlobalError(msg)) return;\n\n const key = this.buildErrorKey(\"unhandledrejection\", msg);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"window.unhandledrejection\",\n messageError: new Error(msg),\n });\n });\n\n // console.error override\n const originalConsoleError = console.error.bind(console);\n console.error = (...args: unknown[]) => {\n originalConsoleError(...args);\n\n const msg = args.map((a) => (a instanceof Error ? a.message : String(a))).join(\" \");\n\n if (this.shouldSkipGlobalError(msg)) return;\n\n const trimmedMsg = msg.length > 150 ? msg.slice(0, 150) + \"...\" : msg;\n const key = this.buildErrorKey(\"console.error\", trimmedMsg);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n const originalError = args.find((a): a is Error => a instanceof Error);\n\n const errorToSend = originalError ?? new Error(trimmedMsg);\n\n void this.error({\n fnName: \"console.error\",\n messageError: errorToSend,\n });\n };\n\n // resource load error (CSS / JS / font)\n window.addEventListener(\n \"error\",\n (event) => {\n const target = event.target;\n if (!(target instanceof HTMLElement)) return;\n if (target === (window as unknown)) return;\n\n const tagName = target.tagName.toUpperCase();\n\n const src =\n tagName === \"LINK\"\n ? (target as HTMLLinkElement).href\n : tagName === \"SCRIPT\"\n ? (target as HTMLScriptElement).src\n : \"\";\n\n if (this.shouldSkipResourceError(src, tagName)) return;\n\n // Deteksi dari ekstensi file, bukan tagName\n const ext = src.split(\"?\")[0].split(\".\").pop()?.toLowerCase();\n const resourceType =\n ext === \"css\"\n ? \"CSS\"\n : ext === \"js\"\n ? \"JS\"\n : ext === \"woff\" || ext === \"woff2\" || ext === \"ttf\"\n ? \"FONT\"\n : tagName;\n\n const trimmedSrc = this.trimUrl(src);\n const finalMessage = `Failed to load ${resourceType}: ${trimmedSrc}`;\n const key = this.buildErrorKey(\"resource\", finalMessage);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"resource.onerror\",\n messageError: new Error(finalMessage),\n payload: { tagName, src: trimmedSrc },\n });\n },\n true,\n );\n }\n\n private sanitizePayload(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => {\n if (value === undefined) return [key, null];\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return [key, this.sanitizePayload(value as Record<string, unknown>)];\n }\n return [key, value];\n }),\n );\n }\n\n private sanitizeForFirestore(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => {\n if (value === undefined) return [key, null];\n if (typeof value === \"function\") return [key, \"[function]\"];\n if (value instanceof Date) return [key, value.toISOString()];\n if (Array.isArray(value)) {\n return [\n key,\n value.map((item) => {\n if (item instanceof Date) return item.toISOString();\n if (typeof item === \"function\") return \"[function]\"; // ← tambah\n if (item !== null && typeof item === \"object\") {\n return this.sanitizeForFirestore(item as Record<string, unknown>);\n }\n return item ?? null;\n }),\n ];\n }\n if (value !== null && typeof value === \"object\") {\n return [key, this.sanitizeForFirestore(value as Record<string, unknown>)];\n }\n return [key, value];\n }),\n );\n }\n\n // interceptFetch — auto breadcrumb, ke Firestore\n interceptFetch() {\n if (typeof window === \"undefined\") return;\n\n const originalFetch = window.fetch;\n\n const skipPatterns = [\n \"google.com\",\n \"googletagmanager.com\",\n \"googleapis.com\",\n \"facebook.com\",\n \"hotjar.com\",\n \"analytics\",\n \"gtm\",\n \"ccm/collect\",\n \"on.aws\",\n \"/locales/\",\n \"/sw.js\",\n \"/manifest.json\",\n \"/sourcemaps/\",\n \"magnolia\",\n ];\n\n const shouldSkipUrl = (url: string): boolean => {\n return skipPatterns.some((pattern) => url.includes(pattern));\n };\n\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n\n // Skip third-party domains\n if (shouldSkipUrl(url)) {\n return originalFetch(input, init);\n }\n\n const method = init?.method ?? \"GET\";\n const startTime = Date.now();\n\n try {\n const response = await originalFetch(input, init);\n const duration = Date.now() - startTime;\n\n this.addBreadcrumb(\"fetch\", `${method} ${url}`, {\n status: response.status,\n duration: `${duration}ms`,\n });\n\n if (response.status >= 400) {\n const dedupKey = this.buildErrorKey(\"interceptFetch\", `${method} ${url} ${response.status}`);\n\n if (!this.loggedErrorKeys.has(dedupKey)) {\n this.loggedErrorKeys.add(dedupKey);\n\n let responseBody: unknown = null;\n try {\n const cloned = response.clone();\n const contentType = cloned.headers.get(\"content-type\") ?? \"\";\n responseBody = contentType.includes(\"application/json\")\n ? await cloned.json()\n : await cloned.text();\n } catch {\n responseBody = \"[unable to read response body]\";\n }\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n this.error({\n fnName: \"interceptFetch\",\n messageError: new Error(`HTTP ${response.status} ${response.statusText} — ${url}`),\n endpointName: url,\n payload: {\n method,\n status: response.status,\n statusText: response.statusText,\n duration: `${duration}ms`,\n responseBody,\n },\n });\n }\n }\n }\n\n return response;\n } catch (networkError) {\n const duration = Date.now() - startTime;\n const error = networkError instanceof Error ? networkError : new Error(String(networkError));\n\n this.addBreadcrumb(\"fetch\", `${method} ${url} — NETWORK ERROR`, {\n duration: `${duration}ms`,\n error: error.message,\n });\n\n const dedupKey = this.buildErrorKey(\"interceptFetch\", `${method} ${url} NETWORK_ERROR`);\n\n if (!this.loggedErrorKeys.has(dedupKey)) {\n this.loggedErrorKeys.add(dedupKey);\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n if (!isLocalhost) {\n this.error({\n fnName: \"interceptFetch\",\n messageError: error,\n endpointName: url,\n payload: { method, duration: `${duration}ms` },\n });\n }\n }\n\n throw networkError;\n }\n };\n\n console.info(\"[ga-logger] fetch intercepted\");\n }\n\n // interceptXHR — auto breadcrumb + error capture untuk axios/XHR-based request\n interceptXHR(): void {\n if (typeof window === \"undefined\") return;\n\n const skipPatterns = [\n \"google.com\",\n \"googletagmanager.com\",\n \"googleapis.com\",\n \"facebook.com\",\n \"hotjar.com\",\n \"analytics\",\n \"ccm/collect\",\n \"on.aws\",\n \"/locales/\",\n \"/sw.js\",\n \"/manifest.json\",\n \"/sourcemaps/\",\n \"magnolia\",\n ];\n\n const shouldSkipUrl = (url: string): boolean => skipPatterns.some((p) => url.includes(p));\n\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n const self = this;\n\n type GaXHR = XMLHttpRequest & {\n _gaMethod?: string;\n _gaUrl?: string;\n _gaStartTime?: number;\n };\n\n XMLHttpRequest.prototype.open = function (this: GaXHR, method: string, url: string | URL, ...rest: unknown[]) {\n this._gaMethod = method;\n this._gaUrl = typeof url === \"string\" ? url : url.href;\n // @ts-expect-error - spreading native arguments\n return originalOpen.call(this, method, url, ...rest);\n };\n\n XMLHttpRequest.prototype.send = function (this: GaXHR, ...args: unknown[]) {\n const url = this._gaUrl ?? \"\";\n const method = this._gaMethod ?? \"GET\";\n\n if (shouldSkipUrl(url)) {\n // @ts-expect-error - spreading native arguments\n return originalSend.call(this, ...args);\n }\n\n this._gaStartTime = Date.now();\n\n this.addEventListener(\"loadend\", () => {\n const duration = Date.now() - (this._gaStartTime ?? Date.now());\n const status = this.status;\n\n self.addBreadcrumb(\"fetch\", `${method} ${url}`, {\n status,\n duration: `${duration}ms`,\n });\n\n if (status >= 400) {\n const dedupKey = self.buildErrorKey(\"interceptXHR\", `${method} ${url} ${status}`);\n if (self.loggedErrorKeys.has(dedupKey)) return;\n self.loggedErrorKeys.add(dedupKey);\n\n let responseBody: unknown = this.responseText;\n try {\n responseBody = JSON.parse(this.responseText);\n } catch {\n // keep as raw text\n }\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n void self.error({\n fnName: \"interceptXHR\",\n messageError: new Error(`HTTP ${status} ${this.statusText} — ${url}`),\n endpointName: url,\n payload: {\n method,\n status,\n statusText: this.statusText,\n duration: `${duration}ms`,\n responseBody,\n },\n });\n }\n }\n });\n\n this.addEventListener(\"error\", () => {\n // network-level failure (status selalu 0)\n const duration = Date.now() - (this._gaStartTime ?? Date.now());\n const dedupKey = self.buildErrorKey(\"interceptXHR\", `${method} ${url} NETWORK_ERROR`);\n if (self.loggedErrorKeys.has(dedupKey)) return;\n self.loggedErrorKeys.add(dedupKey);\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n void self.error({\n fnName: \"interceptXHR\",\n messageError: new Error(`Network error — ${method} ${url}`),\n endpointName: url,\n payload: { method, duration: `${duration}ms` },\n });\n }\n });\n\n // @ts-expect-error - spreading native arguments\n return originalSend.call(this, ...args);\n };\n\n console.info(\"[ga-logger] XHR intercepted\");\n }\n\n interceptClick(): void {\n if (typeof window === \"undefined\") return;\n\n if ((window as any).__ga_click_intercepted) return;\n (window as any).__ga_click_intercepted = true;\n this.initDomActivityObserver();\n\n document.addEventListener(\n \"click\",\n (event: MouseEvent) => {\n const raw = event.target as HTMLElement;\n if (!raw) return;\n\n const target = (raw.closest('button, a, [role=\"button\"], [data-log], input') as HTMLElement) ?? raw;\n\n const innerText = sanitizeClickText(target.innerText?.trim().slice(0, 50) ?? \"\");\n const id = target.id ?? \"\";\n const tagName = target.tagName?.toLowerCase() ?? \"\";\n\n const isInteractive =\n [\"button\", \"a\", \"input\"].includes(tagName) ||\n target.hasAttribute(\"data-log\") ||\n target.getAttribute(\"role\") === \"button\";\n\n if (!innerText && !id && !isInteractive) return;\n\n const message = innerText || id || `(no label: ${tagName || \"unknown\"})`;\n\n // Skip internal React/Router identifiers\n if (CLICK_SKIP_PATTERNS.some((p) => p.test(message))) return;\n\n this.addBreadcrumb(\"click\", message, {\n tagName,\n ...(id ? { id } : {}),\n ...(innerText ? { text: innerText } : {}),\n });\n\n // ── Dead click detection ──\n const clickTime = Date.now();\n const domActivityAtClick = this.lastDomActivity;\n\n if ([\"button\", \"a\", \"input\"].includes(tagName)) {\n setTimeout(() => {\n if (this.lastDomActivity <= domActivityAtClick) {\n this.addBreadcrumb(\"click\", `Dead click: ${message}`, {\n tagName,\n ...(id ? { id } : {}),\n reason: \"no DOM/scroll activity within 7s\",\n });\n }\n }, 7000);\n }\n\n // ── Rage click detection ──\n const historyKey = `${tagName}::${message}`;\n const timestamps = (this.clickHistory.get(historyKey) ?? []).filter((t) => clickTime - t < 7000);\n timestamps.push(clickTime);\n this.clickHistory.set(historyKey, timestamps);\n\n const lastFired = this.rageClickFired.get(historyKey) ?? 0;\n if (timestamps.length >= 3 && clickTime - lastFired > 7000) {\n this.rageClickFired.set(historyKey, clickTime);\n this.addBreadcrumb(\"click\", `Rage click: ${message}`, {\n tagName,\n ...(id ? { id } : {}),\n clickCount: timestamps.length,\n windowMs: 7000,\n });\n }\n },\n true,\n );\n }\n\n captureAction<T>(params: LogParams, fn: () => T | Promise<T>): Promise<T | undefined> {\n return Promise.resolve()\n .then(() => fn())\n .catch((error: unknown) => {\n const err = error instanceof Error ? error : new Error(String(error));\n this.send(\"error\", params.fnName, params.payload, err, params.endpointName);\n return undefined;\n });\n }\n\n withLogger<T extends (...args: any[]) => any>(\n fnName: string,\n fn: T,\n options?: {\n endpointName?: string;\n payload?: Record<string, unknown>;\n },\n ): T {\n return ((...args: Parameters<T>): ReturnType<T> | undefined => {\n try {\n const result = fn(...args);\n\n // Handle async function\n if (result instanceof Promise) {\n return result.catch((error: unknown) => {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error({\n fnName,\n messageError: err,\n endpointName: options?.endpointName,\n payload: options?.payload,\n });\n return undefined;\n }) as ReturnType<T>;\n }\n\n return result;\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error({\n fnName,\n messageError: err,\n endpointName: options?.endpointName,\n payload: options?.payload,\n });\n return undefined;\n }\n }) as T;\n }\n\n private async send(\n level: LogLevel,\n message: string,\n payload: Record<string, unknown> = {},\n error?: Error,\n endpoint?: string,\n ) {\n if (!this.initialized || !this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n // console only, skip Firestore\n if (this.config.env === \"localhost\") {\n console.error(`[ga-localhost][DEV] ${message}`, { payload, error });\n return;\n }\n\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n message,\n env: this.config.env,\n userId: this.config.userId ?? null,\n sessionId,\n page: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n stackTrace: error?.stack ?? null,\n payload: this.sanitizePayload(payload),\n repo: this.config.repo,\n endpoint: endpoint ?? null,\n breadcrumbs: [...this.breadcrumbs],\n ...getEnvironmentPayload(),\n };\n\n try {\n const db = getDb();\n const safeEntry = this.sanitizeForFirestore(entry as unknown as Record<string, unknown>);\n await addDoc(collection(db, \"logs\"), {\n ...safeEntry,\n timestamp: Timestamp.fromDate(entry.timestamp),\n });\n } catch (e) {\n console.error(\"[ga-logger] failed to send log:\", e);\n }\n }\n\n info(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"info\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n\n warn(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"warn\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n\n error(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"error\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n}\n\nexport const logger = new Logger();\n\n","import { initializeApp, getApps, getApp } from \"firebase/app\";\nimport { getFirestore } from \"firebase/firestore\";\nimport type { Firestore } from \"firebase/firestore\";\nimport type { LoggerConfig } from \"../types\";\n\nconst APP_NAME = \"ga-logger\";\nlet db: Firestore | null = null;\n\nexport const initFirebase = (config: LoggerConfig) => {\n // Cek apakah named instance \"ga-logger\" sudah ada\n const existingApp = getApps().find((app) => app.name === APP_NAME);\n\n const app =\n existingApp ??\n initializeApp(\n {\n apiKey: config.apiKey,\n authDomain: config.authDomain,\n projectId: config.projectId,\n storageBucket: config.storageBucket,\n messagingSenderId: config.messagingSenderId,\n appId: config.appId,\n },\n APP_NAME,\n );\n\n db = getFirestore(app);\n return db;\n};\n\nexport const getDb = (): Firestore => {\n if (!db) throw new Error(\"[ga-logger] Firebase not initialized. Call logger.init() first.\");\n return db;\n};\n","interface EnvironmentPayload {\n userAgent: string;\n deviceType: \"Mobile\" | \"Tablet\" | \"Desktop\";\n screenWidth: number;\n screenHeight: number;\n}\n\nlet cachedEnvironment: EnvironmentPayload | null = null;\n\nfunction getDeviceType(width: number): \"Mobile\" | \"Tablet\" | \"Desktop\" {\n if (width < 768) return \"Mobile\";\n if (width <= 1024) return \"Tablet\";\n return \"Desktop\";\n}\n\nexport function initEnvironment(): void {\n if (cachedEnvironment) return;\n\n const width = window.innerWidth;\n const height = window.innerHeight;\n\n cachedEnvironment = {\n userAgent: navigator.userAgent,\n deviceType: getDeviceType(width),\n screenWidth: width,\n screenHeight: height,\n };\n}\n\nexport function getEnvironmentPayload(): EnvironmentPayload {\n if (!cachedEnvironment) initEnvironment();\n return cachedEnvironment!;\n}","import { Component, type ErrorInfo, type ReactNode } from \"react\";\nimport { logger } from \"../core/logger\";\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n}\n\nexport class LoggerErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): State {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n logger.addBreadcrumb(\"error\", `React crash: ${error.message}`, {\n componentStack: info.componentStack ?? undefined,\n });\n\n logger.error({\n fnName: \"LoggerErrorBoundary\",\n messageError: error,\n payload: {\n componentStack: info.componentStack ?? undefined,\n },\n });\n }\n\n render() {\n if (this.state.hasError) {\n return this.props.fallback ?? (\n <div style={{ padding: \"1rem\", color: \"red\" }}>\n Something went wrong.\n </div>\n );\n }\n\n return this.props.children;\n }\n}"],"mappings":"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","names":["import_firestore","app","db"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/logger.ts","../src/config/firebase.ts","../src/core/environment.ts","../src/components/LoggerErrorBoundary.tsx"],"sourcesContent":["export { logger } from \"./core/logger\";\nexport { LoggerErrorBoundary } from \"./components/LoggerErrorBoundary\";\nexport type { LogEntry, LoggerConfig, LogLevel, LogEnv, Breadcrumb, BreadcrumbType } from \"./types\";\n","import { collection, addDoc, Timestamp } from \"firebase/firestore\";\nimport { initFirebase, getDb } from \"../config/firebase\";\nimport type { Breadcrumb, BreadcrumbType, LogEntry, LogLevel, LogParams, LoggerConfig } from \"../types\";\nimport { initEnvironment } from \"./environment\";\nimport { getEnvironmentPayload } from \"./environment\";\n\nconst sessionId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\nconst MAX_BREADCRUMBS = 50;\n\nconst CLICK_SKIP_PATTERNS = [/^:r[a-z0-9]+:$/, /^\\[object/, /^#/];\n\n// Sanitize PII sebelum masuk Firestore\nconst sanitizeClickText = (text: string): string => {\n return text\n .replace(/\\b[\\w.-]+@[\\w.-]+\\.\\w+\\b/g, \"[email]\")\n .replace(/\\b\\d{10,}\\b/g, \"[number]\")\n .replace(/Rp[\\s]?\\d[\\d.,]*/gi, \"[amount]\")\n .trim();\n};\n\nclass Logger {\n private config: LoggerConfig | null = null;\n private initialized = false;\n private breadcrumbs: Breadcrumb[] = [];\n\n private lastDomActivity = Date.now();\n private clickHistory = new Map<string, number[]>();\n private rageClickFired = new Map<string, number>();\n private domObserverInitialized = false;\n\n constructor() {\n if (typeof window !== \"undefined\") {\n (window as any).__ga_debug_breadcrumbs = () => this.breadcrumbs;\n }\n }\n\n private recentDomChanges: string[] = [];\n\n private initDomActivityObserver(): void {\n if (this.domObserverInitialized) return;\n this.domObserverInitialized = true;\n\n const markActivity = (addedText?: string) => {\n this.lastDomActivity = Date.now();\n if (addedText) {\n this.recentDomChanges.push(addedText);\n // keep only last few seconds worth\n setTimeout(() => {\n this.recentDomChanges = this.recentDomChanges.filter((t) => t !== addedText);\n }, 1000); // ⚠️ perlu konfirmasi durasi\n }\n };\n\n const observer = new MutationObserver((mutations) => {\n markActivity();\n for (const m of mutations) {\n m.addedNodes.forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const text = (node as HTMLElement).innerText?.trim();\n if (text && text.length < 200) markActivity(text);\n }\n });\n }\n });\n\n observer.observe(document.body, { childList: true, subtree: true, attributes: true });\n window.addEventListener(\"scroll\", () => markActivity(), { passive: true, capture: true });\n }\n\n init(config: LoggerConfig) {\n this.config = config;\n initFirebase(config);\n initEnvironment();\n this.initialized = true;\n console.info(\"[ga-logger] initialized —\", config.env);\n }\n setUserId(userId: string | null) {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n this.config.userId = userId;\n }\n\n initAnonymousUser(): void {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n const STORAGE_KEY = \"ga_anon_id\";\n\n try {\n let anonId = localStorage.getItem(STORAGE_KEY);\n\n if (!anonId) {\n anonId =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? crypto.randomUUID()\n : \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n\n localStorage.setItem(STORAGE_KEY, anonId);\n }\n\n const shortId = anonId.slice(-8);\n this.setUserId(`Anonymous #${shortId}`);\n } catch (e) {\n // localStorage blocked (private mode / HTTP restriction)\n console.warn(\"[ga-logger] initAnonymousUser failed:\", e);\n this.setUserId(\"Anonymous\");\n }\n }\n\n // Add breadcrumb ke in-memory array\n addBreadcrumb(type: BreadcrumbType, message: string, data?: Record<string, unknown>) {\n const breadcrumb: Breadcrumb = {\n timestamp: new Date(),\n type,\n message,\n data,\n };\n\n this.breadcrumbs.push(breadcrumb);\n\n // Jaga memory — max 50 breadcrumbs, buang yang paling lama\n if (this.breadcrumbs.length > MAX_BREADCRUMBS) {\n this.breadcrumbs.shift();\n }\n }\n\n // Global error capture — hanya aktif di non-development\n private loggedErrorKeys = new Set<string>();\n\n // Helper: trim URL jadi domain/filename\n private trimUrl(url: string): string {\n try {\n const u = new URL(url);\n const filename = u.pathname.split(\"/\").filter(Boolean).pop() ?? u.pathname;\n return `${u.hostname}/${filename}`;\n } catch {\n // bukan valid URL, potong saja jika terlalu panjang\n return url.length > 80 ? url.slice(0, 80) + \"...\" : url;\n }\n }\n\n // Helper: build dedup key\n private buildErrorKey(type: string, message: string): string {\n return `${type}::${message}`;\n }\n\n // Helper: should skip resource error\n private shouldSkipResourceError(src: string, tagName: string): boolean {\n // Skip IMG — tidak sebabkan blank page\n if (tagName === \"IMG\") return true;\n\n // Skip base64 URL\n if (src.startsWith(\"data:\")) return true;\n\n // Skip known 3rd party trackers\n const THIRD_PARTY = [\n \"omguk.com\",\n \"track.\",\n \"doubleclick\",\n \"adservice\",\n \"googletagmanager\",\n \"google-analytics\",\n \"hotjar\",\n \"facebook.net\",\n \"analytics\",\n \"magnolia\",\n \"gtm.js\",\n ];\n if (THIRD_PARTY.some((p) => src.includes(p))) return true;\n\n return false;\n }\n\n private shouldSkipGlobalError(message: string): boolean {\n const NOISE = [\n \"CORS\",\n \"cross-origin\",\n \"ERR_FAILED\",\n \"Failed to load resource\",\n \"NetworkError\",\n \"ResizeObserver loop\",\n \"Script error\",\n \"ServiceWorker\",\n \"sw.js\",\n \"dev-sw.js\",\n \"Warning:\",\n ];\n const THIRD_PARTY = [\n \"magnolia\",\n \"gtm.js\",\n \"analytics\",\n \"googletagmanager\",\n \"facebook\",\n \"hotjar\",\n \"omguk.com\",\n \"track.\",\n \"doubleclick\",\n \"adservice\",\n ];\n return NOISE.some((p) => message.includes(p)) || THIRD_PARTY.some((p) => message.includes(p));\n }\n\n initGlobalCapture(): void {\n const isLocalhost = window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n if (isLocalhost) return;\n\n window.onerror = (message, source, lineno, colno) => {\n const msg = typeof message === \"string\" ? message : \"Unknown error\";\n if (this.shouldSkipGlobalError(msg)) return false;\n\n const trimmedSource = source ? this.trimUrl(source) : \"unknown source\";\n const finalMessage = `${msg} at ${trimmedSource}:${lineno ?? 0}`;\n const key = this.buildErrorKey(\"onerror\", finalMessage);\n if (this.loggedErrorKeys.has(key)) return false;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"window.onerror\",\n messageError: new Error(finalMessage),\n payload: { source: trimmedSource, lineno, colno },\n });\n\n return false;\n };\n\n // unhandledrejection\n window.addEventListener(\"unhandledrejection\", (event) => {\n const msg =\n event.reason instanceof Error\n ? event.reason.message\n : String(event.reason ?? \"Unhandled Promise rejection\");\n\n if (this.shouldSkipGlobalError(msg)) return;\n\n const key = this.buildErrorKey(\"unhandledrejection\", msg);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"window.unhandledrejection\",\n messageError: new Error(msg),\n });\n });\n\n // console.error override\n const originalConsoleError = console.error.bind(console);\n console.error = (...args: unknown[]) => {\n originalConsoleError(...args);\n\n const msg = args.map((a) => (a instanceof Error ? a.message : String(a))).join(\" \");\n\n if (this.shouldSkipGlobalError(msg)) return;\n\n const trimmedMsg = msg.length > 150 ? msg.slice(0, 150) + \"...\" : msg;\n const key = this.buildErrorKey(\"console.error\", trimmedMsg);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n const originalError = args.find((a): a is Error => a instanceof Error);\n\n const errorToSend = originalError ?? new Error(trimmedMsg);\n\n void this.error({\n fnName: \"console.error\",\n messageError: errorToSend,\n });\n };\n\n // resource load error (CSS / JS / font)\n window.addEventListener(\n \"error\",\n (event) => {\n const target = event.target;\n if (!(target instanceof HTMLElement)) return;\n if (target === (window as unknown)) return;\n\n const tagName = target.tagName.toUpperCase();\n\n const src =\n tagName === \"LINK\"\n ? (target as HTMLLinkElement).href\n : tagName === \"SCRIPT\"\n ? (target as HTMLScriptElement).src\n : \"\";\n\n if (this.shouldSkipResourceError(src, tagName)) return;\n\n // Deteksi dari ekstensi file, bukan tagName\n const ext = src.split(\"?\")[0].split(\".\").pop()?.toLowerCase();\n const resourceType =\n ext === \"css\"\n ? \"CSS\"\n : ext === \"js\"\n ? \"JS\"\n : ext === \"woff\" || ext === \"woff2\" || ext === \"ttf\"\n ? \"FONT\"\n : tagName;\n\n const trimmedSrc = this.trimUrl(src);\n const finalMessage = `Failed to load ${resourceType}: ${trimmedSrc}`;\n const key = this.buildErrorKey(\"resource\", finalMessage);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"resource.onerror\",\n messageError: new Error(finalMessage),\n payload: { tagName, src: trimmedSrc },\n });\n },\n true,\n );\n }\n\n private sanitizePayload(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => {\n if (value === undefined) return [key, null];\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return [key, this.sanitizePayload(value as Record<string, unknown>)];\n }\n return [key, value];\n }),\n );\n }\n\n private sanitizeForFirestore(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => {\n if (value === undefined) return [key, null];\n if (typeof value === \"function\") return [key, \"[function]\"];\n if (value instanceof Date) return [key, value.toISOString()];\n if (Array.isArray(value)) {\n return [\n key,\n value.map((item) => {\n if (item instanceof Date) return item.toISOString();\n if (typeof item === \"function\") return \"[function]\"; // ← tambah\n if (item !== null && typeof item === \"object\") {\n return this.sanitizeForFirestore(item as Record<string, unknown>);\n }\n return item ?? null;\n }),\n ];\n }\n if (value !== null && typeof value === \"object\") {\n return [key, this.sanitizeForFirestore(value as Record<string, unknown>)];\n }\n return [key, value];\n }),\n );\n }\n\n // interceptFetch — auto breadcrumb, ke Firestore\n interceptFetch() {\n if (typeof window === \"undefined\") return;\n\n const originalFetch = window.fetch;\n\n const skipPatterns = [\n \"google.com\",\n \"googletagmanager.com\",\n \"googleapis.com\",\n \"facebook.com\",\n \"hotjar.com\",\n \"analytics\",\n \"gtm\",\n \"ccm/collect\",\n \"on.aws\",\n \"/locales/\",\n \"/sw.js\",\n \"/manifest.json\",\n \"/sourcemaps/\",\n \"magnolia\",\n ];\n\n const shouldSkipUrl = (url: string): boolean => {\n return skipPatterns.some((pattern) => url.includes(pattern));\n };\n\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n\n // Skip third-party domains\n if (shouldSkipUrl(url)) {\n return originalFetch(input, init);\n }\n\n const method = init?.method ?? \"GET\";\n const startTime = Date.now();\n\n try {\n const response = await originalFetch(input, init);\n const duration = Date.now() - startTime;\n\n this.addBreadcrumb(\"fetch\", `${method} ${url}`, {\n status: response.status,\n duration: `${duration}ms`,\n });\n\n if (response.status >= 400) {\n const dedupKey = this.buildErrorKey(\"interceptFetch\", `${method} ${url} ${response.status}`);\n\n if (!this.loggedErrorKeys.has(dedupKey)) {\n this.loggedErrorKeys.add(dedupKey);\n\n let responseBody: unknown = null;\n try {\n const cloned = response.clone();\n const contentType = cloned.headers.get(\"content-type\") ?? \"\";\n responseBody = contentType.includes(\"application/json\")\n ? await cloned.json()\n : await cloned.text();\n } catch {\n responseBody = \"[unable to read response body]\";\n }\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n this.error({\n fnName: \"interceptFetch\",\n messageError: new Error(`HTTP ${response.status} ${response.statusText} — ${url}`),\n endpointName: url,\n payload: {\n method,\n status: response.status,\n statusText: response.statusText,\n duration: `${duration}ms`,\n responseBody,\n },\n });\n }\n }\n }\n\n return response;\n } catch (networkError) {\n const duration = Date.now() - startTime;\n const error = networkError instanceof Error ? networkError : new Error(String(networkError));\n\n this.addBreadcrumb(\"fetch\", `${method} ${url} — NETWORK ERROR`, {\n duration: `${duration}ms`,\n error: error.message,\n });\n\n const dedupKey = this.buildErrorKey(\"interceptFetch\", `${method} ${url} NETWORK_ERROR`);\n\n if (!this.loggedErrorKeys.has(dedupKey)) {\n this.loggedErrorKeys.add(dedupKey);\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n if (!isLocalhost) {\n this.error({\n fnName: \"interceptFetch\",\n messageError: error,\n endpointName: url,\n payload: { method, duration: `${duration}ms` },\n });\n }\n }\n\n throw networkError;\n }\n };\n\n console.info(\"[ga-logger] fetch intercepted\");\n }\n\n // interceptXHR — auto breadcrumb + error capture untuk axios/XHR-based request\n interceptXHR(): void {\n if (typeof window === \"undefined\") return;\n\n const skipPatterns = [\n \"google.com\",\n \"googletagmanager.com\",\n \"googleapis.com\",\n \"facebook.com\",\n \"hotjar.com\",\n \"analytics\",\n \"ccm/collect\",\n \"on.aws\",\n \"/locales/\",\n \"/sw.js\",\n \"/manifest.json\",\n \"/sourcemaps/\",\n \"magnolia\",\n ];\n\n const shouldSkipUrl = (url: string): boolean => skipPatterns.some((p) => url.includes(p));\n\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n const self = this;\n\n type GaXHR = XMLHttpRequest & {\n _gaMethod?: string;\n _gaUrl?: string;\n _gaStartTime?: number;\n };\n\n XMLHttpRequest.prototype.open = function (this: GaXHR, method: string, url: string | URL, ...rest: unknown[]) {\n this._gaMethod = method;\n this._gaUrl = typeof url === \"string\" ? url : url.href;\n // @ts-expect-error - spreading native arguments\n return originalOpen.call(this, method, url, ...rest);\n };\n\n XMLHttpRequest.prototype.send = function (this: GaXHR, ...args: unknown[]) {\n const url = this._gaUrl ?? \"\";\n const method = this._gaMethod ?? \"GET\";\n\n if (shouldSkipUrl(url)) {\n // @ts-expect-error - spreading native arguments\n return originalSend.call(this, ...args);\n }\n\n this._gaStartTime = Date.now();\n\n this.addEventListener(\"loadend\", () => {\n const duration = Date.now() - (this._gaStartTime ?? Date.now());\n const status = this.status;\n\n self.addBreadcrumb(\"fetch\", `${method} ${url}`, {\n status,\n duration: `${duration}ms`,\n });\n\n if (status >= 400) {\n const dedupKey = self.buildErrorKey(\"interceptXHR\", `${method} ${url} ${status}`);\n if (self.loggedErrorKeys.has(dedupKey)) return;\n self.loggedErrorKeys.add(dedupKey);\n\n let responseBody: unknown = this.responseText;\n try {\n responseBody = JSON.parse(this.responseText);\n } catch {\n // keep as raw text\n }\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n void self.error({\n fnName: \"interceptXHR\",\n messageError: new Error(`HTTP ${status} ${this.statusText} — ${url}`),\n endpointName: url,\n payload: {\n method,\n status,\n statusText: this.statusText,\n duration: `${duration}ms`,\n responseBody,\n },\n });\n }\n }\n });\n\n this.addEventListener(\"error\", () => {\n // network-level failure (status selalu 0)\n const duration = Date.now() - (this._gaStartTime ?? Date.now());\n const dedupKey = self.buildErrorKey(\"interceptXHR\", `${method} ${url} NETWORK_ERROR`);\n if (self.loggedErrorKeys.has(dedupKey)) return;\n self.loggedErrorKeys.add(dedupKey);\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n void self.error({\n fnName: \"interceptXHR\",\n messageError: new Error(`Network error — ${method} ${url}`),\n endpointName: url,\n payload: { method, duration: `${duration}ms` },\n });\n }\n });\n\n // @ts-expect-error - spreading native arguments\n return originalSend.call(this, ...args);\n };\n\n console.info(\"[ga-logger] XHR intercepted\");\n }\n\n interceptClick(): void {\n if (typeof window === \"undefined\") return;\n\n if ((window as any).__ga_click_intercepted) return;\n (window as any).__ga_click_intercepted = true;\n this.initDomActivityObserver();\n\n document.addEventListener(\n \"click\",\n (event: MouseEvent) => {\n const raw = event.target as HTMLElement;\n if (!raw) return;\n\n const target = (raw.closest('button, a, [role=\"button\"], [data-log], input') as HTMLElement) ?? raw;\n\n const innerText = sanitizeClickText(target.innerText?.trim().slice(0, 50) ?? \"\");\n const id = target.id ?? \"\";\n const tagName = target.tagName?.toLowerCase() ?? \"\";\n\n const isInteractive =\n [\"button\", \"a\", \"input\"].includes(tagName) ||\n target.hasAttribute(\"data-log\") ||\n target.getAttribute(\"role\") === \"button\";\n\n if (!innerText && !id && !isInteractive) return;\n\n const message = innerText || id || `(no label: ${tagName || \"unknown\"})`;\n\n // Skip internal React/Router identifiers\n if (CLICK_SKIP_PATTERNS.some((p) => p.test(message))) return;\n\n this.addBreadcrumb(\"click\", message, {\n tagName,\n ...(id ? { id } : {}),\n ...(innerText ? { text: innerText } : {}),\n });\n\n // ── Dead click detection ──\n const clickTime = Date.now();\n const domActivityAtClick = this.lastDomActivity;\n\n if ([\"button\", \"a\", \"input\"].includes(tagName)) {\n setTimeout(() => {\n if (this.lastDomActivity <= domActivityAtClick) {\n const reason = \"no DOM/scroll activity within 7s\";\n\n this.addBreadcrumb(\"click\", `Dead click: ${message}`, {\n tagName,\n ...(id ? { id } : {}),\n reason,\n });\n\n void this.warn({\n fnName: \"interceptClick.deadClick\",\n messageError: new Error(`Dead click: ${message}`),\n payload: { tagName, ...(id ? { id } : {}), reason },\n });\n }\n }, 7000);\n }\n\n // ── Rage click detection ──\n const historyKey = `${tagName}::${message}`;\n const timestamps = (this.clickHistory.get(historyKey) ?? []).filter((t) => clickTime - t < 7000);\n timestamps.push(clickTime);\n this.clickHistory.set(historyKey, timestamps);\n\n const lastFired = this.rageClickFired.get(historyKey) ?? 0;\n if (timestamps.length >= 3 && clickTime - lastFired > 7000) {\n this.rageClickFired.set(historyKey, clickTime);\n\n const possibleReason = this.recentDomChanges.length\n ? this.recentDomChanges.slice(-1)[0]\n : \"no visible UI feedback detected\";\n\n this.addBreadcrumb(\"click\", `Rage click: ${message}`, {\n tagName,\n clickCount: timestamps.length,\n windowMs: 7000,\n possibleReason,\n });\n\n void this.warn({\n fnName: \"interceptClick.rageClick\",\n messageError: new Error(`Rage click: ${message}`),\n payload: { tagName, clickCount: timestamps.length, windowMs: 7000, possibleReason },\n });\n }\n },\n true,\n );\n }\n\n captureAction<T>(params: LogParams, fn: () => T | Promise<T>): Promise<T | undefined> {\n return Promise.resolve()\n .then(() => fn())\n .catch((error: unknown) => {\n const err = error instanceof Error ? error : new Error(String(error));\n this.send(\"error\", params.fnName, params.payload, err, params.endpointName);\n return undefined;\n });\n }\n\n withLogger<T extends (...args: any[]) => any>(\n fnName: string,\n fn: T,\n options?: {\n endpointName?: string;\n payload?: Record<string, unknown>;\n },\n ): T {\n return ((...args: Parameters<T>): ReturnType<T> | undefined => {\n try {\n const result = fn(...args);\n\n // Handle async function\n if (result instanceof Promise) {\n return result.catch((error: unknown) => {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error({\n fnName,\n messageError: err,\n endpointName: options?.endpointName,\n payload: options?.payload,\n });\n return undefined;\n }) as ReturnType<T>;\n }\n\n return result;\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error({\n fnName,\n messageError: err,\n endpointName: options?.endpointName,\n payload: options?.payload,\n });\n return undefined;\n }\n }) as T;\n }\n\n private async send(\n level: LogLevel,\n message: string,\n payload: Record<string, unknown> = {},\n error?: Error,\n endpoint?: string,\n ) {\n if (!this.initialized || !this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n // console only, skip Firestore\n if (this.config.env === \"localhost\") {\n console.error(`[ga-localhost][DEV] ${message}`, { payload, error });\n return;\n }\n\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n message,\n env: this.config.env,\n userId: this.config.userId ?? null,\n sessionId,\n page: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n stackTrace: error?.stack ?? null,\n payload: this.sanitizePayload(payload),\n repo: this.config.repo,\n endpoint: endpoint ?? null,\n breadcrumbs: [...this.breadcrumbs],\n ...getEnvironmentPayload(),\n };\n\n try {\n const db = getDb();\n const safeEntry = this.sanitizeForFirestore(entry as unknown as Record<string, unknown>);\n await addDoc(collection(db, \"logs\"), {\n ...safeEntry,\n timestamp: Timestamp.fromDate(entry.timestamp),\n });\n } catch (e) {\n console.error(\"[ga-logger] failed to send log:\", e);\n }\n }\n\n info(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"info\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n\n warn(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"warn\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n\n error(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"error\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n}\n\nexport const logger = new Logger();\n\n","import { initializeApp, getApps, getApp } from \"firebase/app\";\nimport { getFirestore } from \"firebase/firestore\";\nimport type { Firestore } from \"firebase/firestore\";\nimport type { LoggerConfig } from \"../types\";\n\nconst APP_NAME = \"ga-logger\";\nlet db: Firestore | null = null;\n\nexport const initFirebase = (config: LoggerConfig) => {\n // Cek apakah named instance \"ga-logger\" sudah ada\n const existingApp = getApps().find((app) => app.name === APP_NAME);\n\n const app =\n existingApp ??\n initializeApp(\n {\n apiKey: config.apiKey,\n authDomain: config.authDomain,\n projectId: config.projectId,\n storageBucket: config.storageBucket,\n messagingSenderId: config.messagingSenderId,\n appId: config.appId,\n },\n APP_NAME,\n );\n\n db = getFirestore(app);\n return db;\n};\n\nexport const getDb = (): Firestore => {\n if (!db) throw new Error(\"[ga-logger] Firebase not initialized. Call logger.init() first.\");\n return db;\n};\n","interface EnvironmentPayload {\n userAgent: string;\n deviceType: \"Mobile\" | \"Tablet\" | \"Desktop\";\n screenWidth: number;\n screenHeight: number;\n}\n\nlet cachedEnvironment: EnvironmentPayload | null = null;\n\nfunction getDeviceType(width: number): \"Mobile\" | \"Tablet\" | \"Desktop\" {\n if (width < 768) return \"Mobile\";\n if (width <= 1024) return \"Tablet\";\n return \"Desktop\";\n}\n\nexport function initEnvironment(): void {\n if (cachedEnvironment) return;\n\n const width = window.innerWidth;\n const height = window.innerHeight;\n\n cachedEnvironment = {\n userAgent: navigator.userAgent,\n deviceType: getDeviceType(width),\n screenWidth: width,\n screenHeight: height,\n };\n}\n\nexport function getEnvironmentPayload(): EnvironmentPayload {\n if (!cachedEnvironment) initEnvironment();\n return cachedEnvironment!;\n}","import { Component, type ErrorInfo, type ReactNode } from \"react\";\nimport { logger } from \"../core/logger\";\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n}\n\nexport class LoggerErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): State {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n logger.addBreadcrumb(\"error\", `React crash: ${error.message}`, {\n componentStack: info.componentStack ?? undefined,\n });\n\n logger.error({\n fnName: \"LoggerErrorBoundary\",\n messageError: error,\n payload: {\n componentStack: info.componentStack ?? undefined,\n },\n });\n }\n\n render() {\n if (this.state.hasError) {\n return this.props.fallback ?? (\n <div style={{ padding: \"1rem\", color: \"red\" }}>\n Something went wrong.\n </div>\n );\n }\n\n return this.props.children;\n }\n}"],"mappings":"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","names":["import_firestore","app","db"]}
package/dist/index.mjs CHANGED
@@ -66,6 +66,7 @@ var Logger = class {
66
66
  this.clickHistory = /* @__PURE__ */ new Map();
67
67
  this.rageClickFired = /* @__PURE__ */ new Map();
68
68
  this.domObserverInitialized = false;
69
+ this.recentDomChanges = [];
69
70
  // Global error capture — hanya aktif di non-development
70
71
  this.loggedErrorKeys = /* @__PURE__ */ new Set();
71
72
  if (typeof window !== "undefined") {
@@ -75,16 +76,28 @@ var Logger = class {
75
76
  initDomActivityObserver() {
76
77
  if (this.domObserverInitialized) return;
77
78
  this.domObserverInitialized = true;
78
- const markActivity = () => {
79
+ const markActivity = (addedText) => {
79
80
  this.lastDomActivity = Date.now();
81
+ if (addedText) {
82
+ this.recentDomChanges.push(addedText);
83
+ setTimeout(() => {
84
+ this.recentDomChanges = this.recentDomChanges.filter((t) => t !== addedText);
85
+ }, 1e3);
86
+ }
80
87
  };
81
- const observer = new MutationObserver(markActivity);
82
- observer.observe(document.body, {
83
- childList: true,
84
- subtree: true,
85
- attributes: true
88
+ const observer = new MutationObserver((mutations) => {
89
+ markActivity();
90
+ for (const m of mutations) {
91
+ m.addedNodes.forEach((node) => {
92
+ if (node.nodeType === Node.ELEMENT_NODE) {
93
+ const text = node.innerText?.trim();
94
+ if (text && text.length < 200) markActivity(text);
95
+ }
96
+ });
97
+ }
86
98
  });
87
- window.addEventListener("scroll", markActivity, { passive: true, capture: true });
99
+ observer.observe(document.body, { childList: true, subtree: true, attributes: true });
100
+ window.addEventListener("scroll", () => markActivity(), { passive: true, capture: true });
88
101
  }
89
102
  init(config) {
90
103
  this.config = config;
@@ -511,10 +524,16 @@ var Logger = class {
511
524
  if (["button", "a", "input"].includes(tagName)) {
512
525
  setTimeout(() => {
513
526
  if (this.lastDomActivity <= domActivityAtClick) {
527
+ const reason = "no DOM/scroll activity within 7s";
514
528
  this.addBreadcrumb("click", `Dead click: ${message}`, {
515
529
  tagName,
516
530
  ...id ? { id } : {},
517
- reason: "no DOM/scroll activity within 7s"
531
+ reason
532
+ });
533
+ void this.warn({
534
+ fnName: "interceptClick.deadClick",
535
+ messageError: new Error(`Dead click: ${message}`),
536
+ payload: { tagName, ...id ? { id } : {}, reason }
518
537
  });
519
538
  }
520
539
  }, 7e3);
@@ -526,11 +545,17 @@ var Logger = class {
526
545
  const lastFired = this.rageClickFired.get(historyKey) ?? 0;
527
546
  if (timestamps.length >= 3 && clickTime - lastFired > 7e3) {
528
547
  this.rageClickFired.set(historyKey, clickTime);
548
+ const possibleReason = this.recentDomChanges.length ? this.recentDomChanges.slice(-1)[0] : "no visible UI feedback detected";
529
549
  this.addBreadcrumb("click", `Rage click: ${message}`, {
530
550
  tagName,
531
- ...id ? { id } : {},
532
551
  clickCount: timestamps.length,
533
- windowMs: 7e3
552
+ windowMs: 7e3,
553
+ possibleReason
554
+ });
555
+ void this.warn({
556
+ fnName: "interceptClick.rageClick",
557
+ messageError: new Error(`Rage click: ${message}`),
558
+ payload: { tagName, clickCount: timestamps.length, windowMs: 7e3, possibleReason }
534
559
  });
535
560
  }
536
561
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/logger.ts","../src/config/firebase.ts","../src/core/environment.ts","../src/components/LoggerErrorBoundary.tsx"],"sourcesContent":["import { collection, addDoc, Timestamp } from \"firebase/firestore\";\nimport { initFirebase, getDb } from \"../config/firebase\";\nimport type { Breadcrumb, BreadcrumbType, LogEntry, LogLevel, LogParams, LoggerConfig } from \"../types\";\nimport { initEnvironment } from \"./environment\";\nimport { getEnvironmentPayload } from \"./environment\";\n\nconst sessionId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\nconst MAX_BREADCRUMBS = 50;\n\nconst CLICK_SKIP_PATTERNS = [/^:r[a-z0-9]+:$/, /^\\[object/, /^#/];\n\n// Sanitize PII sebelum masuk Firestore\nconst sanitizeClickText = (text: string): string => {\n return text\n .replace(/\\b[\\w.-]+@[\\w.-]+\\.\\w+\\b/g, \"[email]\")\n .replace(/\\b\\d{10,}\\b/g, \"[number]\")\n .replace(/Rp[\\s]?\\d[\\d.,]*/gi, \"[amount]\")\n .trim();\n};\n\nclass Logger {\n private config: LoggerConfig | null = null;\n private initialized = false;\n private breadcrumbs: Breadcrumb[] = [];\n\n private lastDomActivity = Date.now();\n private clickHistory = new Map<string, number[]>();\n private rageClickFired = new Map<string, number>();\n private domObserverInitialized = false;\n\n constructor() {\n if (typeof window !== \"undefined\") {\n (window as any).__ga_debug_breadcrumbs = () => this.breadcrumbs;\n }\n }\n\n private initDomActivityObserver(): void {\n if (this.domObserverInitialized) return;\n this.domObserverInitialized = true;\n\n const markActivity = () => {\n this.lastDomActivity = Date.now();\n };\n\n const observer = new MutationObserver(markActivity);\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n });\n\n window.addEventListener(\"scroll\", markActivity, { passive: true, capture: true });\n }\n\n init(config: LoggerConfig) {\n this.config = config;\n initFirebase(config);\n initEnvironment();\n this.initialized = true;\n console.info(\"[ga-logger] initialized —\", config.env);\n }\n setUserId(userId: string | null) {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n this.config.userId = userId;\n }\n\n initAnonymousUser(): void {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n const STORAGE_KEY = \"ga_anon_id\";\n\n try {\n let anonId = localStorage.getItem(STORAGE_KEY);\n\n if (!anonId) {\n anonId =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? crypto.randomUUID()\n : \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n\n localStorage.setItem(STORAGE_KEY, anonId);\n }\n\n const shortId = anonId.slice(-8);\n this.setUserId(`Anonymous #${shortId}`);\n } catch (e) {\n // localStorage blocked (private mode / HTTP restriction)\n console.warn(\"[ga-logger] initAnonymousUser failed:\", e);\n this.setUserId(\"Anonymous\");\n }\n }\n\n // Add breadcrumb ke in-memory array\n addBreadcrumb(type: BreadcrumbType, message: string, data?: Record<string, unknown>) {\n const breadcrumb: Breadcrumb = {\n timestamp: new Date(),\n type,\n message,\n data,\n };\n\n this.breadcrumbs.push(breadcrumb);\n\n // Jaga memory — max 50 breadcrumbs, buang yang paling lama\n if (this.breadcrumbs.length > MAX_BREADCRUMBS) {\n this.breadcrumbs.shift();\n }\n }\n\n // Global error capture — hanya aktif di non-development\n private loggedErrorKeys = new Set<string>();\n\n // Helper: trim URL jadi domain/filename\n private trimUrl(url: string): string {\n try {\n const u = new URL(url);\n const filename = u.pathname.split(\"/\").filter(Boolean).pop() ?? u.pathname;\n return `${u.hostname}/${filename}`;\n } catch {\n // bukan valid URL, potong saja jika terlalu panjang\n return url.length > 80 ? url.slice(0, 80) + \"...\" : url;\n }\n }\n\n // Helper: build dedup key\n private buildErrorKey(type: string, message: string): string {\n return `${type}::${message}`;\n }\n\n // Helper: should skip resource error\n private shouldSkipResourceError(src: string, tagName: string): boolean {\n // Skip IMG — tidak sebabkan blank page\n if (tagName === \"IMG\") return true;\n\n // Skip base64 URL\n if (src.startsWith(\"data:\")) return true;\n\n // Skip known 3rd party trackers\n const THIRD_PARTY = [\n \"omguk.com\",\n \"track.\",\n \"doubleclick\",\n \"adservice\",\n \"googletagmanager\",\n \"google-analytics\",\n \"hotjar\",\n \"facebook.net\",\n \"analytics\",\n \"magnolia\",\n \"gtm.js\",\n ];\n if (THIRD_PARTY.some((p) => src.includes(p))) return true;\n\n return false;\n }\n\n private shouldSkipGlobalError(message: string): boolean {\n const NOISE = [\n \"CORS\",\n \"cross-origin\",\n \"ERR_FAILED\",\n \"Failed to load resource\",\n \"NetworkError\",\n \"ResizeObserver loop\",\n \"Script error\",\n \"ServiceWorker\",\n \"sw.js\",\n \"dev-sw.js\",\n \"Warning:\",\n ];\n const THIRD_PARTY = [\n \"magnolia\",\n \"gtm.js\",\n \"analytics\",\n \"googletagmanager\",\n \"facebook\",\n \"hotjar\",\n \"omguk.com\",\n \"track.\",\n \"doubleclick\",\n \"adservice\",\n ];\n return NOISE.some((p) => message.includes(p)) || THIRD_PARTY.some((p) => message.includes(p));\n }\n\n initGlobalCapture(): void {\n const isLocalhost = window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n if (isLocalhost) return;\n\n window.onerror = (message, source, lineno, colno) => {\n const msg = typeof message === \"string\" ? message : \"Unknown error\";\n if (this.shouldSkipGlobalError(msg)) return false;\n\n const trimmedSource = source ? this.trimUrl(source) : \"unknown source\";\n const finalMessage = `${msg} at ${trimmedSource}:${lineno ?? 0}`;\n const key = this.buildErrorKey(\"onerror\", finalMessage);\n if (this.loggedErrorKeys.has(key)) return false;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"window.onerror\",\n messageError: new Error(finalMessage),\n payload: { source: trimmedSource, lineno, colno },\n });\n\n return false;\n };\n\n // unhandledrejection\n window.addEventListener(\"unhandledrejection\", (event) => {\n const msg =\n event.reason instanceof Error\n ? event.reason.message\n : String(event.reason ?? \"Unhandled Promise rejection\");\n\n if (this.shouldSkipGlobalError(msg)) return;\n\n const key = this.buildErrorKey(\"unhandledrejection\", msg);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"window.unhandledrejection\",\n messageError: new Error(msg),\n });\n });\n\n // console.error override\n const originalConsoleError = console.error.bind(console);\n console.error = (...args: unknown[]) => {\n originalConsoleError(...args);\n\n const msg = args.map((a) => (a instanceof Error ? a.message : String(a))).join(\" \");\n\n if (this.shouldSkipGlobalError(msg)) return;\n\n const trimmedMsg = msg.length > 150 ? msg.slice(0, 150) + \"...\" : msg;\n const key = this.buildErrorKey(\"console.error\", trimmedMsg);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n const originalError = args.find((a): a is Error => a instanceof Error);\n\n const errorToSend = originalError ?? new Error(trimmedMsg);\n\n void this.error({\n fnName: \"console.error\",\n messageError: errorToSend,\n });\n };\n\n // resource load error (CSS / JS / font)\n window.addEventListener(\n \"error\",\n (event) => {\n const target = event.target;\n if (!(target instanceof HTMLElement)) return;\n if (target === (window as unknown)) return;\n\n const tagName = target.tagName.toUpperCase();\n\n const src =\n tagName === \"LINK\"\n ? (target as HTMLLinkElement).href\n : tagName === \"SCRIPT\"\n ? (target as HTMLScriptElement).src\n : \"\";\n\n if (this.shouldSkipResourceError(src, tagName)) return;\n\n // Deteksi dari ekstensi file, bukan tagName\n const ext = src.split(\"?\")[0].split(\".\").pop()?.toLowerCase();\n const resourceType =\n ext === \"css\"\n ? \"CSS\"\n : ext === \"js\"\n ? \"JS\"\n : ext === \"woff\" || ext === \"woff2\" || ext === \"ttf\"\n ? \"FONT\"\n : tagName;\n\n const trimmedSrc = this.trimUrl(src);\n const finalMessage = `Failed to load ${resourceType}: ${trimmedSrc}`;\n const key = this.buildErrorKey(\"resource\", finalMessage);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"resource.onerror\",\n messageError: new Error(finalMessage),\n payload: { tagName, src: trimmedSrc },\n });\n },\n true,\n );\n }\n\n private sanitizePayload(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => {\n if (value === undefined) return [key, null];\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return [key, this.sanitizePayload(value as Record<string, unknown>)];\n }\n return [key, value];\n }),\n );\n }\n\n private sanitizeForFirestore(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => {\n if (value === undefined) return [key, null];\n if (typeof value === \"function\") return [key, \"[function]\"];\n if (value instanceof Date) return [key, value.toISOString()];\n if (Array.isArray(value)) {\n return [\n key,\n value.map((item) => {\n if (item instanceof Date) return item.toISOString();\n if (typeof item === \"function\") return \"[function]\"; // ← tambah\n if (item !== null && typeof item === \"object\") {\n return this.sanitizeForFirestore(item as Record<string, unknown>);\n }\n return item ?? null;\n }),\n ];\n }\n if (value !== null && typeof value === \"object\") {\n return [key, this.sanitizeForFirestore(value as Record<string, unknown>)];\n }\n return [key, value];\n }),\n );\n }\n\n // interceptFetch — auto breadcrumb, ke Firestore\n interceptFetch() {\n if (typeof window === \"undefined\") return;\n\n const originalFetch = window.fetch;\n\n const skipPatterns = [\n \"google.com\",\n \"googletagmanager.com\",\n \"googleapis.com\",\n \"facebook.com\",\n \"hotjar.com\",\n \"analytics\",\n \"gtm\",\n \"ccm/collect\",\n \"on.aws\",\n \"/locales/\",\n \"/sw.js\",\n \"/manifest.json\",\n \"/sourcemaps/\",\n \"magnolia\",\n ];\n\n const shouldSkipUrl = (url: string): boolean => {\n return skipPatterns.some((pattern) => url.includes(pattern));\n };\n\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n\n // Skip third-party domains\n if (shouldSkipUrl(url)) {\n return originalFetch(input, init);\n }\n\n const method = init?.method ?? \"GET\";\n const startTime = Date.now();\n\n try {\n const response = await originalFetch(input, init);\n const duration = Date.now() - startTime;\n\n this.addBreadcrumb(\"fetch\", `${method} ${url}`, {\n status: response.status,\n duration: `${duration}ms`,\n });\n\n if (response.status >= 400) {\n const dedupKey = this.buildErrorKey(\"interceptFetch\", `${method} ${url} ${response.status}`);\n\n if (!this.loggedErrorKeys.has(dedupKey)) {\n this.loggedErrorKeys.add(dedupKey);\n\n let responseBody: unknown = null;\n try {\n const cloned = response.clone();\n const contentType = cloned.headers.get(\"content-type\") ?? \"\";\n responseBody = contentType.includes(\"application/json\")\n ? await cloned.json()\n : await cloned.text();\n } catch {\n responseBody = \"[unable to read response body]\";\n }\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n this.error({\n fnName: \"interceptFetch\",\n messageError: new Error(`HTTP ${response.status} ${response.statusText} — ${url}`),\n endpointName: url,\n payload: {\n method,\n status: response.status,\n statusText: response.statusText,\n duration: `${duration}ms`,\n responseBody,\n },\n });\n }\n }\n }\n\n return response;\n } catch (networkError) {\n const duration = Date.now() - startTime;\n const error = networkError instanceof Error ? networkError : new Error(String(networkError));\n\n this.addBreadcrumb(\"fetch\", `${method} ${url} — NETWORK ERROR`, {\n duration: `${duration}ms`,\n error: error.message,\n });\n\n const dedupKey = this.buildErrorKey(\"interceptFetch\", `${method} ${url} NETWORK_ERROR`);\n\n if (!this.loggedErrorKeys.has(dedupKey)) {\n this.loggedErrorKeys.add(dedupKey);\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n if (!isLocalhost) {\n this.error({\n fnName: \"interceptFetch\",\n messageError: error,\n endpointName: url,\n payload: { method, duration: `${duration}ms` },\n });\n }\n }\n\n throw networkError;\n }\n };\n\n console.info(\"[ga-logger] fetch intercepted\");\n }\n\n // interceptXHR — auto breadcrumb + error capture untuk axios/XHR-based request\n interceptXHR(): void {\n if (typeof window === \"undefined\") return;\n\n const skipPatterns = [\n \"google.com\",\n \"googletagmanager.com\",\n \"googleapis.com\",\n \"facebook.com\",\n \"hotjar.com\",\n \"analytics\",\n \"ccm/collect\",\n \"on.aws\",\n \"/locales/\",\n \"/sw.js\",\n \"/manifest.json\",\n \"/sourcemaps/\",\n \"magnolia\",\n ];\n\n const shouldSkipUrl = (url: string): boolean => skipPatterns.some((p) => url.includes(p));\n\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n const self = this;\n\n type GaXHR = XMLHttpRequest & {\n _gaMethod?: string;\n _gaUrl?: string;\n _gaStartTime?: number;\n };\n\n XMLHttpRequest.prototype.open = function (this: GaXHR, method: string, url: string | URL, ...rest: unknown[]) {\n this._gaMethod = method;\n this._gaUrl = typeof url === \"string\" ? url : url.href;\n // @ts-expect-error - spreading native arguments\n return originalOpen.call(this, method, url, ...rest);\n };\n\n XMLHttpRequest.prototype.send = function (this: GaXHR, ...args: unknown[]) {\n const url = this._gaUrl ?? \"\";\n const method = this._gaMethod ?? \"GET\";\n\n if (shouldSkipUrl(url)) {\n // @ts-expect-error - spreading native arguments\n return originalSend.call(this, ...args);\n }\n\n this._gaStartTime = Date.now();\n\n this.addEventListener(\"loadend\", () => {\n const duration = Date.now() - (this._gaStartTime ?? Date.now());\n const status = this.status;\n\n self.addBreadcrumb(\"fetch\", `${method} ${url}`, {\n status,\n duration: `${duration}ms`,\n });\n\n if (status >= 400) {\n const dedupKey = self.buildErrorKey(\"interceptXHR\", `${method} ${url} ${status}`);\n if (self.loggedErrorKeys.has(dedupKey)) return;\n self.loggedErrorKeys.add(dedupKey);\n\n let responseBody: unknown = this.responseText;\n try {\n responseBody = JSON.parse(this.responseText);\n } catch {\n // keep as raw text\n }\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n void self.error({\n fnName: \"interceptXHR\",\n messageError: new Error(`HTTP ${status} ${this.statusText} — ${url}`),\n endpointName: url,\n payload: {\n method,\n status,\n statusText: this.statusText,\n duration: `${duration}ms`,\n responseBody,\n },\n });\n }\n }\n });\n\n this.addEventListener(\"error\", () => {\n // network-level failure (status selalu 0)\n const duration = Date.now() - (this._gaStartTime ?? Date.now());\n const dedupKey = self.buildErrorKey(\"interceptXHR\", `${method} ${url} NETWORK_ERROR`);\n if (self.loggedErrorKeys.has(dedupKey)) return;\n self.loggedErrorKeys.add(dedupKey);\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n void self.error({\n fnName: \"interceptXHR\",\n messageError: new Error(`Network error — ${method} ${url}`),\n endpointName: url,\n payload: { method, duration: `${duration}ms` },\n });\n }\n });\n\n // @ts-expect-error - spreading native arguments\n return originalSend.call(this, ...args);\n };\n\n console.info(\"[ga-logger] XHR intercepted\");\n }\n\n interceptClick(): void {\n if (typeof window === \"undefined\") return;\n\n if ((window as any).__ga_click_intercepted) return;\n (window as any).__ga_click_intercepted = true;\n this.initDomActivityObserver();\n\n document.addEventListener(\n \"click\",\n (event: MouseEvent) => {\n const raw = event.target as HTMLElement;\n if (!raw) return;\n\n const target = (raw.closest('button, a, [role=\"button\"], [data-log], input') as HTMLElement) ?? raw;\n\n const innerText = sanitizeClickText(target.innerText?.trim().slice(0, 50) ?? \"\");\n const id = target.id ?? \"\";\n const tagName = target.tagName?.toLowerCase() ?? \"\";\n\n const isInteractive =\n [\"button\", \"a\", \"input\"].includes(tagName) ||\n target.hasAttribute(\"data-log\") ||\n target.getAttribute(\"role\") === \"button\";\n\n if (!innerText && !id && !isInteractive) return;\n\n const message = innerText || id || `(no label: ${tagName || \"unknown\"})`;\n\n // Skip internal React/Router identifiers\n if (CLICK_SKIP_PATTERNS.some((p) => p.test(message))) return;\n\n this.addBreadcrumb(\"click\", message, {\n tagName,\n ...(id ? { id } : {}),\n ...(innerText ? { text: innerText } : {}),\n });\n\n // ── Dead click detection ──\n const clickTime = Date.now();\n const domActivityAtClick = this.lastDomActivity;\n\n if ([\"button\", \"a\", \"input\"].includes(tagName)) {\n setTimeout(() => {\n if (this.lastDomActivity <= domActivityAtClick) {\n this.addBreadcrumb(\"click\", `Dead click: ${message}`, {\n tagName,\n ...(id ? { id } : {}),\n reason: \"no DOM/scroll activity within 7s\",\n });\n }\n }, 7000);\n }\n\n // ── Rage click detection ──\n const historyKey = `${tagName}::${message}`;\n const timestamps = (this.clickHistory.get(historyKey) ?? []).filter((t) => clickTime - t < 7000);\n timestamps.push(clickTime);\n this.clickHistory.set(historyKey, timestamps);\n\n const lastFired = this.rageClickFired.get(historyKey) ?? 0;\n if (timestamps.length >= 3 && clickTime - lastFired > 7000) {\n this.rageClickFired.set(historyKey, clickTime);\n this.addBreadcrumb(\"click\", `Rage click: ${message}`, {\n tagName,\n ...(id ? { id } : {}),\n clickCount: timestamps.length,\n windowMs: 7000,\n });\n }\n },\n true,\n );\n }\n\n captureAction<T>(params: LogParams, fn: () => T | Promise<T>): Promise<T | undefined> {\n return Promise.resolve()\n .then(() => fn())\n .catch((error: unknown) => {\n const err = error instanceof Error ? error : new Error(String(error));\n this.send(\"error\", params.fnName, params.payload, err, params.endpointName);\n return undefined;\n });\n }\n\n withLogger<T extends (...args: any[]) => any>(\n fnName: string,\n fn: T,\n options?: {\n endpointName?: string;\n payload?: Record<string, unknown>;\n },\n ): T {\n return ((...args: Parameters<T>): ReturnType<T> | undefined => {\n try {\n const result = fn(...args);\n\n // Handle async function\n if (result instanceof Promise) {\n return result.catch((error: unknown) => {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error({\n fnName,\n messageError: err,\n endpointName: options?.endpointName,\n payload: options?.payload,\n });\n return undefined;\n }) as ReturnType<T>;\n }\n\n return result;\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error({\n fnName,\n messageError: err,\n endpointName: options?.endpointName,\n payload: options?.payload,\n });\n return undefined;\n }\n }) as T;\n }\n\n private async send(\n level: LogLevel,\n message: string,\n payload: Record<string, unknown> = {},\n error?: Error,\n endpoint?: string,\n ) {\n if (!this.initialized || !this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n // console only, skip Firestore\n if (this.config.env === \"localhost\") {\n console.error(`[ga-localhost][DEV] ${message}`, { payload, error });\n return;\n }\n\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n message,\n env: this.config.env,\n userId: this.config.userId ?? null,\n sessionId,\n page: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n stackTrace: error?.stack ?? null,\n payload: this.sanitizePayload(payload),\n repo: this.config.repo,\n endpoint: endpoint ?? null,\n breadcrumbs: [...this.breadcrumbs],\n ...getEnvironmentPayload(),\n };\n\n try {\n const db = getDb();\n const safeEntry = this.sanitizeForFirestore(entry as unknown as Record<string, unknown>);\n await addDoc(collection(db, \"logs\"), {\n ...safeEntry,\n timestamp: Timestamp.fromDate(entry.timestamp),\n });\n } catch (e) {\n console.error(\"[ga-logger] failed to send log:\", e);\n }\n }\n\n info(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"info\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n\n warn(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"warn\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n\n error(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"error\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n}\n\nexport const logger = new Logger();\n\n","import { initializeApp, getApps, getApp } from \"firebase/app\";\nimport { getFirestore } from \"firebase/firestore\";\nimport type { Firestore } from \"firebase/firestore\";\nimport type { LoggerConfig } from \"../types\";\n\nconst APP_NAME = \"ga-logger\";\nlet db: Firestore | null = null;\n\nexport const initFirebase = (config: LoggerConfig) => {\n // Cek apakah named instance \"ga-logger\" sudah ada\n const existingApp = getApps().find((app) => app.name === APP_NAME);\n\n const app =\n existingApp ??\n initializeApp(\n {\n apiKey: config.apiKey,\n authDomain: config.authDomain,\n projectId: config.projectId,\n storageBucket: config.storageBucket,\n messagingSenderId: config.messagingSenderId,\n appId: config.appId,\n },\n APP_NAME,\n );\n\n db = getFirestore(app);\n return db;\n};\n\nexport const getDb = (): Firestore => {\n if (!db) throw new Error(\"[ga-logger] Firebase not initialized. Call logger.init() first.\");\n return db;\n};\n","interface EnvironmentPayload {\n userAgent: string;\n deviceType: \"Mobile\" | \"Tablet\" | \"Desktop\";\n screenWidth: number;\n screenHeight: number;\n}\n\nlet cachedEnvironment: EnvironmentPayload | null = null;\n\nfunction getDeviceType(width: number): \"Mobile\" | \"Tablet\" | \"Desktop\" {\n if (width < 768) return \"Mobile\";\n if (width <= 1024) return \"Tablet\";\n return \"Desktop\";\n}\n\nexport function initEnvironment(): void {\n if (cachedEnvironment) return;\n\n const width = window.innerWidth;\n const height = window.innerHeight;\n\n cachedEnvironment = {\n userAgent: navigator.userAgent,\n deviceType: getDeviceType(width),\n screenWidth: width,\n screenHeight: height,\n };\n}\n\nexport function getEnvironmentPayload(): EnvironmentPayload {\n if (!cachedEnvironment) initEnvironment();\n return cachedEnvironment!;\n}","import { Component, type ErrorInfo, type ReactNode } from \"react\";\nimport { logger } from \"../core/logger\";\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n}\n\nexport class LoggerErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): State {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n logger.addBreadcrumb(\"error\", `React crash: ${error.message}`, {\n componentStack: info.componentStack ?? undefined,\n });\n\n logger.error({\n fnName: \"LoggerErrorBoundary\",\n messageError: error,\n payload: {\n componentStack: info.componentStack ?? undefined,\n },\n });\n }\n\n render() {\n if (this.state.hasError) {\n return this.props.fallback ?? (\n <div style={{ padding: \"1rem\", color: \"red\" }}>\n Something went wrong.\n </div>\n );\n }\n\n return this.props.children;\n }\n}"],"mappings":";AAAA,SAAS,YAAY,QAAQ,iBAAiB;;;ACA9C,SAAS,eAAe,eAAuB;AAC/C,SAAS,oBAAoB;AAI7B,IAAM,WAAW;AACjB,IAAI,KAAuB;AAEpB,IAAM,eAAe,CAAC,WAAyB;AAElD,QAAM,cAAc,QAAQ,EAAE,KAAK,CAACA,SAAQA,KAAI,SAAS,QAAQ;AAEjE,QAAM,MACF,eACA;AAAA,IACI;AAAA,MACI,QAAQ,OAAO;AAAA,MACf,YAAY,OAAO;AAAA,MACnB,WAAW,OAAO;AAAA,MAClB,eAAe,OAAO;AAAA,MACtB,mBAAmB,OAAO;AAAA,MAC1B,OAAO,OAAO;AAAA,IAClB;AAAA,IACA;AAAA,EACJ;AAEJ,OAAK,aAAa,GAAG;AACrB,SAAO;AACX;AAEO,IAAM,QAAQ,MAAiB;AAClC,MAAI,CAAC,GAAI,OAAM,IAAI,MAAM,iEAAiE;AAC1F,SAAO;AACX;;;AC1BA,IAAI,oBAA+C;AAEnD,SAAS,cAAc,OAAgD;AACnE,MAAI,QAAQ,IAAK,QAAO;AACxB,MAAI,SAAS,KAAM,QAAO;AAC1B,SAAO;AACX;AAEO,SAAS,kBAAwB;AACpC,MAAI,kBAAmB;AAEvB,QAAM,QAAQ,OAAO;AACrB,QAAM,SAAS,OAAO;AAEtB,sBAAoB;AAAA,IAChB,WAAW,UAAU;AAAA,IACrB,YAAY,cAAc,KAAK;AAAA,IAC/B,aAAa;AAAA,IACb,cAAc;AAAA,EAClB;AACJ;AAEO,SAAS,wBAA4C;AACxD,MAAI,CAAC,kBAAmB,iBAAgB;AACxC,SAAO;AACX;;;AF1BA,IAAM,YAAY,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC9E,IAAM,kBAAkB;AAExB,IAAM,sBAAsB,CAAC,kBAAkB,aAAa,IAAI;AAGhE,IAAM,oBAAoB,CAAC,SAAyB;AAChD,SAAO,KACF,QAAQ,6BAA6B,SAAS,EAC9C,QAAQ,gBAAgB,UAAU,EAClC,QAAQ,sBAAsB,UAAU,EACxC,KAAK;AACd;AAEA,IAAM,SAAN,MAAa;AAAA,EAUT,cAAc;AATd,SAAQ,SAA8B;AACtC,SAAQ,cAAc;AACtB,SAAQ,cAA4B,CAAC;AAErC,SAAQ,kBAAkB,KAAK,IAAI;AACnC,SAAQ,eAAe,oBAAI,IAAsB;AACjD,SAAQ,iBAAiB,oBAAI,IAAoB;AACjD,SAAQ,yBAAyB;AA4FjC;AAAA,SAAQ,kBAAkB,oBAAI,IAAY;AAzFtC,QAAI,OAAO,WAAW,aAAa;AAC/B,MAAC,OAAe,yBAAyB,MAAM,KAAK;AAAA,IACxD;AAAA,EACJ;AAAA,EAEQ,0BAAgC;AACpC,QAAI,KAAK,uBAAwB;AACjC,SAAK,yBAAyB;AAE9B,UAAM,eAAe,MAAM;AACvB,WAAK,kBAAkB,KAAK,IAAI;AAAA,IACpC;AAEA,UAAM,WAAW,IAAI,iBAAiB,YAAY;AAClD,aAAS,QAAQ,SAAS,MAAM;AAAA,MAC5B,WAAW;AAAA,MACX,SAAS;AAAA,MACT,YAAY;AAAA,IAChB,CAAC;AAED,WAAO,iBAAiB,UAAU,cAAc,EAAE,SAAS,MAAM,SAAS,KAAK,CAAC;AAAA,EACpF;AAAA,EAEA,KAAK,QAAsB;AACvB,SAAK,SAAS;AACd,iBAAa,MAAM;AACnB,oBAAgB;AAChB,SAAK,cAAc;AACnB,YAAQ,KAAK,kCAA6B,OAAO,GAAG;AAAA,EACxD;AAAA,EACA,UAAU,QAAuB;AAC7B,QAAI,CAAC,KAAK,QAAQ;AACd,cAAQ,KAAK,wDAAwD;AACrE;AAAA,IACJ;AACA,SAAK,OAAO,SAAS;AAAA,EACzB;AAAA,EAEA,oBAA0B;AACtB,QAAI,CAAC,KAAK,QAAQ;AACd,cAAQ,KAAK,wDAAwD;AACrE;AAAA,IACJ;AAEA,UAAM,cAAc;AAEpB,QAAI;AACA,UAAI,SAAS,aAAa,QAAQ,WAAW;AAE7C,UAAI,CAAC,QAAQ;AACT,iBACI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,aACxD,OAAO,WAAW,IAClB,uCAAuC,QAAQ,SAAS,CAAC,MAAM;AAC3D,gBAAM,IAAK,KAAK,OAAO,IAAI,KAAM;AACjC,gBAAM,IAAI,MAAM,MAAM,IAAK,IAAI,IAAO;AACtC,iBAAO,EAAE,SAAS,EAAE;AAAA,QACxB,CAAC;AAEX,qBAAa,QAAQ,aAAa,MAAM;AAAA,MAC5C;AAEA,YAAM,UAAU,OAAO,MAAM,EAAE;AAC/B,WAAK,UAAU,cAAc,OAAO,EAAE;AAAA,IAC1C,SAAS,GAAG;AAER,cAAQ,KAAK,yCAAyC,CAAC;AACvD,WAAK,UAAU,WAAW;AAAA,IAC9B;AAAA,EACJ;AAAA;AAAA,EAGA,cAAc,MAAsB,SAAiB,MAAgC;AACjF,UAAM,aAAyB;AAAA,MAC3B,WAAW,oBAAI,KAAK;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAEA,SAAK,YAAY,KAAK,UAAU;AAGhC,QAAI,KAAK,YAAY,SAAS,iBAAiB;AAC3C,WAAK,YAAY,MAAM;AAAA,IAC3B;AAAA,EACJ;AAAA;AAAA,EAMQ,QAAQ,KAAqB;AACjC,QAAI;AACA,YAAM,IAAI,IAAI,IAAI,GAAG;AACrB,YAAM,WAAW,EAAE,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK,EAAE;AAClE,aAAO,GAAG,EAAE,QAAQ,IAAI,QAAQ;AAAA,IACpC,QAAQ;AAEJ,aAAO,IAAI,SAAS,KAAK,IAAI,MAAM,GAAG,EAAE,IAAI,QAAQ;AAAA,IACxD;AAAA,EACJ;AAAA;AAAA,EAGQ,cAAc,MAAc,SAAyB;AACzD,WAAO,GAAG,IAAI,KAAK,OAAO;AAAA,EAC9B;AAAA;AAAA,EAGQ,wBAAwB,KAAa,SAA0B;AAEnE,QAAI,YAAY,MAAO,QAAO;AAG9B,QAAI,IAAI,WAAW,OAAO,EAAG,QAAO;AAGpC,UAAM,cAAc;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,QAAI,YAAY,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC,CAAC,EAAG,QAAO;AAErD,WAAO;AAAA,EACX;AAAA,EAEQ,sBAAsB,SAA0B;AACpD,UAAM,QAAQ;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,cAAc;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,WAAO,MAAM,KAAK,CAAC,MAAM,QAAQ,SAAS,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,MAAM,QAAQ,SAAS,CAAC,CAAC;AAAA,EAChG;AAAA,EAEA,oBAA0B;AACtB,UAAM,cAAc,OAAO,SAAS,aAAa,eAAe,OAAO,SAAS,aAAa;AAC7F,QAAI,YAAa;AAEjB,WAAO,UAAU,CAAC,SAAS,QAAQ,QAAQ,UAAU;AACjD,YAAM,MAAM,OAAO,YAAY,WAAW,UAAU;AACpD,UAAI,KAAK,sBAAsB,GAAG,EAAG,QAAO;AAE5C,YAAM,gBAAgB,SAAS,KAAK,QAAQ,MAAM,IAAI;AACtD,YAAM,eAAe,GAAG,GAAG,OAAO,aAAa,IAAI,UAAU,CAAC;AAC9D,YAAM,MAAM,KAAK,cAAc,WAAW,YAAY;AACtD,UAAI,KAAK,gBAAgB,IAAI,GAAG,EAAG,QAAO;AAC1C,WAAK,gBAAgB,IAAI,GAAG;AAE5B,WAAK,KAAK,MAAM;AAAA,QACZ,QAAQ;AAAA,QACR,cAAc,IAAI,MAAM,YAAY;AAAA,QACpC,SAAS,EAAE,QAAQ,eAAe,QAAQ,MAAM;AAAA,MACpD,CAAC;AAED,aAAO;AAAA,IACX;AAGA,WAAO,iBAAiB,sBAAsB,CAAC,UAAU;AACrD,YAAM,MACF,MAAM,kBAAkB,QAClB,MAAM,OAAO,UACb,OAAO,MAAM,UAAU,6BAA6B;AAE9D,UAAI,KAAK,sBAAsB,GAAG,EAAG;AAErC,YAAM,MAAM,KAAK,cAAc,sBAAsB,GAAG;AACxD,UAAI,KAAK,gBAAgB,IAAI,GAAG,EAAG;AACnC,WAAK,gBAAgB,IAAI,GAAG;AAE5B,WAAK,KAAK,MAAM;AAAA,QACZ,QAAQ;AAAA,QACR,cAAc,IAAI,MAAM,GAAG;AAAA,MAC/B,CAAC;AAAA,IACL,CAAC;AAGD,UAAM,uBAAuB,QAAQ,MAAM,KAAK,OAAO;AACvD,YAAQ,QAAQ,IAAI,SAAoB;AACpC,2BAAqB,GAAG,IAAI;AAE5B,YAAM,MAAM,KAAK,IAAI,CAAC,MAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAE,EAAE,KAAK,GAAG;AAElF,UAAI,KAAK,sBAAsB,GAAG,EAAG;AAErC,YAAM,aAAa,IAAI,SAAS,MAAM,IAAI,MAAM,GAAG,GAAG,IAAI,QAAQ;AAClE,YAAM,MAAM,KAAK,cAAc,iBAAiB,UAAU;AAC1D,UAAI,KAAK,gBAAgB,IAAI,GAAG,EAAG;AACnC,WAAK,gBAAgB,IAAI,GAAG;AAE5B,YAAM,gBAAgB,KAAK,KAAK,CAAC,MAAkB,aAAa,KAAK;AAErE,YAAM,cAAc,iBAAiB,IAAI,MAAM,UAAU;AAEzD,WAAK,KAAK,MAAM;AAAA,QACZ,QAAQ;AAAA,QACR,cAAc;AAAA,MAClB,CAAC;AAAA,IACL;AAGA,WAAO;AAAA,MACH;AAAA,MACA,CAAC,UAAU;AACP,cAAM,SAAS,MAAM;AACrB,YAAI,EAAE,kBAAkB,aAAc;AACtC,YAAI,WAAY,OAAoB;AAEpC,cAAM,UAAU,OAAO,QAAQ,YAAY;AAE3C,cAAM,MACF,YAAY,SACL,OAA2B,OAC5B,YAAY,WACT,OAA6B,MAC9B;AAEZ,YAAI,KAAK,wBAAwB,KAAK,OAAO,EAAG;AAGhD,cAAM,MAAM,IAAI,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY;AAC5D,cAAM,eACF,QAAQ,QACF,QACA,QAAQ,OACN,OACA,QAAQ,UAAU,QAAQ,WAAW,QAAQ,QAC3C,SACA;AAEd,cAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,cAAM,eAAe,kBAAkB,YAAY,KAAK,UAAU;AAClE,cAAM,MAAM,KAAK,cAAc,YAAY,YAAY;AACvD,YAAI,KAAK,gBAAgB,IAAI,GAAG,EAAG;AACnC,aAAK,gBAAgB,IAAI,GAAG;AAE5B,aAAK,KAAK,MAAM;AAAA,UACZ,QAAQ;AAAA,UACR,cAAc,IAAI,MAAM,YAAY;AAAA,UACpC,SAAS,EAAE,SAAS,KAAK,WAAW;AAAA,QACxC,CAAC;AAAA,MACL;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AAAA,EAEQ,gBAAgB,KAAuD;AAC3E,WAAO,OAAO;AAAA,MACV,OAAO,QAAQ,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AACtC,YAAI,UAAU,OAAW,QAAO,CAAC,KAAK,IAAI;AAC1C,YAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AACtE,iBAAO,CAAC,KAAK,KAAK,gBAAgB,KAAgC,CAAC;AAAA,QACvE;AACA,eAAO,CAAC,KAAK,KAAK;AAAA,MACtB,CAAC;AAAA,IACL;AAAA,EACJ;AAAA,EAEQ,qBAAqB,KAAuD;AAChF,WAAO,OAAO;AAAA,MACV,OAAO,QAAQ,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AACtC,YAAI,UAAU,OAAW,QAAO,CAAC,KAAK,IAAI;AAC1C,YAAI,OAAO,UAAU,WAAY,QAAO,CAAC,KAAK,YAAY;AAC1D,YAAI,iBAAiB,KAAM,QAAO,CAAC,KAAK,MAAM,YAAY,CAAC;AAC3D,YAAI,MAAM,QAAQ,KAAK,GAAG;AACtB,iBAAO;AAAA,YACH;AAAA,YACA,MAAM,IAAI,CAAC,SAAS;AAChB,kBAAI,gBAAgB,KAAM,QAAO,KAAK,YAAY;AAClD,kBAAI,OAAO,SAAS,WAAY,QAAO;AACvC,kBAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;AAC3C,uBAAO,KAAK,qBAAqB,IAA+B;AAAA,cACpE;AACA,qBAAO,QAAQ;AAAA,YACnB,CAAC;AAAA,UACL;AAAA,QACJ;AACA,YAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC7C,iBAAO,CAAC,KAAK,KAAK,qBAAqB,KAAgC,CAAC;AAAA,QAC5E;AACA,eAAO,CAAC,KAAK,KAAK;AAAA,MACtB,CAAC;AAAA,IACL;AAAA,EACJ;AAAA;AAAA,EAGA,iBAAiB;AACb,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,gBAAgB,OAAO;AAE7B,UAAM,eAAe;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAEA,UAAM,gBAAgB,CAAC,QAAyB;AAC5C,aAAO,aAAa,KAAK,CAAC,YAAY,IAAI,SAAS,OAAO,CAAC;AAAA,IAC/D;AAEA,WAAO,QAAQ,OAAO,OAA0B,SAA0C;AACtF,YAAM,MAAM,OAAO,UAAU,WAAW,QAAQ,iBAAiB,MAAM,MAAM,OAAO,MAAM;AAG1F,UAAI,cAAc,GAAG,GAAG;AACpB,eAAO,cAAc,OAAO,IAAI;AAAA,MACpC;AAEA,YAAM,SAAS,MAAM,UAAU;AAC/B,YAAM,YAAY,KAAK,IAAI;AAE3B,UAAI;AACA,cAAM,WAAW,MAAM,cAAc,OAAO,IAAI;AAChD,cAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,aAAK,cAAc,SAAS,GAAG,MAAM,IAAI,GAAG,IAAI;AAAA,UAC5C,QAAQ,SAAS;AAAA,UACjB,UAAU,GAAG,QAAQ;AAAA,QACzB,CAAC;AAED,YAAI,SAAS,UAAU,KAAK;AACxB,gBAAM,WAAW,KAAK,cAAc,kBAAkB,GAAG,MAAM,IAAI,GAAG,IAAI,SAAS,MAAM,EAAE;AAE3F,cAAI,CAAC,KAAK,gBAAgB,IAAI,QAAQ,GAAG;AACrC,iBAAK,gBAAgB,IAAI,QAAQ;AAEjC,gBAAI,eAAwB;AAC5B,gBAAI;AACA,oBAAM,SAAS,SAAS,MAAM;AAC9B,oBAAM,cAAc,OAAO,QAAQ,IAAI,cAAc,KAAK;AAC1D,6BAAe,YAAY,SAAS,kBAAkB,IAChD,MAAM,OAAO,KAAK,IAClB,MAAM,OAAO,KAAK;AAAA,YAC5B,QAAQ;AACJ,6BAAe;AAAA,YACnB;AAEA,kBAAM,cACF,OAAO,SAAS,aAAa,eAAe,OAAO,SAAS,aAAa;AAE7E,gBAAI,CAAC,aAAa;AACd,mBAAK,MAAM;AAAA,gBACP,QAAQ;AAAA,gBACR,cAAc,IAAI,MAAM,QAAQ,SAAS,MAAM,IAAI,SAAS,UAAU,WAAM,GAAG,EAAE;AAAA,gBACjF,cAAc;AAAA,gBACd,SAAS;AAAA,kBACL;AAAA,kBACA,QAAQ,SAAS;AAAA,kBACjB,YAAY,SAAS;AAAA,kBACrB,UAAU,GAAG,QAAQ;AAAA,kBACrB;AAAA,gBACJ;AAAA,cACJ,CAAC;AAAA,YACL;AAAA,UACJ;AAAA,QACJ;AAEA,eAAO;AAAA,MACX,SAAS,cAAc;AACnB,cAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,cAAM,QAAQ,wBAAwB,QAAQ,eAAe,IAAI,MAAM,OAAO,YAAY,CAAC;AAE3F,aAAK,cAAc,SAAS,GAAG,MAAM,IAAI,GAAG,yBAAoB;AAAA,UAC5D,UAAU,GAAG,QAAQ;AAAA,UACrB,OAAO,MAAM;AAAA,QACjB,CAAC;AAED,cAAM,WAAW,KAAK,cAAc,kBAAkB,GAAG,MAAM,IAAI,GAAG,gBAAgB;AAEtF,YAAI,CAAC,KAAK,gBAAgB,IAAI,QAAQ,GAAG;AACrC,eAAK,gBAAgB,IAAI,QAAQ;AAEjC,gBAAM,cACF,OAAO,SAAS,aAAa,eAAe,OAAO,SAAS,aAAa;AAC7E,cAAI,CAAC,aAAa;AACd,iBAAK,MAAM;AAAA,cACP,QAAQ;AAAA,cACR,cAAc;AAAA,cACd,cAAc;AAAA,cACd,SAAS,EAAE,QAAQ,UAAU,GAAG,QAAQ,KAAK;AAAA,YACjD,CAAC;AAAA,UACL;AAAA,QACJ;AAEA,cAAM;AAAA,MACV;AAAA,IACJ;AAEA,YAAQ,KAAK,+BAA+B;AAAA,EAChD;AAAA;AAAA,EAGA,eAAqB;AACjB,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,eAAe;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAEA,UAAM,gBAAgB,CAAC,QAAyB,aAAa,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC,CAAC;AAExF,UAAM,eAAe,eAAe,UAAU;AAC9C,UAAM,eAAe,eAAe,UAAU;AAC9C,UAAM,OAAO;AAQb,mBAAe,UAAU,OAAO,SAAuB,QAAgB,QAAsB,MAAiB;AAC1G,WAAK,YAAY;AACjB,WAAK,SAAS,OAAO,QAAQ,WAAW,MAAM,IAAI;AAElD,aAAO,aAAa,KAAK,MAAM,QAAQ,KAAK,GAAG,IAAI;AAAA,IACvD;AAEA,mBAAe,UAAU,OAAO,YAA0B,MAAiB;AACvE,YAAM,MAAM,KAAK,UAAU;AAC3B,YAAM,SAAS,KAAK,aAAa;AAEjC,UAAI,cAAc,GAAG,GAAG;AAEpB,eAAO,aAAa,KAAK,MAAM,GAAG,IAAI;AAAA,MAC1C;AAEA,WAAK,eAAe,KAAK,IAAI;AAE7B,WAAK,iBAAiB,WAAW,MAAM;AACnC,cAAM,WAAW,KAAK,IAAI,KAAK,KAAK,gBAAgB,KAAK,IAAI;AAC7D,cAAM,SAAS,KAAK;AAEpB,aAAK,cAAc,SAAS,GAAG,MAAM,IAAI,GAAG,IAAI;AAAA,UAC5C;AAAA,UACA,UAAU,GAAG,QAAQ;AAAA,QACzB,CAAC;AAED,YAAI,UAAU,KAAK;AACf,gBAAM,WAAW,KAAK,cAAc,gBAAgB,GAAG,MAAM,IAAI,GAAG,IAAI,MAAM,EAAE;AAChF,cAAI,KAAK,gBAAgB,IAAI,QAAQ,EAAG;AACxC,eAAK,gBAAgB,IAAI,QAAQ;AAEjC,cAAI,eAAwB,KAAK;AACjC,cAAI;AACA,2BAAe,KAAK,MAAM,KAAK,YAAY;AAAA,UAC/C,QAAQ;AAAA,UAER;AAEA,gBAAM,cACF,OAAO,SAAS,aAAa,eAAe,OAAO,SAAS,aAAa;AAE7E,cAAI,CAAC,aAAa;AACd,iBAAK,KAAK,MAAM;AAAA,cACZ,QAAQ;AAAA,cACR,cAAc,IAAI,MAAM,QAAQ,MAAM,IAAI,KAAK,UAAU,WAAM,GAAG,EAAE;AAAA,cACpE,cAAc;AAAA,cACd,SAAS;AAAA,gBACL;AAAA,gBACA;AAAA,gBACA,YAAY,KAAK;AAAA,gBACjB,UAAU,GAAG,QAAQ;AAAA,gBACrB;AAAA,cACJ;AAAA,YACJ,CAAC;AAAA,UACL;AAAA,QACJ;AAAA,MACJ,CAAC;AAED,WAAK,iBAAiB,SAAS,MAAM;AAEjC,cAAM,WAAW,KAAK,IAAI,KAAK,KAAK,gBAAgB,KAAK,IAAI;AAC7D,cAAM,WAAW,KAAK,cAAc,gBAAgB,GAAG,MAAM,IAAI,GAAG,gBAAgB;AACpF,YAAI,KAAK,gBAAgB,IAAI,QAAQ,EAAG;AACxC,aAAK,gBAAgB,IAAI,QAAQ;AAEjC,cAAM,cACF,OAAO,SAAS,aAAa,eAAe,OAAO,SAAS,aAAa;AAE7E,YAAI,CAAC,aAAa;AACd,eAAK,KAAK,MAAM;AAAA,YACZ,QAAQ;AAAA,YACR,cAAc,IAAI,MAAM,wBAAmB,MAAM,IAAI,GAAG,EAAE;AAAA,YAC1D,cAAc;AAAA,YACd,SAAS,EAAE,QAAQ,UAAU,GAAG,QAAQ,KAAK;AAAA,UACjD,CAAC;AAAA,QACL;AAAA,MACJ,CAAC;AAGD,aAAO,aAAa,KAAK,MAAM,GAAG,IAAI;AAAA,IAC1C;AAEA,YAAQ,KAAK,6BAA6B;AAAA,EAC9C;AAAA,EAEA,iBAAuB;AACnB,QAAI,OAAO,WAAW,YAAa;AAEnC,QAAK,OAAe,uBAAwB;AAC5C,IAAC,OAAe,yBAAyB;AACzC,SAAK,wBAAwB;AAE7B,aAAS;AAAA,MACL;AAAA,MACA,CAAC,UAAsB;AACnB,cAAM,MAAM,MAAM;AAClB,YAAI,CAAC,IAAK;AAEV,cAAM,SAAU,IAAI,QAAQ,+CAA+C,KAAqB;AAEhG,cAAM,YAAY,kBAAkB,OAAO,WAAW,KAAK,EAAE,MAAM,GAAG,EAAE,KAAK,EAAE;AAC/E,cAAM,KAAK,OAAO,MAAM;AACxB,cAAM,UAAU,OAAO,SAAS,YAAY,KAAK;AAEjD,cAAM,gBACF,CAAC,UAAU,KAAK,OAAO,EAAE,SAAS,OAAO,KACzC,OAAO,aAAa,UAAU,KAC9B,OAAO,aAAa,MAAM,MAAM;AAEpC,YAAI,CAAC,aAAa,CAAC,MAAM,CAAC,cAAe;AAEzC,cAAM,UAAU,aAAa,MAAM,cAAc,WAAW,SAAS;AAGrE,YAAI,oBAAoB,KAAK,CAAC,MAAM,EAAE,KAAK,OAAO,CAAC,EAAG;AAEtD,aAAK,cAAc,SAAS,SAAS;AAAA,UACjC;AAAA,UACA,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,UACnB,GAAI,YAAY,EAAE,MAAM,UAAU,IAAI,CAAC;AAAA,QAC3C,CAAC;AAGD,cAAM,YAAY,KAAK,IAAI;AAC3B,cAAM,qBAAqB,KAAK;AAEhC,YAAI,CAAC,UAAU,KAAK,OAAO,EAAE,SAAS,OAAO,GAAG;AAC5C,qBAAW,MAAM;AACb,gBAAI,KAAK,mBAAmB,oBAAoB;AAC5C,mBAAK,cAAc,SAAS,eAAe,OAAO,IAAI;AAAA,gBAClD;AAAA,gBACA,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,gBACnB,QAAQ;AAAA,cACZ,CAAC;AAAA,YACL;AAAA,UACJ,GAAG,GAAI;AAAA,QACX;AAGA,cAAM,aAAa,GAAG,OAAO,KAAK,OAAO;AACzC,cAAM,cAAc,KAAK,aAAa,IAAI,UAAU,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,YAAY,IAAI,GAAI;AAC/F,mBAAW,KAAK,SAAS;AACzB,aAAK,aAAa,IAAI,YAAY,UAAU;AAE5C,cAAM,YAAY,KAAK,eAAe,IAAI,UAAU,KAAK;AACzD,YAAI,WAAW,UAAU,KAAK,YAAY,YAAY,KAAM;AACxD,eAAK,eAAe,IAAI,YAAY,SAAS;AAC7C,eAAK,cAAc,SAAS,eAAe,OAAO,IAAI;AAAA,YAClD;AAAA,YACA,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,YACnB,YAAY,WAAW;AAAA,YACvB,UAAU;AAAA,UACd,CAAC;AAAA,QACL;AAAA,MACJ;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,cAAiB,QAAmB,IAAkD;AAClF,WAAO,QAAQ,QAAQ,EAClB,KAAK,MAAM,GAAG,CAAC,EACf,MAAM,CAAC,UAAmB;AACvB,YAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,WAAK,KAAK,SAAS,OAAO,QAAQ,OAAO,SAAS,KAAK,OAAO,YAAY;AAC1E,aAAO;AAAA,IACX,CAAC;AAAA,EACT;AAAA,EAEA,WACI,QACA,IACA,SAIC;AACD,YAAQ,IAAI,SAAmD;AAC3D,UAAI;AACA,cAAM,SAAS,GAAG,GAAG,IAAI;AAGzB,YAAI,kBAAkB,SAAS;AAC3B,iBAAO,OAAO,MAAM,CAAC,UAAmB;AACpC,kBAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,iBAAK,MAAM;AAAA,cACP;AAAA,cACA,cAAc;AAAA,cACd,cAAc,SAAS;AAAA,cACvB,SAAS,SAAS;AAAA,YACtB,CAAC;AACD,mBAAO;AAAA,UACX,CAAC;AAAA,QACL;AAEA,eAAO;AAAA,MACX,SAAS,OAAgB;AACrB,cAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,aAAK,MAAM;AAAA,UACP;AAAA,UACA,cAAc;AAAA,UACd,cAAc,SAAS;AAAA,UACvB,SAAS,SAAS;AAAA,QACtB,CAAC;AACD,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,MAAc,KACV,OACA,SACA,UAAmC,CAAC,GACpC,OACA,UACF;AACE,QAAI,CAAC,KAAK,eAAe,CAAC,KAAK,QAAQ;AACnC,cAAQ,KAAK,wDAAwD;AACrE;AAAA,IACJ;AAGA,QAAI,KAAK,OAAO,QAAQ,aAAa;AACjC,cAAQ,MAAM,uBAAuB,OAAO,IAAI,EAAE,SAAS,MAAM,CAAC;AAClE;AAAA,IACJ;AAEA,UAAM,QAAkB;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,MACpB;AAAA,MACA;AAAA,MACA,KAAK,KAAK,OAAO;AAAA,MACjB,QAAQ,KAAK,OAAO,UAAU;AAAA,MAC9B;AAAA,MACA,MAAM,OAAO,WAAW,cAAc,OAAO,SAAS,WAAW;AAAA,MACjE,YAAY,OAAO,SAAS;AAAA,MAC5B,SAAS,KAAK,gBAAgB,OAAO;AAAA,MACrC,MAAM,KAAK,OAAO;AAAA,MAClB,UAAU,YAAY;AAAA,MACtB,aAAa,CAAC,GAAG,KAAK,WAAW;AAAA,MACjC,GAAG,sBAAsB;AAAA,IAC7B;AAEA,QAAI;AACA,YAAMC,MAAK,MAAM;AACjB,YAAM,YAAY,KAAK,qBAAqB,KAA2C;AACvF,YAAM,OAAO,WAAWA,KAAI,MAAM,GAAG;AAAA,QACjC,GAAG;AAAA,QACH,WAAW,UAAU,SAAS,MAAM,SAAS;AAAA,MACjD,CAAC;AAAA,IACL,SAAS,GAAG;AACR,cAAQ,MAAM,mCAAmC,CAAC;AAAA,IACtD;AAAA,EACJ;AAAA,EAEA,KAAK,QAAmB;AACpB,UAAM,EAAE,QAAQ,cAAc,SAAS,aAAa,IAAI;AACxD,WAAO,KAAK,KAAK,QAAQ,cAAc,WAAW,QAAQ,EAAE,GAAG,SAAS,OAAO,GAAG,cAAc,YAAY;AAAA,EAChH;AAAA,EAEA,KAAK,QAAmB;AACpB,UAAM,EAAE,QAAQ,cAAc,SAAS,aAAa,IAAI;AACxD,WAAO,KAAK,KAAK,QAAQ,cAAc,WAAW,QAAQ,EAAE,GAAG,SAAS,OAAO,GAAG,cAAc,YAAY;AAAA,EAChH;AAAA,EAEA,MAAM,QAAmB;AACrB,UAAM,EAAE,QAAQ,cAAc,SAAS,aAAa,IAAI;AACxD,WAAO,KAAK,KAAK,SAAS,cAAc,WAAW,QAAQ,EAAE,GAAG,SAAS,OAAO,GAAG,cAAc,YAAY;AAAA,EACjH;AACJ;AAEO,IAAM,SAAS,IAAI,OAAO;;;AGhwBjC,SAAS,iBAAiD;AAuC1C;AA3BT,IAAM,sBAAN,cAAkC,UAAwB;AAAA,EAC7D,YAAY,OAAc;AACtB,UAAM,KAAK;AACX,SAAK,QAAQ,EAAE,UAAU,MAAM;AAAA,EACnC;AAAA,EAEA,OAAO,2BAAkC;AACrC,WAAO,EAAE,UAAU,KAAK;AAAA,EAC5B;AAAA,EAEA,kBAAkB,OAAc,MAAiB;AAC7C,WAAO,cAAc,SAAS,gBAAgB,MAAM,OAAO,IAAI;AAAA,MAC3D,gBAAgB,KAAK,kBAAkB;AAAA,IAC3C,CAAC;AAED,WAAO,MAAM;AAAA,MACT,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,SAAS;AAAA,QACL,gBAAgB,KAAK,kBAAkB;AAAA,MAC3C;AAAA,IACJ,CAAC;AAAA,EACL;AAAA,EAEA,SAAS;AACL,QAAI,KAAK,MAAM,UAAU;AACrB,aAAO,KAAK,MAAM,YACd,oBAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,OAAO,MAAM,GAAG,mCAE/C;AAAA,IAER;AAEA,WAAO,KAAK,MAAM;AAAA,EACtB;AACJ;","names":["app","db"]}
1
+ {"version":3,"sources":["../src/core/logger.ts","../src/config/firebase.ts","../src/core/environment.ts","../src/components/LoggerErrorBoundary.tsx"],"sourcesContent":["import { collection, addDoc, Timestamp } from \"firebase/firestore\";\nimport { initFirebase, getDb } from \"../config/firebase\";\nimport type { Breadcrumb, BreadcrumbType, LogEntry, LogLevel, LogParams, LoggerConfig } from \"../types\";\nimport { initEnvironment } from \"./environment\";\nimport { getEnvironmentPayload } from \"./environment\";\n\nconst sessionId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\nconst MAX_BREADCRUMBS = 50;\n\nconst CLICK_SKIP_PATTERNS = [/^:r[a-z0-9]+:$/, /^\\[object/, /^#/];\n\n// Sanitize PII sebelum masuk Firestore\nconst sanitizeClickText = (text: string): string => {\n return text\n .replace(/\\b[\\w.-]+@[\\w.-]+\\.\\w+\\b/g, \"[email]\")\n .replace(/\\b\\d{10,}\\b/g, \"[number]\")\n .replace(/Rp[\\s]?\\d[\\d.,]*/gi, \"[amount]\")\n .trim();\n};\n\nclass Logger {\n private config: LoggerConfig | null = null;\n private initialized = false;\n private breadcrumbs: Breadcrumb[] = [];\n\n private lastDomActivity = Date.now();\n private clickHistory = new Map<string, number[]>();\n private rageClickFired = new Map<string, number>();\n private domObserverInitialized = false;\n\n constructor() {\n if (typeof window !== \"undefined\") {\n (window as any).__ga_debug_breadcrumbs = () => this.breadcrumbs;\n }\n }\n\n private recentDomChanges: string[] = [];\n\n private initDomActivityObserver(): void {\n if (this.domObserverInitialized) return;\n this.domObserverInitialized = true;\n\n const markActivity = (addedText?: string) => {\n this.lastDomActivity = Date.now();\n if (addedText) {\n this.recentDomChanges.push(addedText);\n // keep only last few seconds worth\n setTimeout(() => {\n this.recentDomChanges = this.recentDomChanges.filter((t) => t !== addedText);\n }, 1000); // ⚠️ perlu konfirmasi durasi\n }\n };\n\n const observer = new MutationObserver((mutations) => {\n markActivity();\n for (const m of mutations) {\n m.addedNodes.forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const text = (node as HTMLElement).innerText?.trim();\n if (text && text.length < 200) markActivity(text);\n }\n });\n }\n });\n\n observer.observe(document.body, { childList: true, subtree: true, attributes: true });\n window.addEventListener(\"scroll\", () => markActivity(), { passive: true, capture: true });\n }\n\n init(config: LoggerConfig) {\n this.config = config;\n initFirebase(config);\n initEnvironment();\n this.initialized = true;\n console.info(\"[ga-logger] initialized —\", config.env);\n }\n setUserId(userId: string | null) {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n this.config.userId = userId;\n }\n\n initAnonymousUser(): void {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n const STORAGE_KEY = \"ga_anon_id\";\n\n try {\n let anonId = localStorage.getItem(STORAGE_KEY);\n\n if (!anonId) {\n anonId =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? crypto.randomUUID()\n : \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n\n localStorage.setItem(STORAGE_KEY, anonId);\n }\n\n const shortId = anonId.slice(-8);\n this.setUserId(`Anonymous #${shortId}`);\n } catch (e) {\n // localStorage blocked (private mode / HTTP restriction)\n console.warn(\"[ga-logger] initAnonymousUser failed:\", e);\n this.setUserId(\"Anonymous\");\n }\n }\n\n // Add breadcrumb ke in-memory array\n addBreadcrumb(type: BreadcrumbType, message: string, data?: Record<string, unknown>) {\n const breadcrumb: Breadcrumb = {\n timestamp: new Date(),\n type,\n message,\n data,\n };\n\n this.breadcrumbs.push(breadcrumb);\n\n // Jaga memory — max 50 breadcrumbs, buang yang paling lama\n if (this.breadcrumbs.length > MAX_BREADCRUMBS) {\n this.breadcrumbs.shift();\n }\n }\n\n // Global error capture — hanya aktif di non-development\n private loggedErrorKeys = new Set<string>();\n\n // Helper: trim URL jadi domain/filename\n private trimUrl(url: string): string {\n try {\n const u = new URL(url);\n const filename = u.pathname.split(\"/\").filter(Boolean).pop() ?? u.pathname;\n return `${u.hostname}/${filename}`;\n } catch {\n // bukan valid URL, potong saja jika terlalu panjang\n return url.length > 80 ? url.slice(0, 80) + \"...\" : url;\n }\n }\n\n // Helper: build dedup key\n private buildErrorKey(type: string, message: string): string {\n return `${type}::${message}`;\n }\n\n // Helper: should skip resource error\n private shouldSkipResourceError(src: string, tagName: string): boolean {\n // Skip IMG — tidak sebabkan blank page\n if (tagName === \"IMG\") return true;\n\n // Skip base64 URL\n if (src.startsWith(\"data:\")) return true;\n\n // Skip known 3rd party trackers\n const THIRD_PARTY = [\n \"omguk.com\",\n \"track.\",\n \"doubleclick\",\n \"adservice\",\n \"googletagmanager\",\n \"google-analytics\",\n \"hotjar\",\n \"facebook.net\",\n \"analytics\",\n \"magnolia\",\n \"gtm.js\",\n ];\n if (THIRD_PARTY.some((p) => src.includes(p))) return true;\n\n return false;\n }\n\n private shouldSkipGlobalError(message: string): boolean {\n const NOISE = [\n \"CORS\",\n \"cross-origin\",\n \"ERR_FAILED\",\n \"Failed to load resource\",\n \"NetworkError\",\n \"ResizeObserver loop\",\n \"Script error\",\n \"ServiceWorker\",\n \"sw.js\",\n \"dev-sw.js\",\n \"Warning:\",\n ];\n const THIRD_PARTY = [\n \"magnolia\",\n \"gtm.js\",\n \"analytics\",\n \"googletagmanager\",\n \"facebook\",\n \"hotjar\",\n \"omguk.com\",\n \"track.\",\n \"doubleclick\",\n \"adservice\",\n ];\n return NOISE.some((p) => message.includes(p)) || THIRD_PARTY.some((p) => message.includes(p));\n }\n\n initGlobalCapture(): void {\n const isLocalhost = window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n if (isLocalhost) return;\n\n window.onerror = (message, source, lineno, colno) => {\n const msg = typeof message === \"string\" ? message : \"Unknown error\";\n if (this.shouldSkipGlobalError(msg)) return false;\n\n const trimmedSource = source ? this.trimUrl(source) : \"unknown source\";\n const finalMessage = `${msg} at ${trimmedSource}:${lineno ?? 0}`;\n const key = this.buildErrorKey(\"onerror\", finalMessage);\n if (this.loggedErrorKeys.has(key)) return false;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"window.onerror\",\n messageError: new Error(finalMessage),\n payload: { source: trimmedSource, lineno, colno },\n });\n\n return false;\n };\n\n // unhandledrejection\n window.addEventListener(\"unhandledrejection\", (event) => {\n const msg =\n event.reason instanceof Error\n ? event.reason.message\n : String(event.reason ?? \"Unhandled Promise rejection\");\n\n if (this.shouldSkipGlobalError(msg)) return;\n\n const key = this.buildErrorKey(\"unhandledrejection\", msg);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"window.unhandledrejection\",\n messageError: new Error(msg),\n });\n });\n\n // console.error override\n const originalConsoleError = console.error.bind(console);\n console.error = (...args: unknown[]) => {\n originalConsoleError(...args);\n\n const msg = args.map((a) => (a instanceof Error ? a.message : String(a))).join(\" \");\n\n if (this.shouldSkipGlobalError(msg)) return;\n\n const trimmedMsg = msg.length > 150 ? msg.slice(0, 150) + \"...\" : msg;\n const key = this.buildErrorKey(\"console.error\", trimmedMsg);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n const originalError = args.find((a): a is Error => a instanceof Error);\n\n const errorToSend = originalError ?? new Error(trimmedMsg);\n\n void this.error({\n fnName: \"console.error\",\n messageError: errorToSend,\n });\n };\n\n // resource load error (CSS / JS / font)\n window.addEventListener(\n \"error\",\n (event) => {\n const target = event.target;\n if (!(target instanceof HTMLElement)) return;\n if (target === (window as unknown)) return;\n\n const tagName = target.tagName.toUpperCase();\n\n const src =\n tagName === \"LINK\"\n ? (target as HTMLLinkElement).href\n : tagName === \"SCRIPT\"\n ? (target as HTMLScriptElement).src\n : \"\";\n\n if (this.shouldSkipResourceError(src, tagName)) return;\n\n // Deteksi dari ekstensi file, bukan tagName\n const ext = src.split(\"?\")[0].split(\".\").pop()?.toLowerCase();\n const resourceType =\n ext === \"css\"\n ? \"CSS\"\n : ext === \"js\"\n ? \"JS\"\n : ext === \"woff\" || ext === \"woff2\" || ext === \"ttf\"\n ? \"FONT\"\n : tagName;\n\n const trimmedSrc = this.trimUrl(src);\n const finalMessage = `Failed to load ${resourceType}: ${trimmedSrc}`;\n const key = this.buildErrorKey(\"resource\", finalMessage);\n if (this.loggedErrorKeys.has(key)) return;\n this.loggedErrorKeys.add(key);\n\n void this.error({\n fnName: \"resource.onerror\",\n messageError: new Error(finalMessage),\n payload: { tagName, src: trimmedSrc },\n });\n },\n true,\n );\n }\n\n private sanitizePayload(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => {\n if (value === undefined) return [key, null];\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return [key, this.sanitizePayload(value as Record<string, unknown>)];\n }\n return [key, value];\n }),\n );\n }\n\n private sanitizeForFirestore(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => {\n if (value === undefined) return [key, null];\n if (typeof value === \"function\") return [key, \"[function]\"];\n if (value instanceof Date) return [key, value.toISOString()];\n if (Array.isArray(value)) {\n return [\n key,\n value.map((item) => {\n if (item instanceof Date) return item.toISOString();\n if (typeof item === \"function\") return \"[function]\"; // ← tambah\n if (item !== null && typeof item === \"object\") {\n return this.sanitizeForFirestore(item as Record<string, unknown>);\n }\n return item ?? null;\n }),\n ];\n }\n if (value !== null && typeof value === \"object\") {\n return [key, this.sanitizeForFirestore(value as Record<string, unknown>)];\n }\n return [key, value];\n }),\n );\n }\n\n // interceptFetch — auto breadcrumb, ke Firestore\n interceptFetch() {\n if (typeof window === \"undefined\") return;\n\n const originalFetch = window.fetch;\n\n const skipPatterns = [\n \"google.com\",\n \"googletagmanager.com\",\n \"googleapis.com\",\n \"facebook.com\",\n \"hotjar.com\",\n \"analytics\",\n \"gtm\",\n \"ccm/collect\",\n \"on.aws\",\n \"/locales/\",\n \"/sw.js\",\n \"/manifest.json\",\n \"/sourcemaps/\",\n \"magnolia\",\n ];\n\n const shouldSkipUrl = (url: string): boolean => {\n return skipPatterns.some((pattern) => url.includes(pattern));\n };\n\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n\n // Skip third-party domains\n if (shouldSkipUrl(url)) {\n return originalFetch(input, init);\n }\n\n const method = init?.method ?? \"GET\";\n const startTime = Date.now();\n\n try {\n const response = await originalFetch(input, init);\n const duration = Date.now() - startTime;\n\n this.addBreadcrumb(\"fetch\", `${method} ${url}`, {\n status: response.status,\n duration: `${duration}ms`,\n });\n\n if (response.status >= 400) {\n const dedupKey = this.buildErrorKey(\"interceptFetch\", `${method} ${url} ${response.status}`);\n\n if (!this.loggedErrorKeys.has(dedupKey)) {\n this.loggedErrorKeys.add(dedupKey);\n\n let responseBody: unknown = null;\n try {\n const cloned = response.clone();\n const contentType = cloned.headers.get(\"content-type\") ?? \"\";\n responseBody = contentType.includes(\"application/json\")\n ? await cloned.json()\n : await cloned.text();\n } catch {\n responseBody = \"[unable to read response body]\";\n }\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n this.error({\n fnName: \"interceptFetch\",\n messageError: new Error(`HTTP ${response.status} ${response.statusText} — ${url}`),\n endpointName: url,\n payload: {\n method,\n status: response.status,\n statusText: response.statusText,\n duration: `${duration}ms`,\n responseBody,\n },\n });\n }\n }\n }\n\n return response;\n } catch (networkError) {\n const duration = Date.now() - startTime;\n const error = networkError instanceof Error ? networkError : new Error(String(networkError));\n\n this.addBreadcrumb(\"fetch\", `${method} ${url} — NETWORK ERROR`, {\n duration: `${duration}ms`,\n error: error.message,\n });\n\n const dedupKey = this.buildErrorKey(\"interceptFetch\", `${method} ${url} NETWORK_ERROR`);\n\n if (!this.loggedErrorKeys.has(dedupKey)) {\n this.loggedErrorKeys.add(dedupKey);\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n if (!isLocalhost) {\n this.error({\n fnName: \"interceptFetch\",\n messageError: error,\n endpointName: url,\n payload: { method, duration: `${duration}ms` },\n });\n }\n }\n\n throw networkError;\n }\n };\n\n console.info(\"[ga-logger] fetch intercepted\");\n }\n\n // interceptXHR — auto breadcrumb + error capture untuk axios/XHR-based request\n interceptXHR(): void {\n if (typeof window === \"undefined\") return;\n\n const skipPatterns = [\n \"google.com\",\n \"googletagmanager.com\",\n \"googleapis.com\",\n \"facebook.com\",\n \"hotjar.com\",\n \"analytics\",\n \"ccm/collect\",\n \"on.aws\",\n \"/locales/\",\n \"/sw.js\",\n \"/manifest.json\",\n \"/sourcemaps/\",\n \"magnolia\",\n ];\n\n const shouldSkipUrl = (url: string): boolean => skipPatterns.some((p) => url.includes(p));\n\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n const self = this;\n\n type GaXHR = XMLHttpRequest & {\n _gaMethod?: string;\n _gaUrl?: string;\n _gaStartTime?: number;\n };\n\n XMLHttpRequest.prototype.open = function (this: GaXHR, method: string, url: string | URL, ...rest: unknown[]) {\n this._gaMethod = method;\n this._gaUrl = typeof url === \"string\" ? url : url.href;\n // @ts-expect-error - spreading native arguments\n return originalOpen.call(this, method, url, ...rest);\n };\n\n XMLHttpRequest.prototype.send = function (this: GaXHR, ...args: unknown[]) {\n const url = this._gaUrl ?? \"\";\n const method = this._gaMethod ?? \"GET\";\n\n if (shouldSkipUrl(url)) {\n // @ts-expect-error - spreading native arguments\n return originalSend.call(this, ...args);\n }\n\n this._gaStartTime = Date.now();\n\n this.addEventListener(\"loadend\", () => {\n const duration = Date.now() - (this._gaStartTime ?? Date.now());\n const status = this.status;\n\n self.addBreadcrumb(\"fetch\", `${method} ${url}`, {\n status,\n duration: `${duration}ms`,\n });\n\n if (status >= 400) {\n const dedupKey = self.buildErrorKey(\"interceptXHR\", `${method} ${url} ${status}`);\n if (self.loggedErrorKeys.has(dedupKey)) return;\n self.loggedErrorKeys.add(dedupKey);\n\n let responseBody: unknown = this.responseText;\n try {\n responseBody = JSON.parse(this.responseText);\n } catch {\n // keep as raw text\n }\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n void self.error({\n fnName: \"interceptXHR\",\n messageError: new Error(`HTTP ${status} ${this.statusText} — ${url}`),\n endpointName: url,\n payload: {\n method,\n status,\n statusText: this.statusText,\n duration: `${duration}ms`,\n responseBody,\n },\n });\n }\n }\n });\n\n this.addEventListener(\"error\", () => {\n // network-level failure (status selalu 0)\n const duration = Date.now() - (this._gaStartTime ?? Date.now());\n const dedupKey = self.buildErrorKey(\"interceptXHR\", `${method} ${url} NETWORK_ERROR`);\n if (self.loggedErrorKeys.has(dedupKey)) return;\n self.loggedErrorKeys.add(dedupKey);\n\n const isLocalhost =\n window.location.hostname === \"localhost\" || window.location.hostname === \"127.0.0.1\";\n\n if (!isLocalhost) {\n void self.error({\n fnName: \"interceptXHR\",\n messageError: new Error(`Network error — ${method} ${url}`),\n endpointName: url,\n payload: { method, duration: `${duration}ms` },\n });\n }\n });\n\n // @ts-expect-error - spreading native arguments\n return originalSend.call(this, ...args);\n };\n\n console.info(\"[ga-logger] XHR intercepted\");\n }\n\n interceptClick(): void {\n if (typeof window === \"undefined\") return;\n\n if ((window as any).__ga_click_intercepted) return;\n (window as any).__ga_click_intercepted = true;\n this.initDomActivityObserver();\n\n document.addEventListener(\n \"click\",\n (event: MouseEvent) => {\n const raw = event.target as HTMLElement;\n if (!raw) return;\n\n const target = (raw.closest('button, a, [role=\"button\"], [data-log], input') as HTMLElement) ?? raw;\n\n const innerText = sanitizeClickText(target.innerText?.trim().slice(0, 50) ?? \"\");\n const id = target.id ?? \"\";\n const tagName = target.tagName?.toLowerCase() ?? \"\";\n\n const isInteractive =\n [\"button\", \"a\", \"input\"].includes(tagName) ||\n target.hasAttribute(\"data-log\") ||\n target.getAttribute(\"role\") === \"button\";\n\n if (!innerText && !id && !isInteractive) return;\n\n const message = innerText || id || `(no label: ${tagName || \"unknown\"})`;\n\n // Skip internal React/Router identifiers\n if (CLICK_SKIP_PATTERNS.some((p) => p.test(message))) return;\n\n this.addBreadcrumb(\"click\", message, {\n tagName,\n ...(id ? { id } : {}),\n ...(innerText ? { text: innerText } : {}),\n });\n\n // ── Dead click detection ──\n const clickTime = Date.now();\n const domActivityAtClick = this.lastDomActivity;\n\n if ([\"button\", \"a\", \"input\"].includes(tagName)) {\n setTimeout(() => {\n if (this.lastDomActivity <= domActivityAtClick) {\n const reason = \"no DOM/scroll activity within 7s\";\n\n this.addBreadcrumb(\"click\", `Dead click: ${message}`, {\n tagName,\n ...(id ? { id } : {}),\n reason,\n });\n\n void this.warn({\n fnName: \"interceptClick.deadClick\",\n messageError: new Error(`Dead click: ${message}`),\n payload: { tagName, ...(id ? { id } : {}), reason },\n });\n }\n }, 7000);\n }\n\n // ── Rage click detection ──\n const historyKey = `${tagName}::${message}`;\n const timestamps = (this.clickHistory.get(historyKey) ?? []).filter((t) => clickTime - t < 7000);\n timestamps.push(clickTime);\n this.clickHistory.set(historyKey, timestamps);\n\n const lastFired = this.rageClickFired.get(historyKey) ?? 0;\n if (timestamps.length >= 3 && clickTime - lastFired > 7000) {\n this.rageClickFired.set(historyKey, clickTime);\n\n const possibleReason = this.recentDomChanges.length\n ? this.recentDomChanges.slice(-1)[0]\n : \"no visible UI feedback detected\";\n\n this.addBreadcrumb(\"click\", `Rage click: ${message}`, {\n tagName,\n clickCount: timestamps.length,\n windowMs: 7000,\n possibleReason,\n });\n\n void this.warn({\n fnName: \"interceptClick.rageClick\",\n messageError: new Error(`Rage click: ${message}`),\n payload: { tagName, clickCount: timestamps.length, windowMs: 7000, possibleReason },\n });\n }\n },\n true,\n );\n }\n\n captureAction<T>(params: LogParams, fn: () => T | Promise<T>): Promise<T | undefined> {\n return Promise.resolve()\n .then(() => fn())\n .catch((error: unknown) => {\n const err = error instanceof Error ? error : new Error(String(error));\n this.send(\"error\", params.fnName, params.payload, err, params.endpointName);\n return undefined;\n });\n }\n\n withLogger<T extends (...args: any[]) => any>(\n fnName: string,\n fn: T,\n options?: {\n endpointName?: string;\n payload?: Record<string, unknown>;\n },\n ): T {\n return ((...args: Parameters<T>): ReturnType<T> | undefined => {\n try {\n const result = fn(...args);\n\n // Handle async function\n if (result instanceof Promise) {\n return result.catch((error: unknown) => {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error({\n fnName,\n messageError: err,\n endpointName: options?.endpointName,\n payload: options?.payload,\n });\n return undefined;\n }) as ReturnType<T>;\n }\n\n return result;\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error({\n fnName,\n messageError: err,\n endpointName: options?.endpointName,\n payload: options?.payload,\n });\n return undefined;\n }\n }) as T;\n }\n\n private async send(\n level: LogLevel,\n message: string,\n payload: Record<string, unknown> = {},\n error?: Error,\n endpoint?: string,\n ) {\n if (!this.initialized || !this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n // console only, skip Firestore\n if (this.config.env === \"localhost\") {\n console.error(`[ga-localhost][DEV] ${message}`, { payload, error });\n return;\n }\n\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n message,\n env: this.config.env,\n userId: this.config.userId ?? null,\n sessionId,\n page: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n stackTrace: error?.stack ?? null,\n payload: this.sanitizePayload(payload),\n repo: this.config.repo,\n endpoint: endpoint ?? null,\n breadcrumbs: [...this.breadcrumbs],\n ...getEnvironmentPayload(),\n };\n\n try {\n const db = getDb();\n const safeEntry = this.sanitizeForFirestore(entry as unknown as Record<string, unknown>);\n await addDoc(collection(db, \"logs\"), {\n ...safeEntry,\n timestamp: Timestamp.fromDate(entry.timestamp),\n });\n } catch (e) {\n console.error(\"[ga-logger] failed to send log:\", e);\n }\n }\n\n info(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"info\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n\n warn(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"warn\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n\n error(params: LogParams) {\n const { fnName, messageError, payload, endpointName } = params;\n return this.send(\"error\", messageError?.message ?? fnName, { ...payload, fnName }, messageError, endpointName);\n }\n}\n\nexport const logger = new Logger();\n\n","import { initializeApp, getApps, getApp } from \"firebase/app\";\nimport { getFirestore } from \"firebase/firestore\";\nimport type { Firestore } from \"firebase/firestore\";\nimport type { LoggerConfig } from \"../types\";\n\nconst APP_NAME = \"ga-logger\";\nlet db: Firestore | null = null;\n\nexport const initFirebase = (config: LoggerConfig) => {\n // Cek apakah named instance \"ga-logger\" sudah ada\n const existingApp = getApps().find((app) => app.name === APP_NAME);\n\n const app =\n existingApp ??\n initializeApp(\n {\n apiKey: config.apiKey,\n authDomain: config.authDomain,\n projectId: config.projectId,\n storageBucket: config.storageBucket,\n messagingSenderId: config.messagingSenderId,\n appId: config.appId,\n },\n APP_NAME,\n );\n\n db = getFirestore(app);\n return db;\n};\n\nexport const getDb = (): Firestore => {\n if (!db) throw new Error(\"[ga-logger] Firebase not initialized. Call logger.init() first.\");\n return db;\n};\n","interface EnvironmentPayload {\n userAgent: string;\n deviceType: \"Mobile\" | \"Tablet\" | \"Desktop\";\n screenWidth: number;\n screenHeight: number;\n}\n\nlet cachedEnvironment: EnvironmentPayload | null = null;\n\nfunction getDeviceType(width: number): \"Mobile\" | \"Tablet\" | \"Desktop\" {\n if (width < 768) return \"Mobile\";\n if (width <= 1024) return \"Tablet\";\n return \"Desktop\";\n}\n\nexport function initEnvironment(): void {\n if (cachedEnvironment) return;\n\n const width = window.innerWidth;\n const height = window.innerHeight;\n\n cachedEnvironment = {\n userAgent: navigator.userAgent,\n deviceType: getDeviceType(width),\n screenWidth: width,\n screenHeight: height,\n };\n}\n\nexport function getEnvironmentPayload(): EnvironmentPayload {\n if (!cachedEnvironment) initEnvironment();\n return cachedEnvironment!;\n}","import { Component, type ErrorInfo, type ReactNode } from \"react\";\nimport { logger } from \"../core/logger\";\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n}\n\nexport class LoggerErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): State {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n logger.addBreadcrumb(\"error\", `React crash: ${error.message}`, {\n componentStack: info.componentStack ?? undefined,\n });\n\n logger.error({\n fnName: \"LoggerErrorBoundary\",\n messageError: error,\n payload: {\n componentStack: info.componentStack ?? undefined,\n },\n });\n }\n\n render() {\n if (this.state.hasError) {\n return this.props.fallback ?? (\n <div style={{ padding: \"1rem\", color: \"red\" }}>\n Something went wrong.\n </div>\n );\n }\n\n return this.props.children;\n }\n}"],"mappings":"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","names":["app","db"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ga-components/logger",
3
- "version": "1.0.58",
3
+ "version": "1.0.59",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",