@twinalyze/web-analytics 1.0.17 → 1.0.19
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/README.md +2 -1
- package/dist/cdn.global.min.js +5 -5
- package/dist/cdn.global.min.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"sourcesContent":["import CryptoJS from \"crypto-js\";\nimport html2canvas from \"html2canvas\";\n// import UAParser from \"ua-parser-js\";\nimport * as UAParserPkg from \"ua-parser-js\";\nconst UAParser = UAParserPkg.UAParser;\n\nfunction uuid() {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) return crypto.randomUUID();\n return Math.random().toString(16).slice(2) + Date.now().toString(16);\n}\n\nconst cryptoRandomNonce = () => {\n // simple uuid-like nonce (ok for test)\n return \"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\nconst stableStringify = (obj) => {\n if (obj === null || typeof obj !== \"object\") return JSON.stringify(obj);\n if (Array.isArray(obj)) return \"[\" + obj.map(stableStringify).join(\",\") + \"]\";\n const keys = Object.keys(obj).filter(k => obj[k] !== undefined).sort();\n return \"{\" + keys.map(k => JSON.stringify(k) + \":\" + stableStringify(obj[k])).join(\",\") + \"}\";\n};\n\nclass TwinalyzeAnalyticsImpl {\n constructor() {\n this.cfg = null;\n\n this.deviceId = null;\n this.sessionId = null; // uniqueSessionId (client generated)\n this.sessionStartTime = null; // persistent session start timestamp\n\n this.sessionReady = false; // sessionCreate done\n this._booting = false; // handshake in progress\n this._disabled = false; // STOP state\n\n this.pendingEvents = []; // queued until sessionReady\n this.batchQueue = []; // queued for batch events upload\n this.scrollFired = false;\n\n this._initialized = false;\n this._flushTimer = null;\n\n this.indexId = 0;\n this._indexKey = null;\n\n this._lastShotAt = 0;\n this._shotInFlight = false;\n\n this.batchConfig = { eventsBatchSize: 10, flushIntervalMs: 5000, sessionTimeout: 300000 };\n }\n\n // -------------------------\n // PUBLIC API\n // -------------------------\n init(cfg) {\n if (typeof window === \"undefined\") return;\n if (this._initialized) return; // strict-mode safe\n this._initialized = true;\n\n const resolvedBaseUrl = cfg.apiBaseUrl || cfg.endpoint || cfg.socketUrl || \"https://api.twinalyze.com\";\n const normalizedBaseUrl = resolvedBaseUrl.endsWith(\"/\") ? resolvedBaseUrl.slice(0, -1) : resolvedBaseUrl;\n\n const DEFAULT_SCREEN_ACTIVITY = {\n enabled: false,\n apiUrl: cfg.screenActivity?.apiUrl ?? `${normalizedBaseUrl}/api/app/screenActivity/screenActivityDetails_post`,\n captureOn: [\"pageView\", \"elementClick\", \"formStart\", \"formSubmit\", \"scrollDepth\", \"searchResultsView\", \"customEvent\"],\n throttleMs: 2000,\n jpegQuality: 0.7,\n };\n\n // support: screenshots: true OR screenActivity: true OR screenActivity: { ... }\n const sa =\n typeof cfg.screenActivity === \"object\"\n ? { ...DEFAULT_SCREEN_ACTIVITY, ...cfg.screenActivity }\n : { ...DEFAULT_SCREEN_ACTIVITY };\n\n this.cfg = {\n apiKey: cfg.apiKey,\n secretKey: cfg.secretKey,\n version: cfg.version,\n apiBaseUrl: normalizedBaseUrl,\n\n debug: cfg.debug !== false, // default true in debug builds\n\n // encryption\n encrypt: cfg.encrypt !== false,\n\n // session id from client side\n persistSession: cfg.persistSession !== false, // default true (sessionStorage)\n sessionKey: \"twinalyze_session_id\",\n\n // eventAdd fields\n source: cfg.source || \"web\",\n indexId: cfg.indexId ?? null,\n\n // auto tracking options\n enhancedMeasurement: {\n pageViews: true,\n scrolls: true,\n outboundClicks: true,\n siteSearch: { params: [\"q\", \"s\", \"search\", \"query\"] },\n formInteractions: true,\n fileDownloads: { extensions: [\"pdf\", \"zip\", \"apk\", \"doc\", \"docx\", \"xls\", \"xlsx\", \"ppt\", \"pptx\"] },\n ...(cfg.enhancedMeasurement || {}),\n },\n screenActivity: sa,\n };\n\n if (!this.cfg.apiKey) {\n console.log(\"[Twinalyze] ❌ Missing apiKey\");\n return;\n }\n\n this.deviceId = this._getOrCreateDeviceId();\n\n const startKey = \"twinalyze_session_start_time\";\n if (this.cfg.persistSession) {\n this.sessionId = sessionStorage.getItem(this.cfg.sessionKey) || null;\n this.sessionStartTime = sessionStorage.getItem(startKey) || null;\n }\n if (!this.sessionId) {\n this.sessionId = `sess_${uuid()}`;\n this.sessionStartTime = new Date().toISOString();\n if (this.cfg.persistSession) {\n sessionStorage.setItem(this.cfg.sessionKey, this.sessionId);\n sessionStorage.setItem(startKey, this.sessionStartTime);\n }\n } else if (!this.sessionStartTime) {\n this.sessionStartTime = new Date().toISOString();\n if (this.cfg.persistSession) {\n sessionStorage.setItem(startKey, this.sessionStartTime);\n }\n }\n\n this._setupEnhancedMeasurement();\n this._loadAndSendUnsentEvents();\n this._setupVisibilityAndUnloadHandlers();\n this._startFlow();\n }\n\n // custom event (web dev only uses this)\n track(eventName, properties = {}) {\n if (this._disabled) return;\n if (this.cfg && this.cfg.manualEventStatus === false) return;\n\n if (this.cfg?.debug) console.log(\"[Twinalyze][CUSTOM]\", eventName, properties);\n\n if (!this.sessionReady) {\n this.pendingEvents.push({ eventName, properties: { ...this._pageContext(), ...properties }, ts: Date.now(), eventType: \"manual\" });\n return;\n }\n\n this._emitEventAdd(eventName, { ...this._pageContext(), ...properties }, \"manual\");\n }\n\n // -------------------------\n // -------------------------\n // REST API FLOW\n // -------------------------\n async _startFlow() {\n if (this._disabled) return;\n if (this._booting) return;\n this._booting = true;\n\n try {\n // 1. Init API\n const initRes = await this._fetchApi(\"/api/web/sdk/init\", {});\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] initRes: HAR HAR MAHADEV\", initRes);\n\n if (!initRes || initRes.success === false) {\n this._disabled = true;\n this.sessionReady = false;\n this.cfg.screenActivity.enabled = false;\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] 🛑 STOP (init failed)\");\n return;\n }\n\n const data = initRes.data || {};\n\n this.cfg.screenActivity.enabled = !!data.debugScreenshotCapture;\n\n if (data.eventData) {\n this.cfg.autoEventStatus = data.eventData.autoEventStatus !== false;\n this.cfg.manualEventStatus = data.eventData.manualEventStatus !== false;\n } else {\n this.cfg.autoEventStatus = true;\n this.cfg.manualEventStatus = true;\n }\n\n if (data.eventsBatchConfig) {\n this.batchConfig = {\n eventsBatchSize: data.eventsBatchConfig.eventsBatchSize || 10,\n flushIntervalMs: data.eventsBatchConfig.flushIntervalMs || 5000,\n sessionTimeout: data.eventsBatchConfig.sessionTimeout || 300000\n };\n }\n\n this._initIndexId();\n\n // 2. Identify API\n const identifyPayload = {\n properties: this._userProperties(),\n deviceProperties: this._deviceProperties()\n };\n\n const identifyRes = await this._fetchApi(\"/api/web/sdk/identify\", identifyPayload);\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] identifyRes:\", identifyRes);\n\n if (!identifyRes || identifyRes.success === false) {\n this._disabled = true;\n this.sessionReady = false;\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] 🛑 STOP (identify failed)\");\n return;\n }\n\n // Mark ready\n this.sessionReady = true;\n\n // Flush queued auto/custom events (move from pendingEvents to batchQueue)\n if (this.pendingEvents.length > 0) {\n const items = this.pendingEvents.splice(0, this.pendingEvents.length);\n items.forEach((e) => this._emitEventAdd(e.eventName, e.properties || {}, e.eventType || \"auto\"));\n }\n\n } finally {\n this._booting = false;\n }\n }\n\n async _fetchApi(endpoint, payloadObj) {\n const url = `${this.cfg.apiBaseUrl}${endpoint}`;\n\n const nonce = cryptoRandomNonce();\n const timestamp = new Date().toISOString();\n const bodyStr = payloadObj ? JSON.stringify(payloadObj) : \"{}\";\n\n const canonicalBody = stableStringify(JSON.parse(bodyStr));\n const bodyHash = CryptoJS.SHA256(canonicalBody).toString(CryptoJS.enc.Hex);\n\n const method = \"POST\";\n const baseString = [method, endpoint, timestamp, nonce, this.deviceId, bodyHash].join(\"\\n\");\n\n // Generate HMAC-SHA256 signature using secret key from config\n const SECRET_KEY = this.cfg.secretKey || \"\";\n const signature = CryptoJS.HmacSHA256(baseString, SECRET_KEY).toString(CryptoJS.enc.Hex);\n\n if (this.cfg.debug) {\n console.log(\"[Twinalyze][API] Request signing trace:\", {\n endpoint,\n nonce,\n timestamp,\n canonicalBody,\n bodyHash,\n baseString,\n signature\n });\n }\n\n const headers = {\n \"Content-Type\": \"application/json\",\n \"x-deviceId\": this.deviceId,\n \"x-api-key\": this.cfg.apiKey,\n \"x-analytics-sdk-version\": this.cfg.version || \"1.0.0\",\n \"x-ad-analytics-sdk-version\": \"\",\n \"x-app-package-name\": window.location.href,\n \"x-platform\": \"javascript\",\n \"x-app-version-name\": \"1.0.0\",\n \"x-app-version-mode\": this.cfg.debug ? \"debug\" : \"release\",\n \"x-sdk-version\": \"v1.0.15\",\n \"x-timestamp\": timestamp,\n \"x-nonce\": nonce,\n \"x-signature\": signature\n };\n\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers,\n body: bodyStr,\n keepalive: true\n });\n return await res.json();\n } catch (err) {\n if (this.cfg.debug) console.log(`[Twinalyze][API] Error calling ${endpoint}:`, err);\n return null;\n }\n }\n\n async _waitForRenderStable() {\n // 2 frames\n await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));\n\n // fonts\n try { if (document.fonts?.ready) await document.fonts.ready; } catch { }\n\n // images\n const imgs = Array.from(document.images || []).filter(img => !img.complete);\n await Promise.allSettled(\n imgs.map(img => new Promise(res => {\n img.addEventListener(\"load\", res, { once: true });\n img.addEventListener(\"error\", res, { once: true });\n }))\n );\n }\n\n async _captureViewportJpegBlob() {\n await this._waitForRenderStable();\n\n const isViewport = (this.cfg.screenActivity?.capture || \"viewport\") === \"viewport\";\n const scale = Math.min(2, window.devicePixelRatio || 1);\n\n const canvas = await html2canvas(document.documentElement, {\n useCORS: true,\n allowTaint: false,\n backgroundColor: \"#ffffff\",\n logging: false,\n\n ...(isViewport\n ? { x: window.scrollX, y: window.scrollY, width: window.innerWidth, height: window.innerHeight }\n : { x: 0, y: 0, width: document.documentElement.scrollWidth, height: document.documentElement.scrollHeight }\n ),\n\n scale,\n onclone: (doc) => {\n const style = doc.createElement(\"style\");\n style.textContent = `\n * { animation: none !important; transition: none !important; caret-color: transparent !important; }\n `;\n doc.head.appendChild(style);\n },\n });\n\n // downscale big screenshots (optional but helpful)\n const maxW = this.cfg.screenActivity?.maxWidth ?? 1280;\n if (canvas.width > maxW) {\n const ratio = maxW / canvas.width;\n const c2 = document.createElement(\"canvas\");\n c2.width = Math.round(canvas.width * ratio);\n c2.height = Math.round(canvas.height * ratio);\n c2.getContext(\"2d\").drawImage(canvas, 0, 0, c2.width, c2.height);\n return await new Promise((resolve) =>\n c2.toBlob(resolve, \"image/jpeg\", this.cfg.screenActivity?.jpegQuality ?? 0.7)\n );\n }\n\n return await new Promise((resolve) =>\n canvas.toBlob(resolve, \"image/jpeg\", this.cfg.screenActivity?.jpegQuality ?? 0.7)\n );\n }\n\n async _uploadScreenActivity({ eventName, properties }) {\n if (!this.cfg.screenActivity?.enabled) return;\n if (!this.sessionReady) return;\n\n const now = Date.now();\n const throttleMs = this.cfg.screenActivity?.throttleMs ?? 2000;\n if (now - this._lastShotAt < throttleMs) return;\n if (this._shotInFlight) return;\n\n this._shotInFlight = true;\n this._lastShotAt = now;\n\n try {\n const blob = await this._captureViewportJpegBlob();\n if (!blob) return;\n\n const fd = new FormData();\n fd.append(\"apiKey\", this.cfg.apiKey);\n fd.append(\"screenName\", document.title || \"unknown\");\n fd.append(\"identifier\", JSON.stringify(properties || {})); // ✅ you asked: identifier = properties object\n fd.append(\"appInfo\", JSON.stringify({\n appVersion: this.cfg.version || \"1.0.0\",\n platform: \"javascript\"\n }));\n fd.append(\"description\", eventName || \"event\");\n fd.append(\"image\", blob, `shot_${Date.now()}.jpg`);\n\n const headers = {\n \"x-deviceId\": this.deviceId,\n \"x-api-key\": this.cfg.apiKey,\n \"x-analytics-sdk-version\": this.cfg.version || \"1.0.0\",\n \"x-ad-analytics-sdk-version\": \"\",\n \"x-app-package-name\": window.location.href,\n \"x-platform\": \"javascript\",\n \"x-app-version-name\": \"1.0.0\",\n \"x-app-version-mode\": this.cfg.debug ? \"debug\" : \"release\",\n \"x-sdk-version\": \"v1.0.15\",\n };\n\n await fetch(this.cfg.screenActivity.apiUrl, {\n method: \"POST\",\n headers,\n body: fd,\n // keepalive: true, (commented because only 1 screenshot was coming and other were going in pending)\n });\n } catch (e) {\n if (this.cfg.debug) console.log(\"[Twinalyze][SCREENSHOT] error:\", e?.message || e);\n } finally {\n this._shotInFlight = false;\n }\n }\n\n // -------------------------\n // -------------------------\n // EMITS (REST API BATCHING)\n // -------------------------\n _emitEventAdd(eventName, properties = {}, eventType = \"auto\") {\n if (!this.sessionReady) return;\n\n if (this._indexKey == null) this._initIndexId();\n const indexId = this._nextIndexId();\n\n const eventObj = {\n uniqueSessionId: this.sessionId,\n date: new Date().toISOString(),\n eventType: eventType,\n eventName: eventName,\n properties: { ...properties, eventName: eventName },\n indexId: indexId,\n source: this.cfg.source\n };\n\n // If this is the first event in a new batch, schedule a flush timer\n if (this.batchQueue.length === 0) {\n if (this._flushTimer) clearTimeout(this._flushTimer);\n this._flushTimer = setTimeout(() => this._flushBatchQueue(), this.batchConfig.flushIntervalMs);\n }\n\n this.batchQueue.push(eventObj);\n\n this._uploadScreenActivity({ eventName, properties });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][EVENT_QUEUED]\", eventName, properties, indexId);\n\n // Flush immediately if we hit the batch size limit\n if (this.batchQueue.length >= this.batchConfig.eventsBatchSize) {\n this._flushBatchQueue();\n }\n }\n\n async _flushBatchQueue() {\n // Clear any active timeout timer to prevent duplicate flushes\n if (this._flushTimer) {\n clearTimeout(this._flushTimer);\n this._flushTimer = null;\n }\n\n if (!this.sessionReady) return;\n if (!this.batchQueue.length) return;\n\n // slice to handle new events coming in while flushing\n const batch = this.batchQueue.splice(0, this.batchQueue.length);\n\n if (this.cfg.debug) console.log(`[Twinalyze][FLUSHING] ${batch.length} events...`);\n\n const payload = {\n eventsBatch: [\n {\n events: batch.map(e => ({\n appInfo: {\n appVersion: this.cfg.version || \"1.0.0\",\n platform: \"javascript\"\n },\n date: e.date,\n eventName: e.eventName,\n eventType: e.eventType,\n indexId: e.indexId,\n properties: e.properties\n })),\n startDate: this.sessionStartTime || batch[0].date,\n uniqueSessionId: this.sessionId\n }\n ]\n };\n const res = await this._fetchApi(\"/api/web/sdk/eventsBatch\", payload);\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLUSH_RES]\", res);\n\n if (!res || res.success === false) {\n if (this.cfg.debug) console.log(\"[Twinalyze][FLUSH_FAIL] events dropped\");\n // Could re-queue here if desired: this.batchQueue.unshift(...batch);\n }\n }\n\n // -------------------------\n // AUTO EVENTS (GA-style)\n // -------------------------\n _trackAuto(name, props = {}) {\n if (this._disabled) return;\n if (this.cfg && this.cfg.autoEventStatus === false) return;\n if (this.cfg?.debug) console.log(\"[Twinalyze][AUTO]\", name, props);\n\n if (!this.sessionReady) {\n this.pendingEvents.push({ eventName: name, properties: props, ts: Date.now(), eventType: \"auto\" });\n return;\n }\n\n this._emitEventAdd(name, props, \"auto\");\n }\n\n _setupEnhancedMeasurement() {\n const em = this.cfg.enhancedMeasurement || {};\n\n // pageView (normal + SPA)\n if (em.pageViews) {\n const pv = this._pageViewInfo();\n this._trackAuto(\"pageView\", pv);\n\n const fire = () => {\n this.scrollFired = false;\n const pv2 = this._pageViewInfo();\n this._trackAuto(\"pageView\", pv2);\n this._fireSiteSearch();\n };\n\n const _push = history.pushState;\n const _replace = history.replaceState;\n\n history.pushState = (...args) => { _push.apply(history, args); fire(); };\n history.replaceState = (...args) => { _replace.apply(history, args); fire(); };\n window.addEventListener(\"popstate\", fire);\n }\n\n // scroll (90%)\n if (em.scrolls) {\n window.addEventListener(\"scroll\", () => {\n if (this.scrollFired) return;\n\n const doc = document.documentElement;\n const scrollTop = window.scrollY || doc.scrollTop;\n const scrollHeight = doc.scrollHeight - doc.clientHeight;\n if (scrollHeight <= 0) return;\n\n const percent = Math.round((scrollTop / scrollHeight) * 100);\n if (percent >= 90) {\n this.scrollFired = true;\n this._trackAuto(\"scrollDepth\", { scrollPercent: percent, ...this._pageContext() });\n }\n }, { passive: true });\n }\n\n // // outbound clicks\n // if (em.outboundClicks) {\n // document.addEventListener(\"click\", (e) => {\n // const a = e.target && e.target.closest ? e.target.closest(\"a\") : null;\n // if (!a || !a.href) return;\n // if (/^(javascript:|mailto:|tel:)/i.test(a.href)) return;\n\n // let url;\n // try { url = new URL(a.href); } catch { return; }\n // if (url.hostname !== location.hostname) {\n // console.log(\"click\", { link_url: url.href, link_domain: url.hostname, outbound: true });\n // this._trackAuto(\"click\", { link_url: url.href, link_domain: url.hostname, outbound: true });\n // }\n // }, true);\n // }\n\n // clicks (links + buttons + dropdown items + generic interactive)\n if (em.outboundClicks) {\n document.addEventListener(\"click\", (e) => {\n const hit = this._getClickTarget(e);\n if (!hit) return;\n\n const el = hit.el;\n\n const tag = (el.tagName || \"\").toLowerCase();\n const text = this._getTextFromElement(el);\n\n const props = {\n clickType: hit.kind, // link | button | dropdown_item | interactive\n elementTag: tag,\n elementText: text || \"not_found\", // ✅ innerText/aria-label/title\n elementId: el.id || null,\n elementName: el.getAttribute?.(\"name\") || null,\n elementRole: el.getAttribute?.(\"role\") || null,\n elementClass:\n (el.className && typeof el.className === \"string\") ? el.className.slice(0, 120) : null,\n elementSelector: this._cssPath(el),\n ...((this._pageContext && this._pageContext()) || {}), // if you added _pageContext()\n };\n\n // If link, enrich with URL + outbound\n if (hit.kind === \"link\") {\n const href = el.getAttribute(\"href\") || \"\";\n if (/^(javascript:|mailto:|tel:)/i.test(href)) return;\n\n let url;\n try { url = new URL(el.href); } catch { return; }\n\n props.linkUrl = url.href;\n props.linkDomain = url.hostname;\n props.linkPath = url.pathname;\n props.isOutbound = url.hostname !== location.hostname;\n }\n\n // Button details\n if (hit.kind === \"button\") {\n props.buttonType = el.getAttribute?.(\"type\") || null;\n props.disabled = !!el.disabled;\n }\n\n this._trackAuto(\"elementClick\", props);\n }, true);\n\n }\n\n // site search\n if (em.siteSearch) this._fireSiteSearch();\n\n // form interactions\n if (em.formInteractions) {\n const started = new WeakSet();\n\n document.addEventListener(\"focusin\", (e) => {\n const form = e.target && e.target.closest ? e.target.closest(\"form\") : null;\n if (!form || started.has(form)) return;\n started.add(form);\n\n this._trackAuto(\"formStart\", {\n formId: form.id || undefined,\n formName: form.getAttribute(\"name\") || undefined,\n formActionUrl: form.action || undefined,\n ...this._pageContext(),\n });\n });\n\n document.addEventListener(\"submit\", (e) => {\n const form = e.target;\n if (!form) return;\n\n this._trackAuto(\"formSubmit\", {\n formId: form.id || undefined,\n formName: form.getAttribute(\"name\") || undefined,\n formActionUrl: form.action || undefined,\n formDestinationUrl: location.href,\n formStatus: \"success\",\n ...this._pageContext(),\n });\n }, true);\n }\n\n // file downloads\n if (em.fileDownloads && em.fileDownloads.extensions) {\n const exts = em.fileDownloads.extensions.map((x) => String(x).toLowerCase());\n\n document.addEventListener(\"click\", (e) => {\n const a = e.target && e.target.closest ? e.target.closest(\"a\") : null;\n if (!a || !a.href) return;\n\n const clean = a.href.split(\"?\")[0].toLowerCase();\n const ext = clean.split(\".\").pop() || \"\";\n if (!exts.includes(ext)) return;\n\n this._trackAuto(\"fileDownload\", {\n linkUrl: a.href,\n fileExtension: ext,\n fileName: clean.split(\"/\").pop(),\n ...this._pageContext(),\n });\n }, true);\n }\n }\n\n _fireSiteSearch() {\n const em = this.cfg.enhancedMeasurement || {};\n if (!em.siteSearch) return;\n\n const params = em.siteSearch.params || [\"q\", \"s\", \"search\", \"query\"];\n const usp = new URLSearchParams(location.search);\n const key = params.find((k) => usp.get(k));\n const term = key ? usp.get(key) : null;\n\n if (term && term.trim()) {\n this._trackAuto(\"searchResultsView\", {\n searchTerm: term.trim(),\n searchKey: key,\n searchUrl: location.href,\n ...this._pageContext()\n });\n }\n }\n\n _getTextFromElement(el) {\n if (!el) return null;\n\n // common places (MUI/AntD often store label in aria-label)\n const aria = el.getAttribute?.(\"aria-label\");\n if (aria && aria.trim()) return aria.trim();\n\n const title = el.getAttribute?.(\"title\");\n if (title && title.trim()) return title.trim();\n\n // visible text\n const txt = (el.innerText || el.textContent || \"\").trim();\n if (!txt) return null;\n\n // limit length (avoid huge HTML)\n return txt.length > 80 ? txt.slice(0, 80) : txt;\n }\n\n _cssPath(el) {\n if (!el || !el.tagName) return null;\n const parts = [];\n let node = el;\n let depth = 0;\n while (node && node.nodeType === 1 && depth < 5) {\n let part = node.tagName.toLowerCase();\n if (node.id) {\n part += `#${node.id}`;\n parts.unshift(part);\n break;\n }\n const cls = (node.className && typeof node.className === \"string\")\n ? node.className.trim().split(/\\s+/).slice(0, 2).join(\".\")\n : \"\";\n if (cls) part += `.${cls}`;\n parts.unshift(part);\n node = node.parentElement;\n depth++;\n }\n return parts.join(\" > \");\n }\n\n _getClickTarget(e) {\n // Shadow DOM safe path\n const path = typeof e.composedPath === \"function\" ? e.composedPath() : null;\n const start = (path && path.length ? path[0] : e.target);\n\n const closest = (el, sel) => (el && el.closest ? el.closest(sel) : null);\n\n // 1) Links\n const a = closest(start, 'a[href]');\n if (a) return { el: a, kind: \"link\" };\n\n // 2) Buttons + button-like\n const btn = closest(\n start,\n 'button, input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"], [role=\"button\"]'\n );\n if (btn) return { el: btn, kind: \"button\" };\n\n // 3) Menu / dropdown item (generic roles)\n const menuItem = closest(\n start,\n '[role=\"menuitem\"], [role=\"menuitemradio\"], [role=\"menuitemcheckbox\"], [role=\"option\"]'\n );\n if (menuItem) return { el: menuItem, kind: \"dropdown_item\" };\n\n // 4) Generic \"interactive\" fallback:\n // - role link\n // - tabindex (focusable)\n // - aria-haspopup (opens menu)\n // - contenteditable\n const interactive = closest(\n start,\n '[role=\"link\"], [tabindex]:not([tabindex=\"-1\"]), [aria-haspopup], [contenteditable=\"true\"]'\n );\n if (interactive) return { el: interactive, kind: \"interactive\" };\n\n return null;\n }\n\n\n // -------------------------\n // PROPERTIES (AUTO)\n // -------------------------\n // _deviceProperties() {\n // return {\n // ua: navigator.userAgent,\n // lang: navigator.language,\n // tz: Intl.DateTimeFormat().resolvedOptions().timeZone,\n // screen: { w: screen.width, h: screen.height },\n // viewport: { w: window.innerWidth, h: window.innerHeight },\n // dpr: window.devicePixelRatio || 1,\n // };\n // }\n\n _deviceProperties() {\n const parser = new UAParser(navigator.userAgent);\n const ua = parser.getResult();\n\n const conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\n\n const screenMode =\n window.matchMedia?.(\"(prefers-color-scheme: dark)\")?.matches ? \"dark\" : \"light\";\n\n return {\n // device/browser\n device_screen_mode: screenMode,\n is_data_on: navigator.onLine ? \"true\" : \"false\",\n screen_width: String(screen.width),\n screen_height: String(screen.height),\n viewport_width: String(window.innerWidth),\n viewport_height: String(window.innerHeight),\n color_depth: String(screen.colorDepth || \"not_found\"),\n browser_name: ua.browser?.name || \"not_found\",\n browser_version: ua.browser?.version || \"not_found\",\n os_name: ua.os?.name || \"not_found\",\n os_version: ua.os?.version || \"not_found\",\n app_language: navigator.language || \"not_found\",\n cpu_cores: navigator.hardwareConcurrency != null ? String(navigator.hardwareConcurrency) : \"not_found\",\n touch_points: navigator.maxTouchPoints != null ? String(navigator.maxTouchPoints) : \"0\",\n network_type: conn?.effectiveType || \"not_found\",\n network_speed_mbps: conn?.downlink != null ? String(conn.downlink) : \"not_found\",\n network_latency_ms: conn?.rtt != null ? String(conn.rtt) : \"not_found\",\n data_saver_enabled: conn?.saveData != null ? String(conn.saveData) : \"not_found\",\n user_agent: navigator.userAgent,\n analytics_version: this.cfg?.version || \"not_found\",\n };\n }\n\n _normalizeUrl(urlStr) {\n if (!urlStr) return urlStr;\n try {\n const url = new URL(urlStr);\n const newParams = new URLSearchParams();\n const campaignKeys = [\"source\", \"medium\", \"campaign\", \"term\", \"content\"];\n for (const [key, val] of url.searchParams.entries()) {\n if (key.toLowerCase().startsWith(\"utm\")) {\n newParams.set(key.toLowerCase(), val);\n } else if (campaignKeys.includes(key.toLowerCase())) {\n newParams.set(\"utm_\" + key.toLowerCase(), val);\n } else {\n newParams.set(key, val);\n }\n }\n url.search = newParams.toString();\n return url.href;\n } catch (e) {\n return urlStr;\n }\n }\n\n _userProperties() {\n const parser = new UAParser(navigator.userAgent);\n const ua = parser.getResult();\n\n const normalizedUrlStr = this._normalizeUrl(location.href);\n const url = new URL(normalizedUrlStr);\n const usp = url.searchParams;\n\n const get = (k) => usp.get(k);\n const nf = \"not_found\";\n\n return {\n // From GSheet User Properties (Left Side) - Web Platform\n device_type: ua.device?.type || (matchMedia(\"(pointer:coarse)\").matches ? \"mobile\" : \"desktop\"),\n density: String(window.devicePixelRatio || 1),\n timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone || \"not_found\",\n ram: navigator.deviceMemory != null ? String(navigator.deviceMemory) : \"not_found\",\n device_language: navigator.language || \"not_found\",\n\n // acquisition\n landing_url: normalizedUrlStr,\n utm_source: get(\"utm_source\") || nf,\n utm_medium: get(\"utm_medium\") || nf,\n utm_campaign: get(\"utm_campaign\") || nf,\n utm_term: get(\"utm_term\") || nf,\n utm_content: get(\"utm_content\") || nf,\n\n // ads click ids\n utm_gclid: get(\"gclid\") || nf,\n utm_fbclid: get(\"fbclid\") || nf,\n utm_msclkid: get(\"msclkid\") || nf,\n\n // identity (optional, only if you have it)\n // user_id: this.userId || nf,\n // email: this.email || nf,\n // plan: \"free\" / \"pro\" etc.\n };\n }\n\n\n // -------------------------\n // IDs\n // -------------------------\n _initIndexId() {\n this._indexKey = `twinalyze_index_${this.sessionId}`;\n this.indexId = parseInt(sessionStorage.getItem(this._indexKey) || \"0\", 10);\n if (Number.isNaN(this.indexId)) this.indexId = 0;\n }\n\n _nextIndexId() {\n this.indexId += 1;\n if (this._indexKey) {\n sessionStorage.setItem(this._indexKey, String(this.indexId));\n }\n return this.indexId;\n }\n\n _getOrCreateDeviceId() {\n const key = \"twinalyze_device_id\";\n const old = localStorage.getItem(key);\n if (old) return old;\n\n const id = uuid();\n // const id = `dev_${uuid()}`;\n localStorage.setItem(key, id);\n return id;\n }\n\n _pageContext() {\n const KEY_LAST = \"twinalyze_last_page_location\";\n\n const pageLocation = this._normalizeUrl(location.href);\n const pageDomain = location.hostname;\n const pagePath = location.pathname;\n const pageTitle = document.title;\n\n const storedPrev = sessionStorage.getItem(KEY_LAST);\n const prevLocation = storedPrev || (document.referrer || null);\n\n let prevType = \"direct\";\n if (prevLocation) {\n try {\n const prevHost = new URL(prevLocation).hostname;\n prevType = prevHost === pageDomain ? \"internal\" : \"external\";\n } catch {\n prevType = \"external\";\n }\n }\n\n return {\n pageDomain: pageDomain,\n pageUrl: pageLocation,\n pagePath: pagePath,\n pageTitle: pageTitle,\n referrerUrl: prevLocation ? this._normalizeUrl(prevLocation) : prevLocation,\n referrerType: prevType,\n };\n }\n\n _pageViewInfo() {\n const KEY_LAST = \"twinalyze_last_page_location\";\n const KEY_COUNT = \"twinalyze_page_counter\";\n const KEY_LAST_COUNTED = \"twinalyze_last_counted_path\"; // ✅ new\n\n const ctx = this._pageContext(); // uses current location + previous page\n\n const currentKey = ctx.pagePath; // ✅ count only on path change\n // If you want count only on full URL change, use: const currentKey = ctx.pageUrl;\n\n const lastCounted = sessionStorage.getItem(KEY_LAST_COUNTED);\n\n // If same page refreshed -> DO NOT increment\n let pageCounter = parseInt(sessionStorage.getItem(KEY_COUNT) || \"0\", 10);\n if (Number.isNaN(pageCounter)) pageCounter = 0;\n\n if (lastCounted !== currentKey) {\n pageCounter += 1;\n sessionStorage.setItem(KEY_COUNT, String(pageCounter));\n sessionStorage.setItem(KEY_LAST_COUNTED, currentKey);\n } else {\n // keep same counter\n sessionStorage.setItem(KEY_COUNT, String(pageCounter));\n }\n\n // update last page location (for prev page logic)\n sessionStorage.setItem(KEY_LAST, ctx.pageUrl);\n\n return {\n pageCount: pageCounter,\n ...ctx,\n };\n }\n\n _saveUnsentEvents() {\n try {\n const unsent = [\n ...this.pendingEvents,\n ...this.batchQueue\n ];\n if (unsent.length > 0) {\n localStorage.setItem(\"twinalyze_unsent_events\", JSON.stringify(unsent));\n } else {\n localStorage.removeItem(\"twinalyze_unsent_events\");\n }\n } catch (e) {\n if (this.cfg?.debug) console.log(\"[Twinalyze] Error saving unsent events:\", e);\n }\n }\n\n _loadAndSendUnsentEvents() {\n try {\n const stored = localStorage.getItem(\"twinalyze_unsent_events\");\n if (stored) {\n const events = JSON.parse(stored);\n localStorage.removeItem(\"twinalyze_unsent_events\");\n if (Array.isArray(events) && events.length > 0) {\n if (this.cfg?.debug) console.log(`[Twinalyze] Loaded ${events.length} unsent events from localStorage`);\n events.forEach(e => {\n if (this.sessionReady) {\n this._emitEventAdd(e.eventName, e.properties || {}, e.eventType || \"auto\");\n } else {\n this.pendingEvents.push(e);\n }\n });\n }\n }\n } catch (e) {\n if (this.cfg?.debug) console.log(\"[Twinalyze] Error loading unsent events:\", e);\n }\n }\n\n _setupVisibilityAndUnloadHandlers() {\n const flushAndSave = () => {\n if (this.cfg?.debug) console.log(\"[Twinalyze] Visibility changed or page hiding. Flushing events...\");\n\n const wasReady = this.sessionReady;\n if (!this.sessionReady && this.pendingEvents.length > 0) {\n if (this.cfg?.debug) console.log(\"[Twinalyze] Force flushing pending events on unload...\");\n const items = this.pendingEvents.splice(0, this.pendingEvents.length);\n items.forEach((e) => {\n if (this._indexKey == null) this._initIndexId();\n const indexId = this._nextIndexId();\n this.batchQueue.push({\n uniqueSessionId: this.sessionId,\n date: new Date(e.ts || Date.now()).toISOString(),\n eventType: e.eventType || \"auto\",\n eventName: e.eventName,\n properties: { ...e.properties, eventName: e.eventName },\n indexId: indexId,\n source: this.cfg.source\n });\n });\n this.sessionReady = true;\n }\n\n if (this.batchQueue.length > 0) {\n this._flushBatchQueue();\n }\n\n if (!wasReady) {\n this.sessionReady = wasReady;\n }\n\n this._saveUnsentEvents();\n };\n\n document.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n flushAndSave();\n }\n });\n\n window.addEventListener(\"pagehide\", () => {\n flushAndSave();\n });\n }\n}\n\nconst _instance = new TwinalyzeAnalyticsImpl();\n\nconst PUBLIC_METHODS = [\n \"init\",\n \"track\"\n];\n\nconst TwinalyzeAnalytics = Object.fromEntries(\n PUBLIC_METHODS.map((m) => [m, _instance[m].bind(_instance)])\n);\nexport { TwinalyzeAnalytics };\nexport default TwinalyzeAnalytics;"],"mappings":"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","names":["CryptoJS","html2canvas","UAParserPkg","UAParser","uuid","cryptoRandomNonce","c","r","stableStringify","obj","k","TwinalyzeAnalyticsImpl","cfg","_a","_b","_c","resolvedBaseUrl","normalizedBaseUrl","DEFAULT_SCREEN_ACTIVITY","sa","startKey","eventName","properties","initRes","data","identifyPayload","identifyRes","e","endpoint","payloadObj","url","nonce","timestamp","bodyStr","canonicalBody","bodyHash","baseString","SECRET_KEY","signature","headers","err","imgs","img","res","isViewport","scale","canvas","doc","style","maxW","ratio","c2","resolve","now","throttleMs","blob","fd","eventType","indexId","eventObj","batch","payload","name","props","em","pv","fire","pv2","_push","_replace","args","scrollTop","scrollHeight","percent","hit","el","tag","text","href","started","form","exts","x","a","clean","ext","params","usp","key","term","aria","title","txt","parts","node","depth","part","cls","path","start","closest","sel","btn","menuItem","interactive","_d","_e","_f","_g","ua","conn","urlStr","newParams","campaignKeys","val","normalizedUrlStr","get","nf","old","id","KEY_LAST","pageLocation","pageDomain","pagePath","pageTitle","prevLocation","prevType","KEY_COUNT","KEY_LAST_COUNTED","ctx","currentKey","lastCounted","pageCounter","unsent","stored","events","flushAndSave","wasReady","_instance","PUBLIC_METHODS","TwinalyzeAnalytics","m","src_default","TwinalyzeAnalytics"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.js"],"sourcesContent":["import CryptoJS from \"crypto-js\";\nimport html2canvas from \"html2canvas\";\n// import UAParser from \"ua-parser-js\";\nimport * as UAParserPkg from \"ua-parser-js\";\nconst UAParser = UAParserPkg.UAParser;\n\nfunction uuid() {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID)\n return crypto.randomUUID();\n return Math.random().toString(16).slice(2) + Date.now().toString(16);\n}\n\nconst cryptoRandomNonce = () => {\n // simple uuid-like nonce (ok for test)\n return \"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\nconst stableStringify = (obj) => {\n if (obj === null || typeof obj !== \"object\") return JSON.stringify(obj);\n if (Array.isArray(obj)) return \"[\" + obj.map(stableStringify).join(\",\") + \"]\";\n const keys = Object.keys(obj)\n .filter((k) => obj[k] !== undefined)\n .sort();\n return (\n \"{\" +\n keys\n .map((k) => JSON.stringify(k) + \":\" + stableStringify(obj[k]))\n .join(\",\") +\n \"}\"\n );\n};\n\nclass TwinalyzeAnalyticsImpl {\n constructor() {\n this.cfg = null;\n\n this.deviceId = null;\n this.sessionId = null; // uniqueSessionId (client generated)\n this.sessionStartTime = null; // persistent session start timestamp\n\n this.sessionReady = false; // sessionCreate done\n this._booting = false; // handshake in progress\n this._disabled = false; // STOP state\n\n this.pendingEvents = []; // queued until sessionReady\n this.batchQueue = []; // queued for batch events upload\n this.scrollFired = false;\n\n this._initialized = false;\n this._flushTimer = null;\n\n this.indexId = 0;\n this._indexKey = null;\n\n this._lastShotAt = 0;\n this._shotInFlight = false;\n\n this.batchConfig = {\n eventsBatchSize: 10,\n flushIntervalMs: 5000,\n sessionTimeout: 300000,\n };\n }\n\n // Function for pacakage name -it will only get us subdomain and domain name\n _getAppPackageName() {\n try {\n // Preserve subdomain, remove path/query/protocol\n return window.location.hostname.replace(/^www\\./i, \"\").toLowerCase();\n } catch {\n return \"unknown\";\n }\n }\n\n // Function for getting app_language and device_language before \"-\" from fetched version\n _getLanguageCode(lang) {\n if (!lang) return \"not_found\";\n return lang.split(\"-\")[0].toLowerCase();\n }\n\n //check if it is bot\n _isLikelyBot() {\n try {\n const userAgent = navigator.userAgent || \"\";\n\n \n const botRegex =\n /bot|crawler|spider|crawling|googlebot|bingbot|yandexbot|duckduckbot|baiduspider|facebookexternalhit|twitterbot|linkedinbot|whatsapp|telegrambot|pinterest|ahrefs|semrush|mj12bot|dotbot|petalbot|bytespider|gptbot|ccbot|claudebot|perplexitybot|headlesschrome|puppeteer|playwright|phantomjs|lighthouse|pagespeed|gtmetrix|pingdom/i;\n\n // If userAgent missing, treat as suspicious\n if (!userAgent) return true;\n\n // Example: Googlebot/2.1 will match here\n if (botRegex.test(userAgent)) return true;\n\n // Automation browsers\n if (navigator.webdriver === true) return true;\n\n return false;\n } catch (error) {\n return false;\n }\n}\n\n // -------------------------\n // PUBLIC API\n // -------------------------\n init(cfg) {\n if (typeof window === \"undefined\") return;\n if (this._initialized) return; // strict-mode safe\n this._initialized = true;\n\n const resolvedBaseUrl =\n cfg.apiBaseUrl ||\n cfg.endpoint ||\n cfg.socketUrl ||\n \"https://api.twinalyze.com\";\n const normalizedBaseUrl = resolvedBaseUrl.endsWith(\"/\")\n ? resolvedBaseUrl.slice(0, -1)\n : resolvedBaseUrl;\n\n const DEFAULT_SCREEN_ACTIVITY = {\n enabled: false,\n apiUrl:\n cfg.screenActivity?.apiUrl ??\n `${normalizedBaseUrl}/api/app/screenActivity/screenActivityDetails_post`,\n captureOn: [\n \"pageView\",\n \"elementClick\",\n \"formStart\",\n \"formSubmit\",\n \"scrollDepth\",\n \"searchResultsView\",\n \"customEvent\",\n ],\n throttleMs: 2000,\n jpegQuality: 0.7,\n };\n\n // support: screenshots: true OR screenActivity: true OR screenActivity: { ... }\n const sa =\n typeof cfg.screenActivity === \"object\"\n ? { ...DEFAULT_SCREEN_ACTIVITY, ...cfg.screenActivity }\n : { ...DEFAULT_SCREEN_ACTIVITY };\n\n this.cfg = {\n apiKey: cfg.apiKey,\n secretKey: cfg.secretKey,\n version: cfg.version,\n apiBaseUrl: normalizedBaseUrl,\n\n debug: cfg.debug !== false, // default true in debug builds\n\n // encryption\n encrypt: cfg.encrypt !== false,\n\n // session id from client side\n persistSession: cfg.persistSession !== false, // default true (sessionStorage)\n sessionKey: \"twinalyze_session_id\",\n\n // eventAdd fields\n source: cfg.source || \"web\",\n indexId: cfg.indexId ?? null,\n\n // auto tracking options\n enhancedMeasurement: {\n pageViews: true,\n scrolls: true,\n outboundClicks: true,\n siteSearch: { params: [\"q\", \"s\", \"search\", \"query\"] },\n formInteractions: true,\n fileDownloads: {\n extensions: [\n \"pdf\",\n \"zip\",\n \"apk\",\n \"doc\",\n \"docx\",\n \"xls\",\n \"xlsx\",\n \"ppt\",\n \"pptx\",\n ],\n },\n ...(cfg.enhancedMeasurement || {}),\n },\n screenActivity: sa,\n };\n\n if (!this.cfg.apiKey) {\n console.log(\"[Twinalyze] ❌ Missing apiKey\");\n return;\n }\n // Stop bot before creating deviceId/session or sending API request\n if (this._isLikelyBot()) {\n this._disabled = true;\n this.sessionReady = false;\n this.pendingEvents = [];\n this.batchQueue = [];\n\n if (this.cfg?.debug) {\n console.log(\"[Twinalyze] 🤖 Bot detected. SDK stopped.\", {\n userAgent: navigator.userAgent,\n webdriver: navigator.webdriver === true,\n });\n }\n\n return;\n }\n\n\n\n this.deviceId = this._getOrCreateDeviceId();\n\n const startKey = \"twinalyze_session_start_time\";\n if (this.cfg.persistSession) {\n this.sessionId = sessionStorage.getItem(this.cfg.sessionKey) || null;\n this.sessionStartTime = sessionStorage.getItem(startKey) || null;\n }\n if (!this.sessionId) {\n this.sessionId = `sess_${uuid()}`;\n this.sessionStartTime = new Date().toISOString();\n if (this.cfg.persistSession) {\n sessionStorage.setItem(this.cfg.sessionKey, this.sessionId);\n sessionStorage.setItem(startKey, this.sessionStartTime);\n }\n } else if (!this.sessionStartTime) {\n this.sessionStartTime = new Date().toISOString();\n if (this.cfg.persistSession) {\n sessionStorage.setItem(startKey, this.sessionStartTime);\n }\n }\n\n this._setupEnhancedMeasurement();\n this._loadAndSendUnsentEvents();\n this._setupVisibilityAndUnloadHandlers();\n this._startFlow();\n }\n\n // custom event (web dev only uses this)\n track(eventName, properties = {}) {\n if (this._disabled) return;\n if (this.cfg && this.cfg.manualEventStatus === false) return;\n\n if (this.cfg?.debug)\n console.log(\"[Twinalyze][CUSTOM]\", eventName, properties);\n\n if (!this.sessionReady) {\n this.pendingEvents.push({\n eventName,\n properties: { ...this._pageContext(), ...properties },\n ts: Date.now(),\n eventType: \"manual\",\n });\n return;\n }\n\n this._emitEventAdd(\n eventName,\n { ...this._pageContext(), ...properties },\n \"manual\",\n );\n }\n\n // -------------------------\n // -------------------------\n // REST API FLOW\n // -------------------------\n async _startFlow() {\n if (this._disabled) return;\n if (this._booting) return;\n this._booting = true;\n\n try {\n // 1. Init API\n const initRes = await this._fetchApi(\"/api/web/sdk/init\", {});\n if (this.cfg.debug)\n console.log(\"[Twinalyze][FLOW] initRes: HAR HAR MAHADEV\", initRes);\n\n if (!initRes || initRes.success === false) {\n this._disabled = true;\n this.sessionReady = false;\n this.cfg.screenActivity.enabled = false;\n if (this.cfg.debug)\n console.log(\"[Twinalyze][FLOW] 🛑 STOP (init failed)\");\n return;\n }\n\n const data = initRes.data || {};\n\n // this.cfg.screenActivity.enabled = !!data.debugScreenshotCapture; //stopped screenshot\n this.cfg.screenActivity.enabled = false; // stops screenstop even if backend sends true\n\n if (data.eventData) {\n this.cfg.autoEventStatus = data.eventData.autoEventStatus !== false;\n this.cfg.manualEventStatus = data.eventData.manualEventStatus !== false;\n } else {\n this.cfg.autoEventStatus = true;\n this.cfg.manualEventStatus = true;\n }\n\n if (data.eventsBatchConfig) {\n this.batchConfig = {\n eventsBatchSize: data.eventsBatchConfig.eventsBatchSize || 10,\n flushIntervalMs: data.eventsBatchConfig.flushIntervalMs || 5000,\n sessionTimeout: data.eventsBatchConfig.sessionTimeout || 300000,\n };\n }\n\n this._initIndexId();\n\n // 2. Identify API\n const identifyPayload = {\n properties: this._userProperties(),\n deviceProperties: this._deviceProperties(),\n };\n\n const identifyRes = await this._fetchApi(\n \"/api/web/sdk/identify\",\n identifyPayload,\n );\n if (this.cfg.debug)\n console.log(\"[Twinalyze][FLOW] identifyRes:\", identifyRes);\n\n if (!identifyRes || identifyRes.success === false) {\n this._disabled = true;\n this.sessionReady = false;\n if (this.cfg.debug)\n console.log(\"[Twinalyze][FLOW] 🛑 STOP (identify failed)\");\n return;\n }\n\n // Mark ready\n this.sessionReady = true;\n\n // Flush queued auto/custom events (move from pendingEvents to batchQueue)\n if (this.pendingEvents.length > 0) {\n const items = this.pendingEvents.splice(0, this.pendingEvents.length);\n items.forEach((e) =>\n this._emitEventAdd(\n e.eventName,\n e.properties || {},\n e.eventType || \"auto\",\n ),\n );\n }\n } finally {\n this._booting = false;\n }\n }\n\n async _fetchApi(endpoint, payloadObj) {\n\n\n if (this._disabled || this._isLikelyBot()) {\n if (this.cfg?.debug) {\n console.log(\"[Twinalyze][API] skipped because bot/disabled\", endpoint);\n }\n return null;\n }\n\n const url = `${this.cfg.apiBaseUrl}${endpoint}`;\n\n const nonce = cryptoRandomNonce();\n const timestamp = new Date().toISOString();\n const bodyStr = payloadObj ? JSON.stringify(payloadObj) : \"{}\";\n\n const canonicalBody = stableStringify(JSON.parse(bodyStr));\n const bodyHash = CryptoJS.SHA256(canonicalBody).toString(CryptoJS.enc.Hex);\n\n const method = \"POST\";\n const baseString = [\n method,\n endpoint,\n timestamp,\n nonce,\n this.deviceId,\n bodyHash,\n ].join(\"\\n\");\n\n // Generate HMAC-SHA256 signature using secret key from config\n const SECRET_KEY = this.cfg.secretKey || \"\";\n const signature = CryptoJS.HmacSHA256(baseString, SECRET_KEY).toString(\n CryptoJS.enc.Hex,\n );\n\n if (this.cfg.debug) {\n console.log(\"[Twinalyze][API] Request signing trace:\", {\n endpoint,\n nonce,\n timestamp,\n canonicalBody,\n bodyHash,\n baseString,\n signature,\n });\n }\n\n const headers = {\n \"Content-Type\": \"application/json\",\n \"x-deviceId\": this.deviceId,\n \"x-api-key\": this.cfg.apiKey,\n \"x-analytics-sdk-version\": this.cfg.version || \"1.0.0\",\n \"x-ad-analytics-sdk-version\": \"\",\n // \"x-app-package-name\": window.location.href,\n \"x-app-package-name\": this._getAppPackageName(),\n \"x-platform\": \"javascript\",\n \"x-app-version-name\": \"1.0.0\",\n \"x-app-version-mode\": this.cfg.debug ? \"debug\" : \"release\",\n \"x-sdk-version\": \"latest\",\n \"x-timestamp\": timestamp,\n \"x-nonce\": nonce,\n \"x-signature\": signature,\n };\n\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers,\n body: bodyStr,\n keepalive: true,\n });\n return await res.json();\n } catch (err) {\n if (this.cfg.debug)\n console.log(`[Twinalyze][API] Error calling ${endpoint}:`, err);\n return null;\n }\n }\n\n async _waitForRenderStable() {\n // 2 frames\n await new Promise((r) =>\n requestAnimationFrame(() => requestAnimationFrame(r)),\n );\n\n // fonts\n try {\n if (document.fonts?.ready) await document.fonts.ready;\n } catch {}\n\n // images\n const imgs = Array.from(document.images || []).filter(\n (img) => !img.complete,\n );\n await Promise.allSettled(\n imgs.map(\n (img) =>\n new Promise((res) => {\n img.addEventListener(\"load\", res, { once: true });\n img.addEventListener(\"error\", res, { once: true });\n }),\n ),\n );\n }\n\n async _captureViewportJpegBlob() {\n await this._waitForRenderStable();\n\n const isViewport =\n (this.cfg.screenActivity?.capture || \"viewport\") === \"viewport\";\n const scale = Math.min(2, window.devicePixelRatio || 1);\n\n const canvas = await html2canvas(document.documentElement, {\n useCORS: true,\n allowTaint: false,\n backgroundColor: \"#ffffff\",\n logging: false,\n\n ...(isViewport\n ? {\n x: window.scrollX,\n y: window.scrollY,\n width: window.innerWidth,\n height: window.innerHeight,\n }\n : {\n x: 0,\n y: 0,\n width: document.documentElement.scrollWidth,\n height: document.documentElement.scrollHeight,\n }),\n\n scale,\n onclone: (doc) => {\n const style = doc.createElement(\"style\");\n style.textContent = `\n * { animation: none !important; transition: none !important; caret-color: transparent !important; }\n `;\n doc.head.appendChild(style);\n },\n });\n\n // downscale big screenshots (optional but helpful)\n const maxW = this.cfg.screenActivity?.maxWidth ?? 1280;\n if (canvas.width > maxW) {\n const ratio = maxW / canvas.width;\n const c2 = document.createElement(\"canvas\");\n c2.width = Math.round(canvas.width * ratio);\n c2.height = Math.round(canvas.height * ratio);\n c2.getContext(\"2d\").drawImage(canvas, 0, 0, c2.width, c2.height);\n return await new Promise((resolve) =>\n c2.toBlob(\n resolve,\n \"image/jpeg\",\n this.cfg.screenActivity?.jpegQuality ?? 0.7,\n ),\n );\n }\n\n return await new Promise((resolve) =>\n canvas.toBlob(\n resolve,\n \"image/jpeg\",\n this.cfg.screenActivity?.jpegQuality ?? 0.7,\n ),\n );\n }\n\n async _uploadScreenActivity({ eventName, properties }) {\n if (!this.cfg.screenActivity?.enabled) return;\n if (!this.sessionReady) return;\n\n const now = Date.now();\n const throttleMs = this.cfg.screenActivity?.throttleMs ?? 2000;\n if (now - this._lastShotAt < throttleMs) return;\n if (this._shotInFlight) return;\n\n this._shotInFlight = true;\n this._lastShotAt = now;\n\n try {\n const blob = await this._captureViewportJpegBlob();\n if (!blob) return;\n\n const fd = new FormData();\n fd.append(\"apiKey\", this.cfg.apiKey);\n fd.append(\"screenName\", document.title || \"unknown\");\n fd.append(\"identifier\", JSON.stringify(properties || {})); // ✅ you asked: identifier = properties object\n fd.append(\n \"appInfo\",\n JSON.stringify({\n appVersion: this.cfg.version || \"1.0.0\",\n platform: \"javascript\",\n }),\n );\n fd.append(\"description\", eventName || \"event\");\n fd.append(\"image\", blob, `shot_${Date.now()}.jpg`);\n\n const headers = {\n \"x-deviceId\": this.deviceId,\n \"x-api-key\": this.cfg.apiKey,\n \"x-analytics-sdk-version\": this.cfg.version || \"1.0.0\",\n \"x-ad-analytics-sdk-version\": \"\",\n // \"x-app-package-name\": window.location.href,\n \"x-app-package-name\": this._getAppPackageName(),\n \"x-platform\": \"javascript\",\n \"x-app-version-name\": \"1.0.0\",\n \"x-app-version-mode\": this.cfg.debug ? \"debug\" : \"release\",\n \"x-sdk-version\": \"latest\",\n };\n\n await fetch(this.cfg.screenActivity.apiUrl, {\n method: \"POST\",\n headers,\n body: fd,\n // keepalive: true, (commented because only 1 screenshot was coming and other were going in pending)\n });\n } catch (e) {\n if (this.cfg.debug)\n console.log(\"[Twinalyze][SCREENSHOT] error:\", e?.message || e);\n } finally {\n this._shotInFlight = false;\n }\n }\n\n // -------------------------\n // -------------------------\n // EMITS (REST API BATCHING)\n // -------------------------\n _emitEventAdd(eventName, properties = {}, eventType = \"auto\") {\n if (!this.sessionReady) return;\n\n this._checkSessionTimeoutBeforeEvent(); //function for session timeout check before emitting event and creating new session if needed\n\n if (this._indexKey == null) this._initIndexId();\n const indexId = this._nextIndexId();\n\n const eventObj = {\n uniqueSessionId: this.sessionId,\n date: new Date().toISOString(),\n eventType: eventType,\n eventName: eventName,\n properties: { eventName: eventName, ...properties }, //changed sequence so that eventName can be been first\n indexId: indexId,\n source: this.cfg.source,\n };\n\n // If this is the first event in a new batch, schedule a flush timer\n if (this.batchQueue.length === 0) {\n if (this._flushTimer) clearTimeout(this._flushTimer);\n this._flushTimer = setTimeout(\n () => this._flushBatchQueue(),\n this.batchConfig.flushIntervalMs,\n );\n }\n\n this.batchQueue.push(eventObj);\n\n // this._uploadScreenActivity({ eventName, properties }); // commented to stop screenshot\n\n if (this.cfg.debug)\n console.log(\"[Twinalyze][EVENT_QUEUED]\", eventName, properties, indexId);\n\n // Flush immediately if we hit the batch size limit\n if (this.batchQueue.length >= this.batchConfig.eventsBatchSize) {\n this._flushBatchQueue();\n }\n }\n\n async _flushBatchQueue() {\n // Clear any active timeout timer to prevent duplicate flushes\n if (this._flushTimer) {\n clearTimeout(this._flushTimer);\n this._flushTimer = null;\n }\n\n if (!this.sessionReady) return;\n if (!this.batchQueue.length) return;\n\n // slice to handle new events coming in while flushing\n const batch = this.batchQueue.splice(0, this.batchQueue.length);\n\n if (this.cfg.debug)\n console.log(`[Twinalyze][FLUSHING] ${batch.length} events...`);\n\n const payload = {\n eventsBatch: [\n {\n events: batch.map((e) => ({\n appInfo: {\n appVersion: this.cfg.version || \"1.0.0\",\n platform: \"javascript\",\n },\n date: e.date,\n eventName: e.eventName,\n eventType: e.eventType,\n indexId: e.indexId,\n properties: e.properties,\n })),\n startDate: this.sessionStartTime || batch[0].date,\n uniqueSessionId: this.sessionId,\n },\n ],\n };\n const res = await this._fetchApi(\"/api/web/sdk/eventsBatch\", payload);\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLUSH_RES]\", res);\n\n if (!res || res.success === false) {\n if (this.cfg.debug) console.log(\"[Twinalyze][FLUSH_FAIL] events dropped\");\n // Could re-queue here if desired: this.batchQueue.unshift(...batch);\n }\n }\n\n // -------------------------\n // AUTO EVENTS (GA-style)\n // -------------------------\n _trackAuto(name, props = {}) {\n if (this._disabled) return;\n if (this.cfg && this.cfg.autoEventStatus === false) return;\n if (this.cfg?.debug) console.log(\"[Twinalyze][AUTO]\", name, props);\n\n if (!this.sessionReady) {\n this.pendingEvents.push({\n eventName: name,\n properties: props,\n ts: Date.now(),\n eventType: \"auto\",\n });\n return;\n }\n\n this._emitEventAdd(name, props, \"auto\");\n }\n\n _setupEnhancedMeasurement() {\n const em = this.cfg.enhancedMeasurement || {};\n\n // pageView (normal + SPA)\n if (em.pageViews) {\n const pv = this._pageViewInfo();\n this._trackAuto(\"pageView\", pv);\n\n const fire = () => {\n this.scrollFired = false;\n const pv2 = this._pageViewInfo();\n this._trackAuto(\"pageView\", pv2);\n this._fireSiteSearch();\n };\n\n const _push = history.pushState;\n const _replace = history.replaceState;\n\n history.pushState = (...args) => {\n _push.apply(history, args);\n fire();\n };\n history.replaceState = (...args) => {\n _replace.apply(history, args);\n fire();\n };\n window.addEventListener(\"popstate\", fire);\n }\n\n // if user scrolls above 90% than event will come\n if (em.scrolls) {\n window.addEventListener(\n \"scroll\",\n () => {\n if (this.scrollFired) return;\n\n const doc = document.documentElement;\n const scrollTop = window.scrollY || doc.scrollTop;\n const scrollHeight = doc.scrollHeight - doc.clientHeight;\n if (scrollHeight <= 0) return;\n\n const percent = Math.round((scrollTop / scrollHeight) * 100);\n if (percent >= 90) {\n this.scrollFired = true;\n this._trackAuto(\"scrollDepth\", {\n scrollPercent: percent,\n ...this._pageContext(),\n });\n }\n },\n { passive: true },\n );\n }\n\n // // outbound clicks\n // if (em.outboundClicks) {\n // document.addEventListener(\"click\", (e) => {\n // const a = e.target && e.target.closest ? e.target.closest(\"a\") : null;\n // if (!a || !a.href) return;\n // if (/^(javascript:|mailto:|tel:)/i.test(a.href)) return;\n\n // let url;\n // try { url = new URL(a.href); } catch { return; }\n // if (url.hostname !== location.hostname) {\n // console.log(\"click\", { link_url: url.href, link_domain: url.hostname, outbound: true });\n // this._trackAuto(\"click\", { link_url: url.href, link_domain: url.hostname, outbound: true });\n // }\n // }, true);\n // }\n\n // clicks (links + buttons + dropdown items + generic interactive)\n if (em.outboundClicks) {\n document.addEventListener(\n \"click\",\n (e) => {\n const hit = this._getClickTarget(e);\n if (!hit) return;\n\n const el = hit.el;\n\n const tag = (el.tagName || \"\").toLowerCase();\n const text = this._getTextFromElement(el);\n\n const props = {\n clickType: hit.kind, // link | button | dropdown_item | interactive\n elementTag: tag,\n elementText: text || \"not_found\", // ✅ innerText/aria-label/title\n elementId: el.id || null,\n elementName: el.getAttribute?.(\"name\") || null,\n elementRole: el.getAttribute?.(\"role\") || null,\n /* elementClass:\n (el.className && typeof el.className === \"string\") ? el.className.slice(0, 120) : null,\n elementSelector: this._cssPath(el), */\n ...((this._pageContext && this._pageContext()) || {}), // if you added _pageContext().\n };\n\n // If link, enrich with URL + outbound\n if (hit.kind === \"link\") {\n const href = el.getAttribute(\"href\") || \"\";\n if (/^(javascript:|mailto:|tel:)/i.test(href)) return;\n\n let url;\n try {\n url = new URL(el.href);\n } catch {\n return;\n }\n\n props.linkUrl = url.href;\n props.linkDomain = url.hostname;\n props.linkPath = url.pathname;\n props.isExternalLink = url.hostname !== location.hostname; // changed name from isOutbound to isExternalLink\n }\n\n // Button details\n if (hit.kind === \"button\") {\n props.buttonType = el.getAttribute?.(\"type\") || null;\n props.disabled = !!el.disabled;\n }\n\n this._trackAuto(\"elementClick\", props);\n },\n true,\n );\n }\n\n // site search\n if (em.siteSearch) this._fireSiteSearch();\n\n // form interactions\n if (em.formInteractions) {\n const started = new WeakSet();\n\n document.addEventListener(\"focusin\", (e) => {\n const form =\n e.target && e.target.closest ? e.target.closest(\"form\") : null;\n if (!form || started.has(form)) return;\n started.add(form);\n\n this._trackAuto(\"formStart\", {\n formId: form.id || undefined,\n formName: form.getAttribute(\"name\") || undefined,\n formActionUrl: form.action || undefined,\n ...this._pageContext(),\n });\n });\n\n document.addEventListener(\n \"submit\",\n (e) => {\n const form = e.target;\n if (!form) return;\n\n this._trackAuto(\"formSubmit\", {\n formStatus: \"success\", // changed sequence\n formActionUrl: form.action || undefined,\n formDestinationUrl: location.href,\n formId: form.id || undefined,\n formName: form.getAttribute(\"name\") || undefined,\n ...this._pageContext(),\n });\n },\n true,\n );\n }\n\n // file downloads\n if (em.fileDownloads && em.fileDownloads.extensions) {\n const exts = em.fileDownloads.extensions.map((x) =>\n String(x).toLowerCase(),\n );\n\n document.addEventListener(\n \"click\",\n (e) => {\n const a = e.target && e.target.closest ? e.target.closest(\"a\") : null;\n if (!a || !a.href) return;\n\n const clean = a.href.split(\"?\")[0].toLowerCase();\n const ext = clean.split(\".\").pop() || \"\";\n if (!exts.includes(ext)) return;\n\n this._trackAuto(\"fileDownload\", {\n linkUrl: a.href,\n fileExtension: ext,\n fileName: clean.split(\"/\").pop(),\n ...this._pageContext(),\n });\n },\n true,\n );\n }\n }\n\n _fireSiteSearch() {\n const em = this.cfg.enhancedMeasurement || {};\n if (!em.siteSearch) return;\n\n const params = em.siteSearch.params || [\"q\", \"s\", \"search\", \"query\"];\n const usp = new URLSearchParams(location.search);\n const key = params.find((k) => usp.get(k));\n const term = key ? usp.get(key) : null;\n\n if (term && term.trim()) {\n this._trackAuto(\"searchResultsView\", {\n searchKey: key, //changed sequence\n searchTerm: term.trim(),\n searchUrl: location.href,\n ...this._pageContext(),\n });\n }\n }\n\n _getTextFromElement(el) {\n if (!el) return null;\n\n // common places (MUI/AntD often store label in aria-label)\n const aria = el.getAttribute?.(\"aria-label\");\n if (aria && aria.trim()) return aria.trim();\n\n const title = el.getAttribute?.(\"title\");\n if (title && title.trim()) return title.trim();\n\n // visible text\n const txt = (el.innerText || el.textContent || \"\").trim();\n if (!txt) return null;\n\n // limit length (avoid huge HTML)\n return txt.length > 80 ? txt.slice(0, 80) : txt;\n }\n\n _cssPath(el) {\n if (!el || !el.tagName) return null;\n const parts = [];\n let node = el;\n let depth = 0;\n while (node && node.nodeType === 1 && depth < 5) {\n let part = node.tagName.toLowerCase();\n if (node.id) {\n part += `#${node.id}`;\n parts.unshift(part);\n break;\n }\n const cls =\n node.className && typeof node.className === \"string\"\n ? node.className.trim().split(/\\s+/).slice(0, 2).join(\".\")\n : \"\";\n if (cls) part += `.${cls}`;\n parts.unshift(part);\n node = node.parentElement;\n depth++;\n }\n return parts.join(\" > \");\n }\n\n _getClickTarget(e) {\n // Shadow DOM safe path\n const path = typeof e.composedPath === \"function\" ? e.composedPath() : null;\n const start = path && path.length ? path[0] : e.target;\n\n const closest = (el, sel) => (el && el.closest ? el.closest(sel) : null);\n\n // 1) Links\n const a = closest(start, \"a[href]\");\n if (a) return { el: a, kind: \"link\" };\n\n // 2) Buttons + button-like\n const btn = closest(\n start,\n 'button, input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"], [role=\"button\"]',\n );\n if (btn) return { el: btn, kind: \"button\" };\n\n // 3) Menu / dropdown item (generic roles)\n const menuItem = closest(\n start,\n '[role=\"menuitem\"], [role=\"menuitemradio\"], [role=\"menuitemcheckbox\"], [role=\"option\"]',\n );\n if (menuItem) return { el: menuItem, kind: \"dropdown_item\" };\n\n // 4) Generic \"interactive\" fallback:\n // - role link\n // - tabindex (focusable)\n // - aria-haspopup (opens menu)\n // - contenteditable\n const interactive = closest(\n start,\n '[role=\"link\"], [tabindex]:not([tabindex=\"-1\"]), [aria-haspopup], [contenteditable=\"true\"]',\n );\n if (interactive) return { el: interactive, kind: \"interactive\" };\n\n return null;\n }\n\n // -------------------------\n // PROPERTIES (AUTO)\n // -------------------------\n // _deviceProperties() {\n // return {\n // ua: navigator.userAgent,\n // lang: navigator.language,\n // tz: Intl.DateTimeFormat().resolvedOptions().timeZone,\n // screen: { w: screen.width, h: screen.height },\n // viewport: { w: window.innerWidth, h: window.innerHeight },\n // dpr: window.devicePixelRatio || 1,\n // };\n // }\n\n _deviceProperties() {\n const parser = new UAParser(navigator.userAgent);\n const ua = parser.getResult();\n\n const conn =\n navigator.connection ||\n navigator.mozConnection ||\n navigator.webkitConnection;\n\n const screenMode = window.matchMedia?.(\"(prefers-color-scheme: dark)\")\n ?.matches\n ? \"dark\"\n : \"light\";\n\n return {\n // device/browser\n device_screen_mode: screenMode,\n is_data_on: navigator.onLine ? \"true\" : \"false\",\n screen_width: String(screen.width),\n screen_height: String(screen.height),\n viewport_width: String(window.innerWidth),\n viewport_height: String(window.innerHeight),\n color_depth: String(screen.colorDepth || \"not_found\"),\n browser_name: ua.browser?.name || \"not_found\",\n browser_version: ua.browser?.version || \"not_found\",\n os_name: ua.os?.name || \"not_found\",\n os_version: ua.os?.version || \"not_found\",\n // app_language: navigator.language || \"not_found\",\n app_language: this._getLanguageCode(navigator.language),\n cpu_cores:\n navigator.hardwareConcurrency != null\n ? String(navigator.hardwareConcurrency)\n : \"not_found\",\n touch_points:\n navigator.maxTouchPoints != null\n ? String(navigator.maxTouchPoints)\n : \"0\",\n network_type: conn?.effectiveType || \"not_found\",\n network_speed_mbps:\n conn?.downlink != null ? String(conn.downlink) : \"not_found\",\n network_latency_ms: conn?.rtt != null ? String(conn.rtt) : \"not_found\",\n data_saver_enabled:\n conn?.saveData != null ? String(conn.saveData) : \"not_found\",\n user_agent: navigator.userAgent,\n analytics_version: this.cfg?.version || \"not_found\",\n };\n }\n\n _normalizeUrl(urlStr) {\n if (!urlStr) return urlStr;\n try {\n const url = new URL(urlStr);\n const newParams = new URLSearchParams();\n const campaignKeys = [\"source\", \"medium\", \"campaign\", \"term\", \"content\"];\n for (const [key, val] of url.searchParams.entries()) {\n if (key.toLowerCase().startsWith(\"utm\")) {\n newParams.set(key.toLowerCase(), val);\n } else if (campaignKeys.includes(key.toLowerCase())) {\n newParams.set(\"utm_\" + key.toLowerCase(), val);\n } else {\n newParams.set(key, val);\n }\n }\n url.search = newParams.toString();\n return url.href;\n } catch (e) {\n return urlStr;\n }\n }\n\n // _userProperties() {\n // const parser = new UAParser(navigator.userAgent);\n // const ua = parser.getResult();\n\n // const normalizedUrlStr = this._normalizeUrl(location.href);\n // const url = new URL(normalizedUrlStr);\n // const usp = url.searchParams;\n\n // const get = (k) => usp.get(k);\n // const nf = \"not_found\";\n\n // return {\n // // From GSheet User Properties (Left Side) - Web Platform\n // device_type:\n // ua.device?.type ||\n // (matchMedia(\"(pointer:coarse)\").matches ? \"mobile\" : \"desktop\"),\n // density: String(window.devicePixelRatio || 1),\n // // timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone || \"not_found\", // commented because timezone is fetched by backend\n // ram:\n // navigator.deviceMemory != null\n // ? String(navigator.deviceMemory)\n // : \"not_found\",\n // // device_language: navigator.language || \"not_found\",\n // device_language: this._getLanguageCode(navigator.language),\n // // acquisition\n // landing_url: normalizedUrlStr,\n // utm_source: get(\"utm_source\") || nf,\n // utm_medium: get(\"utm_medium\") || nf,\n // utm_campaign: get(\"utm_campaign\") || nf,\n // utm_term: get(\"utm_term\") || nf,\n // utm_content: get(\"utm_content\") || nf,\n\n // // ads click ids\n // utm_gclid: get(\"gclid\") || nf,\n // utm_fbclid: get(\"fbclid\") || nf,\n // utm_msclkid: get(\"msclkid\") || nf,\n\n // // identity (optional, only if you have it)\n // // user_id: this.userId || nf,\n // // email: this.email || nf,\n // // plan: \"free\" / \"pro\" etc.\n // };\n // }\n\n // If Utm source not found then it will not be sent to backend. This is done to avoid sending not_found values to backend for utm params and ads click ids.\n\n _userProperties() {\n const parser = new UAParser(navigator.userAgent);\n const ua = parser.getResult();\n\n const normalizedUrlStr = this._normalizeUrl(location.href);\n const url = new URL(normalizedUrlStr);\n const usp = url.searchParams;\n\n const get = (k) => usp.get(k);\n\n const properties = {\n // From GSheet User Properties (Left Side) - Web Platform\n device_type:\n ua.device?.type ||\n (matchMedia(\"(pointer:coarse)\").matches ? \"mobile\" : \"desktop\"),\n\n density: String(window.devicePixelRatio || 1),\n\n // timeZone is fetched by backend\n ram:\n navigator.deviceMemory != null\n ? String(navigator.deviceMemory)\n : \"not_found\",\n\n device_language: this._getLanguageCode(navigator.language),\n\n // acquisition\n landing_url: normalizedUrlStr,\n };\n\n const addIfFound = (key, value) => {\n if (value !== null && value !== undefined && String(value).trim() !== \"\") {\n properties[key] = value;\n }\n };\n\n // UTM params - only send if found\n addIfFound(\"utm_source\", get(\"utm_source\"));\n addIfFound(\"utm_medium\", get(\"utm_medium\"));\n addIfFound(\"utm_campaign\", get(\"utm_campaign\"));\n addIfFound(\"utm_term\", get(\"utm_term\"));\n addIfFound(\"utm_content\", get(\"utm_content\"));\n\n // Ads click ids - only send if found\n addIfFound(\"utm_gclid\", get(\"gclid\"));\n addIfFound(\"utm_fbclid\", get(\"fbclid\"));\n addIfFound(\"utm_msclkid\", get(\"msclkid\"));\n\n return properties;\n}\n\n // -------------------------\n // IDs\n // -------------------------\n _initIndexId() {\n this._indexKey = `twinalyze_index_${this.sessionId}`;\n this.indexId = parseInt(sessionStorage.getItem(this._indexKey) || \"0\", 10);\n if (Number.isNaN(this.indexId)) this.indexId = 0;\n }\n\n _nextIndexId() {\n this.indexId += 1;\n if (this._indexKey) {\n sessionStorage.setItem(this._indexKey, String(this.indexId));\n }\n return this.indexId;\n }\n\n // added below section for session timeout and new session creation after idle time\n\n _getLastEventTime() {\n try {\n return parseInt(\n sessionStorage.getItem(\"twinalyze_last_event_time\") || \"0\",\n 10,\n );\n } catch {\n return 0;\n }\n }\n\n _setLastEventTime() {\n try {\n sessionStorage.setItem(\"twinalyze_last_event_time\", String(Date.now()));\n } catch {\n // ignore\n }\n }\n\n _createNewSessionAfterIdle() {\n const startKey = \"twinalyze_session_start_time\";\n\n this.sessionId = `sess_${uuid()}`;\n this.sessionStartTime = new Date().toISOString();\n\n if (this.cfg?.persistSession !== false) {\n sessionStorage.setItem(this.cfg.sessionKey, this.sessionId);\n sessionStorage.setItem(startKey, this.sessionStartTime);\n }\n\n // reset event index for new session\n this._indexKey = null;\n this.indexId = 0;\n this._initIndexId();\n\n if (this.cfg?.debug) {\n console.log(\n \"[Twinalyze][SESSION] New session created after idle:\",\n this.sessionId,\n );\n }\n }\n\n _checkSessionTimeoutBeforeEvent() {\n const lastEventTime = this._getLastEventTime();\n const timeout = this.batchConfig?.sessionTimeout || 300000;\n\n if (lastEventTime && Date.now() - lastEventTime > timeout) {\n this._createNewSessionAfterIdle();\n }\n\n this._setLastEventTime();\n }\n // added above section for sessiontime\n _getOrCreateDeviceId() {\n const key = \"twinalyze_device_id\";\n const old = localStorage.getItem(key);\n if (old) return old;\n\n const id = uuid();\n // const id = `dev_${uuid()}`;\n localStorage.setItem(key, id);\n return id;\n }\n\n _pageContext() {\n const KEY_LAST = \"twinalyze_last_page_location\";\n\n const pageTitle = document.title;\n const pageLocation = this._normalizeUrl(location.href);\n const pageDomain = location.hostname;\n const pagePath = location.pathname;\n\n const storedPrev = sessionStorage.getItem(KEY_LAST);\n const prevLocation = storedPrev || document.referrer || null;\n\n let prevType = \"direct\";\n if (prevLocation) {\n try {\n const prevHost = new URL(prevLocation).hostname;\n prevType = prevHost === pageDomain ? \"internal\" : \"external\";\n } catch {\n prevType = \"external\";\n }\n }\n\n return {\n pageTitle: pageTitle, //path changed from 4th to first position\n pageDomain: pageDomain,\n pageUrl: pageLocation,\n pagePath: pagePath,\n\n previousPageUrl: prevLocation\n ? this._normalizeUrl(prevLocation)\n : prevLocation, // PreviousName = referrerUrl\n previousPageType: prevType, // PreviousName = referrerType\n };\n }\n\n _pageViewInfo() {\n const KEY_LAST = \"twinalyze_last_page_location\";\n // const KEY_COUNT = \"twinalyze_page_counter\";\n // const KEY_LAST_COUNTED = \"twinalyze_last_counted_path\"; // ✅ new\n\n const ctx = this._pageContext(); // uses current location + previous page\n\n /*\n const currentKey = ctx.pagePath; // ✅ count only on path change\n // If you want count only on full URL change, use: const currentKey = ctx.pageUrl;\n\n const lastCounted = sessionStorage.getItem(KEY_LAST_COUNTED);\n\n // If same page refreshed -> DO NOT increment\n let pageCounter = parseInt(sessionStorage.getItem(KEY_COUNT) || \"0\", 10);\n if (Number.isNaN(pageCounter)) pageCounter = 0;\n\n if (lastCounted !== currentKey) {\n pageCounter += 1;\n sessionStorage.setItem(KEY_COUNT, String(pageCounter));\n sessionStorage.setItem(KEY_LAST_COUNTED, currentKey);\n } else {\n // keep same counter\n sessionStorage.setItem(KEY_COUNT, String(pageCounter));\n }\n*/\n // update last page location (for prev page logic)\n sessionStorage.setItem(KEY_LAST, ctx.pageUrl);\n\n return {\n // pageCount: pageCounter,\n ...ctx,\n };\n }\n\n _saveUnsentEvents() {\n try {\n const unsent = [...this.pendingEvents, ...this.batchQueue];\n if (unsent.length > 0) {\n localStorage.setItem(\"twinalyze_unsent_events\", JSON.stringify(unsent));\n } else {\n localStorage.removeItem(\"twinalyze_unsent_events\");\n }\n } catch (e) {\n if (this.cfg?.debug)\n console.log(\"[Twinalyze] Error saving unsent events:\", e);\n }\n }\n\n _loadAndSendUnsentEvents() {\n try {\n const stored = localStorage.getItem(\"twinalyze_unsent_events\");\n if (stored) {\n const events = JSON.parse(stored);\n localStorage.removeItem(\"twinalyze_unsent_events\");\n if (Array.isArray(events) && events.length > 0) {\n if (this.cfg?.debug)\n console.log(\n `[Twinalyze] Loaded ${events.length} unsent events from localStorage`,\n );\n events.forEach((e) => {\n if (this.sessionReady) {\n this._emitEventAdd(\n e.eventName,\n e.properties || {},\n e.eventType || \"auto\",\n );\n } else {\n this.pendingEvents.push(e);\n }\n });\n }\n }\n } catch (e) {\n if (this.cfg?.debug)\n console.log(\"[Twinalyze] Error loading unsent events:\", e);\n }\n }\n\n _setupVisibilityAndUnloadHandlers() {\n const flushAndSave = () => {\n if (this.cfg?.debug)\n console.log(\n \"[Twinalyze] Visibility changed or page hiding. Flushing events...\",\n );\n\n const wasReady = this.sessionReady;\n if (!this.sessionReady && this.pendingEvents.length > 0) {\n if (this.cfg?.debug)\n console.log(\"[Twinalyze] Force flushing pending events on unload...\");\n const items = this.pendingEvents.splice(0, this.pendingEvents.length);\n items.forEach((e) => {\n if (this._indexKey == null) this._initIndexId();\n const indexId = this._nextIndexId();\n this.batchQueue.push({\n uniqueSessionId: this.sessionId,\n date: new Date(e.ts || Date.now()).toISOString(),\n eventType: e.eventType || \"auto\",\n eventName: e.eventName,\n properties: { eventName: e.eventName, ...e.properties }, // changed sequence\n indexId: indexId,\n source: this.cfg.source,\n });\n });\n this.sessionReady = true;\n }\n\n if (this.batchQueue.length > 0) {\n this._flushBatchQueue();\n }\n\n if (!wasReady) {\n this.sessionReady = wasReady;\n }\n\n this._saveUnsentEvents();\n };\n\n document.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n flushAndSave();\n }\n });\n\n window.addEventListener(\"pagehide\", () => {\n flushAndSave();\n });\n }\n}\n\nconst _instance = new TwinalyzeAnalyticsImpl();\n\nconst PUBLIC_METHODS = [\"init\", \"track\"];\n\nconst TwinalyzeAnalytics = Object.fromEntries(\n PUBLIC_METHODS.map((m) => [m, _instance[m].bind(_instance)]),\n);\nexport { TwinalyzeAnalytics };\nexport default TwinalyzeAnalytics;\n"],"mappings":"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","names":["CryptoJS","html2canvas","UAParserPkg","UAParser","uuid","cryptoRandomNonce","c","r","stableStringify","obj","k","TwinalyzeAnalyticsImpl","lang","userAgent","botRegex","cfg","_a","_b","_c","_d","resolvedBaseUrl","normalizedBaseUrl","DEFAULT_SCREEN_ACTIVITY","sa","startKey","eventName","properties","initRes","data","identifyPayload","identifyRes","e","endpoint","payloadObj","url","nonce","timestamp","bodyStr","canonicalBody","bodyHash","baseString","SECRET_KEY","signature","headers","err","imgs","img","res","isViewport","scale","canvas","doc","style","maxW","ratio","c2","resolve","now","throttleMs","blob","fd","eventType","indexId","eventObj","batch","payload","name","props","em","pv","fire","pv2","_push","_replace","args","scrollTop","scrollHeight","percent","hit","el","tag","text","href","started","form","exts","x","a","clean","ext","params","usp","key","term","aria","title","txt","parts","node","depth","part","cls","path","start","closest","sel","btn","menuItem","interactive","_e","_f","_g","ua","conn","urlStr","newParams","campaignKeys","val","normalizedUrlStr","get","addIfFound","value","lastEventTime","timeout","old","id","KEY_LAST","pageTitle","pageLocation","pageDomain","pagePath","prevLocation","prevType","ctx","unsent","stored","events","flushAndSave","wasReady","_instance","PUBLIC_METHODS","TwinalyzeAnalytics","m","src_default","TwinalyzeAnalytics"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinalyze/web-analytics",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.19",
|
|
4
4
|
"description": "Twinalyze Web Analytics SDK for tracking events, sessions, users, and performance in modern web applications.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|