@twinalyze/web-analytics 1.0.11 → 1.0.13

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.js"],"sourcesContent":["import { io } from \"socket.io-client\";\nimport 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\nclass TwinalyzeAnalyticsImpl {\n constructor() {\n this.cfg = null;\n\n this.socket = null;\n this.socketReady = false;\n\n this.deviceId = null;\n this.sessionId = null; // uniqueSessionId (client generated)\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.scrollFired = false;\n\n this._initialized = false;\n\n this._sentSessionUpdate = false; // one-time\n this._sentUserUpdate = false; // one-time\n\n this.indexId = 0;\n this._indexKey = null;\n\n this._lastShotAt = 0;\n this._shotInFlight = false;\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 organization = cfg.organization || cfg.orgId;\n\n const DEFAULT_SCREEN_ACTIVITY = {\n enabled: false,\n apiUrl: cfg.screenActivity?.apiUrl ?? `${cfg.socketUrl}/api/app/screenActivity/screenActivityDetails_post`,\n captureOn: [\"page_view\", \"click\", \"form_start\", \"form_submit\", \"scroll\", \"view_search_results\", \"custom_event\"],\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 organization,\n socketUrl: \"https://api.twinalyze.com\",\n // socketUrl: \"http://192.168.1.26:3000\",\n\n debug: true,\n\n // encryption like Android (AES key = socket.id)\n encrypt: true, // default true\n\n // session id from client side\n persistSession: cfg.persistSession !== false, // default true (sessionStorage)\n sessionKey: \"twinalyze_session_id\",\n\n // server response event naming\n // we listen to multiple possible response events to be safe:\n // `${event}:res`, `${event}Res`, `${event}Response`, `${event}`\n responseSuffix: cfg.responseSuffix || \":res\",\n responseTimeoutMs: cfg.responseTimeoutMs || 15000,\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 apiBaseUrl: cfg.apiBaseUrl || cfg.endpoint || cfg.socketUrl, // http base for REST APIs\n screenActivity: sa,\n // screenActivity: {\n // enabled: cfg.screenActivity?.enabled ?? true,\n // apiUrl: cfg.screenActivity?.apiUrl ?? `${cfg.socketUrl}/api/app/screenActivity/screenActivityDetails_post`,\n // jpegQuality: cfg.screenActivity?.jpegQuality ?? 0.7,\n // throttleMs: cfg.screenActivity?.throttleMs ?? 2000, // don't screenshot every click instantly\n // capture: cfg.screenActivity?.capture ?? \"viewport\", // \"viewport\" | \"fullpage\"\n // maxWidth: cfg.screenActivity?.maxWidth ?? 1280, // reduce size\n // },\n };\n\n if (!this.cfg.apiKey || !this.cfg.organization) {\n console.log(\"[Twinalyze] ❌ Missing apiKey / organization / socketUrl\");\n return;\n }\n\n this.deviceId = this._getOrCreateDeviceId();\n\n if (this.cfg.persistSession) {\n this.sessionId = sessionStorage.getItem(this.cfg.sessionKey) || null;\n }\n\n this._connectSocket();\n this._setupEnhancedMeasurement();\n }\n\n // custom event (web dev only uses this)\n track(eventName, properties = {}) {\n if (this._disabled) 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: \"custom\" });\n return;\n }\n\n this._emitEventAdd(eventName, { ...this._pageContext(), ...properties }, \"custom\");\n }\n\n // -------------------------\n // SOCKET\n // -------------------------\n _connectSocket() {\n if (this.socket) return;\n\n const options = ({\n transports: [\"websocket\"], // Force WebSocket transport\n reconnection: true,\n reconnectionAttempts: Infinity, // Keep reconnecting indefinitely\n reconnectionDelay: 2000, // 2 seconds delay between reconnection attempts\n reconnectionDelayMax: 10000, // Max reconnection delay (10 seconds)\n timeout: 20000, // Connection timeout (20 seconds)\n path: \"/socket.io/\",\n auth: {\n \"x-api-key\": this.cfg.apiKey,\n \"x-organization-id\": this.cfg.organization,\n \"x-app-version-name\": this.cfg.appVersionName || \"not_found\",\n \"x-analytics-sdk-version\": this.cfg.analyticsSdkVersion || this.cfg.version || \"1.0.0\",\n \"x-ad-analytics-sdk-version\": this.cfg.adAnalyticsSdkVersion || \"not_found\",\n \"x-app-package-name\": this.cfg.appPackageName || location.hostname,\n \"x-platform\": \"web\",\n \"x-sdk-version\": this.cfg.version || \"1.0.0\",\n },\n extraHeaders: {\n \"Origin\": this.cfg.socketUrl,\n \"x-api-key\": this.cfg.apiKey,\n \"x-organization-id\": this.cfg.organization,\n \"x-app-version-name\": this.cfg.appVersionName || \"not_found\",\n \"x-analytics-sdk-version\": this.cfg.analyticsSdkVersion || this.cfg.version || \"1.0.0\",\n \"x-ad-analytics-sdk-version\": this.cfg.adAnalyticsSdkVersion || \"not_found\",\n \"x-app-package-name\": this.cfg.appPackageName || location.hostname,\n \"x-platform\": \"web\",\n \"x-sdk-version\": this.cfg.version || \"1.0.0\",\n },\n methods: [\"GET\", \"POST\"],\n })\n\n this.socket = io(this.cfg.socketUrl, options);\n\n this.socket.on(\"connect\", async () => {\n this.socketReady = true;\n\n if (this.cfg.debug) {\n console.log(\"[Twinalyze][SOCKET] ✅ connected CHANGED NEW 1\", {\n id: this.socket.id,\n transport: this.socket.io.engine.transport.name,\n });\n }\n\n await this._startFlow();\n });\n\n this.socket.on(\"disconnect\", (reason) => {\n this.socketReady = false;\n\n // on reconnect, flow should run again (sessionCreate + one-time updates)\n this.sessionReady = false;\n this._booting = false;\n this._sentSessionUpdate = false;\n this._sentUserUpdate = false;\n this._resetIndexId();\n\n if (this.cfg.debug) console.log(\"[Twinalyze][SOCKET] ❌ disconnected:\", reason);\n });\n\n this.socket.on(\"connect_error\", (err) => {\n this.socketReady = false;\n if (this.cfg.debug) console.log(\"[Twinalyze][SOCKET] ❌ connect_error:\", err?.message || err);\n });\n\n // Listening to sdk_upgrade_warning\n this.socket.on(\"sdk_upgrade_warning\", (data) => {\n if (data && data.message) {\n console.log(\"SDK Upgrade Warning:\", data.message);\n\n // Show the upgrade message\n alert(data.message);\n\n // Optionally, check for updateUrl and redirect\n if (data.updateUrl) {\n const proceedToUpdate = confirm(\"A new SDK version is available. Do you want to upgrade now?\");\n\n if (proceedToUpdate) {\n window.location.href = data.updateUrl; // Redirect to the update page\n }\n }\n } else {\n console.error(\"Received invalid data in sdk_upgrade_warning event:\", data);\n }\n });\n\n // optional incoming debug\n // this.socket.onAny((event, ...args) => {\n // if (this.cfg.debug) console.log(\"[Twinalyze][IN]\", event, args);\n // });\n }\n\n _initIndexId() {\n // call only when sessionId is available\n this._indexKey = `twinalyze_event_index_${this.sessionId}`;\n\n // always start from 0 for new session\n // if you want resume on refresh within same session, load from sessionStorage\n const stored = sessionStorage.getItem(this._indexKey);\n this.indexId = stored ? parseInt(stored, 10) : 0;\n if (Number.isNaN(this.indexId)) this.indexId = 0;\n }\n\n _nextIndexId() {\n const id = this.indexId;\n this.indexId += 1;\n\n if (this._indexKey) {\n sessionStorage.setItem(this._indexKey, String(this.indexId));\n }\n return id; // ✅ return current id then increment\n }\n\n _resetIndexId() {\n this.indexId = 0;\n if (this._indexKey) sessionStorage.removeItem(this._indexKey);\n this._indexKey = null;\n }\n\n _normalizeHttpBase(url) {\n return String(url || \"\")\n .replace(/^ws:\\/\\//, \"http://\")\n .replace(/^wss:\\/\\//, \"https://\")\n .replace(/\\/$/, \"\");\n }\n\n // -------------------------\n // YOUR EXACT FLOW\n // -------------------------\n async _startFlow() {\n if (this._disabled) return;\n if (!this.socketReady) return;\n if (this._booting) return;\n\n this._booting = true;\n\n try {\n // 1) user|userCheckApp { apiKey, organization }\n const checkRes = await this._request(\"user|userCheckApp\", {\n apiKey: this.cfg.apiKey,\n organization: this.cfg.organization,\n });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] userCheckRes:\", checkRes);\n\n // STOP condition:\n // \"if success true and status 0 then next else STOP\"\n const ok =\n checkRes &&\n checkRes.success === true &&\n (checkRes.status === 0 || checkRes.status === \"0\");\n\n const serverScreenshot = !!checkRes?.debugScreenshotCapture;\n this.cfg.screenActivity.enabled = serverScreenshot;\n\n if (!ok) {\n this._disabled = true;\n this.sessionReady = false;\n this.cfg.screenActivity.enabled = false;\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] 🛑 STOP (userCheck failed)\");\n return;\n }\n\n // 2) user|userExistsApp { apiKey, deviceId, organization }\n const existsRes = await this._request(\"user|userExistsApp\", {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n organization: this.cfg.organization,\n });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] userExistsRes:\", existsRes);\n\n // your diagram says: if success===true => user exists\n const userExists = !!(existsRes && (existsRes.success === true) && (existsRes.userRegister === true));\n\n // 3) if user not exists => user|web|userCreateApp { apiKey, deviceId, properties, organization }\n if (!userExists) {\n const createRes = await this._request(\"user|web|userCreateApp\", {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n properties: this._userProperties(),\n organization: this.cfg.organization,\n });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] userCreateRes:\", createRes);\n\n // if backend returns explicit failure, stop\n if (createRes && createRes.success === false) {\n this._disabled = true;\n this.sessionReady = false;\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] 🛑 STOP (userCreate failed)\");\n return;\n }\n }\n\n // 4) create session id from client (your requirement)\n if (!this.sessionId) {\n this.sessionId = `sess_${uuid()}`;\n if (this.cfg.persistSession) {\n sessionStorage.setItem(this.cfg.sessionKey, this.sessionId);\n }\n }\n\n // 5) session|web|sessionCreateApp\n // { apiKey, deviceId, socketId, uniqueSessionId, deviceProperties, organization }\n const sessionRes = await this._request(\"session|web|sessionCreateApp\", {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n socketId: this.socket.id,\n uniqueSessionId: this.sessionId,\n deviceProperties: this._deviceProperties(),\n organization: this.cfg.organization,\n });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] sessionCreateRes:\", sessionRes);\n\n if (sessionRes && sessionRes.success === false) {\n this._disabled = true;\n this.sessionReady = false;\n return;\n }\n\n // Mark ready even if backend doesn't return anything useful\n this.sessionReady = true;\n this._initIndexId();\n\n // // 6) one-time updates (exact payloads)\n // this._emitSessionUpdateOnce();\n // this._emitUserUpdateOnce();\n\n // 7) flush queued auto/custom events\n this._flushPendingEvents();\n } finally {\n this._booting = false;\n }\n }\n\n // -------------------------\n // REQUEST/RESPONSE (NO ACK)\n // waits for server response event using \"on/once\"\n // -------------------------\n _request(eventName, payloadObj) {\n const timeoutMs = this.cfg.responseTimeoutMs;\n\n const candidates = [];\n const suffix = this.cfg.responseSuffix;\n\n // Try multiple common response event names (so you don’t have to guess)\n candidates.push(`${eventName}${suffix}`); // user|userCheckApp:res\n candidates.push(`${eventName}Res`); // user|userCheckAppRes\n candidates.push(`${eventName}Response`); // user|userCheckAppResponse\n candidates.push(eventName); // same event name as response (some backends do this)\n\n // unique\n const resEvents = [...new Set(candidates)];\n\n return new Promise((resolve) => {\n if (!this.socketReady) return resolve(null);\n\n let done = false;\n\n const cleanup = () => {\n resEvents.forEach((ev) => this.socket.off(ev, onRes));\n clearTimeout(timer);\n };\n\n const onRes = (res) => {\n if (done) return;\n done = true;\n cleanup();\n resolve(res);\n };\n\n // IMPORTANT: register listeners before emit (so we don't miss fast responses)\n resEvents.forEach((ev) => this.socket.on(ev, onRes));\n\n const timer = setTimeout(() => {\n if (done) return;\n done = true;\n cleanup();\n resolve(null);\n }, timeoutMs);\n\n const sendData = this.cfg.encrypt ? this._encrypt(payloadObj) : payloadObj;\n this.socket.emit(eventName, sendData);\n });\n }\n\n _encrypt(obj) {\n const CRYPTOJS_SECRET_KEY = \"3Xn8vQp2Lm9sAa7ZkT1yCw5eR0uH6dJ4\"\n // AES key = socket.id (matches your Android/backend style)\n return CryptoJS.AES.encrypt(JSON.stringify(obj), CRYPTOJS_SECRET_KEY).toString();\n // return CryptoJS.AES.encrypt(JSON.stringify(obj), this.socket.id).toString();\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(\"organization\", this.cfg.organization);\n fd.append(\"screenName\", document.title || \"unknown\");\n fd.append(\"identifier\", JSON.stringify(properties || {})); // ✅ you asked: identifier = properties object\n fd.append(\"description\", eventName || \"event\");\n fd.append(\"image\", blob, `shot_${Date.now()}.jpg`);\n\n await fetch(this.cfg.screenActivity.apiUrl, {\n method: \"POST\",\n body: fd,\n keepalive: true,\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 // EMITS (exact payloads you gave)\n // -------------------------\n _emitSessionUpdateOnce() {\n if (!this.sessionReady) return;\n if (this._sentSessionUpdate) return;\n this._sentSessionUpdate = true;\n\n const payload = {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n deviceProperties: this._deviceProperties(),\n organization: this.cfg.organization,\n };\n\n const sendData = this.cfg.encrypt ? this._encrypt(payload) : payload;\n this.socket.emit(\"session|sessionUpdateApp\", sendData);\n\n if (this.cfg.debug) console.log(\"[Twinalyze] ✅ sessionUpdate sent\");\n }\n\n _emitUserUpdateOnce() {\n if (!this.sessionReady) return;\n if (this._sentUserUpdate) return;\n this._sentUserUpdate = true;\n\n const payload = {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n properties: this._userProperties(),\n organization: this.cfg.organization,\n };\n\n const sendData = this.cfg.encrypt ? this._encrypt(payload) : payload;\n this.socket.emit(\"user|userUpdateApp\", sendData);\n\n if (this.cfg.debug) console.log(\"[Twinalyze] ✅ userUpdate sent\");\n }\n\n _emitEventAdd(eventName, properties = {}, eventType = \"auto\") {\n if (!this.sessionReady) return;\n\n // if session just got ready and index not set\n if (this._indexKey == null) this._initIndexId();\n const indexId = this._nextIndexId();\n\n const payload = {\n socketId: this.socket.id,\n date: new Date().toISOString(),\n eventType: eventType,\n uniqueSessionId: this.sessionId,\n deviceId: this.deviceId,\n eventName,\n properties: properties,\n apiKey: this.cfg.apiKey,\n source: this.cfg.source,\n // ✅ auto index\n indexId,\n organization: this.cfg.organization,\n };\n\n console.log(\"payload session|web|sessionEventAddApp\", payload);\n\n const sendData = this.cfg.encrypt ? this._encrypt(payload) : payload;\n this.socket.emit(\"session|web|sessionEventAddApp\", sendData);\n\n // this._maybeUploadScreenActivity(eventName, properties, indexId).catch(() => { });\n this._uploadScreenActivity({ eventName, properties });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][EVENT_ADD]\", eventName, properties, indexId);\n }\n\n _flushPendingEvents() {\n if (!this.sessionReady) return;\n if (!this.pendingEvents.length) return;\n\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 // -------------------------\n // AUTO EVENTS (GA-style)\n // -------------------------\n _trackAuto(name, props = {}) {\n if (this._disabled) 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 // page_view (normal + SPA)\n if (em.pageViews) {\n const pv = this._pageViewInfo();\n this._trackAuto(\"page_view\", pv);\n\n const fire = () => {\n this.scrollFired = false;\n const pv2 = this._pageViewInfo();\n this._trackAuto(\"page_view\", 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(\"scroll\", { percent_scrolled: 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 click_type: hit.kind, // link | button | dropdown_item | interactive\n element_tag: tag,\n element_text: text || \"not_found\", // ✅ innerText/aria-label/title\n element_id: el.id || null,\n element_name: el.getAttribute?.(\"name\") || null,\n element_role: el.getAttribute?.(\"role\") || null,\n element_classes:\n (el.className && typeof el.className === \"string\") ? el.className.slice(0, 120) : null,\n element_path: 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.link_url = url.href;\n props.link_domain = url.hostname;\n props.link_path = url.pathname;\n props.outbound = url.hostname !== location.hostname;\n }\n\n // Button details\n if (hit.kind === \"button\") {\n props.button_type = el.getAttribute?.(\"type\") || null;\n props.disabled = !!el.disabled;\n }\n\n this._trackAuto(\"click\", 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(\"form_start\", {\n form_id: form.id || undefined,\n form_name: form.getAttribute(\"name\") || undefined,\n form_action: 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(\"form_submit\", {\n form_id: form.id || undefined,\n form_name: form.getAttribute(\"name\") || undefined,\n form_action: form.action || undefined,\n form_destination: location.href,\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(\"file_download\", {\n link_url: a.href,\n file_extension: ext,\n file_name: clean.split(\"/\").pop(),\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(\"view_search_results\", {\n search_term: term.trim(),\n search_param: key,\n page_path: location.pathname,\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_type: ua.device?.type || (matchMedia(\"(pointer:coarse)\").matches ? \"mobile\" : \"desktop\"),\n os_name: ua.os?.name || \"not_found\",\n os_version: ua.os?.version || \"not_found\",\n browser_name: ua.browser?.name || \"not_found\",\n browser_version: ua.browser?.version || \"not_found\",\n\n // app/sdk\n sdk: \"web\",\n sdk_version: this.cfg?.version || \"not_found\",\n\n // screen\n device_screen_mode: screenMode,\n screen_w: String(screen.width),\n screen_h: String(screen.height),\n viewport_w: String(window.innerWidth),\n viewport_h: String(window.innerHeight),\n density: String(window.devicePixelRatio || 1),\n color_depth: String(screen.colorDepth || \"not_found\"),\n\n // system-ish\n device_language: navigator.language || \"not_found\",\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || \"not_found\",\n cores: navigator.hardwareConcurrency != null ? String(navigator.hardwareConcurrency) : \"not_found\",\n memory_gb: navigator.deviceMemory != null ? String(navigator.deviceMemory) : \"not_found\",\n touch_points: navigator.maxTouchPoints != null ? String(navigator.maxTouchPoints) : \"0\",\n\n // network (best-effort)\n is_data_on: navigator.onLine ? \"true\" : \"false\",\n connection_effective_type: conn?.effectiveType || \"not_found\",\n connection_downlink: conn?.downlink != null ? String(conn.downlink) : \"not_found\",\n connection_rtt: conn?.rtt != null ? String(conn.rtt) : \"not_found\",\n connection_save_data: conn?.saveData != null ? String(conn.saveData) : \"not_found\",\n\n // raw\n user_agent: navigator.userAgent,\n };\n }\n\n _userProperties() {\n const url = new URL(location.href);\n const usp = url.searchParams;\n\n const get = (k) => usp.get(k);\n const nf = \"not_found\";\n\n return {\n // acquisition\n landing_url: url.href,\n referrer: [\n {\n utm_source: get(\"utm_source\") || nf,\n },\n {\n utm_medium: get(\"utm_medium\") || nf,\n },\n {\n utm_campaign: get(\"utm_campaign\") || nf,\n },\n {\n utm_term: get(\"utm_term\") || nf,\n },\n {\n utm_content: get(\"utm_content\") || nf,\n }\n ],\n\n // ads click ids\n gclid: get(\"gclid\") || nf,\n fbclid: get(\"fbclid\") || nf,\n msclkid: get(\"msclkid\") || nf,\n\n // user preferences\n language_pref: navigator.language || 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 _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 = 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 page_domain: pageDomain,\n page_location: pageLocation,\n page_url: pageLocation,\n page_path: pagePath,\n page_title: pageTitle,\n previous_page_location: prevLocation,\n previous_page_type: prevType,\n };\n }\n\n // _pageViewInfo() {\n // const KEY_LAST = \"twinalyze_last_page_location\";\n // const KEY_COUNT = \"twinalyze_page_counter\";\n\n // const ctx = this._pageContext();\n\n // const prevCount = parseInt(sessionStorage.getItem(KEY_COUNT) || \"0\", 10);\n // const pageCounter = (Number.isNaN(prevCount) ? 0 : prevCount) + 1;\n\n // sessionStorage.setItem(KEY_COUNT, String(pageCounter));\n // sessionStorage.setItem(KEY_LAST, ctx.page_location);\n\n // return {\n // page_counter: pageCounter,\n // ...ctx,\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.page_path; // ✅ count only on path change\n // If you want count only on full URL change, use: const currentKey = ctx.page_location;\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.page_location);\n\n return {\n page_counter: pageCounter,\n ...ctx,\n };\n }\n}\n\nconst _instance = new TwinalyzeAnalyticsImpl();\n\nconst PUBLIC_METHODS = [\n \"init\",\n \"track\"\n];\n\nexport const TwinalyzeAnalytics = Object.fromEntries(\n PUBLIC_METHODS.map((m) => [m, _instance[m].bind(_instance)])\n);\n\nexport default TwinalyzeAnalytics;"],"mappings":"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","names":["io","CryptoJS","html2canvas","UAParserPkg","UAParser","uuid","TwinalyzeAnalyticsImpl","cfg","_a","organization","DEFAULT_SCREEN_ACTIVITY","sa","eventName","properties","options","reason","err","data","stored","id","url","checkRes","ok","serverScreenshot","existsRes","createRes","sessionRes","payloadObj","timeoutMs","candidates","suffix","resEvents","resolve","done","cleanup","ev","onRes","timer","res","sendData","obj","r","imgs","img","_b","isViewport","scale","canvas","doc","style","maxW","ratio","c2","now","throttleMs","blob","fd","e","payload","eventType","indexId","name","props","em","pv","fire","pv2","_push","_replace","args","scrollTop","scrollHeight","percent","_c","hit","el","tag","text","href","started","form","exts","x","a","clean","ext","params","usp","key","k","term","aria","title","txt","parts","node","depth","part","cls","path","start","closest","sel","btn","menuItem","interactive","_d","_e","_f","_g","_h","ua","conn","screenMode","get","nf","old","KEY_LAST","pageLocation","pageDomain","pagePath","pageTitle","prevLocation","prevType","KEY_COUNT","KEY_LAST_COUNTED","ctx","currentKey","lastCounted","pageCounter","_instance","PUBLIC_METHODS","TwinalyzeAnalytics","m","index_default"]}
1
+ {"version":3,"sources":["../src/index.js"],"sourcesContent":["import { io } from \"socket.io-client\";\nimport 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\nclass TwinalyzeAnalyticsImpl {\n constructor() {\n this.cfg = null;\n\n this.socket = null;\n this.socketReady = false;\n\n this.deviceId = null;\n this.sessionId = null; // uniqueSessionId (client generated)\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.scrollFired = false;\n\n this._initialized = false;\n\n this._sentSessionUpdate = false; // one-time\n this._sentUserUpdate = false; // one-time\n\n this.indexId = 0;\n this._indexKey = null;\n\n this._lastShotAt = 0;\n this._shotInFlight = false;\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 organization = cfg.organization || cfg.orgId;\n\n const DEFAULT_SCREEN_ACTIVITY = {\n enabled: false,\n apiUrl: cfg.screenActivity?.apiUrl ?? `${cfg.socketUrl}/api/app/screenActivity/screenActivityDetails_post`,\n captureOn: [\"page_view\", \"click\", \"form_start\", \"form_submit\", \"scroll\", \"view_search_results\", \"custom_event\"],\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 organization,\n socketUrl: \"https://api.twinalyze.com\",\n // socketUrl: \"http://192.168.1.26:3000\",\n\n debug: true,\n\n // encryption like Android (AES key = socket.id)\n encrypt: true, // default true\n\n // session id from client side\n persistSession: cfg.persistSession !== false, // default true (sessionStorage)\n sessionKey: \"twinalyze_session_id\",\n\n // server response event naming\n // we listen to multiple possible response events to be safe:\n // `${event}:res`, `${event}Res`, `${event}Response`, `${event}`\n responseSuffix: cfg.responseSuffix || \":res\",\n responseTimeoutMs: cfg.responseTimeoutMs || 15000,\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 apiBaseUrl: cfg.apiBaseUrl || cfg.endpoint || cfg.socketUrl, // http base for REST APIs\n screenActivity: sa,\n // screenActivity: {\n // enabled: cfg.screenActivity?.enabled ?? true,\n // apiUrl: cfg.screenActivity?.apiUrl ?? `${cfg.socketUrl}/api/app/screenActivity/screenActivityDetails_post`,\n // jpegQuality: cfg.screenActivity?.jpegQuality ?? 0.7,\n // throttleMs: cfg.screenActivity?.throttleMs ?? 2000, // don't screenshot every click instantly\n // capture: cfg.screenActivity?.capture ?? \"viewport\", // \"viewport\" | \"fullpage\"\n // maxWidth: cfg.screenActivity?.maxWidth ?? 1280, // reduce size\n // },\n };\n\n if (!this.cfg.apiKey || !this.cfg.organization) {\n console.log(\"[Twinalyze] ❌ Missing apiKey / organization / socketUrl\");\n return;\n }\n\n this.deviceId = this._getOrCreateDeviceId();\n\n if (this.cfg.persistSession) {\n this.sessionId = sessionStorage.getItem(this.cfg.sessionKey) || null;\n }\n\n this._connectSocket();\n this._setupEnhancedMeasurement();\n }\n\n // custom event (web dev only uses this)\n track(eventName, properties = {}) {\n if (this._disabled) 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: \"custom\" });\n return;\n }\n\n this._emitEventAdd(eventName, { ...this._pageContext(), ...properties }, \"custom\");\n }\n\n // -------------------------\n // SOCKET\n // -------------------------\n _connectSocket() {\n if (this.socket) return;\n\n const options = ({\n transports: [\"websocket\"], // Force WebSocket transport\n reconnection: true,\n reconnectionAttempts: Infinity, // Keep reconnecting indefinitely\n reconnectionDelay: 2000, // 2 seconds delay between reconnection attempts\n reconnectionDelayMax: 10000, // Max reconnection delay (10 seconds)\n timeout: 20000, // Connection timeout (20 seconds)\n path: \"/socket.io/\",\n auth: {\n \"x-api-key\": this.cfg.apiKey,\n \"x-organization-id\": this.cfg.organization,\n \"x-app-version-name\": this.cfg.appVersionName || \"not_found\",\n \"x-analytics-sdk-version\": this.cfg.analyticsSdkVersion || this.cfg.version || \"1.0.0\",\n \"x-ad-analytics-sdk-version\": this.cfg.adAnalyticsSdkVersion || \"not_found\",\n \"x-app-package-name\": this.cfg.appPackageName || location.hostname,\n \"x-platform\": \"web\",\n \"x-sdk-version\": this.cfg.version || \"1.0.0\",\n },\n extraHeaders: {\n \"Origin\": this.cfg.socketUrl,\n \"x-api-key\": this.cfg.apiKey,\n \"x-organization-id\": this.cfg.organization,\n \"x-app-version-name\": this.cfg.appVersionName || \"not_found\",\n \"x-analytics-sdk-version\": this.cfg.analyticsSdkVersion || this.cfg.version || \"1.0.0\",\n \"x-ad-analytics-sdk-version\": this.cfg.adAnalyticsSdkVersion || \"not_found\",\n \"x-app-package-name\": this.cfg.appPackageName || location.hostname,\n \"x-platform\": \"web\",\n \"x-sdk-version\": this.cfg.version || \"1.0.0\",\n },\n methods: [\"GET\", \"POST\"],\n })\n\n this.socket = io(this.cfg.socketUrl, options);\n\n this.socket.on(\"connect\", async () => {\n this.socketReady = true;\n\n if (this.cfg.debug) {\n console.log(\"[Twinalyze][SOCKET] ✅ connected CHANGED NEW 1\", {\n id: this.socket.id,\n transport: this.socket.io.engine.transport.name,\n });\n }\n\n await this._startFlow();\n });\n\n this.socket.on(\"disconnect\", (reason) => {\n this.socketReady = false;\n\n // on reconnect, flow should run again (sessionCreate + one-time updates)\n this.sessionReady = false;\n this._booting = false;\n this._sentSessionUpdate = false;\n this._sentUserUpdate = false;\n this._resetIndexId();\n\n if (this.cfg.debug) console.log(\"[Twinalyze][SOCKET] ❌ disconnected:\", reason);\n });\n\n this.socket.on(\"connect_error\", (err) => {\n this.socketReady = false;\n if (this.cfg.debug) console.log(\"[Twinalyze][SOCKET] ❌ connect_error:\", err?.message || err);\n });\n\n // Listening to sdk_upgrade_warning\n this.socket.on(\"sdk_upgrade_warning\", (data) => {\n if (data && data.message) {\n console.log(\"SDK Upgrade Warning:\", data.message);\n\n // Show the upgrade message\n alert(data.message);\n\n // Optionally, check for updateUrl and redirect\n if (data.updateUrl) {\n const proceedToUpdate = confirm(\"A new SDK version is available. Do you want to upgrade now?\");\n\n if (proceedToUpdate) {\n window.location.href = data.updateUrl; // Redirect to the update page\n }\n }\n } else {\n console.error(\"Received invalid data in sdk_upgrade_warning event:\", data);\n }\n });\n\n // optional incoming debug\n // this.socket.onAny((event, ...args) => {\n // if (this.cfg.debug) console.log(\"[Twinalyze][IN]\", event, args);\n // });\n }\n\n _initIndexId() {\n // call only when sessionId is available\n this._indexKey = `twinalyze_event_index_${this.sessionId}`;\n\n // always start from 0 for new session\n // if you want resume on refresh within same session, load from sessionStorage\n const stored = sessionStorage.getItem(this._indexKey);\n this.indexId = stored ? parseInt(stored, 10) : 0;\n if (Number.isNaN(this.indexId)) this.indexId = 0;\n }\n\n _nextIndexId() {\n const id = this.indexId;\n this.indexId += 1;\n\n if (this._indexKey) {\n sessionStorage.setItem(this._indexKey, String(this.indexId));\n }\n return id; // ✅ return current id then increment\n }\n\n _resetIndexId() {\n this.indexId = 0;\n if (this._indexKey) sessionStorage.removeItem(this._indexKey);\n this._indexKey = null;\n }\n\n _normalizeHttpBase(url) {\n return String(url || \"\")\n .replace(/^ws:\\/\\//, \"http://\")\n .replace(/^wss:\\/\\//, \"https://\")\n .replace(/\\/$/, \"\");\n }\n\n // -------------------------\n // YOUR EXACT FLOW\n // -------------------------\n async _startFlow() {\n if (this._disabled) return;\n if (!this.socketReady) return;\n if (this._booting) return;\n\n this._booting = true;\n\n try {\n // 1) user|userCheckApp { apiKey, organization }\n const checkRes = await this._request(\"user|userCheckApp\", {\n apiKey: this.cfg.apiKey,\n organization: this.cfg.organization,\n });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] userCheckRes:\", checkRes);\n\n // STOP condition:\n // \"if success true and status 0 then next else STOP\"\n const ok =\n checkRes &&\n checkRes.success === true &&\n (checkRes.status === 1 || checkRes.status === \"1\");\n\n const serverScreenshot = !!checkRes?.debugScreenshotCapture;\n this.cfg.screenActivity.enabled = serverScreenshot;\n\n if (!ok) {\n this._disabled = true;\n this.sessionReady = false;\n this.cfg.screenActivity.enabled = false;\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] 🛑 STOP (userCheck failed)\");\n return;\n }\n\n // 2) user|userExistsApp { apiKey, deviceId, organization }\n const existsRes = await this._request(\"user|userExistsApp\", {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n organization: this.cfg.organization,\n });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] userExistsRes:\", existsRes);\n\n // your diagram says: if success===true => user exists\n const userExists = !!(existsRes && (existsRes.success === true) && (existsRes.userRegister === true));\n\n // 3) if user not exists => user|web|userCreateApp { apiKey, deviceId, properties, organization }\n if (!userExists) {\n const createRes = await this._request(\"user|web|userCreateApp\", {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n properties: this._userProperties(),\n organization: this.cfg.organization,\n });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] userCreateRes:\", createRes);\n\n // if backend returns explicit failure, stop\n // if (createRes && createRes.success === false) {\n // this._disabled = true;\n // this.sessionReady = false;\n // if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] 🛑 STOP (userCreate failed)\");\n // return;\n // }\n\n\n if (createRes && createRes.success === false) {\n console.log(\"[Twinalyze][FLOW] 🛑 userCreate failed, continuing...\");\n // Allow the SDK to continue processing events even if user creation fails\n this.sessionReady = true; // Manually set session as ready\n // Do NOT disable SDK, let events continue flowing\n}\n\n }\n\n // 4) create session id from client (your requirement)\n if (!this.sessionId) {\n this.sessionId = `sess_${uuid()}`;\n if (this.cfg.persistSession) {\n sessionStorage.setItem(this.cfg.sessionKey, this.sessionId);\n }\n }\n\n // 5) session|web|sessionCreateApp\n // { apiKey, deviceId, socketId, uniqueSessionId, deviceProperties, organization }\n const sessionRes = await this._request(\"session|web|sessionCreateApp\", {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n socketId: this.socket.id,\n uniqueSessionId: this.sessionId,\n deviceProperties: this._deviceProperties(),\n organization: this.cfg.organization,\n });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][FLOW] sessionCreateRes:\", sessionRes);\n\n if (sessionRes && sessionRes.success === false) {\n this._disabled = true;\n this.sessionReady = false;\n return;\n }\n\n // Mark ready even if backend doesn't return anything useful\n this.sessionReady = true;\n this._initIndexId();\n\n // // 6) one-time updates (exact payloads)\n // this._emitSessionUpdateOnce();\n // this._emitUserUpdateOnce();\n\n // 7) flush queued auto/custom events\n this._flushPendingEvents();\n } finally {\n this._booting = false;\n }\n }\n\n // -------------------------\n // REQUEST/RESPONSE (NO ACK)\n // waits for server response event using \"on/once\"\n // -------------------------\n _request(eventName, payloadObj) {\n const timeoutMs = this.cfg.responseTimeoutMs;\n\n const candidates = [];\n const suffix = this.cfg.responseSuffix;\n\n // Try multiple common response event names (so you don’t have to guess)\n candidates.push(`${eventName}${suffix}`); // user|userCheckApp:res\n candidates.push(`${eventName}Res`); // user|userCheckAppRes\n candidates.push(`${eventName}Response`); // user|userCheckAppResponse\n candidates.push(eventName); // same event name as response (some backends do this)\n\n // unique\n const resEvents = [...new Set(candidates)];\n\n return new Promise((resolve) => {\n if (!this.socketReady) return resolve(null);\n\n let done = false;\n\n const cleanup = () => {\n resEvents.forEach((ev) => this.socket.off(ev, onRes));\n clearTimeout(timer);\n };\n\n const onRes = (res) => {\n if (done) return;\n done = true;\n cleanup();\n resolve(res);\n };\n\n // IMPORTANT: register listeners before emit (so we don't miss fast responses)\n resEvents.forEach((ev) => this.socket.on(ev, onRes));\n\n const timer = setTimeout(() => {\n if (done) return;\n done = true;\n cleanup();\n resolve(null);\n }, timeoutMs);\n\n const sendData = this.cfg.encrypt ? this._encrypt(payloadObj) : payloadObj;\n this.socket.emit(eventName, sendData);\n });\n }\n\n _encrypt(obj) {\n const CRYPTOJS_SECRET_KEY = \"3Xn8vQp2Lm9sAa7ZkT1yCw5eR0uH6dJ4\"\n // AES key = socket.id (matches your Android/backend style)\n return CryptoJS.AES.encrypt(JSON.stringify(obj), CRYPTOJS_SECRET_KEY).toString();\n // return CryptoJS.AES.encrypt(JSON.stringify(obj), this.socket.id).toString();\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(\"organization\", this.cfg.organization);\n fd.append(\"screenName\", document.title || \"unknown\");\n fd.append(\"identifier\", JSON.stringify(properties || {})); // ✅ you asked: identifier = properties object\n fd.append(\"description\", eventName || \"event\");\n fd.append(\"image\", blob, `shot_${Date.now()}.jpg`);\n\n await fetch(this.cfg.screenActivity.apiUrl, {\n method: \"POST\",\n body: fd,\n keepalive: true,\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 // EMITS (exact payloads you gave)\n // -------------------------\n _emitSessionUpdateOnce() {\n if (!this.sessionReady) return;\n if (this._sentSessionUpdate) return;\n this._sentSessionUpdate = true;\n\n const payload = {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n deviceProperties: this._deviceProperties(),\n organization: this.cfg.organization,\n };\n\n const sendData = this.cfg.encrypt ? this._encrypt(payload) : payload;\n this.socket.emit(\"session|sessionUpdateApp\", sendData);\n\n if (this.cfg.debug) console.log(\"[Twinalyze] ✅ sessionUpdate sent\");\n }\n\n _emitUserUpdateOnce() {\n if (!this.sessionReady) return;\n if (this._sentUserUpdate) return;\n this._sentUserUpdate = true;\n\n const payload = {\n apiKey: this.cfg.apiKey,\n deviceId: this.deviceId,\n properties: this._userProperties(),\n organization: this.cfg.organization,\n };\n\n const sendData = this.cfg.encrypt ? this._encrypt(payload) : payload;\n this.socket.emit(\"user|userUpdateApp\", sendData);\n\n if (this.cfg.debug) console.log(\"[Twinalyze] ✅ userUpdate sent\");\n }\n\n _emitEventAdd(eventName, properties = {}, eventType = \"auto\") {\n if (!this.sessionReady) return;\n\n // if session just got ready and index not set\n if (this._indexKey == null) this._initIndexId();\n const indexId = this._nextIndexId();\n\n const payload = {\n socketId: this.socket.id,\n date: new Date().toISOString(),\n eventType: eventType,\n uniqueSessionId: this.sessionId,\n deviceId: this.deviceId,\n eventName,\n properties: properties,\n apiKey: this.cfg.apiKey,\n source: this.cfg.source,\n // ✅ auto index\n indexId,\n organization: this.cfg.organization,\n };\n\n console.log(\"payload session|web|sessionEventAddApp\", payload);\n\n const sendData = this.cfg.encrypt ? this._encrypt(payload) : payload;\n this.socket.emit(\"session|web|sessionEventAddApp\", sendData);\n\n // this._maybeUploadScreenActivity(eventName, properties, indexId).catch(() => { });\n this._uploadScreenActivity({ eventName, properties });\n\n if (this.cfg.debug) console.log(\"[Twinalyze][EVENT_ADD]\", eventName, properties, indexId);\n }\n\n _flushPendingEvents() {\n if (!this.sessionReady) return;\n if (!this.pendingEvents.length) return;\n\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 // -------------------------\n // AUTO EVENTS (GA-style)\n // -------------------------\n _trackAuto(name, props = {}) {\n if (this._disabled) 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 // page_view (normal + SPA)\n if (em.pageViews) {\n const pv = this._pageViewInfo();\n this._trackAuto(\"page_view\", pv);\n\n const fire = () => {\n this.scrollFired = false;\n const pv2 = this._pageViewInfo();\n this._trackAuto(\"page_view\", 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(\"scroll\", { percent_scrolled: 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 click_type: hit.kind, // link | button | dropdown_item | interactive\n element_tag: tag,\n element_text: text || \"not_found\", // ✅ innerText/aria-label/title\n element_id: el.id || null,\n element_name: el.getAttribute?.(\"name\") || null,\n element_role: el.getAttribute?.(\"role\") || null,\n element_classes:\n (el.className && typeof el.className === \"string\") ? el.className.slice(0, 120) : null,\n element_path: 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.link_url = url.href;\n props.link_domain = url.hostname;\n props.link_path = url.pathname;\n props.outbound = url.hostname !== location.hostname;\n }\n\n // Button details\n if (hit.kind === \"button\") {\n props.button_type = el.getAttribute?.(\"type\") || null;\n props.disabled = !!el.disabled;\n }\n\n this._trackAuto(\"click\", 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(\"form_start\", {\n form_id: form.id || undefined,\n form_name: form.getAttribute(\"name\") || undefined,\n form_action: 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(\"form_submit\", {\n form_id: form.id || undefined,\n form_name: form.getAttribute(\"name\") || undefined,\n form_action: form.action || undefined,\n form_destination: location.href,\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(\"file_download\", {\n link_url: a.href,\n file_extension: ext,\n file_name: clean.split(\"/\").pop(),\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(\"view_search_results\", {\n search_term: term.trim(),\n search_param: key,\n page_path: location.pathname,\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_type: ua.device?.type || (matchMedia(\"(pointer:coarse)\").matches ? \"mobile\" : \"desktop\"),\n os_name: ua.os?.name || \"not_found\",\n os_version: ua.os?.version || \"not_found\",\n browser_name: ua.browser?.name || \"not_found\",\n browser_version: ua.browser?.version || \"not_found\",\n\n // app/sdk\n sdk: \"web\",\n sdk_version: this.cfg?.version || \"not_found\",\n\n // screen\n device_screen_mode: screenMode,\n screen_w: String(screen.width),\n screen_h: String(screen.height),\n viewport_w: String(window.innerWidth),\n viewport_h: String(window.innerHeight),\n density: String(window.devicePixelRatio || 1),\n color_depth: String(screen.colorDepth || \"not_found\"),\n\n // system-ish\n device_language: navigator.language || \"not_found\",\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || \"not_found\",\n cores: navigator.hardwareConcurrency != null ? String(navigator.hardwareConcurrency) : \"not_found\",\n memory_gb: navigator.deviceMemory != null ? String(navigator.deviceMemory) : \"not_found\",\n touch_points: navigator.maxTouchPoints != null ? String(navigator.maxTouchPoints) : \"0\",\n\n // network (best-effort)\n is_data_on: navigator.onLine ? \"true\" : \"false\",\n connection_effective_type: conn?.effectiveType || \"not_found\",\n connection_downlink: conn?.downlink != null ? String(conn.downlink) : \"not_found\",\n connection_rtt: conn?.rtt != null ? String(conn.rtt) : \"not_found\",\n connection_save_data: conn?.saveData != null ? String(conn.saveData) : \"not_found\",\n\n // raw\n user_agent: navigator.userAgent,\n };\n }\n\n _userProperties() {\n const url = new URL(location.href);\n const usp = url.searchParams;\n\n const get = (k) => usp.get(k);\n const nf = \"not_found\";\n\n return {\n // acquisition\n landing_url: url.href,\n referrer: [\n {\n utm_source: get(\"utm_source\") || nf,\n },\n {\n utm_medium: get(\"utm_medium\") || nf,\n },\n {\n utm_campaign: get(\"utm_campaign\") || nf,\n },\n {\n utm_term: get(\"utm_term\") || nf,\n },\n {\n utm_content: get(\"utm_content\") || nf,\n }\n ],\n\n // ads click ids\n gclid: get(\"gclid\") || nf,\n fbclid: get(\"fbclid\") || nf,\n msclkid: get(\"msclkid\") || nf,\n\n // user preferences\n language_pref: navigator.language || 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 _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 = 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 page_domain: pageDomain,\n page_location: pageLocation,\n page_url: pageLocation,\n page_path: pagePath,\n page_title: pageTitle,\n previous_page_location: prevLocation,\n previous_page_type: prevType,\n };\n }\n\n // _pageViewInfo() {\n // const KEY_LAST = \"twinalyze_last_page_location\";\n // const KEY_COUNT = \"twinalyze_page_counter\";\n\n // const ctx = this._pageContext();\n\n // const prevCount = parseInt(sessionStorage.getItem(KEY_COUNT) || \"0\", 10);\n // const pageCounter = (Number.isNaN(prevCount) ? 0 : prevCount) + 1;\n\n // sessionStorage.setItem(KEY_COUNT, String(pageCounter));\n // sessionStorage.setItem(KEY_LAST, ctx.page_location);\n\n // return {\n // page_counter: pageCounter,\n // ...ctx,\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.page_path; // ✅ count only on path change\n // If you want count only on full URL change, use: const currentKey = ctx.page_location;\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.page_location);\n\n return {\n page_counter: pageCounter,\n ...ctx,\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":["io","CryptoJS","html2canvas","UAParserPkg","UAParser","uuid","TwinalyzeAnalyticsImpl","cfg","_a","organization","DEFAULT_SCREEN_ACTIVITY","sa","eventName","properties","options","reason","err","data","stored","id","url","checkRes","ok","serverScreenshot","existsRes","createRes","sessionRes","payloadObj","timeoutMs","candidates","suffix","resEvents","resolve","done","cleanup","ev","onRes","timer","res","sendData","obj","r","imgs","img","_b","isViewport","scale","canvas","doc","style","maxW","ratio","c2","now","throttleMs","blob","fd","e","payload","eventType","indexId","name","props","em","pv","fire","pv2","_push","_replace","args","scrollTop","scrollHeight","percent","_c","hit","el","tag","text","href","started","form","exts","x","a","clean","ext","params","usp","key","k","term","aria","title","txt","parts","node","depth","part","cls","path","start","closest","sel","btn","menuItem","interactive","_d","_e","_f","_g","_h","ua","conn","screenMode","get","nf","old","KEY_LAST","pageLocation","pageDomain","pagePath","pageTitle","prevLocation","prevType","KEY_COUNT","KEY_LAST_COUNTED","ctx","currentKey","lastCounted","pageCounter","_instance","PUBLIC_METHODS","TwinalyzeAnalytics","m","index_default","TwinalyzeAnalytics"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twinalyze/web-analytics",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
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",