@log-drop/web 1.0.0-alpha1 → 1.0.0-alpha2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/logdrop.min.js +1 -1
- package/dist/logdrop.min.js.map +2 -2
- package/package.json +1 -1
package/dist/logdrop.min.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.js", "../src/constants.js", "../src/instrumentation/networkInstrumentation.js", "../src/push/pushModule.js", "../src/push/inAppMessagePresenter.js", "../src/protobuf.js", "../src/events/eventModule.js", "../src/risk/signals/headlessBrowserSignal.js", "../src/risk/signals/automationEnvironmentSignal.js", "../src/risk/signals/pointerBehaviorSignal.js", "../src/risk/signals/keyboardCadenceSignal.js", "../src/risk/signals/hardwareConsistencySignal.js", "../src/risk/signals/devToolsSignal.js", "../src/risk/signals/devToolsConsoleSignal.js", "../src/risk/signals/incognitoSignal.js", "../src/risk/signals/sessionPersistenceSignal.js", "../src/risk/riskPolicy.js", "../src/risk/riskModule.js"],
|
|
4
|
-
"sourcesContent": ["// LogDrop Web SDK (minimal, local-dev oriented)\n// Public API is intentionally close to the Swift facade (levels + basic flush behavior).\n\nimport { LogDropConstants } from \"./constants.js\";\nimport { NetworkInstrumentation } from \"./instrumentation/networkInstrumentation.js\";\nimport { PushModule } from \"./push/pushModule.js\";\nimport { InAppMessagePresenter } from \"./push/inAppMessagePresenter.js\";\nimport { EventModule } from \"./events/eventModule.js\";\nimport { RiskModule } from \"./risk/riskModule.js\";\nimport { actionName, RiskActionIds } from \"./risk/riskPolicy.js\";\nimport {\n encodeUserUpdateRequest,\n decodeSdkTokenResponse,\n encodeInitRequest,\n decodeConfigResponse,\n encodeLogRequest,\n decodeLogResponse,\n encodeCrashReportRequest\n} from \"./protobuf.js\";\n\nexport const LogLevel = Object.freeze({\n ERROR: \"ERROR\",\n WARNING: \"WARNING\",\n INFO: \"INFO\",\n DEBUG: \"DEBUG\",\n CRASH: \"CRASH\",\n DEVICEINFO: \"DEVICEINFO\",\n NETWORK_ACTIVITY: \"NETWORK_ACTIVITY\",\n REMOTE_MESSAGE: \"REMOTE_MESSAGE\",\n EVENT: \"EVENT\"\n});\n\n// Cached once at module scope \u2014 LogLevel is frozen so this never changes\nconst _logLevelValues = Object.values(LogLevel);\n\n/**\n * LogFlow - Used to group related logs together\n * @param {string} name - Flow name (e.g., \"checkout\", \"login\")\n * @param {string} id - Unique flow instance ID\n * @param {Object} [customAttributes] - Optional custom key-value pairs\n */\nexport class LogFlow {\n constructor(name, id, customAttributes = null) {\n this.name = String(name || \"\");\n this.id = String(id || \"\");\n this.customAttributes = customAttributes || null;\n }\n}\n\nconst LOGDROP_DOMAIN_EXCLUDE = /(^https?:\\/\\/([^/]+\\.)?logdrop\\.io(\\/|$))/i;\nconst LOGDROP_INIT_CACHE_KEY = \"logdrop_init_cache\";\nconst LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY = \"logdrop_token_recovery_identity\";\nconst LOGDROP_IP_REPUTATION_ACTION_KEY = \"logdrop_ip_reputation_active_action\";\nconst LOGDROP_IP_REPUTATION_SIGNATURES_KEY = \"logdrop_ip_reputation_processed_signatures\";\nconst LOGDROP_LAST_USER_UPDATE_KEY = \"logdrop_last_user_update\";\nconst REDACTED_PROTO_PLACEHOLDER = \"[REDACTED]\";\nconst SENSITIVE_PROTO_FIELD_NAMES = new Set([\n \"accesstoken\",\n \"refreshtoken\",\n \"token\",\n \"auth\"\n]);\n\nfunction nowIso() {\n // Backend expects: \"YYYY-MM-DD HH:MM:SS:ms\"\n // Example: \"2026-02-10 11:48:13:200\"\n const d = new Date();\n\n const pad2 = (n) => String(n).padStart(2, \"0\");\n const pad3 = (n) => String(n).padStart(3, \"0\");\n\n // Use UTC to be consistent; backend treats it as \"local\" anyway.\n const yyyy = d.getUTCFullYear();\n const mm = pad2(d.getUTCMonth() + 1);\n const dd = pad2(d.getUTCDate());\n\n const HH = pad2(d.getUTCHours());\n const MM = pad2(d.getUTCMinutes());\n const SS = pad2(d.getUTCSeconds());\n const ms = pad3(d.getUTCMilliseconds());\n\n return `${yyyy}-${mm}-${dd} ${HH}:${MM}:${SS}:${ms}`;\n}\n\nfunction safeStringify(obj) {\n try {\n if (obj instanceof Error) {\n return JSON.stringify({ name: obj.name, message: obj.message, stack: obj.stack });\n }\n return JSON.stringify(obj);\n } catch {\n return \"\\\"[unserializable]\\\"\";\n }\n}\n\nfunction hasWindow() {\n return typeof window !== \"undefined\";\n}\n\nfunction getBaseHref() {\n if (hasWindow() && window.location && typeof window.location.href === \"string\") return window.location.href;\n return \"http://localhost/\";\n}\n\n/**\n * Normalize an input base URL to a canonical SDK endpoint base.\n *\n * Trims whitespace and trailing slashes, applies a fallback when `baseUrl` is empty, and ensures the result targets the `/api/v2/sdk` path.\n * @param {string} baseUrl - The user-provided base URL (may be empty or already include a path).\n * @returns {string} A base URL string that ends with `/api/v2/sdk`, using `LogDropConstants.DEFAULT_BASE_URL` when `baseUrl` is falsy.\n */\nfunction normalizeBaseUrl(baseUrl) {\n const trimmed = String(baseUrl || \"\").trim();\n const normalized = trimmed.replace(/\\/+$/, \"\");\n const fallback = LogDropConstants.DEFAULT_BASE_URL;\n const base = normalized || fallback;\n // V2: base URL points to /api/v2/sdk\n if (base.endsWith(\"/api/v2/sdk\")) return base;\n if (base.endsWith(\"/api\")) return `${base}/v2/sdk`;\n return `${base}/api/v2/sdk`;\n}\n\n/**\n * Concatenates multiple Uint8Array instances into a single contiguous Uint8Array in the order provided.\n * @param {Uint8Array[]} chunks - Array of byte chunks to concatenate.\n * @returns {Uint8Array} The combined Uint8Array containing all input bytes.\n */\nfunction concatUint8Arrays(chunks) {\n const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const out = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.length;\n }\n return out;\n}\n\n/**\n * Compute the CRC32 checksum of the provided bytes.\n * @param {Uint8Array} bytes - The input byte sequence to checksum.\n * @returns {number} CRC32 checksum as an unsigned 32-bit integer.\n */\nfunction crc32(bytes) {\n let crc = 0xffffffff;\n for (let i = 0; i < bytes.length; i += 1) {\n let c = (crc ^ bytes[i]) & 0xff;\n for (let k = 0; k < 8; k += 1) {\n c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1);\n }\n crc = (crc >>> 8) ^ c;\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n/**\n * Generate a version-4 (random) UUID string.\n *\n * Uses secure browser crypto APIs when available and falls back to a Math.random-based generator in legacy environments.\n * @returns {string} A v4 UUID in the standard 8-4-4-4-12 dashed hexadecimal format (lowercase).\n */\nexport function generateUUID() {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4\n bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10xx\n const hex = Array.from(bytes).map(b => b.toString(16).padStart(2, '0'));\n return `${hex.slice(0,4).join('')}-${hex.slice(4,6).join('')}-${hex.slice(6,8).join('')}-${hex.slice(8,10).join('')}-${hex.slice(10).join('')}`;\n }\n // Math.random fallback (last resort for legacy environments)\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\n/**\n * Compute a compact fingerprint for a stack trace to identify similar crashes.\n *\n * Extracts the error type (first line) and up to the first five stack-frame function names,\n * supporting common V8/Chrome and Firefox/Safari stack formats, concatenates them into a key,\n * and returns its CRC32 checksum.\n *\n * @param {string} stack - The stack trace text to fingerprint; non-string values are treated as empty string.\n * @returns {number} CRC32 checksum of the derived key to use as a crash fingerprint.\n */\nexport function fingerprintStack(stack) {\n const s = typeof stack === 'string' ? stack : '';\n const lines = s.trim().split('\\n');\n const errorType = lines[0] ? lines[0].trim() : '';\n // V8/Chrome: \" at funcName (file:line:col)\" | Firefox/Safari: \"funcName@file:line:col\"\n const frameLines = lines.slice(1).filter(l => /^\\s*at /.test(l) || /@/.test(l));\n const top5 = frameLines.slice(0, 5);\n const frameNames = top5.map(line => {\n if (/^\\s*at /.test(line)) {\n // V8/Chrome format\n const m = line.trim().match(/^at\\s+([^\\s(]+)/);\n const raw = m ? m[1] : '';\n return raw.split('/').pop() || 'anonymous';\n } else {\n // Firefox/Safari format: \"funcName@file:line:col\"\n const m = line.match(/^([^@]*)@/);\n const raw = m ? m[1].trim() : '';\n return raw.split('/').pop() || 'anonymous';\n }\n });\n const key = errorType + ':' + frameNames.join(',');\n const bytes = new TextEncoder().encode(key);\n return crc32(bytes);\n}\n\n/**\n * Capture a best-effort snapshot of the current page and runtime state for diagnostic and crash reports.\n *\n * @returns {{url: string, referrer: string, visibilityState: string, onLine: boolean, viewportWidth: number, viewportHeight: number, heapUsed: number|null}} An object containing:\n * - `url`: current page URL or empty string,\n * - `referrer`: document referrer or empty string,\n * - `visibilityState`: document visibility state (defaults to `\"visible\"`),\n * - `onLine`: navigator online status (defaults to `true` when unavailable),\n * - `viewportWidth`: window inner width or `0`,\n * - `viewportHeight`: window inner height or `0`,\n * - `heapUsed`: `performance.memory.usedJSHeapSize` when available, otherwise `null`.\n */\nexport function capturePageState() {\n return {\n url: (typeof location !== 'undefined' && location.href) || '',\n referrer: (typeof document !== 'undefined' && document.referrer) || '',\n visibilityState: (typeof document !== 'undefined' && document.visibilityState) || 'visible',\n onLine: (typeof navigator !== 'undefined' && typeof navigator.onLine === 'boolean') ? navigator.onLine : true,\n viewportWidth: (typeof window !== 'undefined' && window.innerWidth) || 0,\n viewportHeight: (typeof window !== 'undefined' && window.innerHeight) || 0,\n heapUsed: (typeof performance !== 'undefined' && performance.memory)\n ? performance.memory.usedJSHeapSize\n : null,\n };\n}\n\n/**\n * Build a minimal ZIP archive (single file) containing the given text content.\n *\n * Produces a byte array representing a valid ZIP file with one entry named by `filename`\n * whose contents are `textContent`.\n *\n * @param {string} filename - The file name to store inside the ZIP archive.\n * @param {string} textContent - The UTF-8 text content to place into the file entry.\n * @returns {Uint8Array} A contiguous Uint8Array containing the ZIP file bytes.\n */\nfunction buildZipBytes(filename, textContent) {\n const encoder = new TextEncoder();\n const fileNameBytes = encoder.encode(filename);\n const fileBytes = encoder.encode(textContent);\n const fileCrc = crc32(fileBytes);\n const localHeader = new Uint8Array(30 + fileNameBytes.length);\n const localView = new DataView(localHeader.buffer);\n localView.setUint32(0, 0x04034b50, true);\n localView.setUint16(4, 20, true);\n localView.setUint16(6, 0, true);\n localView.setUint16(8, 0, true);\n localView.setUint16(10, 0, true);\n localView.setUint16(12, 0, true);\n localView.setUint32(14, fileCrc, true);\n localView.setUint32(18, fileBytes.length, true);\n localView.setUint32(22, fileBytes.length, true);\n localView.setUint16(26, fileNameBytes.length, true);\n localView.setUint16(28, 0, true);\n localHeader.set(fileNameBytes, 30);\n\n const centralHeader = new Uint8Array(46 + fileNameBytes.length);\n const centralView = new DataView(centralHeader.buffer);\n centralView.setUint32(0, 0x02014b50, true);\n centralView.setUint16(4, 20, true);\n centralView.setUint16(6, 20, true);\n centralView.setUint16(8, 0, true);\n centralView.setUint16(10, 0, true);\n centralView.setUint16(12, 0, true);\n centralView.setUint16(14, 0, true);\n centralView.setUint32(16, fileCrc, true);\n centralView.setUint32(20, fileBytes.length, true);\n centralView.setUint32(24, fileBytes.length, true);\n centralView.setUint16(28, fileNameBytes.length, true);\n centralView.setUint16(30, 0, true);\n centralView.setUint16(32, 0, true);\n centralView.setUint16(34, 0, true);\n centralView.setUint16(36, 0, true);\n centralView.setUint32(38, 0, true);\n centralView.setUint32(42, 0, true);\n centralHeader.set(fileNameBytes, 46);\n\n const endHeader = new Uint8Array(22);\n const endView = new DataView(endHeader.buffer);\n endView.setUint32(0, 0x06054b50, true);\n endView.setUint16(4, 0, true);\n endView.setUint16(6, 0, true);\n endView.setUint16(8, 1, true);\n endView.setUint16(10, 1, true);\n endView.setUint32(12, centralHeader.length, true);\n endView.setUint32(16, localHeader.length + fileBytes.length, true);\n endView.setUint16(20, 0, true);\n\n return concatUint8Arrays([localHeader, fileBytes, centralHeader, endHeader]);\n}\n\n\nexport class LogDropClient {\n constructor() {\n this._config = null;\n this._debugLogEnabled = false;\n this._queue = [];\n this._flushTimer = null;\n this._fileFlushTimer = null;\n this._fileFlushInProgress = false;\n this._crashFlushTimer = null;\n this._crashFlushDelayMs = 5000;\n this._crashFlushInProgress = false;\n this._deviceInfoTimer = null;\n this._storageCheckTimer = null;\n this._dbPromise = null;\n this._initialized = false;\n this._initResponse = null;\n this._tokenRecoveryPromise = null;\n this._tokenValidationState = {\n logdrop_access_token: null,\n logdrop_refresh_token: null\n };\n\n // Session info\n this._sessionId = this._generateUUID();\n this._sessionCreateDate = nowIso();\n\n // Device ID (persistent across sessions)\n this._deviceId = this._getOrCreateDeviceId();\n\n // Server config from init response. These are pre-init defaults; the real\n // values come from the ConfigResponse (see _applyServerConfig). Event\n // tracking stays off until the server enables it via isEventTrackingEnabled.\n this._serverConfig = {\n isSDKDisabled: false,\n isHttpLoggingEnabled: true,\n isCrashTrackingEnabled: true,\n isEventTrackingEnabled: false,\n riskConfig: null,\n webPushConfig: null,\n };\n\n this._activeIpReputationAction = this._loadStoredIpReputationAction();\n this._ipReputationExpiryTimer = null;\n\n // Try to load cached server config\n this._loadCachedServerConfig();\n\n // Restore a previously identified user (via updateUser). Until updateUser is\n // called, _user stays null and the deviceUuid is used as the effective userUuid.\n this._user = this._loadPersistedExternalUser();\n\n // Prevent duplicate listeners across re-init\n this._errorHandlersInstalled = false;\n\n // Network instrumentation\n this._net = null;\n\n // Push notifications\n this._pushModule = null;\n this._inAppMessagePresenter = null;\n this.push = null;\n this._desiredWebPushSubscription = undefined;\n\n // User/device updates follow the same shape as the mobile SDKs: retain the\n // last successful snapshot, coalesce newer changes while one request is in\n // flight, and never run overlapping users/update requests.\n this._lastSentUserUpdate = this._loadLastSentUserUpdate();\n this._activeUserUpdate = null;\n this._pendingUserUpdate = null;\n this._drainingUserUpdates = false;\n\n // Event tracking\n this._eventModule = null;\n this._eventFlushTimer = null;\n\n // Risk & bot detection\n this._riskModule = null;\n this._activeRiskPolicyEvaluation = null;\n this._riskPolicyOverlay = null;\n\n this._seenCrashes = new Set();\n this._crashTrackingOverride = null;\n\n this._originalFetch = null;\n }\n\n _generateUUID() {\n // General-purpose UUID (session IDs may keep the standard dashed form).\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older browsers\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\n _isInternalLoggingEnabled() {\n return this._debugLogEnabled === true;\n }\n\n _logInternal(...args) {\n if (!this._isInternalLoggingEnabled()) return;\n // eslint-disable-next-line no-console\n console.log(...args);\n }\n\n _warnInternal(...args) {\n if (!this._isInternalLoggingEnabled()) return;\n // eslint-disable-next-line no-console\n console.warn(...args);\n }\n\n _errorInternal(...args) {\n if (!this._isInternalLoggingEnabled()) return;\n // eslint-disable-next-line no-console\n console.error(...args);\n }\n\n _getProtoHexPreview(bytes, limit = 64) {\n if (!(bytes instanceof Uint8Array) || bytes.length === 0) return \"empty\";\n\n const preview = Array.from(bytes.slice(0, limit))\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\" \");\n\n return bytes.length > limit ? `${preview} ...` : preview;\n }\n\n _isSensitiveProtoFieldName(fieldName) {\n if (typeof fieldName !== \"string\" || fieldName.length === 0) return false;\n\n const normalizedFieldName = fieldName.replace(/[^a-z0-9]/gi, \"\").toLowerCase();\n return SENSITIVE_PROTO_FIELD_NAMES.has(normalizedFieldName);\n }\n\n _summarizeProtoPayloadEntry(value, fieldName = null) {\n if (this._isSensitiveProtoFieldName(fieldName)) {\n return {\n containsSensitiveData: true,\n summary: REDACTED_PROTO_PLACEHOLDER\n };\n }\n\n if (value instanceof Uint8Array) {\n return {\n containsSensitiveData: false,\n summary: {\n byteLength: value.length,\n hexPreview: this._getProtoHexPreview(value)\n }\n };\n }\n\n if (Array.isArray(value)) {\n let containsSensitiveData = false;\n const summary = value.map((entry) => {\n const summarizedEntry = this._summarizeProtoPayloadEntry(entry);\n containsSensitiveData = containsSensitiveData || summarizedEntry.containsSensitiveData;\n return summarizedEntry.summary;\n });\n\n return { containsSensitiveData, summary };\n }\n\n if (value && typeof value === \"object\") {\n const summary = {};\n let containsSensitiveData = false;\n for (const [key, entry] of Object.entries(value)) {\n const summarizedEntry = this._summarizeProtoPayloadEntry(entry, key);\n summary[key] = summarizedEntry.summary;\n containsSensitiveData = containsSensitiveData || summarizedEntry.containsSensitiveData;\n }\n\n return { containsSensitiveData, summary };\n }\n\n return {\n containsSensitiveData: false,\n summary: value\n };\n }\n\n _summarizeProtoPayload(value) {\n return this._summarizeProtoPayloadEntry(value).summary;\n }\n\n _debugLogProtoBody(label, payload, protoBytes) {\n if (!this._isInternalLoggingEnabled()) return;\n\n const payloadSummary = this._summarizeProtoPayloadEntry(payload);\n\n this._logInternal(`[LogDrop DEBUG] ${label} payload:`, payloadSummary.summary);\n this._logInternal(\n `[LogDrop DEBUG] ${label} protobuf bytes (${protoBytes.length} B): ${payloadSummary.containsSensitiveData ? REDACTED_PROTO_PLACEHOLDER : this._getProtoHexPreview(protoBytes)}`\n );\n }\n\n _debugLogProtoResponse(label, responseBytes, decoder = null) {\n if (!this._isInternalLoggingEnabled()) return;\n\n if (!(responseBytes instanceof Uint8Array) || responseBytes.length === 0) {\n this._logInternal(`[LogDrop DEBUG] ${label} response body: empty`);\n return;\n }\n\n let containsSensitiveData = false;\n\n if (typeof decoder === \"function\") {\n try {\n const decodedSummary = this._summarizeProtoPayloadEntry(decoder(responseBytes));\n containsSensitiveData = decodedSummary.containsSensitiveData;\n this._logInternal(`[LogDrop DEBUG] ${label} decoded response:`, decodedSummary.summary);\n } catch (err) {\n this._warnInternal(`[LogDrop DEBUG] ${label} response decode failed:`, err?.message || err);\n }\n }\n\n this._logInternal(\n `[LogDrop DEBUG] ${label} response protobuf bytes (${responseBytes.length} B): ${containsSensitiveData ? REDACTED_PROTO_PLACEHOLDER : this._getProtoHexPreview(responseBytes)}`\n );\n }\n\n _getOrCreateDeviceId() {\n this._isNewDevice = false;\n if (!hasWindow() || typeof localStorage === \"undefined\") {\n this._isNewDevice = true;\n return this._generateUUID().replace(/-/g, \"\");\n }\n const key = \"logdrop_device_id\";\n let deviceId = localStorage.getItem(key);\n const normalizedDeviceId = deviceId ? deviceId.replace(/-/g, \"\") : \"\";\n if (normalizedDeviceId.length === 32) {\n if (normalizedDeviceId !== deviceId) {\n deviceId = normalizedDeviceId;\n this._isNewDevice = true;\n try {\n localStorage.setItem(key, deviceId);\n localStorage.removeItem(\"logdrop_access_token\");\n localStorage.removeItem(\"logdrop_refresh_token\");\n localStorage.removeItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n localStorage.removeItem(LOGDROP_LAST_USER_UPDATE_KEY);\n } catch {\n // ignore storage errors\n }\n }\n return deviceId;\n }\n\n deviceId = this._generateUUID().replace(/-/g, \"\");\n this._isNewDevice = true;\n try {\n localStorage.setItem(key, deviceId);\n if (normalizedDeviceId) {\n localStorage.removeItem(\"logdrop_access_token\");\n localStorage.removeItem(\"logdrop_refresh_token\");\n localStorage.removeItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n localStorage.removeItem(LOGDROP_LAST_USER_UPDATE_KEY);\n }\n } catch {\n // ignore storage errors\n }\n return deviceId;\n }\n\n // Effective userUuid for events / logs / device info:\n // - the external user id once updateUser() has been called (persisted), or\n // - the deviceUuid until then (so the user is never truly \"anonymous\").\n _getEffectiveUserUuid() {\n return this._user?.userUuid ?? this._deviceId;\n }\n\n // Load the persisted external user id (set via updateUser) so it survives\n // page reloads/restarts until the host app calls updateUser again.\n _loadPersistedExternalUser() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n try {\n const uuid = localStorage.getItem(\"logdrop_external_user_uuid\");\n return uuid ? { userUuid: uuid } : null;\n } catch {\n return null;\n }\n }\n\n _persistExternalUser(userUuid) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(\"logdrop_external_user_uuid\", userUuid);\n } catch {\n // ignore storage errors\n }\n }\n\n _clearPersistedExternalUser() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.removeItem(\"logdrop_external_user_uuid\");\n } catch {\n // ignore storage errors\n }\n }\n\n _isUserRegistered() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return false;\n return localStorage.getItem(\"logdrop_user_registered\") === \"true\";\n }\n\n _markUserRegistered() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(\"logdrop_user_registered\", \"true\");\n } catch {\n // ignore storage errors\n }\n }\n\n _loadLastSentUserUpdate() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(LOGDROP_LAST_USER_UPDATE_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? parsed : null;\n } catch {\n return null;\n }\n }\n\n _saveLastSentUserUpdate(snapshot) {\n this._lastSentUserUpdate = snapshot;\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(LOGDROP_LAST_USER_UPDATE_KEY, JSON.stringify(snapshot));\n } catch {\n // A failed optimization cache must never fail the actual user update.\n }\n }\n\n _normalizeWebPushSubscription(subscription) {\n if (subscription == null) return null;\n const keys = subscription.keys || {};\n const endpoint = String(subscription.endpoint || \"\").trim();\n const p256dh = String(keys.p256dh || subscription.p256dh || \"\").trim();\n const auth = String(keys.auth || subscription.auth || \"\").trim();\n if (!endpoint || !p256dh || !auth) return null;\n const expirationTime = Number(subscription.expirationTime);\n return {\n endpoint,\n p256dh,\n auth,\n expirationTime: Number.isSafeInteger(expirationTime) && expirationTime > 0\n ? expirationTime\n : null,\n };\n }\n\n _webPushSubscriptionFingerprint(subscription) {\n return subscription == null ? null : JSON.stringify(subscription);\n }\n\n _handleWebPushSubscriptionChanged(subscription) {\n if (subscription == null) {\n this._desiredWebPushSubscription = null;\n return Promise.resolve(true);\n }\n const normalizedSubscription = this._normalizeWebPushSubscription(subscription);\n if (normalizedSubscription == null) {\n console.warn(\"[LogDrop] Ignoring invalid Web Push subscription\");\n return Promise.resolve(false);\n }\n this._desiredWebPushSubscription = normalizedSubscription;\n return this._sendUserUpdate(this._getEffectiveUserUuid(), !!this._user, {\n reason: \"web_push_subscription_changed\",\n });\n }\n\n // \u2500\u2500 V2 Token Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n _normalizeTokenValue(value) {\n if (typeof value !== \"string\") return null;\n const normalized = value.trim();\n if (!normalized || normalized === \"null\" || normalized === \"undefined\") {\n return null;\n }\n return normalized;\n }\n\n _normalizeTokenRecoveryIdentity(recoveryIdentity) {\n if (!recoveryIdentity || typeof recoveryIdentity !== \"object\") return null;\n\n const userUuid = this._normalizeTokenValue(recoveryIdentity.userUuid);\n if (!userUuid) return null;\n\n return {\n userUuid,\n isExternalUser: recoveryIdentity.isExternalUser === true\n };\n }\n\n _getPersistedTokenRecoveryIdentity() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n\n const rawValue = localStorage.getItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n if (rawValue == null) return null;\n\n try {\n const persistedIdentity = this._normalizeTokenRecoveryIdentity(JSON.parse(rawValue));\n if (persistedIdentity) {\n return persistedIdentity;\n }\n } catch {\n // Fall through to cleanup.\n }\n\n try {\n localStorage.removeItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n } catch {\n // ignore storage cleanup errors\n }\n\n return null;\n }\n\n _clearPersistedTokenRecoveryIdentity() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n\n try {\n localStorage.removeItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n } catch {\n // ignore storage cleanup errors\n }\n }\n\n _clearStoredTokens() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n\n try {\n localStorage.removeItem(\"logdrop_access_token\");\n localStorage.removeItem(\"logdrop_refresh_token\");\n this._clearPersistedTokenRecoveryIdentity();\n this._tokenValidationState.logdrop_access_token = null;\n this._tokenValidationState.logdrop_refresh_token = null;\n } catch (err) {\n this._warnInternal(\"[LogDrop] Failed to clear stored auth state:\", err?.message || err);\n }\n }\n\n _getTokenRecoveryTarget() {\n if (this._user?.userUuid) {\n return { userUuid: this._user.userUuid, isExternalUser: true };\n }\n const persistedRecoveryIdentity = this._getPersistedTokenRecoveryIdentity();\n if (persistedRecoveryIdentity) {\n return persistedRecoveryIdentity;\n }\n if (this._deviceId) {\n return { userUuid: this._deviceId, isExternalUser: false };\n }\n return null;\n }\n\n async _recoverSessionTokens(reason) {\n if (!this._config) {\n this._warnInternal(`[LogDrop] ${reason}; cannot recover tokens before init`);\n return false;\n }\n\n if (!this._config.webSecretKey) {\n this._warnInternal(`[LogDrop] ${reason}; cannot recover tokens without webSecretKey`);\n return false;\n }\n\n const recoveryTarget = this._getTokenRecoveryTarget();\n if (!recoveryTarget) {\n this._warnInternal(`[LogDrop] ${reason}; no recovery identity is available`);\n return false;\n }\n\n if (this._tokenRecoveryPromise) {\n return this._tokenRecoveryPromise;\n }\n\n this._warnInternal(`[LogDrop] ${reason}; attempting signature-based re-auth`);\n\n this._tokenRecoveryPromise = (async () => {\n const recovered = await this._sendUserUpdate(\n recoveryTarget.userUuid,\n recoveryTarget.isExternalUser\n );\n\n if (!recovered) {\n this._warnInternal(\"[LogDrop] Signature-based re-auth did not recover session tokens\");\n }\n\n return recovered;\n })();\n\n try {\n return await this._tokenRecoveryPromise;\n } finally {\n this._tokenRecoveryPromise = null;\n }\n }\n\n _getStoredToken(storageKey, tokenName) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n\n const rawValue = localStorage.getItem(storageKey);\n const normalizedValue = this._normalizeTokenValue(rawValue);\n if (normalizedValue) {\n this._tokenValidationState[storageKey] = null;\n return normalizedValue;\n }\n\n const reason = rawValue == null ? \"missing\" : \"invalid\";\n if (rawValue != null) {\n try {\n localStorage.removeItem(storageKey);\n } catch {\n // ignore storage cleanup errors\n }\n }\n\n if (this._tokenValidationState[storageKey] !== reason) {\n this._tokenValidationState[storageKey] = reason;\n this._warnInternal(`[LogDrop] Stored ${tokenName} is ${reason}; treating it as a deleted token`);\n }\n\n return null;\n }\n\n async _ensureSessionToken(reason) {\n let sessionToken = this._getAccessToken();\n if (sessionToken) return sessionToken;\n\n const recovered = await this._recoverSessionTokens(reason);\n if (!recovered) return null;\n\n sessionToken = this._getAccessToken();\n if (!sessionToken) {\n this._warnInternal(`[LogDrop] ${reason}; re-auth succeeded but no access token was persisted`);\n }\n\n return sessionToken;\n }\n\n _getAccessToken() {\n return this._getStoredToken(\"logdrop_access_token\", \"access token\");\n }\n\n _getRefreshToken() {\n return this._getStoredToken(\"logdrop_refresh_token\", \"refresh token\");\n }\n\n _saveTokens(accessToken, refreshToken, recoveryIdentity = null) {\n if (!hasWindow() || typeof localStorage === \"undefined\") {\n this._warnInternal(\"[LogDrop] Failed to persist session tokens: localStorage is unavailable\");\n return false;\n }\n\n const normalizedAccessToken = this._normalizeTokenValue(accessToken);\n const normalizedRefreshToken = this._normalizeTokenValue(refreshToken);\n const normalizedRecoveryIdentity = this._normalizeTokenRecoveryIdentity(\n recoveryIdentity || this._getTokenRecoveryTarget()\n );\n if (!normalizedAccessToken && !normalizedRefreshToken) {\n this._warnInternal(\"[LogDrop] Failed to persist session tokens: no valid tokens were provided\");\n return false;\n }\n\n try {\n if (normalizedRecoveryIdentity) {\n localStorage.setItem(\n LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY,\n JSON.stringify(normalizedRecoveryIdentity)\n );\n } else {\n this._clearPersistedTokenRecoveryIdentity();\n }\n if (normalizedAccessToken) {\n localStorage.setItem(\"logdrop_access_token\", normalizedAccessToken);\n this._tokenValidationState.logdrop_access_token = null;\n }\n if (normalizedRefreshToken) {\n localStorage.setItem(\"logdrop_refresh_token\", normalizedRefreshToken);\n this._tokenValidationState.logdrop_refresh_token = null;\n }\n return true;\n } catch (err) {\n this._warnInternal(\"[LogDrop] Failed to persist session tokens:\", err?.message || err);\n return false;\n }\n }\n\n /**\n * Compute SHA-256 signature: SHA256(webSecretKey + deviceUuid)\n * Used as fallback auth when no session token is available.\n */\n async _computeSignature(webSecretKey, deviceUuid) {\n const data = new TextEncoder().encode(webSecretKey + deviceUuid);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map(b => b.toString(16).padStart(2, \"0\")).join(\"\");\n }\n\n _getOsInfo() {\n if (!hasWindow() || !navigator) return { osName: \"Unknown\", osVersion: \"Unknown\" };\n\n const ua = navigator.userAgent;\n let osName = \"Unknown\";\n let osVersion = \"Unknown\";\n\n if (ua.includes(\"Windows\")) {\n osName = \"Windows\";\n const match = ua.match(/Windows NT (\\d+\\.\\d+)/);\n if (match) osVersion = match[1];\n } else if (ua.includes(\"iPhone\") || ua.includes(\"iPad\")) {\n // Must come before \"Mac OS X\" \u2014 real iOS UAs contain both \"iPhone\" and \"Mac OS X\"\n osName = \"iOS\";\n const match = ua.match(/OS (\\d+[._]\\d+)/);\n if (match) osVersion = match[1].replace(/_/g, \".\");\n } else if (ua.includes(\"Mac OS X\")) {\n osName = \"macOS\";\n const match = ua.match(/Mac OS X (\\d+[._]\\d+[._]?\\d*)/);\n if (match) osVersion = match[1].replace(/_/g, \".\");\n } else if (ua.includes(\"Android\")) {\n osName = \"Android\";\n const match = ua.match(/Android (\\d+(\\.\\d+)?)/);\n if (match) osVersion = match[1];\n } else if (ua.includes(\"Linux\")) {\n osName = \"Linux\";\n }\n\n return { osName, osVersion };\n }\n\n\n\n _getDeviceBrand() {\n if (!hasWindow() || !navigator) return \"Unknown\";\n\n const ua = navigator.userAgent;\n\n // Mobile brands\n if (ua.includes(\"Samsung\")) return \"Samsung\";\n if (ua.includes(\"Huawei\")) return \"Huawei\";\n if (ua.includes(\"Xiaomi\") || ua.includes(\"Redmi\")) return \"Xiaomi\";\n if (ua.includes(\"OPPO\")) return \"OPPO\";\n if (ua.includes(\"Vivo\")) return \"Vivo\";\n if (ua.includes(\"OnePlus\")) return \"OnePlus\";\n if (ua.includes(\"LG\")) return \"LG\";\n if (ua.includes(\"Sony\")) return \"Sony\";\n if (ua.includes(\"HTC\")) return \"HTC\";\n if (ua.includes(\"Motorola\")) return \"Motorola\";\n if (ua.includes(\"Nokia\")) return \"Nokia\";\n if (ua.includes(\"Google\") || ua.includes(\"Pixel\")) return \"Google\";\n if (ua.includes(\"iPhone\") || ua.includes(\"iPad\") || ua.includes(\"Macintosh\")) return \"Apple\";\n\n // Desktop browsers as \"brand\"\n if (ua.includes(\"Chrome\")) return \"Google\";\n if (ua.includes(\"Firefox\")) return \"Mozilla\";\n if (ua.includes(\"Safari\")) return \"Apple\";\n if (ua.includes(\"Edge\")) return \"Microsoft\";\n\n return \"Unknown\";\n }\n\n _createUserUpdateTask(userUuid, isExternalUser, options = {}) {\n const subscription = this._desiredWebPushSubscription === undefined\n ? undefined\n : this._normalizeWebPushSubscription(this._desiredWebPushSubscription);\n const descriptor = {\n userUuid: String(userUuid || this._deviceId),\n isExternalUser: isExternalUser === true,\n webPushSubscription: subscription,\n reason: options.reason || \"user_update\",\n };\n return {\n ...descriptor,\n key: JSON.stringify(descriptor),\n waiters: [],\n };\n }\n\n _sendUserUpdate(userUuid, isExternalUser = false, options = {}) {\n if (!this._config) return Promise.resolve(false);\n const task = this._createUserUpdateTask(userUuid, isExternalUser, options);\n\n return new Promise((resolve) => {\n if (this._activeUserUpdate?.key === task.key) {\n this._activeUserUpdate.waiters.push(resolve);\n return;\n }\n\n if (this._pendingUserUpdate?.key === task.key) {\n this._pendingUserUpdate.waiters.push(resolve);\n } else if (this._pendingUserUpdate) {\n // Keep only the newest desired state, but resolve callers waiting on\n // the superseded state when that newest state has been persisted.\n task.waiters.push(...this._pendingUserUpdate.waiters, resolve);\n this._pendingUserUpdate = task;\n } else {\n task.waiters.push(resolve);\n this._pendingUserUpdate = task;\n }\n\n void this._drainUserUpdates();\n });\n }\n\n async _drainUserUpdates() {\n if (this._drainingUserUpdates) return;\n this._drainingUserUpdates = true;\n try {\n while (this._pendingUserUpdate) {\n const task = this._pendingUserUpdate;\n this._pendingUserUpdate = null;\n this._activeUserUpdate = task;\n let result = false;\n try {\n result = await this._performUserUpdate(task);\n } catch (err) {\n console.warn(\"[LogDrop] User update failed:\", err?.message || err);\n }\n for (const resolve of task.waiters) resolve(result);\n this._activeUserUpdate = null;\n }\n } finally {\n this._activeUserUpdate = null;\n this._drainingUserUpdates = false;\n if (this._pendingUserUpdate) void this._drainUserUpdates();\n }\n }\n\n async _performUserUpdate(task) {\n const config = this._config;\n if (!config) return false;\n const fetchFn = hasWindow() ? window.fetch : (typeof fetch !== \"undefined\" ? fetch : null);\n if (typeof fetchFn !== \"function\") return false;\n\n const osInfo = this._getOsInfo();\n const last = this._lastSentUserUpdate?.apiKey === config.apiKey\n ? this._lastSentUserUpdate\n : null;\n const runtime = {\n apiKey: config.apiKey,\n userUuid: task.userUuid,\n osName: osInfo.osName,\n osVersion: osInfo.osVersion,\n deviceBrand: this._getDeviceBrand(),\n deviceModel: this._parseDeviceModel(navigator?.userAgent || \"\") || \"Web Browser\",\n appVersion: config.release || \"1.0\",\n sdkVersion: LogDropConstants.SDK_VERSION,\n webPushFingerprint: task.webPushSubscription === undefined\n ? last?.webPushFingerprint\n : this._webPushSubscriptionFingerprint(task.webPushSubscription),\n };\n const device = { deviceUuid: this._deviceId, sdkType: \"WEB\" };\n const deltaFields = [\"osName\", \"osVersion\", \"deviceBrand\", \"deviceModel\", \"appVersion\", \"sdkVersion\"];\n for (const field of deltaFields) {\n if (!last || runtime[field] !== last[field]) device[field] = runtime[field];\n }\n\n const subscriptionChanged = task.webPushSubscription !== undefined &&\n (!last || runtime.webPushFingerprint !== last.webPushFingerprint);\n if (task.webPushSubscription && subscriptionChanged) {\n device.webPushSubscription = task.webPushSubscription;\n }\n\n const identityChanged = !last || runtime.userUuid !== last.userUuid;\n const hasDeviceDelta = Object.keys(device).some((key) => ![\"deviceUuid\", \"sdkType\"].includes(key));\n const sessionToken = this._getAccessToken();\n const refreshToken = this._getRefreshToken();\n if (!identityChanged && !hasDeviceDelta && sessionToken && refreshToken) {\n this._logInternal(`[LogDrop] User update skipped; no changes (${task.reason})`);\n return true;\n }\n\n const headers = {\n \"content-type\": \"application/x-protobuf\",\n \"accept\": \"application/x-protobuf\",\n \"x-api-key\": config.apiKey,\n };\n let usedSignatureAuth = false;\n if (sessionToken) {\n headers[\"x-session-token\"] = sessionToken;\n } else if (config.webSecretKey) {\n headers[\"x-logdrop-signature\"] = await this._computeSignature(\n config.webSecretKey,\n this._deviceId\n );\n usedSignatureAuth = true;\n } else {\n return false;\n }\n\n const requestPayload = { userUuid: task.userUuid, device };\n const protoBytes = encodeUserUpdateRequest(requestPayload);\n this._debugLogProtoBody(\"User update request\", requestPayload, protoBytes);\n\n try {\n // init() may disable and tear down the SDK while signature creation is\n // awaiting Web Crypto. Do not send a request for an obsolete config.\n if (this._config !== config) return false;\n const url = `${config.baseUrl}${LogDropConstants.USERS_UPDATE_PATH}`;\n const res = await fetchFn(url, {\n method: \"POST\",\n headers,\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" }),\n });\n if (!res.ok) return false;\n if (this._config !== config) return false;\n\n if (usedSignatureAuth) {\n try {\n const responseBytes = new Uint8Array(await res.arrayBuffer());\n this._debugLogProtoResponse(\"User update\", responseBytes, decodeSdkTokenResponse);\n if (responseBytes.length > 0) {\n const tokenResponse = decodeSdkTokenResponse(responseBytes);\n this._saveTokens(tokenResponse.accessToken, tokenResponse.refreshToken, {\n userUuid: task.userUuid,\n isExternalUser: task.isExternalUser,\n });\n }\n } catch {\n // Token parsing failed, non-critical for an otherwise successful update.\n }\n }\n\n this._saveLastSentUserUpdate(runtime);\n if (!task.isExternalUser) this._markUserRegistered();\n this._logInternal(`[LogDrop] User update successful (${task.reason})`);\n\n // A first signed registration may be what made automatic push\n // reconciliation possible. Trigger it only before a subscription state\n // has been observed, avoiding a subscribe -> update loop.\n if (usedSignatureAuth && this._desiredWebPushSubscription === undefined) {\n void this._pushModule?.reconcileGrantedSubscription();\n }\n return true;\n } catch (err) {\n // Preserve the existing user-update diagnostic even when SDK debug logs\n // are disabled; authentication/registration failures must be visible.\n // eslint-disable-next-line no-console\n console.warn(\"[LogDrop] User update failed:\", err.message || err);\n this._warnInternal(\"[LogDrop] User update failed:\", err.message || err);\n return false;\n }\n }\n\n async _getDeviceInfo() {\n const info = {\n sessionID: this._sessionId,\n session_create_date: this._sessionCreateDate,\n device_id: this._deviceId,\n userUuid: this._getEffectiveUserUuid(),\n gmt: -(new Date().getTimezoneOffset()), // Convert to GMT offset in minutes (positive = east of UTC)\n };\n\n if (this._riskModule) {\n const snap = this._riskModule.getBotSnapshot();\n if (snap) {\n info.bot_score = snap.botScore;\n info.bot_label = snap.label;\n info.risk_score = snap.riskScore;\n info.posture = snap.posture;\n }\n }\n\n // OS and browser info from userAgent\n if (hasWindow() && navigator) {\n // Locale\n if (navigator.language) {\n info.locale = navigator.language;\n }\n\n // Network available\n if (typeof navigator.onLine === \"boolean\") {\n info.network_available = navigator.onLine;\n }\n\n // RAM size (approximate, in GB)\n if (navigator.deviceMemory) {\n info.ram_size = `${navigator.deviceMemory} GB`;\n }\n\n // CPU cores\n if (navigator.hardwareConcurrency) {\n info.cpu_cores = navigator.hardwareConcurrency;\n }\n\n // Platform/OS\n if (navigator.platform) {\n info.os_version = navigator.platform;\n }\n\n // User agent for device model approximation\n if (navigator.userAgent) {\n info.user_agent = navigator.userAgent;\n // Try to extract device model from userAgent\n const model = this._parseDeviceModel(navigator.userAgent);\n if (model) {\n info.device_model = model;\n }\n }\n\n // Connection info (Network Information API)\n if (navigator.connection) {\n if (navigator.connection.effectiveType) {\n info.connection_type = navigator.connection.effectiveType;\n }\n if (typeof navigator.connection.downlink === \"number\") {\n info.connection_downlink_mbps = navigator.connection.downlink;\n }\n if (typeof navigator.connection.rtt === \"number\") {\n info.connection_rtt_ms = navigator.connection.rtt;\n }\n if (typeof navigator.connection.saveData === \"boolean\") {\n info.save_data_mode = navigator.connection.saveData;\n }\n }\n\n // Battery info (async)\n try {\n if (navigator.getBattery) {\n const battery = await navigator.getBattery();\n if (typeof battery.level === \"number\") {\n info.battery_level = `${Math.round(battery.level * 100)}%`;\n }\n if (typeof battery.charging === \"boolean\") {\n info.low_power_mode = !battery.charging && battery.level < 0.2;\n info.is_charging = battery.charging;\n }\n }\n } catch {\n // Battery API not available or failed\n }\n\n // Storage estimate (async)\n try {\n if (navigator.storage && navigator.storage.estimate) {\n const estimate = await navigator.storage.estimate();\n if (estimate.quota && estimate.usage) {\n const freeBytes = estimate.quota - estimate.usage;\n info.free_disk_space = this._formatBytes(freeBytes);\n info.total_disk_quota = this._formatBytes(estimate.quota);\n }\n }\n } catch {\n // Storage API not available or failed\n }\n }\n\n // Screen info\n if (hasWindow() && window.screen) {\n info.screen_width = window.screen.width;\n info.screen_height = window.screen.height;\n info.screen_color_depth = window.screen.colorDepth;\n if (window.devicePixelRatio) {\n info.device_pixel_ratio = window.devicePixelRatio;\n }\n }\n\n // Document visibility\n if (hasWindow() && document.visibilityState) {\n info.visibility_state = document.visibilityState;\n }\n\n // Page info\n if (hasWindow() && window.location) {\n info.page_url = window.location.href;\n if (document.referrer) {\n info.referrer = document.referrer;\n }\n }\n\n // App version from config\n if (this._config && this._config.release) {\n info.app_version = this._config.release;\n }\n\n return info;\n }\n\n _getUserAgentData() {\n if (!hasWindow() || !navigator) return null;\n\n const uaData = navigator[\"userAgentData\"]; // avoids \"unresolved\" in some toolchains\n if (!uaData || typeof uaData !== \"object\") return null;\n\n return uaData;\n }\n\n _parseDeviceModel(userAgent) {\n if (!hasWindow() || !navigator) return null;\n\n const uaData = this._getUserAgentData();\n if (uaData && typeof uaData.model === \"string\" && uaData.model.trim()) {\n return uaData.model.trim();\n }\n\n // 2) Android model extraction from UA parens\n const mobileMatch = userAgent.match(/\\(([^)]+)\\)/);\n if (mobileMatch) {\n const parts = mobileMatch[1].split(\";\").map(s => s.trim());\n // Android: \"Linux; Android 10; SM-G970F\"\n const androidDevice = parts.find(p => /^(SM-|Pixel|Nexus|LG-|HTC|Huawei|Xiaomi|OPPO|Vivo|OnePlus)/i.test(p));\n if (androidDevice) return androidDevice;\n // iOS: \"iPhone; CPU iPhone OS 14_0\"\n if (parts.some(p => p.includes(\"iPhone\"))) return \"iPhone\";\n if (parts.some(p => p.includes(\"iPad\"))) return \"iPad\";\n }\n\n // 3) Desktop fallback: OS + Browser + major version\n const os = this._getOsInfo();\n const browser = this._getBrowserInfo();\n\n // Example: \"macOS 10.15.7 - Chrome 144\"\n const osPart = `${os.osName} ${os.osVersion}`.trim();\n const brPart = `${browser.name} ${browser.version}`.trim();\n\n return `${osPart} - ${brPart}`.trim();\n }\n\n _getBrowserInfo() {\n if (!hasWindow() || !navigator) return { name: \"Unknown\", version: \"Unknown\" };\n\n const uaData = this._getUserAgentData();\n if (uaData && Array.isArray(uaData.brands)) {\n const preferred =\n uaData.brands.find(b => /Chrome/i.test(b.brand)) ||\n uaData.brands.find(b => /Chromium/i.test(b.brand)) ||\n uaData.brands[0];\n\n return {\n name: preferred?.brand || \"Unknown\",\n version: preferred?.version || \"Unknown\"\n };\n }\n\n const ua = navigator.userAgent;\n\n // Very lightweight UA parsing\n const edge = ua.match(/Edg\\/(\\d+)/);\n if (edge) return { name: \"Edge\", version: edge[1] };\n\n const chrome = ua.match(/Chrome\\/(\\d+)/);\n if (chrome) return { name: \"Chrome\", version: chrome[1] };\n\n const firefox = ua.match(/Firefox\\/(\\d+)/);\n if (firefox) return { name: \"Firefox\", version: firefox[1] };\n\n // Safari (but not Chrome)\n const safari = ua.match(/Version\\/(\\d+).+Safari/);\n if (safari && !ua.includes(\"Chrome\")) return { name: \"Safari\", version: safari[1] };\n\n return { name: \"Unknown\", version: \"Unknown\" };\n }\n\n _formatBytes(bytes) {\n if (bytes === 0) return \"0 Bytes\";\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n }\n\n _scheduleDeviceInfoCollection() {\n if (this._deviceInfoTimer) clearInterval(this._deviceInfoTimer);\n\n // Collect immediately on start\n this._collectAndLogDeviceInfo();\n\n // Then collect every DEVICE_INFO_INTERVAL_MS\n this._deviceInfoTimer = setInterval(() => {\n this._collectAndLogDeviceInfo();\n }, LogDropConstants.DEVICE_INFO_INTERVAL_MS);\n\n if (this._deviceInfoTimer && typeof this._deviceInfoTimer.unref === \"function\") {\n this._deviceInfoTimer.unref();\n }\n }\n\n async _collectAndLogDeviceInfo() {\n if (!this._config) return;\n try {\n const deviceInfo = await this._getDeviceInfo();\n this._enqueue(LogLevel.DEVICEINFO, deviceInfo);\n } catch {\n // best-effort only\n }\n }\n\n _loadCachedServerConfig() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n const cached = localStorage.getItem(LOGDROP_INIT_CACHE_KEY);\n if (cached) {\n const parsed = JSON.parse(cached);\n if (parsed && parsed.data) {\n // Only apply isSDKDisabled from cache to block init if needed\n // isHttpLoggingEnabled stays true until fresh response arrives\n // This ensures all logs are captured while waiting for init response\n if (typeof parsed.data.isSDKDisabled === \"boolean\") {\n this._serverConfig.isSDKDisabled = parsed.data.isSDKDisabled;\n }\n }\n }\n } catch {\n // ignore parse errors\n }\n }\n\n _saveServerConfigToCache(response) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(LOGDROP_INIT_CACHE_KEY, JSON.stringify(response));\n } catch {\n // ignore storage errors (quota exceeded, etc.)\n }\n }\n\n _applyServerConfig(data, applyNetworkChange = false) {\n if (!data) return;\n\n const prevHttpLogging = this._serverConfig.isHttpLoggingEnabled;\n\n // isSDKDisabled\n if (typeof data.isSDKDisabled === \"boolean\") {\n this._serverConfig.isSDKDisabled = data.isSDKDisabled;\n }\n\n // isHttpLoggingEnabled\n if (typeof data.isHttpLoggingEnabled === \"boolean\") {\n this._serverConfig.isHttpLoggingEnabled = data.isHttpLoggingEnabled;\n }\n\n // isCrashTrackingEnabled \u2014 local override from init config takes precedence\n if (typeof data.isCrashTrackingEnabled === \"boolean\" && this._crashTrackingOverride === null) {\n this._serverConfig.isCrashTrackingEnabled = data.isCrashTrackingEnabled;\n }\n\n // isPushEnabled \u2014 forward remote flag to PushModule (REQ-005)\n if (this._pushModule && typeof data.isPushEnabled === \"boolean\") {\n this._pushModule.isPushEnabled = data.isPushEnabled;\n }\n\n // isEventTrackingEnabled \u2014 forward remote flag to EventModule (REQ-025)\n if (typeof data.isEventTrackingEnabled === \"boolean\") {\n this._serverConfig.isEventTrackingEnabled = data.isEventTrackingEnabled;\n this._eventModule?.setEnabled(data.isEventTrackingEnabled);\n }\n\n if (data.riskConfig && typeof data.riskConfig === \"object\") {\n this._serverConfig.riskConfig = data.riskConfig;\n }\n\n if (data.webPushConfig && typeof data.webPushConfig === \"object\") {\n this._serverConfig.webPushConfig = data.webPushConfig;\n if (this._pushModule) {\n this._pushModule.updateServerConfig({\n isPushEnabled: data.webPushConfig.enabled === true,\n vapidPublicKey: data.webPushConfig.vapidPublicKey || null,\n });\n }\n }\n\n // Check if SDK should be disabled after fresh init response\n if (this._serverConfig.isSDKDisabled && this._initialized) {\n this._warnInternal(\"[LogDrop] SDK disabled by server, clearing all logs and shutting down\");\n // Clear all stored logs before shutting down\n void this._clearLogs().catch(() => {});\n this._initialized = false;\n this._config = null;\n this.teardown();\n return; // Don't process further\n }\n\n if (data.riskConfig && typeof data.riskConfig === \"object\") {\n this._syncRiskModuleFromServerConfig();\n }\n\n // Apply the IP reputation action after rebuilding the risk module. Risk\n // module sync clears stale risk-policy UI, so doing this first would also\n // remove a newly displayed IP reputation warning.\n if (Object.prototype.hasOwnProperty.call(data, \"activeIpReputationAction\")) {\n this._applyIpReputationActionFromInit(\n data.activeIpReputationAction,\n data.serverNowEpochMillis\n );\n }\n\n // Apply network tracking change dynamically if requested\n if (applyNetworkChange && this._config) {\n if (this._serverConfig.isHttpLoggingEnabled && !prevHttpLogging) {\n // Enable network tracking\n this._installNetworkInstrumentation();\n } else if (!this._serverConfig.isHttpLoggingEnabled && prevHttpLogging) {\n // Disable network tracking and clear all network logs from DB\n this._logInternal(\"[LogDrop] HTTP logging disabled by server, clearing network logs\");\n this._uninstallNetworkInstrumentation();\n void this._clearNetworkLogs();\n }\n if (this._activeRiskPolicyEvaluation?.actionIds?.includes(RiskActionIds.BLOCK_ALL_NETWORK)) {\n this._refreshNetworkInstrumentationForRiskPolicy();\n }\n }\n }\n\n _installNetworkInstrumentation(forceRiskGuard = false) {\n if (!this._config || this._net) return;\n\n this._net = new NetworkInstrumentation({\n onEvent: (eventName, payload) => {\n if (eventName !== \"network_activity\") return;\n if (!this._serverConfig.isHttpLoggingEnabled || !this._config?.network?.enabled) return;\n this._enqueue(LogLevel.NETWORK_ACTIVITY, payload, new LogFlow(\"NetworkActivity\", payload.uuid));\n },\n getBaseHref,\n excludeUrls: this._config.network.excludeUrls,\n shouldBlockRequest: (url) => this._shouldBlockNetworkRequest(url),\n redaction: { stripQuery: this._config.network.stripQuery, stripHash: this._config.network.stripHash },\n sampling: {\n rate: this._config.network.sampleRate,\n onlyErrors: this._config.network.onlyErrors,\n slowThresholdMs: this._config.network.slowThresholdMs\n },\n capture: {\n fetch: forceRiskGuard || this._config.network.captureFetch,\n xhr: forceRiskGuard || this._config.network.captureXHR,\n headersAllowlist: this._config.network.headersAllowlist\n }\n });\n\n this._net.install();\n }\n\n _uninstallNetworkInstrumentation() {\n if (this._net) {\n this._net.uninstall();\n this._net = null;\n }\n }\n\n _shouldBlockNetworkRequest(rawUrl) {\n const riskPolicyBlocks = this._activeRiskPolicyEvaluation?.actionIds?.includes(\n RiskActionIds.BLOCK_ALL_NETWORK\n ) === true;\n const ipReputationBlocks = this._getActiveIpReputationAction()?.actionIds?.includes(\n RiskActionIds.BLOCK_ALL_NETWORK\n ) === true;\n if (!riskPolicyBlocks && !ipReputationBlocks) return false;\n\n try {\n const requestUrl = new URL(rawUrl, getBaseHref());\n const sdkUrl = new URL(this._config?.baseUrl ?? LogDropConstants.DEFAULT_BASE_URL);\n if (requestUrl.origin.toLowerCase() !== sdkUrl.origin.toLowerCase()) return true;\n\n // On Web, the host alone is not enough: the application and LogDrop may\n // share an origin through a reverse proxy. Exempt only the SDK base path,\n // not every request on the same host/origin.\n const sdkPath = sdkUrl.pathname.replace(/\\/+$/, \"\");\n const requestPath = requestUrl.pathname.replace(/\\/+$/, \"\");\n const isSdkEndpoint = requestPath === sdkPath || requestPath.startsWith(`${sdkPath}/`);\n return !isSdkEndpoint;\n } catch {\n return true;\n }\n }\n\n _loadStoredIpReputationAction() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(LOGDROP_IP_REPUTATION_ACTION_KEY);\n const action = raw ? JSON.parse(raw) : null;\n return action && typeof action.signature === \"string\" && action.signature\n ? action\n : null;\n } catch {\n return null;\n }\n }\n\n _persistIpReputationAction(action) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n if (action) localStorage.setItem(LOGDROP_IP_REPUTATION_ACTION_KEY, JSON.stringify(action));\n else localStorage.removeItem(LOGDROP_IP_REPUTATION_ACTION_KEY);\n } catch {\n // best effort only\n }\n }\n\n _trustedNowForIpReputation(action) {\n const serverNow = Number(action?.receivedServerEpochMillis);\n const receivedAt = Number(action?.receivedAtClientEpochMillis);\n const receivedMonotonic = Number(action?.receivedAtMonotonicMillis);\n const receivedTimeOrigin = Number(action?.receivedPerformanceTimeOrigin);\n const currentMonotonic = typeof performance !== \"undefined\" ? Number(performance.now?.()) : NaN;\n const currentTimeOrigin = typeof performance !== \"undefined\" ? Number(performance.timeOrigin) : NaN;\n if (Number.isFinite(serverNow) && serverNow > 0 &&\n Number.isFinite(receivedMonotonic) && Number.isFinite(currentMonotonic) &&\n Number.isFinite(receivedTimeOrigin) && receivedTimeOrigin === currentTimeOrigin) {\n return serverNow + Math.max(0, currentMonotonic - receivedMonotonic);\n }\n if (Number.isFinite(serverNow) && serverNow > 0 && Number.isFinite(receivedAt) && receivedAt > 0) {\n return serverNow + Math.max(0, Date.now() - receivedAt);\n }\n return Date.now();\n }\n\n _isIpReputationActionExpired(action) {\n const expiresAt = Number(action?.expireAtEpochMillis);\n return !Number.isFinite(expiresAt) || expiresAt <= this._trustedNowForIpReputation(action);\n }\n\n _getActiveIpReputationAction() {\n const action = this._activeIpReputationAction;\n if (!action) return null;\n if (this._isIpReputationActionExpired(action)) {\n this._clearIpReputationAction(\"expired\");\n return null;\n }\n return action;\n }\n\n _resolveIpReputationPresentation(action) {\n const policyRules = this._serverConfig.riskConfig?.ipReputationDetected?.riskPolicy?.rules ?? [];\n const matchingRule = policyRules\n .filter((rule) => rule?.enabled === true && (rule.threatLevels ?? []).includes(action.threatLevel))\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0))[0];\n return {\n ...action,\n title: action.title || matchingRule?.title || null,\n message: action.message || matchingRule?.message || null,\n buttonText: action.buttonText || matchingRule?.buttonText || null,\n };\n }\n\n _hasProcessedIpReputationSignature(signature) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return false;\n try {\n const values = JSON.parse(localStorage.getItem(LOGDROP_IP_REPUTATION_SIGNATURES_KEY) || \"[]\");\n return Array.isArray(values) && values.includes(signature);\n } catch {\n return false;\n }\n }\n\n _markIpReputationSignatureProcessed(signature) {\n if (!hasWindow() || typeof localStorage === \"undefined\" || !signature) return;\n try {\n const parsed = JSON.parse(localStorage.getItem(LOGDROP_IP_REPUTATION_SIGNATURES_KEY) || \"[]\");\n const values = Array.isArray(parsed) ? parsed.filter((value) => typeof value === \"string\") : [];\n const next = [...values.filter((value) => value !== signature), signature].slice(-100);\n localStorage.setItem(LOGDROP_IP_REPUTATION_SIGNATURES_KEY, JSON.stringify(next));\n } catch {\n // best effort only\n }\n }\n\n _scheduleIpReputationExpiry() {\n if (this._ipReputationExpiryTimer) clearTimeout(this._ipReputationExpiryTimer);\n this._ipReputationExpiryTimer = null;\n const action = this._activeIpReputationAction;\n if (!action) return;\n const remaining = Number(action.expireAtEpochMillis) - this._trustedNowForIpReputation(action);\n if (remaining <= 0) {\n this._clearIpReputationAction(\"expired\");\n return;\n }\n this._ipReputationExpiryTimer = setTimeout(\n () => this._scheduleIpReputationExpiry(),\n Math.min(remaining, 2_147_000_000)\n );\n if (typeof this._ipReputationExpiryTimer?.unref === \"function\") {\n this._ipReputationExpiryTimer.unref();\n }\n }\n\n _applyIpReputationActionFromInit(action, serverNowEpochMillis) {\n if (!action || typeof action.signature !== \"string\" || !action.signature.trim()) {\n this._clearIpReputationAction(\"cleared\");\n return;\n }\n const receivedAtClientEpochMillis = Date.now();\n const normalized = this._resolveIpReputationPresentation({\n ...action,\n signature: action.signature.trim(),\n eventId: String(action.eventId || action.signature),\n actionIds: [...new Set((action.actionIds ?? []).filter((id) => actionName(id)))],\n receivedServerEpochMillis: Number(serverNowEpochMillis) || receivedAtClientEpochMillis,\n receivedAtClientEpochMillis,\n receivedAtMonotonicMillis: typeof performance !== \"undefined\" ? Number(performance.now?.()) : null,\n receivedPerformanceTimeOrigin: typeof performance !== \"undefined\" ? Number(performance.timeOrigin) : null,\n });\n if (this._isIpReputationActionExpired(normalized)) {\n this._clearIpReputationAction(\"expired\");\n return;\n }\n const showWarning = !this._hasProcessedIpReputationSignature(normalized.signature);\n this._activeIpReputationAction = normalized;\n this._persistIpReputationAction(normalized);\n this._markIpReputationSignatureProcessed(normalized.signature);\n this._scheduleIpReputationExpiry();\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(this._activeRiskPolicyEvaluation, showWarning);\n }\n\n _restoreIpReputationActionIfNeeded() {\n const action = this._getActiveIpReputationAction();\n if (!action) return;\n this._scheduleIpReputationExpiry();\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(this._activeRiskPolicyEvaluation, false);\n }\n\n _clearIpReputationAction(clearReason = \"cleared\") {\n const previous = this._activeIpReputationAction;\n if (this._ipReputationExpiryTimer) clearTimeout(this._ipReputationExpiryTimer);\n this._ipReputationExpiryTimer = null;\n this._activeIpReputationAction = null;\n this._persistIpReputationAction(null);\n if (previous && this._eventModule) {\n const actionIds = previous.actionIds ?? [];\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.SDK_ACTION_CLEARED, {\n as: \"ip_reputation\",\n cr: clearReason,\n bl: actionIds.includes(RiskActionIds.BLOCK_APP) || actionIds.includes(RiskActionIds.BLOCK_ALL_NETWORK),\n sig: previous.signature,\n saa: actionIds.map(actionName).filter(Boolean).join(\",\") || \"none\",\n });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n if (this._config) {\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(this._activeRiskPolicyEvaluation);\n }\n }\n\n _syncRiskModuleFromServerConfig() {\n const riskDetected = this._serverConfig.riskConfig?.riskDetected;\n const enabled = riskDetected?.enabled === true && (\n riskDetected.botDetectionEnabled === true ||\n riskDetected.otherRiskTypesEnabled === true\n );\n\n this._riskModule?.teardown();\n this._riskModule = null;\n if (this._activeRiskPolicyEvaluation) {\n this._handleRiskPolicyChanged({\n matchedRules: [], actionIds: [], title: null, message: null, buttonText: null,\n });\n } else {\n this._activeRiskPolicyEvaluation = null;\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(null);\n }\n\n if (!enabled || !this._initialized || !this._config) return;\n\n this._riskModule = new RiskModule({\n botDetectionEnabled: riskDetected.botDetectionEnabled === true,\n otherRiskTypesEnabled: riskDetected.otherRiskTypesEnabled === true,\n riskPolicy: riskDetected.riskPolicy,\n onThreatChanged: this._config.onSessionThreatChanged ?? null,\n onRiskEvent: (evt) => this._handleRiskEvent(evt),\n onPolicyChanged: (evaluation) => this._handleRiskPolicyChanged(evaluation),\n checkIntervalMs: 30_000,\n });\n this._riskModule.install();\n }\n\n init(config) {\n this._debugLogEnabled = config?.debugLogEnabled === true || config?.isDebugLogEnabled === true;\n\n if (this._initialized) return;\n\n // Check if SDK is disabled from cached server config\n if (this._serverConfig.isSDKDisabled) {\n this._warnInternal(\"[LogDrop] SDK is disabled by server configuration\");\n return;\n }\n\n if (!config || !config.appId) throw new Error(\"LogDrop.init requires config.appId\");\n const apiKey = String(config.apiKey || \"\").trim();\n if (!apiKey) throw new Error(\"LogDrop.init requires config.apiKey\");\n const defaultWebSecretKey =\n config.webSecretKey == null ? LogDropConstants.DEFAULT_WEB_SECRET_KEY : config.webSecretKey;\n const webSecretKey = String(defaultWebSecretKey || \"\").trim() || null;\n\n // Build config - use provided baseUrl or fall back to default from constants\n const baseUrl = normalizeBaseUrl(config.baseUrl);\n const endpoint = baseUrl;\n\n // NEW: unified network config\n const networkCfg = {\n enabled: config.network?.enabled !== false,\n\n captureFetch: config.network?.captureFetch !== false,\n captureXHR: config.network?.captureXHR !== false,\n\n // Safe defaults\n stripQuery: config.network?.stripQuery !== false,\n stripHash: config.network?.stripHash !== false,\n\n // Sampling defaults\n sampleRate: typeof config.network?.sampleRate === \"number\" ? config.network.sampleRate : 1,\n onlyErrors: config.network?.onlyErrors === true,\n slowThresholdMs:\n typeof config.network?.slowThresholdMs === \"number\" ? config.network.slowThresholdMs : undefined,\n\n // Header capture (default none)\n headersAllowlist: Array.isArray(config.network?.headersAllowlist) ? config.network.headersAllowlist : [],\n\n excludeUrls: [\n LOGDROP_DOMAIN_EXCLUDE,\n baseUrl,\n endpoint,\n LogDropConstants.DEFAULT_BASE_URL,\n ...(Array.isArray(config.network?.excludeUrls) ? config.network.excludeUrls : [])\n ]\n };\n\n this._config = {\n appId: String(config.appId),\n apiKey,\n webSecretKey,\n baseUrl,\n endpoint,\n env: config.env ? String(config.env) : \"prod\",\n release: config.release ? String(config.release) : undefined,\n debugLogEnabled: this._debugLogEnabled,\n flushIntervalMs: typeof config.flushIntervalMs === \"number\" ? config.flushIntervalMs : 60000,\n maxBatchSize: typeof config.maxBatchSize === \"number\" ? config.maxBatchSize : 50,\n\n // NEW\n network: networkCfg,\n\n // Push notifications\n vapidPublicKey: config.vapidPublicKey ? String(config.vapidPublicKey) : null,\n manualServiceWorkerRegistration: config.manualServiceWorkerRegistration === true,\n serviceWorkerUrl: config.serviceWorkerUrl ? String(config.serviceWorkerUrl) : LogDropConstants.PUSH_SW_PATH,\n serviceWorkerScope: config.serviceWorkerScope ? String(config.serviceWorkerScope) : LogDropConstants.PUSH_SW_SCOPE,\n serviceWorkerRegistration: config.serviceWorkerRegistration ?? null,\n onRemoteMessageReceived: typeof config.onRemoteMessageReceived === \"function\" ? config.onRemoteMessageReceived : null,\n\n // Risk & bot detection\n onSessionThreatChanged: typeof config.onSessionThreatChanged === \"function\" ? config.onSessionThreatChanged : null,\n onRiskPolicyActionTaken: typeof config.onRiskPolicyActionTaken === \"function\" ? config.onRiskPolicyActionTaken : null,\n };\n\n // If crashTracking is explicitly set in config, apply it as a local override\n // that takes precedence over whatever the server returns in the init response.\n if (typeof config.crashTracking === \"boolean\") {\n this._serverConfig.isCrashTrackingEnabled = config.crashTracking;\n this._crashTrackingOverride = config.crashTracking;\n } else {\n this._crashTrackingOverride = null;\n }\n\n // Enable debug logs for non-production environments\n LogDropConstants.DEBUG_LOGS_ENABLED = ![\"prod\", \"production\"].includes(this._config.env);\n\n // Global JS error capture (idempotent)\n this._installGlobalErrorHandlers();\n\n // Init persistent log storage (best-effort)\n this._initDb();\n\n this._inAppMessagePresenter = new InAppMessagePresenter({\n onAction: (payload) => this._handleWebPushClick(payload),\n });\n\n // Instantiate PushModule (install lifecycle mirrors NetworkInstrumentation)\n this._pushModule = new PushModule({\n vapidPublicKey: this._config.vapidPublicKey,\n manualServiceWorkerRegistration: this._config.manualServiceWorkerRegistration,\n serviceWorkerUrl: this._config.serviceWorkerUrl,\n serviceWorkerScope: this._config.serviceWorkerScope,\n serviceWorkerRegistration: this._config.serviceWorkerRegistration,\n isPushEnabled: true, // default; overridden by server config in _applyServerConfig\n onRemoteMessageReceived: this._config.onRemoteMessageReceived,\n apiKey: this._config.apiKey,\n apiBase: this._config.baseUrl,\n deviceId: this._deviceId,\n getSessionToken: () => this._getAccessToken(),\n onPushReceived: (payload) => this._handleWebPushReceived(payload),\n onNotificationClick: (payload) => this._handleWebPushClick(payload),\n onSubscriptionChanged: (subscription) => this._handleWebPushSubscriptionChanged(subscription),\n });\n this._pushModule.install();\n this.push = {\n subscribe: () => this._pushModule.subscribe(),\n unsubscribe: () => this._pushModule.unsubscribe(),\n getPermissionState: () => this._pushModule.getPermissionState(),\n };\n\n // Compute release comparison for event tracking (REQ-030)\n const storedRelease = hasWindow() && localStorage\n ? localStorage.getItem(\"logdrop_last_release\")\n : null;\n const isSdkUpdated = !!(this._config.release && storedRelease && this._config.release !== storedRelease);\n const previousRelease = storedRelease;\n if (this._config.release && hasWindow() && localStorage) {\n try { localStorage.setItem(\"logdrop_last_release\", this._config.release); } catch {}\n }\n\n // Instantiate EventModule (lifecycle mirrors PushModule)\n this._eventModule = new EventModule({\n deviceId: this._deviceId,\n getSessionId: () => this._sessionId,\n getUserUuid: () => this._getEffectiveUserUuid(),\n // firstRealUserUuid must reflect the first *real* (identified) user only \u2014\n // it stays empty while the user is anonymous (deviceUuid fallback).\n getRealUserUuid: () => this._user?.userUuid ?? null,\n getSessionToken: () => this._ensureSessionToken(\"Event upload requires a valid access token\"),\n // Mirror every successfully sent event into the log stream at EVENT level.\n logEvent: (eventLog) => this._enqueue(LogLevel.EVENT, eventLog),\n release: this._config.release,\n apiKey: this._config.apiKey,\n apiBase: this._config.baseUrl,\n isEventTrackingEnabled: this._serverConfig.isEventTrackingEnabled,\n isFirstVisit: this._isNewDevice,\n isSdkUpdated,\n previousRelease,\n dbPromise: this._dbPromise,\n });\n this._eventModule.install();\n this._pushModule?.requestPendingMessages();\n this._scheduleEventFlush();\n\n // Init handshake (best-effort, fire-and-forget)\n this._initialized = true;\n void this._sendInitRequest();\n\n // Ensure any previous instrumentation is cleaned up on re-init\n this._uninstallNetworkInstrumentation();\n\n // NEW: Install network instrumentation (preferred path)\n // Only install if both config and server allow it\n if (this._config.network.enabled && this._serverConfig.isHttpLoggingEnabled) {\n this._installNetworkInstrumentation();\n }\n\n // Restore an unexpired server-issued IP reputation action immediately;\n // the fresh init response will confirm, replace, or clear it.\n this._restoreIpReputationActionIfNeeded();\n\n // periodic flush (mirrors Swift's delayed sendLogs behavior)\n this._scheduleFlush();\n this._scheduleFileFlush();\n\n // Start device info collection (every 10 seconds)\n this._scheduleDeviceInfoCollection();\n\n // Start storage monitoring (every 2 minutes)\n this._scheduleStorageCheck();\n\n this.i(\"LogDrop initialized\", {\n appId: this._config.appId,\n env: this._config.env,\n release: this._config.release,\n networkEnabled: this._config.network.enabled\n });\n }\n\n async updateUser(externalId, completion) {\n if (!externalId) {\n this._user = null;\n this._clearPersistedExternalUser();\n this._clearStoredTokens();\n this.i(\"User cleared\");\n if (typeof completion === \"function\") completion(true);\n return;\n }\n\n const userUuid = String(externalId);\n\n // Rotate session when switching from one identified user to a different identified user.\n // Do NOT rotate when going from anonymous (null) to an identified user.\n if (this._user?.userUuid && this._user.userUuid !== userUuid) {\n this._sessionId = this._generateUUID();\n this._sessionCreateDate = nowIso();\n }\n\n this._user = { userUuid };\n // Persist so the identified user survives reloads/restarts until changed.\n this._persistExternalUser(userUuid);\n\n // Send user update request with external ID\n const success = await this._sendUserUpdate(userUuid, true, { reason: \"developer_user_update\" });\n\n this.i(\"User updated\", { userUuid, success });\n if (typeof completion === \"function\") completion(success);\n }\n\n // Severity helpers - with optional LogFlow support\n e(arg0, arg1, logFlow = null) {\n const tagged = typeof arg0 === 'string' && typeof arg1 === 'string' && !_logLevelValues.includes(arg0);\n this._enqueue(LogLevel.ERROR, tagged ? arg1 : arg0, tagged ? logFlow : arg1 instanceof LogFlow ? arg1 : null, tagged ? arg0 : null);\n }\n w(arg0, arg1, logFlow = null) {\n const tagged = typeof arg0 === 'string' && typeof arg1 === 'string' && !_logLevelValues.includes(arg0);\n this._enqueue(LogLevel.WARNING, tagged ? arg1 : arg0, tagged ? logFlow : arg1 instanceof LogFlow ? arg1 : null, tagged ? arg0 : null);\n }\n i(arg0, arg1, logFlow = null) {\n const tagged = typeof arg0 === 'string' && typeof arg1 === 'string' && !_logLevelValues.includes(arg0);\n this._enqueue(LogLevel.INFO, tagged ? arg1 : arg0, tagged ? logFlow : arg1 instanceof LogFlow ? arg1 : null, tagged ? arg0 : null);\n }\n d(arg0, arg1, logFlow = null) {\n const tagged = typeof arg0 === 'string' && typeof arg1 === 'string' && !_logLevelValues.includes(arg0);\n this._enqueue(LogLevel.DEBUG, tagged ? arg1 : arg0, tagged ? logFlow : arg1 instanceof LogFlow ? arg1 : null, tagged ? arg0 : null);\n }\n\n log(tag, message, level, logFlow = null) {\n this._enqueue(level, message, logFlow, tag);\n }\n\n onRemoteMessageReceived(userInfo) {\n // Primary path is now SW \u2192 postMessage \u2192 PushModule \u2192 registered callback.\n // This method remains as a thin delegator for back-compat.\n if (this._config && typeof this._config.onRemoteMessageReceived === \"function\") {\n this._config.onRemoteMessageReceived(userInfo);\n }\n }\n\n saveCustomCrashReport(threadName, stackTrace, crashType = \"CUSTOM\") {\n if (!this._serverConfig.isCrashTrackingEnabled) return;\n this._recordCrash({\n threadName: threadName || \"MainThread\",\n stackTrace: String(stackTrace || \"\"),\n crashType: crashType || \"CUSTOM\",\n isCustomCrash: true\n });\n }\n\n // Emits a discrete risk event (e.g. DevTools opened) as an internal event to\n // the /events/collect endpoint (protobuf) and flushes promptly.\n _handleRiskEvent(evt) {\n if (!this._config || !evt || !this._eventModule) return;\n // Map SDK risk events onto the server's `rd` (risk_detected) event.\n // Required properties: rt (risk_type), rs (risk_score).\n const riskScore = evt.score ?? evt.snapshot?.riskScore ?? evt.snapshot?.score ?? 0;\n const actionIds = this._activeRiskPolicyEvaluation?.actionIds ?? [];\n const actionsApplied = actionIds.map(actionName).filter(Boolean);\n const blocked = actionIds.includes(RiskActionIds.BLOCK_APP) ||\n actionIds.includes(RiskActionIds.BLOCK_ALL_NETWORK);\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.RISK_DETECTED, {\n rt: evt.type,\n rs: riskScore,\n bl: blocked,\n ev: evt.evidence ?? {},\n saa: actionsApplied.join(\",\") || \"none\",\n });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n\n _webPushData(payload) {\n if (!payload || typeof payload !== \"object\") return {};\n return payload.data && typeof payload.data === \"object\" ? payload.data : payload;\n }\n\n _handleWebPushReceived(payload) {\n const data = this._webPushData(payload);\n const action = typeof data.action === \"string\" ? data.action : data.rawExtras?.action;\n const notificationId = String(\n data.notificationId || data.receiveEvent?.properties?.pn || \"\"\n ).trim();\n if (notificationId && this._eventModule) {\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.PUSH_RECEIVED, { pn: notificationId });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n\n this._inAppMessagePresenter?.enqueue(payload);\n\n if (action === \"ip_reputation_action\") {\n this._applyIpReputationActionFromInit({\n signature: data.signature || \"\",\n eventId: data.eventId || data.signature || \"\",\n threatLevel: data.threatLevel || \"UNSPECIFIED\",\n riskScore: Number(data.riskScore) || 0,\n actionIds: String(data.actionIds || \"\")\n .split(\",\")\n .map((value) => Number(value.trim()))\n .filter(Number.isInteger),\n expireAtEpochMillis: Number(data.expireAt) || 0,\n title: data.title || null,\n message: data.message || null,\n buttonText: data.buttonText || null,\n }, Number(data.serverNow) || Date.now());\n } else if (action === \"send_log\") {\n void this.sendLogs().catch(() => {});\n Promise.resolve(this._eventModule?._flush()).catch(() => {});\n }\n\n if (typeof this._config?.onRemoteMessageReceived === \"function\") {\n try { this._config.onRemoteMessageReceived(payload); } catch {}\n }\n }\n\n _handleWebPushClick(payload) {\n const data = this._webPushData(payload);\n const notificationId = String(\n data.notificationId || data.clickEvent?.properties?.pn || \"\"\n ).trim();\n if (notificationId && this._eventModule) {\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.PUSH_CLICK, { pn: notificationId });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n if (typeof this._config?.onRemoteMessageReceived === \"function\") {\n try { this._config.onRemoteMessageReceived(payload); } catch {}\n }\n }\n\n _handleRiskPolicyChanged(evaluation) {\n const previous = this._activeRiskPolicyEvaluation;\n this._activeRiskPolicyEvaluation = evaluation?.actionIds?.length ? evaluation : null;\n if (previous && !this._activeRiskPolicyEvaluation && this._eventModule) {\n const previousNames = previous.actionIds.map(actionName).filter(Boolean);\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.SDK_ACTION_CLEARED, {\n as: \"risk_detected\",\n cr: \"cleared\",\n bl: previous.actionIds.includes(RiskActionIds.BLOCK_APP) ||\n previous.actionIds.includes(RiskActionIds.BLOCK_ALL_NETWORK),\n saa: previousNames.join(\",\") || \"none\",\n });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(this._activeRiskPolicyEvaluation);\n if (!this._activeRiskPolicyEvaluation || !this._config?.onRiskPolicyActionTaken) return;\n\n const matchedEventIds = [...new Set(\n evaluation.matchedRules.flatMap((rule) => rule.eventIds ?? [])\n )];\n try {\n this._config.onRiskPolicyActionTaken({\n actionIds: [...evaluation.actionIds],\n actionNames: evaluation.actionIds.map(actionName).filter(Boolean),\n matchedEventIds,\n matchedRulePriorities: evaluation.matchedRules.map((rule) => rule.priority ?? 0),\n title: evaluation.title,\n message: evaluation.message,\n buttonText: evaluation.buttonText,\n });\n } catch {\n // never break the host app\n }\n }\n\n _refreshNetworkInstrumentationForRiskPolicy() {\n if (!this._config) return;\n const riskPolicyBlock = this._activeRiskPolicyEvaluation?.actionIds?.includes(\n RiskActionIds.BLOCK_ALL_NETWORK\n ) === true;\n const ipReputationBlock = this._getActiveIpReputationAction()?.actionIds?.includes(\n RiskActionIds.BLOCK_ALL_NETWORK\n ) === true;\n const blockAll = riskPolicyBlock || ipReputationBlock;\n const normalCapture = this._config.network?.enabled === true && this._serverConfig.isHttpLoggingEnabled;\n\n this._uninstallNetworkInstrumentation();\n if (normalCapture || blockAll) this._installNetworkInstrumentation(blockAll);\n }\n\n _applyRiskPolicyUi(evaluation, showIpReputationWarning = false) {\n if (this._riskPolicyOverlay?.parentNode) {\n try { this._riskPolicyOverlay.parentNode.removeChild(this._riskPolicyOverlay); } catch {}\n }\n this._riskPolicyOverlay = null;\n\n const ipAction = this._activeIpReputationAction;\n const ipBlocksApp = ipAction?.actionIds?.includes(RiskActionIds.BLOCK_APP) === true;\n const policyBlocksApp = evaluation?.actionIds?.includes(RiskActionIds.BLOCK_APP) === true;\n if (ipBlocksApp) {\n evaluation = ipAction;\n } else if (!policyBlocksApp && showIpReputationWarning &&\n ipAction?.actionIds?.includes(RiskActionIds.SHOW_WARNING)) {\n evaluation = ipAction;\n }\n\n if (!evaluation || typeof document === \"undefined\" || !document.body ||\n typeof document.createElement !== \"function\") return;\n\n const blockApp = evaluation.actionIds.includes(RiskActionIds.BLOCK_APP);\n const showWarning = evaluation.actionIds.includes(RiskActionIds.SHOW_WARNING);\n if (!blockApp && !showWarning) return;\n\n const overlay = document.createElement(\"div\");\n overlay.setAttribute(\"role\", \"alertdialog\");\n overlay.setAttribute(\"aria-modal\", \"true\");\n overlay.style.cssText = [\n \"position:fixed\", \"inset:0\", \"z-index:2147483647\", \"display:flex\",\n \"align-items:center\", \"justify-content:center\", \"padding:24px\",\n \"background:rgba(15,23,42,.72)\", \"font-family:system-ui,sans-serif\",\n ].join(\";\");\n\n const panel = document.createElement(\"div\");\n panel.style.cssText = \"max-width:520px;width:100%;background:white;border-radius:12px;padding:24px;box-shadow:0 24px 64px rgba(0,0,0,.35);color:#111827\";\n const title = document.createElement(\"h2\");\n title.textContent = evaluation.title || (blockApp ? \"Security block\" : \"Security warning\");\n title.style.cssText = \"margin:0 0 12px;font-size:20px\";\n const message = document.createElement(\"p\");\n message.textContent = evaluation.message || \"A security risk was detected.\";\n message.style.cssText = \"margin:0;line-height:1.5\";\n panel.append(title, message);\n\n if (!blockApp) {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = evaluation.buttonText || \"OK\";\n button.style.cssText = \"margin-top:20px;padding:9px 16px;border:0;border-radius:8px;background:#111827;color:white;cursor:pointer\";\n button.addEventListener(\"click\", () => {\n try { overlay.remove(); } catch {}\n if (this._riskPolicyOverlay === overlay) this._riskPolicyOverlay = null;\n }, { once: true });\n panel.appendChild(button);\n }\n\n overlay.appendChild(panel);\n document.body.appendChild(overlay);\n this._riskPolicyOverlay = overlay;\n }\n\n getBotSnapshot() {\n return this._riskModule?.getBotSnapshot() ?? null;\n }\n\n refreshBotSnapshot() {\n this._riskModule?.evaluate();\n return this._riskModule?.getBotSnapshot() ?? null;\n }\n\n getSessionThreat() {\n return this._riskModule?.getSessionThreat() ?? null;\n }\n\n async sendLogs(completion) {\n // Public API - delegates to the new flush system\n if (!this._config) {\n if (typeof completion === \"function\") completion(false);\n return;\n }\n\n const [logsSuccess, crashesSuccess] = await Promise.all([\n this._flushLogs(),\n this._flushCrashes()\n ]);\n const success = logsSuccess && crashesSuccess;\n if (typeof completion === \"function\") completion(success);\n }\n\n _enqueue(level, message, logFlow = null, tag = null) {\n if (!this._config) return;\n\n const entry = {\n ts: nowIso(),\n level,\n // IMPORTANT: if message object convert => JSON string\n message: typeof message === \"string\" ? message : safeStringify(message)\n };\n\n if (tag) {\n entry.tag = tag;\n }\n\n // Add flow info if provided\n if (logFlow && logFlow instanceof LogFlow) {\n entry.flowId = logFlow.id;\n entry.flowName = logFlow.name;\n if (logFlow.customAttributes) {\n entry.flowAttributes = logFlow.customAttributes;\n }\n }\n\n this._queue.push(entry);\n const persistPromise = this._persistLogEntry(entry, logFlow);\n\n // Avoid unbounded memory growth\n if (this._queue.length > 2000) this._queue.splice(0, this._queue.length - 2000);\n\n // Auto-flush when batch is large\n if (this._queue.length >= this._config.maxBatchSize) this.sendLogs();\n\n // Mirror to console only when internal debug logging is enabled.\n this._logInternal(`[LogDrop:${level}] ${entry.message}`);\n return persistPromise;\n \n }\n\n _scheduleFlush() {\n if (!this._config) return;\n\n if (this._flushTimer) clearInterval(this._flushTimer);\n\n this._flushTimer = setInterval(() => this.sendLogs(), this._config.flushIntervalMs);\n\n // In Node dev environments, avoid keeping the process alive\n if (this._flushTimer && typeof this._flushTimer.unref === \"function\") {\n this._flushTimer.unref();\n }\n }\n\n _scheduleEventFlush() {\n if (this._eventFlushTimer) clearInterval(this._eventFlushTimer);\n\n this._eventFlushTimer = setInterval(() => {\n this._eventModule?._flush();\n }, LogDropConstants.EVENT_FLUSH_INTERVAL_MS);\n\n // PERF-002: unref to avoid keeping Node.js process alive in tests\n if (this._eventFlushTimer && typeof this._eventFlushTimer.unref === \"function\") {\n this._eventFlushTimer.unref();\n }\n }\n\n _scheduleFileFlush() {\n if (!this._config) return;\n if (this._fileFlushTimer) clearInterval(this._fileFlushTimer);\n\n this._fileFlushTimer = setInterval(() => {\n this._flushDbToZip();\n }, LogDropConstants.FILE_EXPORT_INTERVAL_MS);\n\n if (this._fileFlushTimer && typeof this._fileFlushTimer.unref === \"function\") {\n this._fileFlushTimer.unref();\n }\n }\n\n _initDb() {\n if (!hasWindow() || !window.indexedDB) return;\n if (this._dbPromise) return;\n\n this._dbPromise = new Promise((resolve, reject) => {\n const request = window.indexedDB.open(\"logdrop\", 3);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(\"logs\")) {\n db.createObjectStore(\"logs\", { keyPath: \"id\", autoIncrement: true });\n }\n if (!db.objectStoreNames.contains(\"crashes\")) {\n db.createObjectStore(\"crashes\", { keyPath: \"id\", autoIncrement: true });\n }\n if (!db.objectStoreNames.contains(\"events\")) {\n db.createObjectStore(\"events\", { keyPath: \"id\", autoIncrement: true });\n }\n if (!db.objectStoreNames.contains(\"event_upload_batch\")) {\n db.createObjectStore(\"event_upload_batch\", { keyPath: \"id\", autoIncrement: true });\n }\n if (!db.objectStoreNames.contains(\"log_upload_batch\")) {\n db.createObjectStore(\"log_upload_batch\", { keyPath: \"id\", autoIncrement: true });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async _persistLogEntry(entry, logFlow = null) {\n if (!this._dbPromise) return;\n try {\n // Check storage size before adding\n await this._enforceStorageLimit();\n\n const db = await this._dbPromise;\n const tx = db.transaction(\"logs\", \"readwrite\");\n\n const logRecord = {\n sessionId: this._sessionId,\n userUuid: this._getEffectiveUserUuid(),\n ts: entry.ts,\n level: entry.level,\n message: entry.message\n };\n\n if (entry.tag) logRecord.tag = entry.tag;\n\n // Add flow info if provided\n if (logFlow && logFlow instanceof LogFlow) {\n logRecord.flowId = logFlow.id;\n logRecord.flowName = logFlow.name;\n if (logFlow.customAttributes) {\n logRecord.flowAttributes = logFlow.customAttributes;\n }\n }\n\n await new Promise((resolve, reject) => {\n tx.objectStore(\"logs\").add(logRecord);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n } catch {\n // best-effort only\n }\n }\n\n async _readAllLogs() {\n if (!this._dbPromise) return [];\n const db = await this._dbPromise;\n return new Promise((resolve, reject) => {\n const tx = db.transaction(\"logs\", \"readonly\");\n const store = tx.objectStore(\"logs\");\n const request = store.getAll();\n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => reject(request.error);\n });\n }\n\n async _readLogUploadBatch() {\n if (!this._dbPromise) return null;\n const db = await this._dbPromise;\n const tx = db.transaction(\"log_upload_batch\", \"readonly\");\n const request = tx.objectStore(\"log_upload_batch\").getAll();\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve((request.result || [])[0] ?? null);\n request.onerror = () => reject(request.error);\n });\n }\n\n async _replaceLogUploadBatch(batch) {\n if (!this._dbPromise) return;\n const db = await this._dbPromise;\n const tx = db.transaction(\"log_upload_batch\", \"readwrite\");\n const store = tx.objectStore(\"log_upload_batch\");\n store.clear();\n if (batch) store.add(batch);\n await new Promise((resolve, reject) => {\n tx.oncomplete = resolve;\n tx.onerror = () => reject(tx.error);\n });\n }\n\n async _persistCrash(crash) {\n if (!this._dbPromise) return;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"crashes\", \"readwrite\");\n tx.objectStore(\"crashes\").add(crash);\n await new Promise((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n } catch {\n // Best effort. The matching CRASH log is still persisted separately.\n }\n }\n\n async _readAllCrashes() {\n if (!this._dbPromise) return [];\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"crashes\", \"readonly\");\n const request = tx.objectStore(\"crashes\").getAll();\n return await new Promise((resolve, reject) => {\n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => reject(request.error);\n });\n } catch {\n return [];\n }\n }\n\n async _deleteCrashesByIds(ids) {\n if (!this._dbPromise || !ids.length) return;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"crashes\", \"readwrite\");\n const store = tx.objectStore(\"crashes\");\n ids.forEach(id => store.delete(id));\n await new Promise((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n } catch {\n // Retry on the next flush.\n }\n }\n\n _buildCrashData({ threadName, stackTrace, crashType, isCustomCrash, sourceUrl = \"\", line = 0, column = 0 }) {\n const pageState = capturePageState();\n const sessionStartedAt = Date.parse(this._sessionCreateDate);\n return {\n timestamp: Date.now(),\n threadName,\n stackTrace: stackTrace.slice(0, 500000),\n sessionId: this._sessionId,\n userUuid: this._getEffectiveUserUuid(),\n crashType,\n appVersion: this._config?.release || \"UNKNOWN\",\n buildNumber: \"\",\n isAppOnBackground: pageState.visibilityState !== \"visible\",\n sessionTime: Number.isFinite(sessionStartedAt) ? Math.max(0, Date.now() - sessionStartedAt) : 0,\n uuid: generateUUID().replace(/-/g, \"\"),\n isCustomCrash,\n url: pageState.url,\n sourceUrl,\n line,\n column\n };\n }\n\n _recordCrash(crashInput) {\n const stackTrace = String(crashInput.stackTrace || \"\");\n const errorIdentity = crashInput.errorIdentity;\n if (errorIdentity && (typeof errorIdentity === \"object\" || typeof errorIdentity === \"function\")) {\n if (this._seenCrashes.has(errorIdentity)) return;\n this._seenCrashes.add(errorIdentity);\n }\n\n const crash = this._buildCrashData({ ...crashInput, stackTrace });\n const logPromise = this._enqueue(\n LogLevel.CRASH,\n stackTrace,\n new LogFlow(\"Crash\", crash.uuid),\n \"LogDropCrashTracker\"\n );\n const crashPromise = this._persistCrash(crash);\n Promise.allSettled([Promise.resolve(logPromise), crashPromise])\n .then(() => this._scheduleCrashFlush())\n .catch(() => {});\n }\n\n _scheduleCrashFlush() {\n if (this._crashFlushTimer) clearTimeout(this._crashFlushTimer);\n\n this._crashFlushTimer = setTimeout(() => {\n this._crashFlushTimer = null;\n void this._flushCrashes().catch(() => {});\n }, this._crashFlushDelayMs);\n\n if (this._crashFlushTimer && typeof this._crashFlushTimer.unref === \"function\") {\n this._crashFlushTimer.unref();\n }\n }\n\n async _clearLogs() {\n if (!this._dbPromise) return;\n const db = await this._dbPromise;\n return new Promise((resolve, reject) => {\n const tx = db.transaction(\"logs\", \"readwrite\");\n const store = tx.objectStore(\"logs\");\n const request = store.clear();\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n });\n }\n\n async _clearNetworkLogs() {\n if (!this._dbPromise) return;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"logs\", \"readwrite\");\n const store = tx.objectStore(\"logs\");\n const request = store.openCursor();\n\n return new Promise((resolve, reject) => {\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n if (cursor.value && cursor.value.level === LogLevel.NETWORK_ACTIVITY) {\n cursor.delete();\n }\n cursor.continue();\n } else {\n resolve();\n }\n };\n request.onerror = () => reject(request.error);\n });\n } catch {\n // best-effort only\n }\n }\n\n async _getStorageSize() {\n if (!this._dbPromise) return 0;\n try {\n const logs = await this._readAllLogs();\n // Estimate size by stringifying\n const jsonStr = JSON.stringify(logs);\n return new Blob([jsonStr]).size;\n } catch {\n return 0;\n }\n }\n\n _getMaxStorageLimit() {\n // V2: Get from init response or use default\n const initData = this._initResponse;\n return initData?.databaseMaxStorageLimitInBytes ?? LogDropConstants.DATABASE_MAX_STORAGE_LIMIT;\n }\n\n async _enforceStorageLimit() {\n if (!this._dbPromise) return;\n\n try {\n const currentSize = await this._getStorageSize();\n const maxLimit = this._getMaxStorageLimit();\n\n if (currentSize >= maxLimit) {\n // Try to upload first\n const uploadSuccess = await this._flushLogs();\n\n if (!uploadSuccess) {\n // Upload failed, need to delete oldest logs (FIFO)\n await this._deleteOldestLogs(currentSize - maxLimit + LogDropConstants.MAX_LOCAL_STORAGE_SIZE);\n }\n }\n } catch {\n // best-effort only\n }\n }\n\n async _deleteOldestLogs(bytesToFree) {\n if (!this._dbPromise || bytesToFree <= 0) return;\n\n try {\n const logs = await this._readAllLogs();\n if (!logs.length) return;\n\n // Sort by timestamp (oldest first)\n logs.sort((a, b) => new Date(a.ts) - new Date(b.ts));\n\n const idsToDelete = [];\n let freedBytes = 0;\n\n for (const log of logs) {\n if (freedBytes >= bytesToFree) break;\n\n const logSize = new Blob([JSON.stringify(log)]).size;\n idsToDelete.push(log.id);\n freedBytes += logSize;\n }\n\n if (idsToDelete.length > 0) {\n await this._deleteLogsByIds(idsToDelete);\n this._logInternal(`[LogDrop] Deleted ${idsToDelete.length} oldest logs to free storage`);\n }\n } catch {\n // best-effort only\n }\n }\n\n _scheduleStorageCheck() {\n if (this._storageCheckTimer) clearInterval(this._storageCheckTimer);\n\n this._storageCheckTimer = setInterval(async () => {\n await this._checkStorageAndFlush();\n }, LogDropConstants.STORAGE_CHECK_INTERVAL_MS);\n\n if (this._storageCheckTimer && typeof this._storageCheckTimer.unref === \"function\") {\n this._storageCheckTimer.unref();\n }\n }\n\n async _checkStorageAndFlush() {\n if (!this._config) return;\n\n try {\n const currentSize = await this._getStorageSize();\n\n // If storage exceeds 5MB, trigger upload\n if (currentSize >= LogDropConstants.MAX_LOCAL_STORAGE_SIZE) {\n this._logInternal(`[LogDrop] Storage size ${this._formatBytes(currentSize)} exceeds limit, triggering upload`);\n await this._flushLogs();\n }\n } catch {\n // best-effort only\n }\n }\n\n // V2: _getRemainingLimit is no longer needed as a separate API call.\n // The remaining limit is returned in the LogResponse from the /logs endpoint.\n // We keep a cached value from the last init or log response.\n _getCachedRemainingLimit() {\n if (this._cachedRemainingLimit != null) return this._cachedRemainingLimit;\n return LogDropConstants.DEFAULT_INITIAL_REMAINING_LIMIT;\n }\n\n _getMaxFileSize() {\n // V2: Get from init response (now a direct ConfigResponse, not nested under .data)\n const initData = this._initResponse;\n return initData?.perUserMaxFileSizeLimitInBytes ?? 5242880;\n }\n\n _getMinFileSize() {\n // V2: Get minimum file size from init response\n const initData = this._initResponse;\n return initData?.perUserMinFileSizeLimitInBytes ?? 524288;\n }\n\n _groupLogsBySession(logs) {\n const groups = {};\n for (const log of logs) {\n const sessionId = log.sessionId || \"unknown\";\n if (!groups[sessionId]) {\n groups[sessionId] = [];\n }\n groups[sessionId].push(log);\n }\n return groups;\n }\n\n async _getDeviceInfoForSession(sessionId) {\n // Find the most recent device_info for this session\n const logs = await this._readAllLogs();\n const deviceInfoLogs = logs.filter(\n (log) => log.sessionId === sessionId && log.level === LogLevel.DEVICEINFO\n );\n\n if (deviceInfoLogs.length > 0) {\n const last = deviceInfoLogs[deviceInfoLogs.length - 1];\n const msg = last?.message;\n\n if (typeof msg === \"string\" && msg.trim()) {\n try {\n const parsed = JSON.parse(msg);\n if (parsed && typeof parsed === \"object\") return parsed;\n } catch {\n }\n }\n }\n\n // Fallback: generate current device info\n return await this._getDeviceInfo();\n }\n\n _buildLogChunk(sessionGroups, maxFileSize, remainingLimit) {\n const effectiveMaxSize = Math.min(maxFileSize, remainingLimit);\n\n if (effectiveMaxSize <= 0) {\n return null;\n }\n\n const chunk = { sessions: [], size: 0, logIds: [], droppedLogIds: [] };\n\n const appendSessionLogs = (sessionId, sessionLogs) => {\n if (!sessionLogs.length) return;\n chunk.sessions.push({ sessionId, logs: sessionLogs });\n };\n\n for (const [sessionId, logs] of Object.entries(sessionGroups)) {\n const sessionLogs = [];\n\n for (const log of logs) {\n const logEntry = {\n id: log.id,\n ts: log.ts,\n level: log.level,\n message: log.message,\n flowId: log.flowId,\n flowName: log.flowName,\n flowAttributes: log.flowAttributes\n };\n\n const entrySize = JSON.stringify(logEntry).length;\n\n if (entrySize > effectiveMaxSize) {\n chunk.droppedLogIds.push(log.id);\n this._warnInternal(\n `[LogDrop] Dropping oversized log ${log.id} for session ${sessionId}; entry size ${this._formatBytes(entrySize)} exceeds chunk limit ${this._formatBytes(effectiveMaxSize)}`\n );\n continue;\n }\n\n if (chunk.size + entrySize > effectiveMaxSize && chunk.size > 0) {\n appendSessionLogs(sessionId, sessionLogs);\n return chunk.sessions.length > 0 || chunk.droppedLogIds.length > 0 ? chunk : null;\n }\n\n sessionLogs.push(logEntry);\n chunk.logIds.push(log.id);\n chunk.size += entrySize;\n }\n\n appendSessionLogs(sessionId, sessionLogs);\n }\n\n return chunk.sessions.length > 0 || chunk.droppedLogIds.length > 0 ? chunk : null;\n }\n\n async _compressToGzip(data) {\n const jsonString = JSON.stringify(data);\n const encoder = new TextEncoder();\n const uint8Array = encoder.encode(jsonString);\n\n // Try CompressionStream API (modern browsers)\n if (typeof CompressionStream !== \"undefined\") {\n try {\n const stream = new Blob([uint8Array]).stream();\n const compressedStream = stream.pipeThrough(new CompressionStream(\"gzip\"));\n const compressedBlob = await new Response(compressedStream).blob();\n return new Uint8Array(await compressedBlob.arrayBuffer());\n } catch {\n // Fall through to uncompressed\n }\n }\n\n // Fallback: return uncompressed JSON as Uint8Array\n return uint8Array;\n }\n\n async _sendLogFile(gzipBytes, uploadId = \"\") {\n if (!this._config) {\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n }\n\n const fetchFn = hasWindow() ? window.fetch : (typeof fetch !== \"undefined\" ? fetch : null);\n if (typeof fetchFn !== \"function\") {\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n }\n\n const sessionToken = await this._ensureSessionToken(\"Log upload requires a valid access token\");\n if (!sessionToken) {\n this._warnInternal(\"[LogDrop] No valid session token after recovery attempt, skipping log upload\");\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n }\n\n try {\n const osInfo = this._getOsInfo();\n let remainingLimit = this._cachedRemainingLimit;\n\n // V2: Wrap gzipped content in a LogRequest protobuf\n const requestPayload = {\n content: gzipBytes,\n deviceUuid: this._deviceId,\n appVersion: this._config.release || \"1.0\",\n sdkVersion: LogDropConstants.SDK_VERSION,\n osVersion: osInfo.osVersion,\n errorCount: \"0\",\n uploadId,\n };\n const protoBytes = encodeLogRequest(requestPayload);\n this._debugLogProtoBody(\"Log upload request\", requestPayload, protoBytes);\n\n const url = `${this._config.baseUrl}${LogDropConstants.LOGS_PATH}`;\n const res = await fetchFn(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-protobuf\",\n \"accept\": \"application/x-protobuf\",\n \"x-api-key\": this._config.apiKey,\n \"x-session-token\": sessionToken\n },\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" })\n });\n\n if (res.ok) {\n // Parse LogResponse to get remaining limit\n try {\n const responseBytes = new Uint8Array(await res.arrayBuffer());\n this._debugLogProtoResponse(\"Log upload\", responseBytes, decodeLogResponse);\n if (responseBytes.length > 0) {\n const logResponse = decodeLogResponse(responseBytes);\n this._cachedRemainingLimit = logResponse.remainingLimit;\n remainingLimit = this._cachedRemainingLimit;\n }\n } catch {\n // Non-critical, response parsing failed\n }\n return { success: true, remainingLimit };\n }\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n } catch {\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n }\n }\n\n async _sendCrashReport(gzipBytes) {\n if (!this._config) return false;\n\n const fetchFn = hasWindow() ? window.fetch : (typeof fetch !== \"undefined\" ? fetch : null);\n if (typeof fetchFn !== \"function\") return false;\n\n const sessionToken = await this._ensureSessionToken(\"Crash upload requires a valid access token\");\n if (!sessionToken) {\n this._warnInternal(\"[LogDrop] No valid session token after recovery attempt, skipping crash upload\");\n return false;\n }\n\n try {\n const requestPayload = {\n content: gzipBytes,\n deviceUuid: this._deviceId,\n sdkVersion: LogDropConstants.SDK_VERSION\n };\n const protoBytes = encodeCrashReportRequest(requestPayload);\n this._debugLogProtoBody(\"Crash upload request\", requestPayload, protoBytes);\n\n const url = `${this._config.baseUrl}${LogDropConstants.CRASH_PATH}`;\n const res = await fetchFn(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-protobuf\",\n \"accept\": \"application/x-protobuf\",\n \"x-api-key\": this._config.apiKey,\n \"x-session-token\": sessionToken\n },\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" })\n });\n\n return res.ok;\n } catch {\n return false;\n }\n }\n\n async _flushCrashes() {\n if (!this._config || !this._dbPromise || this._crashFlushInProgress) return false;\n this._crashFlushInProgress = true;\n try {\n const crashes = await this._readAllCrashes();\n if (!crashes.length) {\n this._seenCrashes.clear();\n return true;\n }\n\n const crashIds = crashes.map(crash => crash.id).filter(id => id !== undefined);\n const payload = {\n crashes: crashes.map(({ id, ...crash }) => crash)\n };\n const gzipBytes = await this._compressToGzip(payload);\n const success = await this._sendCrashReport(gzipBytes);\n if (success) {\n await this._deleteCrashesByIds(crashIds);\n this._seenCrashes.clear();\n }\n return success;\n } finally {\n this._crashFlushInProgress = false;\n }\n }\n\n async _deleteLogsByIds(ids) {\n if (!this._dbPromise || !ids.length) return;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"logs\", \"readwrite\");\n const store = tx.objectStore(\"logs\");\n\n for (const id of ids) {\n store.delete(id);\n }\n\n return new Promise((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n } catch {\n // best-effort only\n }\n }\n\n _formatLogForExport(log) {\n // Format log entry for export\n // Required: level, message, timestamp, file_and_line\n // Optional: id (flowId), flow_name\n const formatted = {\n level: log.level || \"\",\n message: log.message || \"\",\n timestamp: log.ts || \"\",\n file_and_line: \"\" // Web SDK doesn't have file/line info\n };\n\n // Add flow info if present\n if (log.flowId) {\n formatted.id = log.flowId;\n }\n if (log.flowName) {\n formatted.flow_name = log.flowName;\n }\n\n if (log.tag) {\n formatted.tag = log.tag;\n }\n\n return formatted;\n }\n\n _formatDeviceInfoForExport(deviceInfo) {\n const di = deviceInfo && typeof deviceInfo === \"object\" ? deviceInfo : {};\n\n return {\n sessionID: di.sessionID || \"\",\n session_create_date: di.session_create_date || \"\",\n os_version: di.os_version || \"\",\n app_version: di.app_version || \"\",\n device_model: di.device_model || \"\",\n locale: di.locale || \"\",\n free_disk_space: di.free_disk_space || \"\",\n battery_level: di.battery_level || \"\",\n low_power_mode: di.low_power_mode || \"\",\n ram_size: di.ram_size || \"\",\n device_id: di.device_id || \"\",\n userUuid: di.userUuid ?? null,\n sim_operator_name: \"\",\n network_available: di.network_available ?? true,\n gmt: di.gmt ?? 0,\n ...(di.bot_score !== undefined && {\n bot_score: di.bot_score,\n bot_label: di.bot_label,\n posture: di.posture,\n }),\n };\n }\n\n async _flushLogs() {\n if (!this._config || this._fileFlushInProgress) return false;\n if (!this._dbPromise) return false;\n this._fileFlushInProgress = true;\n\n try {\n // Step 1: Check if there are any logs to send BEFORE making API calls\n const allLogs = await this._readAllLogs();\n\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n this._logInternal(`[LogDrop DEBUG] _flushLogs called. DB log count: ${allLogs.length}`);\n }\n\n if (!allLogs.length) {\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n this._logInternal(\"[LogDrop DEBUG] No logs in DB, skipping flush (no API call made)\");\n }\n // Nothing to send, skip API calls\n return true;\n }\n\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n this._logInternal(\"[LogDrop DEBUG] Logs from DB:\", allLogs);\n }\n\n if (this._cachedRemainingLimit == null) {\n this._logInternal(\n `[LogDrop] Remaining upload quota unknown; using conservative default limit of ${this._formatBytes(LogDropConstants.DEFAULT_INITIAL_REMAINING_LIMIT)} until a successful upload response updates the cache`\n );\n }\n\n // Step 2: Get max file size from init response\n const maxFileSize = this._getMaxFileSize();\n\n // Step 3: Build and send chunks one at a time using the latest cached quota.\n let pendingLogs = allLogs;\n let anySuccess = false;\n\n while (pendingLogs.length > 0) {\n const remainingLimit = this._getCachedRemainingLimit();\n if (remainingLimit <= 0) {\n this._logInternal(\"[LogDrop] Remaining limit reached, stopping upload\");\n break;\n }\n\n const activeBatch = await this._readLogUploadBatch();\n let uploadId = activeBatch?.uploadId ?? null;\n let chunk;\n\n if (activeBatch) {\n const activeIds = new Set(activeBatch.logIds || []);\n const activeLogs = pendingLogs.filter((log) => activeIds.has(log.id));\n if (activeLogs.length === 0) {\n await this._replaceLogUploadBatch(null);\n continue;\n }\n chunk = this._buildLogChunk(\n this._groupLogsBySession(activeLogs),\n Number.MAX_SAFE_INTEGER,\n Number.MAX_SAFE_INTEGER,\n );\n } else {\n const sessionGroups = this._groupLogsBySession(pendingLogs);\n chunk = this._buildLogChunk(sessionGroups, maxFileSize, remainingLimit);\n }\n if (!chunk) {\n break;\n }\n\n if (chunk.droppedLogIds.length > 0) {\n await this._deleteLogsByIds(chunk.droppedLogIds);\n const droppedLogIds = new Set(chunk.droppedLogIds);\n pendingLogs = pendingLogs.filter(log => !droppedLogIds.has(log.id));\n anySuccess = true;\n }\n\n if (!chunk.sessions.length) {\n continue;\n }\n\n if (!uploadId) {\n uploadId = this._generateUUID();\n await this._replaceLogUploadBatch({ uploadId, logIds: chunk.logIds });\n }\n\n // Build the payload in the required format:\n // [{ device_info: {...}, logs: [...] }, ...]\n const payload = [];\n\n for (const session of chunk.sessions) {\n const rawDeviceInfo = await this._getDeviceInfoForSession(session.sessionId);\n const deviceInfo = this._formatDeviceInfoForExport(rawDeviceInfo);\n\n const formattedLogs = session.logs.map(log => this._formatLogForExport(log));\n\n payload.push({\n device_info: deviceInfo,\n logs: formattedLogs\n });\n }\n\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n const payloadJson = JSON.stringify(payload);\n const payloadSize = new Blob([payloadJson]).size;\n this._logInternal(`[LogDrop DEBUG] Payload before gzip - Size: ${this._formatBytes(payloadSize)}, Log IDs: ${chunk.logIds.join(\", \")}`);\n this._logInternal(\"[LogDrop DEBUG] Payload content:\", payload);\n }\n\n // Step 7: Compress to gzip\n const gzipBlob = await this._compressToGzip(payload);\n\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n this._logInternal(`[LogDrop DEBUG] After gzip - Size: ${this._formatBytes(gzipBlob.length)}`);\n }\n\n // Step 8: Send to backend\n const uploadResult = await this._sendLogFile(gzipBlob, uploadId);\n\n if (uploadResult.success) {\n this._logInternal(`[LogDrop] Successfully sent ${chunk.logIds.length} logs`);\n\n // Step 9: Delete sent logs from DB\n await this._deleteLogsByIds(chunk.logIds);\n await this._replaceLogUploadBatch(null);\n const sentLogIds = new Set(chunk.logIds);\n pendingLogs = pendingLogs.filter(log => !sentLogIds.has(log.id));\n anySuccess = true;\n\n if (uploadResult.remainingLimit != null && uploadResult.remainingLimit <= 0) {\n this._logInternal(\"[LogDrop] Remaining limit exhausted after upload, stopping flush\");\n break;\n }\n } else {\n this._warnInternal(\"[LogDrop] Failed to send log chunk, will retry later\");\n // Don't delete logs, they'll be retried\n break;\n }\n }\n\n return anySuccess;\n } catch (err) {\n this._warnInternal(\"[LogDrop] Flush failed:\", err.message || err);\n return false;\n } finally {\n this._fileFlushInProgress = false;\n }\n }\n\n // Legacy method - kept for backward compatibility\n async _flushDbToZip() {\n return this._flushLogs();\n }\n\n async _sendInitRequest(attempt = 1) {\n const MAX_ATTEMPTS = 3;\n\n if (!this._config) {\n this._failInit(\"LogDrop init failed: no config\");\n return;\n }\n\n const fetchFn = hasWindow() ? window.fetch : (typeof fetch !== \"undefined\" ? fetch : null);\n if (typeof fetchFn !== \"function\") {\n this._failInit(\"LogDrop init failed: fetch not available\");\n return;\n }\n\n try {\n const headers = {\n \"content-type\": \"application/x-protobuf\",\n \"accept\": \"application/x-protobuf\",\n \"x-api-key\": this._config.apiKey\n };\n\n const sessionToken = this._getAccessToken();\n const refreshToken = this._getRefreshToken();\n\n if (!sessionToken || !refreshToken) {\n const recoveryReasons = [];\n if (!sessionToken) {\n recoveryReasons.push(\n `Stored access token is ${this._tokenValidationState.logdrop_access_token || \"unavailable\"}`\n );\n }\n if (!refreshToken) {\n recoveryReasons.push(\n `Stored refresh token is ${this._tokenValidationState.logdrop_refresh_token || \"unavailable\"}`\n );\n }\n void this._recoverSessionTokens(recoveryReasons.join(\"; \"));\n }\n\n // Add session token if available\n if (sessionToken) {\n headers[\"x-session-token\"] = sessionToken;\n }\n\n const requestPayload = {\n refreshToken: refreshToken || \"\",\n deviceUuid: this._deviceId\n };\n const protoBytes = encodeInitRequest(requestPayload);\n this._debugLogProtoBody(\"Init request\", requestPayload, protoBytes);\n\n const url = `${this._config.baseUrl}${LogDropConstants.INIT_PATH}`;\n const res = await fetchFn(url, {\n method: \"POST\",\n headers,\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" })\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n // V2: Decode protobuf ConfigResponse\n const responseBytes = new Uint8Array(await res.arrayBuffer());\n this._debugLogProtoResponse(\"Init\", responseBytes, decodeConfigResponse);\n if (responseBytes.length > 0) {\n this._initResponse = decodeConfigResponse(responseBytes);\n\n // Cache the response in localStorage (as JSON for simplicity)\n this._saveServerConfigToCache({ data: this._initResponse });\n\n // If a new access token was returned, save it\n if (this._initResponse.accessToken) {\n this._saveTokens(this._initResponse.accessToken, null, this._getTokenRecoveryTarget());\n }\n\n // Apply server config (with dynamic network change)\n this._applyServerConfig(this._initResponse, true);\n }\n\n this._logInternal(\"[LogDrop] Init successful\");\n\n // Auto-register user if this is a new device and user not yet registered\n if (this._isNewDevice && !this._isUserRegistered()) {\n // Use device UUID as userUuid for automatic registration\n void this._sendUserUpdate(this._deviceId, false, { reason: \"automatic_device_registration\" });\n }\n } catch (err) {\n if (attempt < MAX_ATTEMPTS) {\n this._warnInternal(`[LogDrop] Init attempt ${attempt} failed, retrying... (${err.message || err})`);\n // Wait before retry (exponential backoff: 1s, 2s)\n await new Promise(r => setTimeout(r, attempt * 1000));\n return this._sendInitRequest(attempt + 1);\n }\n\n this._failInit(`LogDrop init failed after ${MAX_ATTEMPTS} attempts: ${err.message || err}`);\n }\n }\n\n _failInit(message) {\n this._errorInternal(message);\n this._initialized = false;\n this._config = null;\n this.teardown();\n }\n\n _installGlobalErrorHandlers() {\n if (!hasWindow()) return;\n if (this._errorHandlersInstalled) return;\n this._errorHandlersInstalled = true;\n\n window.addEventListener(\"error\", (event) => {\n if (!this._serverConfig.isCrashTrackingEnabled) return;\n const err = event.error;\n const stack = (err && err.stack) ? String(err.stack) : (event.message || \"\");\n this._recordCrash({\n threadName: \"window\",\n stackTrace: stack,\n crashType: err?.name || \"Error\",\n isCustomCrash: false,\n sourceUrl: event.filename || \"\",\n line: event.lineno || 0,\n column: event.colno || 0,\n errorIdentity: err\n });\n });\n\n window.addEventListener(\"unhandledrejection\", (event) => {\n if (!this._serverConfig.isCrashTrackingEnabled) return;\n const reason = event.reason;\n const stack = (reason instanceof Error && reason.stack) ? String(reason.stack) : String(reason || \"\");\n this._recordCrash({\n threadName: \"unhandledrejection\",\n stackTrace: stack,\n crashType: reason instanceof Error ? reason.name : \"UnhandledRejection\",\n isCustomCrash: false,\n errorIdentity: reason instanceof Error ? reason : null\n });\n });\n }\n\n // Optional: restore original fetch (useful for teardown/debug)\n restoreFetch() {\n if (!hasWindow()) return;\n if (this._originalFetch) window.fetch = this._originalFetch;\n this._fetchInstrumented = false;\n this._originalFetch = null;\n }\n\n // Optional: teardown everything (recommended for tests / hot reload)\n teardown() {\n if (this._flushTimer) clearInterval(this._flushTimer);\n this._flushTimer = null;\n if (this._fileFlushTimer) clearInterval(this._fileFlushTimer);\n this._fileFlushTimer = null;\n if (this._crashFlushTimer) clearTimeout(this._crashFlushTimer);\n this._crashFlushTimer = null;\n if (this._deviceInfoTimer) clearInterval(this._deviceInfoTimer);\n this._deviceInfoTimer = null;\n if (this._storageCheckTimer) clearInterval(this._storageCheckTimer);\n this._storageCheckTimer = null;\n\n this._seenCrashes.clear();\n this._uninstallNetworkInstrumentation();\n\n // Push module teardown (REQ-014)\n this._pushModule?.teardown();\n this._pushModule = null;\n this._inAppMessagePresenter?.teardown();\n this._inAppMessagePresenter = null;\n this.push = null;\n\n // Event module teardown (REQ-031)\n if (this._eventFlushTimer) clearInterval(this._eventFlushTimer);\n this._eventFlushTimer = null;\n this._eventModule?.teardown();\n this._eventModule = null;\n\n this._riskModule?.teardown();\n this._riskModule = null;\n this._activeRiskPolicyEvaluation = null;\n if (this._ipReputationExpiryTimer) clearTimeout(this._ipReputationExpiryTimer);\n this._ipReputationExpiryTimer = null;\n if (this._riskPolicyOverlay?.parentNode) {\n try { this._riskPolicyOverlay.parentNode.removeChild(this._riskPolicyOverlay); } catch {}\n }\n this._riskPolicyOverlay = null;\n\n // Deprecated path cleanup\n this.restoreFetch();\n this._debugLogEnabled = false;\n }\n}\n\n// Singleton facade\nexport const LogDrop = new LogDropClient();\n", "export class LogDropConstants {}\n\n/**\n * Default base URL for the LogDrop API.\n *\n * This points to the development/staging server. Production applications\n * should override this by passing a `baseUrl` option to `LogDrop.init()`.\n *\n * The SDK's `normalizeBaseUrl()` function automatically appends `/api/v2/sdk`\n * to this value, so the effective base for all requests becomes:\n * `https://dev-server.logdrop.io/api/v2/sdk`\n */\nLogDropConstants.DEFAULT_BASE_URL = \"https://dev-server.logdrop.io\";\nLogDropConstants.DEFAULT_WEB_SECRET_KEY = \"xuM9w0BAQEFx\";\nLogDropConstants.FILE_EXPORT_INTERVAL_MS = 300000;\nLogDropConstants.DEVICE_INFO_INTERVAL_MS = 10000;\nLogDropConstants.SDK_VERSION =\n typeof __LOGDROP_SDK_VERSION__ !== \"undefined\" ? __LOGDROP_SDK_VERSION__ : \"1.0.0\";\n\n// Storage management\nLogDropConstants.STORAGE_CHECK_INTERVAL_MS = 120000; // 2 minutes\nLogDropConstants.MAX_LOCAL_STORAGE_SIZE = 5242880; // 5MB\nLogDropConstants.DATABASE_MAX_STORAGE_LIMIT = 16000000; // 16MB (from init response default)\n\n// Off by default. init() sets this to true when config.env is not \"prod\" or \"production\".\nLogDropConstants.DEBUG_LOGS_ENABLED = true;\n\n// DevTools detection \u2014 the size-diff heuristic only catches *docked* DevTools.\n// The console-getter probe can additionally detect DevTools opened in a\n// separate (undocked) window, but every probe is necessarily visible in the\n// browser console. Keep it opt-in so the SDK never pollutes host-app logs.\nLogDropConstants.DEVTOOLS_CONSOLE_PROBE_ENABLED = false;\nLogDropConstants.DEVTOOLS_PROBE_INTERVAL_MS = 1500;\n\n// Endpoint paths \u2014 all SDK HTTP calls construct URLs using these constants\nLogDropConstants.INIT_PATH = \"/logdrop/init\";\nLogDropConstants.LOGS_PATH = \"/logs\";\nLogDropConstants.CRASH_PATH = \"/crash\";\nLogDropConstants.USERS_UPDATE_PATH = \"/users/update\";\n\n// Push notification paths\nLogDropConstants.PUSH_SW_PATH = \"/_logdrop/logdrop-sw.js\";\nLogDropConstants.PUSH_SW_SCOPE = \"/\";\n\n// Event tracking paths\nLogDropConstants.EVENTS_PATH = \"/events/collect\";\nLogDropConstants.EVENT_FLUSH_INTERVAL_MS = 10000;\n\n// Server-recognized event short codes (from the LogDrop event registry).\n// The /events/collect endpoint rejects the ENTIRE batch with HTTP 400 if it\n// contains any event whose code is not in this set, so events with unknown\n// codes must be dropped before batching. Each code also has required property\n// keys the server enforces (see EVENT_REQUIRED_PROPS).\nLogDropConstants.EVENT_CODES = Object.freeze({\n APP_INSTALL: \"ai\",\n APP_OPEN: \"ao\",\n APP_FOREGROUNDED: \"af\",\n APP_BACKGROUNDED: \"ab\",\n APP_PERMISSIONS: \"ap\",\n APP_UPDATE: \"au\",\n DEEPLINK_OPEN: \"do\",\n TIME_IN_APP: \"ta\",\n PUSH_RECEIVED: \"pr\",\n PUSH_CLICK: \"pc\",\n WHITELIST_DOMAIN_DETECTED: \"wd\",\n RISK_DETECTED: \"rd\",\n SDK_ACTION_CLEARED: \"sac\",\n});\n\nLogDropConstants.VALID_EVENT_CODES = Object.freeze(\n Object.values(LogDropConstants.EVENT_CODES)\n);\n\n// Human-readable event names keyed by short code. Used when mirroring a sent\n// event into the log stream (LogLevel.EVENT) so log payloads carry eventName.\nLogDropConstants.EVENT_NAMES = Object.freeze({\n ai: \"app_install\",\n ao: \"app_open\",\n af: \"app_foregrounded\",\n ab: \"app_backgrounded\",\n ap: \"app_permissions\",\n au: \"app_update\",\n do: \"deeplink_open\",\n ta: \"time_in_app\",\n pr: \"push_received\",\n pc: \"push_click\",\n wd: \"whitelist_domain_detected\",\n rd: \"risk_detected\",\n sac: \"sdk_action_cleared\",\n});\n\n// Required property keys per event code. The server returns HTTP 400 (empty\n// body) when a valid code is missing any of its required properties.\nLogDropConstants.EVENT_REQUIRED_PROPS = Object.freeze({\n ai: [],\n ao: [],\n af: [],\n ab: [],\n ap: [\"pt\", \"ps\"],\n au: [\"pv\", \"nv\"],\n do: [\"ol\"],\n ta: [\"ed\"],\n pr: [\"pn\"],\n pc: [\"pn\"],\n wd: [\"rs\", \"dm\"],\n rd: [\"rt\", \"rs\"],\n sac: [\"as\", \"cr\"],\n});\nLogDropConstants.DEFAULT_INITIAL_REMAINING_LIMIT = 15728640; // 15MB conservative upload cap before quota is known\n", "// instrumentation/networkInstrumentation.js\n// Fetch + XHR instrumentation with recursion guard, redaction, and optional sampling.\n// Updated: exclude checks now evaluate both raw and absolute URLs (so domain rules like /logdrop\\.io/ work even for relative URLs).\n\nfunction genId() {\n return Math.random().toString(16).slice(2) + Date.now().toString(16);\n}\n\nfunction hasWindow() {\n return typeof window !== \"undefined\";\n}\n\nfunction perfNow() {\n if (hasWindow() && window.performance && typeof window.performance.now === \"function\") {\n return window.performance.now();\n }\n return Date.now();\n}\n\nfunction safeUrlToString(input) {\n try {\n if (typeof input === \"string\") return input;\n if (input && typeof input.url === \"string\") return input.url;\n return String(input ?? \"unknown\");\n } catch {\n return \"unknown\";\n }\n}\n\nfunction safeJsonParse(str) {\n try {\n return JSON.parse(str);\n } catch {\n return null;\n }\n}\n\nfunction parseXhrResponseHeaders(raw) {\n try {\n if (!raw || typeof raw !== \"string\") return null;\n const out = {};\n const lines = raw.trim().split(/[\\r\\n]+/);\n for (const line of lines) {\n const idx = line.indexOf(\":\");\n if (idx === -1) continue;\n const k = line.slice(0, idx).trim().toLowerCase();\n const v = line.slice(idx + 1).trim();\n if (k) out[k] = v;\n }\n return Object.keys(out).length ? out : null;\n } catch {\n return null;\n }\n}\n\nfunction normalizeBody(body) {\n if (body == null) return null;\n\n // fetch init.body can be string/Blob/FormData/etc.\n if (typeof body === \"string\") {\n const asJson = safeJsonParse(body);\n return asJson ?? body;\n }\n\n // XHR body can be string/Document/FormData/etc.\n if (typeof body === \"object\") {\n // Don't try to serialize FormData/Blob/ArrayBuffer aggressively\n if (typeof FormData !== \"undefined\" && body instanceof FormData) return \"[FormData]\";\n if (typeof Blob !== \"undefined\" && body instanceof Blob) return `[Blob ${body.type || \"unknown\"} ${body.size} bytes]`;\n if (typeof ArrayBuffer !== \"undefined\" && body instanceof ArrayBuffer) return `[ArrayBuffer ${body.byteLength} bytes]`;\n }\n\n try {\n return String(body);\n } catch {\n return \"[unserializable]\";\n }\n}\n\nfunction buildFinalNetworkPayload({requestId, method, url, status, tookMs, requestHeaders, requestBody, responseHeaders, responseBody, errorType, errorMessage, didComplete}) {\n // didComplete = \"a response lifecycle completed\" (fetch resolved or XHR loadend)\n // isSuccess = transport success (request completed), NOT \"2xx\"\n const isSuccess = didComplete === true;\n\n const payload = {\n isSuccess,\n uuid: String(requestId || \"\"),\n method: String(method || \"\"),\n url: String(url || \"\"),\n requestHeaders: requestHeaders || {},\n requestBody: requestBody ?? null,\n status: typeof status === \"number\" ? status : 0,\n responseHeaders: responseHeaders || {},\n responseBody: responseBody ?? null,\n tookMs: typeof tookMs === \"number\" ? tookMs : 0\n };\n\n // Only attach error fields when transport failed.\n // This matches your iOS example behavior: responseBody can contain error details while isSuccess stays true.\n if (!isSuccess) {\n payload.errorType = errorType ?? \"network_error\";\n payload.errorMessage = errorMessage ?? \"network_error\";\n }\n\n return payload;\n}\n\n\n\nfunction normalizeUrl(rawUrl, baseHref, {stripQuery = true, stripHash = true} = {}) {\n try {\n const u = new URL(rawUrl, baseHref);\n if (stripQuery) u.search = \"\";\n if (stripHash) u.hash = \"\";\n return u.toString();\n } catch {\n // rawUrl may be relative or malformed; best-effort\n return String(rawUrl || \"unknown\");\n }\n}\n\nfunction toAbsoluteUrl(rawUrl, baseHref) {\n try {\n return new URL(String(rawUrl || \"\"), baseHref).toString();\n } catch {\n return String(rawUrl || \"\");\n }\n}\n\nfunction matchExclude(url, exclude = []) {\n const s = String(url || \"\");\n return exclude.some((rule) => {\n if (!rule) return false;\n if (rule instanceof RegExp) return rule.test(s);\n return s.includes(String(rule));\n });\n}\n\nfunction shouldSample(sampleRate) {\n // sampleRate: 0..1\n if (typeof sampleRate !== \"number\") return true;\n if (sampleRate <= 0) return false;\n if (sampleRate >= 1) return true;\n return Math.random() < sampleRate;\n}\n\nfunction extractFetchMethod(input, init) {\n // fetch(input, init)\n // input may be Request\n try {\n if (init && init.method) return String(init.method).toUpperCase();\n if (input && typeof input.method === \"string\") return String(input.method).toUpperCase();\n } catch {\n }\n return \"GET\";\n}\n\nfunction extractResponseHeaders(res) {\n try {\n if (!res || !res.headers) return null;\n const out = {};\n // Headers.forEach is supported widely\n res.headers.forEach((v, k) => { out[String(k).toLowerCase()] = String(v); });\n return Object.keys(out).length ? out : null;\n } catch {\n return null;\n }\n}\n\nfunction extractFetchHeaders(input, init) {\n const out = {};\n const source = init?.headers ?? input?.headers;\n\n try {\n if (!source) return null;\n\n if (typeof Headers !== \"undefined\" && source instanceof Headers) {\n source.forEach((v, k) => { out[String(k).toLowerCase()] = String(v); });\n return Object.keys(out).length ? out : null;\n }\n\n if (Array.isArray(source)) {\n for (const [k, v] of source) out[String(k).toLowerCase()] = String(v);\n return Object.keys(out).length ? out : null;\n }\n\n if (typeof source === \"object\") {\n for (const k of Object.keys(source)) out[String(k).toLowerCase()] = String(source[k]);\n return Object.keys(out).length ? out : null;\n }\n } catch {}\n\n return null;\n}\n\nexport class NetworkInstrumentation {\n /**\n * @param {{\n * onEvent: (eventName: string, meta: any) => void,\n * getBaseHref?: () => string,\n * excludeUrls?: (string|RegExp)[],\n * redaction?: { stripQuery?: boolean, stripHash?: boolean },\n * sampling?: { rate?: number, onlyErrors?: boolean, slowThresholdMs?: number },\n * capture?: { fetch?: boolean, xhr?: boolean },\n * shouldBlockRequest?: (url: string) => boolean\n * }} opts\n */\n constructor(opts) {\n this._onEvent = opts.onEvent;\n this._getBaseHref = opts.getBaseHref || (() => (hasWindow() ? window.location.href : \"http://localhost/\"));\n this._excludeUrls = opts.excludeUrls || [];\n this._redaction = opts.redaction || {stripQuery: true, stripHash: true};\n this._sampling = opts.sampling || {rate: 1, onlyErrors: false, slowThresholdMs: undefined};\n this._capture = opts.capture || {fetch: true, xhr: true};\n this._shouldBlockRequest = typeof opts.shouldBlockRequest === \"function\"\n ? opts.shouldBlockRequest\n : () => false;\n\n // Fetch state\n this._fetchInstalled = false;\n this._originalFetch = null;\n\n // XHR state\n this._xhrInstalled = false;\n this._xhrProto = null;\n this._xhrOrigOpen = null;\n this._xhrOrigSend = null;\n this._xhrOrigSetHeader = null;\n }\n\n install() {\n if (!hasWindow()) return;\n\n if (this._capture.fetch) this._installFetch();\n if (this._capture.xhr) this._installXHR();\n }\n\n uninstall() {\n if (!hasWindow()) return;\n\n this._uninstallFetch();\n this._uninstallXHR();\n }\n\n _shouldExclude(rawUrl) {\n const baseHref = this._getBaseHref();\n const absUrl = toAbsoluteUrl(rawUrl, baseHref);\n\n // Check both raw and absolute form to support:\n // - relative URLs (/api/x)\n // - domain-based excludes (e.g., /logdrop\\.io/i)\n return matchExclude(rawUrl, this._excludeUrls) || matchExclude(absUrl, this._excludeUrls);\n }\n\n _shouldBlock(rawUrl) {\n try { return this._shouldBlockRequest(String(rawUrl || \"\")) === true; }\n catch { return false; }\n }\n\n _emit(eventName, meta) {\n try {\n this._onEvent(eventName, meta);\n } catch {\n // never break host app\n }\n }\n\n _installFetch() {\n if (this._fetchInstalled) return;\n if (typeof window.fetch !== \"function\") return;\n\n this._fetchInstalled = true;\n this._originalFetch = window.fetch.bind(window);\n\n window.fetch = async (input, init) => {\n const method = extractFetchMethod(input, init);\n const rawUrl = safeUrlToString(input);\n\n if (this._shouldBlock(rawUrl)) {\n throw new TypeError(\"Request blocked by LogDrop risk policy\");\n }\n // recursion guard / logging exclusions\n if (this._shouldExclude(rawUrl)) {\n return this._originalFetch(input, init);\n }\n\n const baseHref = this._getBaseHref();\n const url = normalizeUrl(rawUrl, baseHref, this._redaction);\n\n const requestId = genId();\n const start = perfNow();\n\n let headers = {};\n try {\n // This merges input(Request) + init headers like the browser will\n const req = new Request(input, init);\n const h = {};\n req.headers.forEach((v, k) => { h[String(k).toLowerCase()] = String(v); });\n headers = h;\n } catch {\n // fallback (still better than empty)\n headers = extractFetchHeaders(input, init) || {};\n }\n\n try {\n const reqBody = normalizeBody(init?.body);\n\n const res = await this._originalFetch(input, init);\n\n const tookMs = Math.round(perfNow() - start);\n const status = res?.status ?? 0;\n\n const isError = !res || status >= 400 || status === 0;\n const isSlow =\n typeof this._sampling.slowThresholdMs === \"number\" &&\n tookMs >= this._sampling.slowThresholdMs;\n\n if (!this._sampling.onlyErrors || isError || isSlow) {\n if (shouldSample(this._sampling.rate)) {\n // best-effort response body (clone)\n let responseBody = null;\n try {\n const ct = res?.headers?.get?.(\"content-type\") || \"\";\n const cloned = res.clone();\n const text = await cloned.text();\n const asJson = ct.includes(\"application/json\") ? safeJsonParse(text) : null;\n responseBody = asJson ?? text;\n } catch {\n // ignore\n }\n\n const respHeaders = extractResponseHeaders(res) || {};\n\n const payload = buildFinalNetworkPayload({\n requestId,\n method,\n url,\n status,\n tookMs,\n requestHeaders: headers,\n requestBody: reqBody,\n responseHeaders: respHeaders,\n responseBody,\n errorType: null,\n errorMessage: null,\n didComplete: true\n });\n\n this._emit(\"network_activity\", payload);\n }\n }\n\n return res;\n } catch (err) {\n const tookMs = Math.round(perfNow() - start);\n\n if (shouldSample(this._sampling.rate)) {\n const reqBody = normalizeBody(init?.body);\n\n const payload = buildFinalNetworkPayload({\n requestId,\n method,\n url,\n status: 0,\n tookMs,\n requestHeaders: headers,\n requestBody: reqBody,\n responseHeaders: {},\n responseBody: null,\n errorType: err?.name ?? \"fetch_error\",\n errorMessage: String(err),\n didComplete: false\n });\n\n this._emit(\"network_activity\", payload);\n }\n\n throw err;\n }\n };\n }\n\n _uninstallFetch() {\n if (!this._fetchInstalled) return;\n if (!this._originalFetch) return;\n window.fetch = this._originalFetch;\n this._fetchInstalled = false;\n this._originalFetch = null;\n }\n\n _installXHR() {\n if (this._xhrInstalled) return;\n if (typeof window.XMLHttpRequest !== \"function\") return;\n\n this._xhrInstalled = true;\n\n const proto = window.XMLHttpRequest.prototype;\n this._xhrProto = proto;\n\n this._xhrOrigOpen = proto.open;\n this._xhrOrigSend = proto.send;\n this._xhrOrigSetHeader = proto.setRequestHeader;\n\n // Preserve originals for our overrides\n proto.__ld_open_orig = this._xhrOrigOpen;\n proto.__ld_send_orig = this._xhrOrigSend;\n proto.__ld_setheader_orig = this._xhrOrigSetHeader;\n\n // Attach metadata to each XHR instance\n proto.open = function (method, url, async, user, password) {\n this.__ld = {\n requestId: genId(),\n method: String(method || \"GET\").toUpperCase(),\n rawUrl: String(url || \"unknown\"),\n start: 0,\n headers: {}\n };\n return proto.__ld_open_orig.call(this, method, url, async, user, password);\n };\n\n proto.setRequestHeader = function (name, value) {\n try {\n if (this.__ld && name) this.__ld.headers[String(name).toLowerCase()] = String(value);\n } catch {\n }\n return proto.__ld_setheader_orig.call(this, name, value);\n };\n\n const client = this; // capture instrumentation instance\n\n proto.send = function (body) {\n const ld = this.__ld;\n if (!ld) return proto.__ld_send_orig.call(this, body);\n\n if (client._shouldBlock(ld.rawUrl)) {\n try { this.abort(); } catch {}\n return;\n }\n if (client._shouldExclude(ld.rawUrl)) {\n return proto.__ld_send_orig.call(this, body);\n }\n\n const baseHref = client._getBaseHref();\n const url = normalizeUrl(ld.rawUrl, baseHref, client._redaction);\n\n const headers = ld.headers || {};\n\n ld.start = perfNow();\n\n const finalize = async (eventName) => {\n const tookMs = Math.round(perfNow() - ld.start);\n const status = this.status ?? 0;\n\n const isError = eventName !== \"loadend\" || status >= 400 || status === 0;\n const isSlow =\n typeof client._sampling.slowThresholdMs === \"number\" &&\n tookMs >= client._sampling.slowThresholdMs;\n\n if (!client._sampling.onlyErrors || isError || isSlow) {\n if (shouldSample(client._sampling.rate)) {\n\n // request body best-effort\n const requestBody = normalizeBody(body);\n\n // response body best-effort\n let responseBody = null;\n try {\n // NOTE: responseType \"\" or \"text\" -> use responseText, otherwise use response\n if (!this.responseType || this.responseType === \"text\") {\n const txt = this.responseText;\n const asJson = safeJsonParse(txt);\n responseBody = asJson ?? txt;\n } else {\n responseBody = this.response ?? null;\n }\n } catch {\n // ignore\n }\n\n let responseHeaders = {};\n try {\n const raw = this.getAllResponseHeaders?.();\n const parsed = parseXhrResponseHeaders(raw);\n if (parsed) responseHeaders = parsed;\n } catch {\n // ignore\n }\n\n const didComplete = eventName === \"loadend\";\n\n const payload = buildFinalNetworkPayload({\n requestId: ld.requestId,\n method: ld.method,\n url,\n status: didComplete ? status : 0,\n tookMs,\n requestHeaders: headers,\n requestBody,\n responseHeaders: responseHeaders,\n responseBody: didComplete ? responseBody : null,\n errorType: didComplete ? null : eventName,\n errorMessage: didComplete ? null : eventName,\n didComplete\n });\n\n client._emit(\"network_activity\", payload);\n }\n }\n };\n\n // Use loadend as \"finished\" signal; plus error/abort/timeout\n this.addEventListener(\"loadend\", () => { void finalize(\"loadend\"); }, { once: true });\n this.addEventListener(\"error\", () => { void finalize(\"error\"); }, { once: true });\n this.addEventListener(\"abort\", () => { void finalize(\"abort\"); }, { once: true });\n this.addEventListener(\"timeout\", () => { void finalize(\"timeout\"); }, { once: true });\n\n return proto.__ld_send_orig.call(this, body);\n };\n }\n\n _uninstallXHR() {\n if (!this._xhrInstalled) return;\n if (!this._xhrProto) return;\n\n // Restore originals (best-effort)\n if (this._xhrOrigOpen) this._xhrProto.open = this._xhrOrigOpen;\n if (this._xhrOrigSend) this._xhrProto.send = this._xhrOrigSend;\n if (this._xhrOrigSetHeader) this._xhrProto.setRequestHeader = this._xhrOrigSetHeader;\n\n // Cleanup helper refs\n try {\n delete this._xhrProto.__ld_open_orig;\n delete this._xhrProto.__ld_send_orig;\n delete this._xhrProto.__ld_setheader_orig;\n } catch {\n }\n\n this._xhrInstalled = false;\n this._xhrProto = null;\n this._xhrOrigOpen = null;\n this._xhrOrigSend = null;\n this._xhrOrigSetHeader = null;\n }\n}\n", "// LogDrop PushModule \u2014 full implementation\n// Mirrors the lifecycle pattern used by NetworkInstrumentation\n// (constructor config slice, install() / uninstall() / teardown()).\n//\n// Scope notes:\n// - This module ONLY touches push-specific APIs (navigator.serviceWorker,\n// PushManager, Notification) and delegates config plumbing to the caller.\n// - It does NOT patch global fetch/XHR. The SDK-wide recursion guard for\n// instrumentation lives in networkInstrumentation.js.\n//\n// Requirements covered: REQ-001, REQ-003, REQ-005, REQ-007, REQ-011, REQ-012,\n// REQ-013, REQ-014, REQ-015, REQ-026.\n\nimport { LogDropConstants } from \"../constants.js\";\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n/**\n * Detects whether a global browser `window` object is available.\n * @returns {boolean} `true` if a global `window` object is defined, `false` otherwise.\n */\n\nfunction hasWindow() {\n return typeof window !== \"undefined\";\n}\n\n/**\n * Selects the best available fetch implementation for the current environment.\n * Prefers a `window.fetch` bound to `window` when present, falls back to the global `fetch`, and yields `null` if none exist.\n * @returns {Function|null} The chosen `fetch` function (bound to `window` when applicable), or `null` if no fetch is available.\n */\n/**\n * Decode a base64url-encoded VAPID public key into a byte array for PushManager.\n *\n * Converts a base64url string (RFC 4648 URL-safe alphabet, no padding) into a\n * Uint8Array of raw bytes suitable for use as `applicationServerKey` when\n * subscribing to push notifications.\n *\n * @param {string} base64String - The base64url-encoded VAPID public key.\n * @returns {Uint8Array} The decoded public key as a byte array.\n */\nfunction urlBase64ToUint8Array(base64String) {\n const padding = \"=\".repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, \"+\").replace(/_/g, \"/\");\n const rawData = atob(base64);\n const output = new Uint8Array(rawData.length);\n for (let i = 0; i < rawData.length; i++) {\n output[i] = rawData.charCodeAt(i);\n }\n return output;\n}\n\n/**\n * Create an Error with a machine-readable `code` property.\n * @param {string} code - Short error code identifying the error.\n * @param {string} [message] - Human-readable error message.\n * @returns {Error} The Error instance with its `code` property set.\n */\nfunction createError(code, message) {\n const err = new Error(message);\n err.code = code;\n return err;\n}\n\n// ---------------------------------------------------------------------------\n// PushModule\n// ---------------------------------------------------------------------------\n\nexport class PushModule {\n /**\n * @param {{\n * vapidPublicKey?: string,\n * manualServiceWorkerRegistration?: boolean,\n * serviceWorkerUrl?: string,\n * serviceWorkerScope?: string,\n * serviceWorkerRegistration?: ServiceWorkerRegistration | null,\n * isPushEnabled?: boolean,\n * onRemoteMessageReceived?: ((payload: any) => void) | null,\n * apiKey?: string,\n * apiBase?: string,\n * deviceId?: string,\n * getSessionToken?: (() => string | null) | null,\n * onPushReceived?: ((payload: any) => void) | null,\n * onNotificationClick?: ((payload: any) => void) | null,\n * onSubscriptionChanged?: ((subscription: Object|null) => Promise<void>|void) | null,\n * }} [config]\n */\n constructor(config) {\n const cfg = config ?? {};\n this.vapidPublicKey = cfg.vapidPublicKey ?? null;\n this.manualServiceWorkerRegistration = cfg.manualServiceWorkerRegistration === true;\n this.serviceWorkerUrl = cfg.serviceWorkerUrl ?? LogDropConstants.PUSH_SW_PATH;\n this.serviceWorkerScope = cfg.serviceWorkerScope ?? LogDropConstants.PUSH_SW_SCOPE;\n this.serviceWorkerRegistration = cfg.serviceWorkerRegistration ?? null;\n // Default to enabled so callers that omit the flag still get push; explicit\n // false disables subscribe().\n this.isPushEnabled = cfg.isPushEnabled !== false;\n this.onRemoteMessageReceived =\n typeof cfg.onRemoteMessageReceived === \"function\"\n ? cfg.onRemoteMessageReceived\n : null;\n this.apiKey = cfg.apiKey ?? null;\n this.apiBase = cfg.apiBase ?? \"\";\n this.deviceId = cfg.deviceId ?? null;\n this.getSessionToken = typeof cfg.getSessionToken === \"function\" ? cfg.getSessionToken : null;\n this.onPushReceived = typeof cfg.onPushReceived === \"function\" ? cfg.onPushReceived : null;\n this.onNotificationClick =\n typeof cfg.onNotificationClick === \"function\" ? cfg.onNotificationClick : null;\n this.onSubscriptionChanged =\n typeof cfg.onSubscriptionChanged === \"function\" ? cfg.onSubscriptionChanged : null;\n\n this._messageHandler = null;\n this._installed = false;\n this._tornDown = false;\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n install() {\n if (this._installed || this._tornDown) return;\n if (!hasWindow()) return;\n const sw = this._getServiceWorkerContainer();\n if (!sw || typeof sw.addEventListener !== \"function\") return;\n\n this._messageHandler = (event) => {\n try {\n const data = event && event.data;\n if (!data || typeof data !== \"object\") return;\n if (data.type === \"logdrop:push-received\" && this.onPushReceived) {\n try { this.onPushReceived(data.payload); } catch {}\n } else if (data.type === \"logdrop:notification-click\") {\n if (this.onNotificationClick) {\n try { this.onNotificationClick(data.payload); } catch {}\n } else if (typeof this.onRemoteMessageReceived === \"function\") {\n try { this.onRemoteMessageReceived(data.payload); } catch {}\n }\n }\n } catch {\n // swallow listener errors \u2014 we must not propagate into the SW bridge\n }\n };\n\n sw.addEventListener(\"message\", this._messageHandler);\n this._installed = true;\n }\n\n uninstall() {\n if (!this._installed) {\n this._messageHandler = null;\n return;\n }\n if (hasWindow()) {\n const sw = this._getServiceWorkerContainer();\n if (sw && typeof sw.removeEventListener === \"function\" && this._messageHandler) {\n try {\n sw.removeEventListener(\"message\", this._messageHandler);\n } catch {\n // ignore\n }\n }\n }\n this._messageHandler = null;\n this._installed = false;\n }\n\n teardown() {\n this.uninstall();\n this._tornDown = true;\n }\n\n // -------------------------------------------------------------------------\n // Permission\n // -------------------------------------------------------------------------\n\n getPermissionState() {\n if (typeof Notification === \"undefined\") return \"unsupported\";\n try {\n return Notification.permission ?? \"unsupported\";\n } catch {\n return \"unsupported\";\n }\n }\n\n updateServerConfig({ isPushEnabled, vapidPublicKey } = {}) {\n if (typeof isPushEnabled === \"boolean\") this.isPushEnabled = isPushEnabled;\n if (typeof vapidPublicKey === \"string\" || vapidPublicKey === null) {\n this.vapidPublicKey = vapidPublicKey;\n }\n void this._syncServiceWorkerConfig();\n void this._syncGrantedSubscription();\n }\n\n requestPendingMessages() {\n const sw = this._getServiceWorkerContainer();\n try {\n if (sw?.controller && typeof sw.controller.postMessage === \"function\") {\n sw.controller.postMessage({ type: \"logdrop:drain-pending\" });\n }\n } catch {\n // best effort\n }\n }\n\n // -------------------------------------------------------------------------\n // subscribe()\n // -------------------------------------------------------------------------\n\n async subscribe() {\n if (this._tornDown) {\n throw createError(\n \"TEARDOWN\",\n \"PushModule has been torn down; subscribe() is no longer available\"\n );\n }\n\n // 1. Secure context check (REQ-026)\n if (hasWindow() && window.isSecureContext === false) {\n throw createError(\n \"INSECURE_CONTEXT\",\n \"Push requires a secure context (HTTPS). window.isSecureContext is false.\"\n );\n }\n\n // 2. Feature detection (REQ-015). We intentionally look at the feature\n // that actually matters (navigator.serviceWorker + Notification). The\n // concrete PushManager capability is probed a second time against the\n // registration below, which catches environments that expose\n // navigator.serviceWorker but cannot register push (e.g. iOS Safari\n // without Home-Screen install, tests that explicitly strip pushManager).\n const notificationAvailable = typeof Notification !== \"undefined\";\n const serviceWorkerAvailable =\n typeof navigator !== \"undefined\" && !!navigator.serviceWorker;\n if (!serviceWorkerAvailable || !notificationAvailable) {\n throw createError(\n \"PUSH_UNSUPPORTED\",\n \"Push notifications are not supported in this browser (serviceWorker or Notification API unavailable).\"\n );\n }\n\n // 3. isPushEnabled === false \u2192 no-op (REQ-005)\n if (this.isPushEnabled === false) {\n return null;\n }\n\n // 4. Require vapidPublicKey\n if (!this.vapidPublicKey) {\n throw createError(\n \"MISSING_VAPID_KEY\",\n \"vapidPublicKey is required to subscribe to push notifications\"\n );\n }\n\n // 5. Permission state handling\n const current = this.getPermissionState();\n if (current === \"denied\") {\n throw createError(\n \"PERMISSION_DENIED\",\n \"Notification permission has been denied by the user\"\n );\n }\n if (current === \"default\") {\n const result = await Notification.requestPermission();\n if (result !== \"granted\") {\n throw createError(\n \"PERMISSION_DENIED\",\n \"Notification permission was not granted\"\n );\n }\n } else if (current !== \"granted\") {\n // 'unsupported' or anything unexpected\n throw createError(\n \"PUSH_UNSUPPORTED\",\n `Unsupported Notification.permission state: ${current}`\n );\n }\n\n const sw = this._getServiceWorkerContainer();\n if (!sw) {\n throw createError(\n \"PUSH_UNSUPPORTED\",\n \"navigator.serviceWorker is not available\"\n );\n }\n\n // 6. Acquire registration (REQ-004, REQ-006)\n // register() returns immediately with an installing/waiting registration.\n // pushManager.subscribe() requires an *active* SW, so we always wait for\n // navigator.serviceWorker.ready after registering to get the active one.\n let registration;\n if (this.serviceWorkerRegistration) {\n registration = this.serviceWorkerRegistration;\n } else if (this.manualServiceWorkerRegistration) {\n registration = await sw.ready;\n } else {\n await sw.register(this.serviceWorkerUrl, {\n scope: this.serviceWorkerScope,\n });\n registration = this.serviceWorkerRegistration || await sw.ready;\n }\n\n if (!registration) {\n throw createError(\n \"PUSH_UNSUPPORTED\",\n \"Failed to obtain a service worker registration\"\n );\n }\n\n if (!registration.pushManager) {\n throw createError(\n \"PUSH_UNSUPPORTED\",\n \"ServiceWorkerRegistration.pushManager is not available\"\n );\n }\n\n // 7. Best-effort ping/pong handshake (REQ-007). We fire-and-await with a\n // short timeout so a missing or non-LogDrop SW does not block subscribe.\n await this._handshake(sw, registration);\n\n // 8. Subscribe via PushManager.\n // If a subscription exists with a different VAPID key, unsubscribe it first\n // then retry \u2014 this happens when the dev server restarts (new ephemeral keys).\n const applicationServerKey = urlBase64ToUint8Array(this.vapidPublicKey);\n const existingSubscription = await registration.pushManager.getSubscription();\n const existingApplicationServerKey = existingSubscription?.options?.applicationServerKey;\n if (\n existingSubscription &&\n existingApplicationServerKey &&\n !this._keysEqual(existingApplicationServerKey, applicationServerKey)\n ) {\n await existingSubscription.unsubscribe();\n }\n let subscription;\n try {\n subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey,\n });\n } catch (err) {\n const msg = err && err.message ? err.message : String(err);\n if (msg.includes(\"applicationServerKey\") || msg.includes(\"gcm_sender_id\")) {\n // Stale subscription with different key \u2014 clear it and retry once\n const stale = await registration.pushManager.getSubscription();\n if (stale) await stale.unsubscribe();\n subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey,\n });\n } else {\n throw err;\n }\n }\n\n // 9. POST subscription to backend (REQ-011). Failures here must NOT lose\n // the live subscription; we surface them as errors so callers can retry.\n const subscriptionPayload = typeof subscription.toJSON === \"function\"\n ? subscription.toJSON()\n : subscription;\n if (this.onSubscriptionChanged) {\n await this.onSubscriptionChanged(subscriptionPayload);\n }\n await this._syncServiceWorkerConfig(registration);\n\n return subscription;\n }\n\n // -------------------------------------------------------------------------\n // unsubscribe()\n // -------------------------------------------------------------------------\n\n async unsubscribe() {\n if (this._tornDown) {\n throw createError(\n \"TEARDOWN\",\n \"PushModule has been torn down; unsubscribe() is no longer available\"\n );\n }\n\n const sw = this._getServiceWorkerContainer();\n if (!sw) return null;\n\n let registration;\n try {\n registration = await sw.ready;\n } catch {\n return null;\n }\n\n if (!registration || !registration.pushManager) return null;\n\n let subscription = null;\n try {\n subscription = await registration.pushManager.getSubscription();\n } catch {\n subscription = null;\n }\n\n if (!subscription) return null;\n\n try {\n await subscription.unsubscribe();\n } catch {\n // The push service will eventually invalidate the endpoint. Backend\n // cleanup follows the same provider-rejection flow as mobile tokens.\n }\n\n return null;\n }\n\n // -------------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------------\n\n _getServiceWorkerContainer() {\n if (typeof navigator === \"undefined\") return null;\n return navigator.serviceWorker ?? null;\n }\n\n /**\n * Sends a `logdrop:ping` to the SW and resolves when either a\n * `logdrop:pong` arrives or a 500ms timeout elapses \u2014 whichever comes first.\n */\n _handshake(sw, registration) {\n return new Promise((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n try {\n if (typeof sw.removeEventListener === \"function\") {\n sw.removeEventListener(\"message\", onMessage);\n }\n } catch {\n // ignore\n }\n clearTimeout(timer);\n resolve();\n };\n\n const onMessage = (event) => {\n try {\n const data = event && event.data;\n if (data && data.type === \"logdrop:pong\") {\n finish();\n }\n } catch {\n // ignore\n }\n };\n\n try {\n if (typeof sw.addEventListener === \"function\") {\n sw.addEventListener(\"message\", onMessage);\n }\n } catch {\n // ignore\n }\n\n const timer = setTimeout(finish, 500);\n // Do not keep the event loop alive for the handshake timeout.\n if (timer && typeof timer.unref === \"function\") {\n try { timer.unref(); } catch { /* ignore */ }\n }\n\n try {\n if (registration && registration.active && typeof registration.active.postMessage === \"function\") {\n registration.active.postMessage({ type: \"logdrop:ping\" });\n } else {\n // No active worker to ping \u2014 skip handshake entirely.\n finish();\n }\n } catch {\n finish();\n }\n });\n }\n\n async _syncServiceWorkerConfig(registration = null) {\n const sw = this._getServiceWorkerContainer();\n if (!sw) return;\n let resolvedRegistration = registration || this.serviceWorkerRegistration;\n if (!resolvedRegistration) {\n try { resolvedRegistration = await sw.ready; } catch { return; }\n }\n const target = resolvedRegistration?.active || sw.controller;\n if (!target || typeof target.postMessage !== \"function\") return;\n target.postMessage({\n type: \"logdrop:push-config\",\n config: {\n vapidPublicKey: this.vapidPublicKey,\n apiBase: this.apiBase,\n apiKey: this.apiKey,\n sessionToken: this.getSessionToken ? this.getSessionToken() : null,\n deviceUuid: this.deviceId,\n },\n });\n }\n\n async _syncGrantedSubscription() {\n if (\n this.isPushEnabled !== true ||\n !this.vapidPublicKey ||\n this.getPermissionState() !== \"granted\" ||\n !this.deviceId ||\n !this.getSessionToken?.()\n ) {\n return;\n }\n try {\n await this.subscribe();\n } catch {\n // Existing permission/subscription reconciliation is best effort. A\n // later init or explicit subscribe() call retries without prompting.\n }\n }\n\n reconcileGrantedSubscription() {\n return this._syncGrantedSubscription();\n }\n\n _keysEqual(left, right) {\n const leftBytes = new Uint8Array(left);\n const rightBytes = new Uint8Array(right);\n if (leftBytes.length !== rightBytes.length) return false;\n for (let i = 0; i < leftBytes.length; i++) {\n if (leftBytes[i] !== rightBytes[i]) return false;\n }\n return true;\n }\n\n}\n", "function pushData(payload) {\n if (!payload || typeof payload !== \"object\") return {};\n return payload.data && typeof payload.data === \"object\" ? payload.data : payload;\n}\n\nexport function executeWebPushAction(action) {\n if (!action || String(action.kind || \"\").toUpperCase() !== \"OPEN_DEEPLINK\") return false;\n const target = String(action.target || action.fallbackTarget || \"\").trim();\n if (!target || typeof window === \"undefined\") return false;\n try {\n if (String(action.deeplinkMode || \"\").toUpperCase() === \"EXTERNAL_BROWSER\") {\n window.open(target, \"_blank\", \"noopener,noreferrer\");\n } else {\n window.location.assign(target);\n }\n return true;\n } catch {\n const fallback = String(action.fallbackTarget || \"\").trim();\n if (!fallback || fallback === target) return false;\n try {\n window.location.assign(fallback);\n return true;\n } catch {\n return false;\n }\n }\n}\n\nexport class InAppMessagePresenter {\n constructor({ onAction } = {}) {\n this.onAction = typeof onAction === \"function\" ? onAction : null;\n this.queue = [];\n this.active = null;\n this._visibilityHandler = () => this._showNext();\n if (typeof document !== \"undefined\") {\n document.addEventListener?.(\"visibilitychange\", this._visibilityHandler);\n }\n }\n\n enqueue(payload) {\n const data = pushData(payload);\n if (String(data.messageKind || \"\").toUpperCase() !== \"IN_APP\" ||\n !data.inApp || typeof data.inApp !== \"object\") return false;\n const notificationId = String(data.notificationId || \"\").trim();\n if (notificationId && (this.active?.notificationId === notificationId ||\n this.queue.some((item) => item.notificationId === notificationId))) return false;\n const ttlSeconds = Number(data.inApp.ttlSeconds);\n this.queue.push({\n payload,\n notificationId,\n expiresAt: Number.isFinite(ttlSeconds) && ttlSeconds > 0\n ? Date.now() + ttlSeconds * 1000\n : null,\n });\n this._showNext();\n return true;\n }\n\n teardown() {\n if (typeof document !== \"undefined\") {\n document.removeEventListener?.(\"visibilitychange\", this._visibilityHandler);\n }\n this.queue = [];\n this._finish(false);\n }\n\n _showNext() {\n if (this.active || typeof document === \"undefined\" || !document.body ||\n document.visibilityState === \"hidden\") return;\n while (this.queue.length && this.queue[0].expiresAt && this.queue[0].expiresAt <= Date.now()) {\n this.queue.shift();\n }\n const item = this.queue.shift();\n if (!item) return;\n this.active = { ...item, element: this._render(item) };\n }\n\n _render(item) {\n const data = pushData(item.payload);\n const message = data.inApp;\n const isBanner = String(message.template || \"\").toUpperCase() === \"BANNER\";\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-logdrop-in-app\", \"true\");\n root.setAttribute(\"role\", \"dialog\");\n root.setAttribute(\"aria-modal\", isBanner ? \"false\" : \"true\");\n root.style.cssText = isBanner\n ? `position:fixed;${String(message.position).toUpperCase() === \"BOTTOM\" ? \"bottom\" : \"top\"}:16px;left:50%;transform:translateX(-50%);z-index:2147483646;width:min(560px,calc(100% - 32px));font-family:system-ui,sans-serif`\n : \"position:fixed;inset:0;z-index:2147483646;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(15,23,42,.62);font-family:system-ui,sans-serif\";\n\n const panel = document.createElement(\"div\");\n panel.style.cssText = `position:relative;box-sizing:border-box;width:100%;max-width:${isBanner ? \"560px\" : \"520px\"};${message.isFullHeight === true && !isBanner ? \"height:calc(100vh - 48px);\" : \"max-height:calc(100vh - 48px);\"}overflow:auto;background:#fff;color:#111827;border-radius:14px;padding:20px;box-shadow:0 20px 55px rgba(0,0,0,.3)`;\n\n if (message.dismissible !== false) {\n const close = document.createElement(\"button\");\n close.type = \"button\";\n close.setAttribute(\"aria-label\", \"Close\");\n close.textContent = \"\u00D7\";\n close.style.cssText = \"position:absolute;top:8px;right:10px;border:0;background:transparent;font-size:24px;line-height:1;color:#6b7280;cursor:pointer\";\n close.addEventListener(\"click\", () => this._finish(true), { once: true });\n panel.appendChild(close);\n }\n\n if (message.imageUrl) {\n const image = document.createElement(\"img\");\n image.src = String(message.imageUrl);\n image.alt = \"\";\n image.style.cssText = \"display:block;width:100%;max-height:280px;object-fit:cover;border-radius:10px;margin-bottom:16px\";\n panel.appendChild(image);\n }\n if (message.headline) {\n const title = document.createElement(\"h2\");\n title.textContent = String(message.headline);\n title.style.cssText = \"margin:0 28px 8px 0;font-size:20px;line-height:1.3\";\n panel.appendChild(title);\n }\n if (message.body) {\n const body = document.createElement(\"p\");\n body.textContent = String(message.body);\n body.style.cssText = \"margin:0;color:#4b5563;line-height:1.5;white-space:pre-wrap\";\n panel.appendChild(body);\n }\n\n const buttons = [message.secondaryButton, message.primaryButton].filter((button) => button?.label);\n if (buttons.length) {\n const row = document.createElement(\"div\");\n row.style.cssText = \"display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-top:18px\";\n buttons.forEach((button, index) => {\n const element = document.createElement(\"button\");\n element.type = \"button\";\n element.textContent = String(button.label);\n const primary = index === buttons.length - 1 && message.primaryButton === button;\n element.style.cssText = primary\n ? \"padding:9px 15px;border:0;border-radius:8px;background:#111827;color:#fff;cursor:pointer\"\n : \"padding:9px 15px;border:1px solid #d1d5db;border-radius:8px;background:#fff;color:#111827;cursor:pointer\";\n element.addEventListener(\"click\", () => {\n try { this.onAction?.(item.payload, button.action || null); } catch {}\n executeWebPushAction(button.action);\n this._finish(true);\n }, { once: true });\n row.appendChild(element);\n });\n panel.appendChild(row);\n }\n\n root.appendChild(panel);\n if (!isBanner && message.dismissible !== false) {\n root.addEventListener(\"click\", (event) => {\n if (event.target === root) this._finish(true);\n });\n }\n document.body.appendChild(root);\n return root;\n }\n\n _finish(showNext) {\n if (this.active?.element?.parentNode) this.active.element.parentNode.removeChild(this.active.element);\n this.active = null;\n if (showNext) this._showNext();\n }\n}\n", "// Minimal Protobuf encoder/decoder for LogDrop SDK V2\n// Supports: string, bytes, int64, bool, enum, repeated string, embedded message\n// Wire types: 0 = varint, 2 = length-delimited\n\n// \u2500\u2500\u2500 Writer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ProtoWriter {\n constructor() {\n /** @type {number[]} */\n this._buf = [];\n }\n\n /** Encode a varint (unsigned 64-bit safe up to Number.MAX_SAFE_INTEGER). */\n _writeVarint(value) {\n let v = value >>> 0; // ensure unsigned 32-bit for small values\n if (value <= 0x7f) { this._buf.push(v); return; }\n // Handle values > 32 bits by using BigInt-free manual encoding\n // For SDK purposes values will stay within safe integer range\n while (v > 0x7f) {\n this._buf.push((v & 0x7f) | 0x80);\n v >>>= 7;\n }\n this._buf.push(v);\n }\n\n /** Write a tag (field number + wire type). */\n _writeTag(fieldNumber, wireType) {\n this._writeVarint((fieldNumber << 3) | wireType);\n }\n\n /** Write a string field (wire type 2). Skips if empty (proto3 default). */\n writeString(fieldNumber, value) {\n if (!value) return;\n const bytes = new TextEncoder().encode(value);\n this._writeTag(fieldNumber, 2);\n this._writeVarint(bytes.length);\n for (let i = 0; i < bytes.length; i++) this._buf.push(bytes[i]);\n }\n\n /** Write a bytes field (wire type 2). Skips if empty. */\n writeBytes(fieldNumber, value) {\n if (!value || value.length === 0) return;\n this._writeTag(fieldNumber, 2);\n this._writeVarint(value.length);\n for (let i = 0; i < value.length; i++) this._buf.push(value[i]);\n }\n\n /** Write an int64 / int32 field as varint (wire type 0). Skips if 0 (proto3 default). */\n writeInt64(fieldNumber, value) {\n if (!value) return;\n this._writeTag(fieldNumber, 0);\n this._writeVarint(value);\n }\n\n /**\n * Encode a varint for values that may exceed 32 bits (up to\n * Number.MAX_SAFE_INTEGER). The base `_writeVarint` truncates via `>>> 0`,\n * so it must not be used for large numbers such as millisecond timestamps.\n */\n _writeVarintLong(value) {\n let v = Math.floor(value);\n while (v > 0x7f) {\n this._buf.push((v % 128) | 0x80);\n v = Math.floor(v / 128);\n }\n this._buf.push(v % 128);\n }\n\n /** Write an int64 field that may exceed 32 bits (wire type 0). Skips if 0. */\n writeInt64Long(fieldNumber, value) {\n if (!value) return;\n this._writeTag(fieldNumber, 0);\n this._writeVarintLong(value);\n }\n\n /** Write a double field (wire type 1, fixed 64-bit little-endian IEEE-754). */\n writeDouble(fieldNumber, value) {\n this._writeTag(fieldNumber, 1);\n const buf = new ArrayBuffer(8);\n new DataView(buf).setFloat64(0, value, true);\n const bytes = new Uint8Array(buf);\n for (let i = 0; i < 8; i++) this._buf.push(bytes[i]);\n }\n\n /** Write a raw length-delimited string, even when empty (bypasses proto3 default skip). */\n writeStringForce(fieldNumber, value) {\n const bytes = new TextEncoder().encode(value ?? \"\");\n this._writeTag(fieldNumber, 2);\n this._writeVarint(bytes.length);\n for (let i = 0; i < bytes.length; i++) this._buf.push(bytes[i]);\n }\n\n /** Write a bool, even when false (bypasses proto3 default skip). */\n writeBoolForce(fieldNumber, value) {\n this._writeTag(fieldNumber, 0);\n this._buf.push(value ? 1 : 0);\n }\n\n /** Write a bool field (wire type 0). Skips if false (proto3 default). */\n writeBool(fieldNumber, value) {\n if (!value) return;\n this._writeTag(fieldNumber, 0);\n this._buf.push(1);\n }\n\n /** Write an enum field (wire type 0). Skips if 0 (proto3 default). */\n writeEnum(fieldNumber, value) {\n this.writeInt64(fieldNumber, value);\n }\n\n /** Write a repeated string field. */\n writeRepeatedString(fieldNumber, values) {\n if (!values || !values.length) return;\n for (const v of values) {\n this.writeString(fieldNumber, v);\n }\n }\n\n /** Write an embedded message field (wire type 2). */\n writeMessage(fieldNumber, writerFn) {\n const sub = new ProtoWriter();\n writerFn(sub);\n const bytes = sub.finish();\n if (bytes.length === 0) return; // skip empty sub-messages\n this._writeTag(fieldNumber, 2);\n this._writeVarint(bytes.length);\n for (let i = 0; i < bytes.length; i++) this._buf.push(bytes[i]);\n }\n\n /** Return the finished Uint8Array. */\n finish() {\n return new Uint8Array(this._buf);\n }\n}\n\n// \u2500\u2500\u2500 Reader \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ProtoReader {\n /**\n * @param {Uint8Array} buf\n */\n constructor(buf) {\n this._buf = buf;\n this._pos = 0;\n }\n\n /** Are there more bytes to read? */\n hasMore() {\n return this._pos < this._buf.length;\n }\n\n /** Read a varint and return as a JS number (safe for values < 2^53). */\n _readVarint() {\n let result = 0;\n let shift = 0;\n while (this._pos < this._buf.length) {\n const byte = this._buf[this._pos++];\n result |= (byte & 0x7f) << shift;\n if ((byte & 0x80) === 0) return result >>> 0;\n shift += 7;\n if (shift > 35) {\n // For >32-bit values, just skip to end of varint\n while (this._pos < this._buf.length && (this._buf[this._pos++] & 0x80) !== 0) { }\n return result >>> 0;\n }\n }\n return result >>> 0;\n }\n\n /** Read a tag and return { fieldNumber, wireType }. */\n readTag() {\n if (!this.hasMore()) return null;\n const v = this._readVarint();\n return { fieldNumber: v >>> 3, wireType: v & 0x07 };\n }\n\n /** Read a length-delimited field and return as Uint8Array. */\n readBytes() {\n const startPos = this._pos;\n const len = this._readVarint();\n\n if (!Number.isInteger(len) || len < 0 || this._pos + len > this._buf.length) {\n this._pos = startPos;\n throw new Error(\"Unexpected end of buffer in readBytes\");\n }\n\n const slice = this._buf.slice(this._pos, this._pos + len);\n this._pos += len;\n return slice;\n }\n\n /** Read a length-delimited field and return as string. */\n readString() {\n const bytes = this.readBytes();\n return new TextDecoder().decode(bytes);\n }\n\n /** Read a varint field and return as number. */\n readVarint() {\n return this._readVarint();\n }\n\n /**\n * Read a varint that may exceed 32 bits (up to Number.MAX_SAFE_INTEGER),\n * using multiplication instead of bit-shifting to avoid 32-bit truncation.\n */\n readVarintLong() {\n let result = 0;\n let multiplier = 1;\n while (this._pos < this._buf.length) {\n const byte = this._buf[this._pos++];\n result += (byte & 0x7f) * multiplier;\n if ((byte & 0x80) === 0) break;\n multiplier *= 128;\n }\n return result;\n }\n\n /** Read a fixed 64-bit little-endian IEEE-754 double (wire type 1). */\n readDouble() {\n if (this._pos + 8 > this._buf.length) {\n throw new Error(\"Unexpected end of buffer in readDouble\");\n }\n const dv = new DataView(this._buf.buffer, this._buf.byteOffset + this._pos, 8);\n const val = dv.getFloat64(0, true);\n this._pos += 8;\n return val;\n }\n\n /** Read a bool field. */\n readBool() {\n return this._readVarint() !== 0;\n }\n\n /** Skip a field based on wireType. */\n skip(wireType) {\n switch (wireType) {\n case 0: // varint\n this._readVarint();\n break;\n case 1: // 64-bit\n if (this._pos + 8 > this._buf.length) {\n throw new Error(\"Unexpected end of buffer while skipping 64-bit field\");\n }\n this._pos += 8;\n break;\n case 2: // length-delimited\n {\n const len = this._readVarint();\n if (!Number.isInteger(len) || len < 0 || this._pos + len > this._buf.length) {\n throw new Error(\"Unexpected end of buffer while skipping length-delimited field\");\n }\n this._pos += len;\n }\n break;\n case 5: // 32-bit\n if (this._pos + 4 > this._buf.length) {\n throw new Error(\"Unexpected end of buffer while skipping 32-bit field\");\n }\n this._pos += 4;\n break;\n default:\n throw new Error(`Unknown wire type: ${wireType}`);\n }\n }\n}\n\n// \u2500\u2500\u2500 Message Encoders \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Encode a Device message into the provided ProtoWriter.\n *\n * Writes the following string fields when present:\n * 1: deviceUuid\n * 3: iosApnsDeviceToken\n * 4: androidFirebaseToken\n * 5: huaweiToken\n * 6: osName\n * 7: osVersion\n * 8: deviceBrand\n * 9: deviceModel\n * 10: appVersion\n * 11: sdkVersion\n * 12: sdkType\n * 13: bridgeSdkType\n * 14: customAttributes\n * 15: removedCustomAttributeKeys\n * 16: webPushSubscription\n *\n * @param {ProtoWriter} w - The ProtoWriter to write bytes into.\n * @param {Object} device - Object containing device fields (see list above).\n */\nfunction encodeDevice(w, device) {\n w.writeString(1, device.deviceUuid);\n w.writeString(3, device.iosApnsDeviceToken);\n w.writeString(4, device.androidFirebaseToken);\n w.writeString(5, device.huaweiToken);\n w.writeString(6, device.osName);\n w.writeString(7, device.osVersion);\n w.writeString(8, device.deviceBrand);\n w.writeString(9, device.deviceModel);\n w.writeString(10, device.appVersion);\n w.writeString(11, device.sdkVersion);\n w.writeString(12, device.sdkType);\n w.writeString(13, device.bridgeSdkType);\n for (const [key, value] of Object.entries(device.customAttributes || {})) {\n w.writeMessage(14, (entry) => {\n entry.writeString(1, key);\n entry.writeString(2, value);\n });\n }\n for (const key of device.removedCustomAttributeKeys || []) {\n w.writeString(15, key);\n }\n if (device.webPushSubscription) {\n w.writeMessage(16, (sub) => {\n sub.writeString(1, device.webPushSubscription.endpoint);\n sub.writeString(2, device.webPushSubscription.p256dh);\n sub.writeString(3, device.webPushSubscription.auth);\n sub.writeInt64Long(4, device.webPushSubscription.expirationTime);\n });\n }\n}\n\n/**\n * Serialize a UserUpdateRequest into protobuf binary.\n * @param {{ userUuid: string, device?: Object }} req - Request object containing `userUuid` and an optional `device` (encoded as a nested Device message when present).\n * @returns {Uint8Array} The protobuf-encoded bytes for the UserUpdateRequest.\n */\nexport function encodeUserUpdateRequest(req) {\n const w = new ProtoWriter();\n w.writeString(1, req.userUuid);\n if (req.device) {\n w.writeMessage(2, (sub) => encodeDevice(sub, req.device));\n }\n return w.finish();\n}\n\n/**\n * Decode an SdkTokenResponse protobuf message from the provided bytes.\n * @param {Uint8Array} buf - The encoded SdkTokenResponse message.\n * @returns {{ accessToken: string, refreshToken: string }} Object with `accessToken` and `refreshToken` decoded from the message.\n */\nexport function decodeSdkTokenResponse(buf) {\n const r = new ProtoReader(buf);\n const result = { accessToken: \"\", refreshToken: \"\" };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: result.accessToken = r.readString(); break;\n case 2: result.refreshToken = r.readString(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Encode an InitRequest protobuf message.\n * @param {{ refreshToken?: string, deviceUuid: string }} req - Request fields where `refreshToken` is optional and `deviceUuid` is the device identifier.\n * @returns {Uint8Array} The serialized InitRequest message.\n */\nexport function encodeInitRequest(req) {\n const w = new ProtoWriter();\n w.writeString(2, req.refreshToken);\n w.writeString(3, req.deviceUuid);\n return w.finish();\n}\n\nfunction readOptionalString(value) {\n return value ? value : null;\n}\n\nfunction decodeHttpWhitelistEntry(buf) {\n const r = new ProtoReader(buf);\n const result = { domain: \"\", path: null };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.domain = r.readString(); break;\n case 2: result.path = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeSdkRiskActionConfig(buf) {\n const r = new ProtoReader(buf);\n const result = {\n showPopupEnabled: false,\n appBlockEnabled: false,\n networkBlockEnabled: false,\n blockedRequestPaths: [],\n blockedDomains: [],\n title: null,\n message: null,\n buttonText: null,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.showPopupEnabled = r.readBool(); break;\n case 2: result.appBlockEnabled = r.readBool(); break;\n case 3: result.networkBlockEnabled = r.readBool(); break;\n case 4: result.blockedRequestPaths.push(r.readString()); break;\n case 5: result.blockedDomains.push(r.readString()); break;\n case 6: result.title = readOptionalString(r.readString()); break;\n case 7: result.message = readOptionalString(r.readString()); break;\n case 8: result.buttonText = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeHttpWhitelistRiskConfig(buf) {\n const r = new ProtoReader(buf);\n const result = {\n enabled: false,\n whitelist: [],\n actions: decodeSdkRiskActionConfig(new Uint8Array()),\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.enabled = r.readBool(); break;\n case 2: result.whitelist.push(decodeHttpWhitelistEntry(r.readBytes())); break;\n case 3: result.actions = decodeSdkRiskActionConfig(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeRiskPolicyRule(buf) {\n const r = new ProtoReader(buf);\n const result = {\n enabled: false,\n priority: 0,\n matchType: \"ANY\",\n eventIds: [],\n actionIds: [],\n message: null,\n title: null,\n buttonText: null,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.enabled = r.readBool(); break;\n case 2: result.priority = r.readVarint(); break;\n case 3: result.matchType = r.readVarint() === 1 ? \"ALL\" : \"ANY\"; break;\n case 4:\n if (tag.wireType === 2) result.eventIds.push(...decodePackedVarints(r.readBytes()));\n else result.eventIds.push(r.readVarint());\n break;\n case 5:\n if (tag.wireType === 2) result.actionIds.push(...decodePackedVarints(r.readBytes()));\n else result.actionIds.push(r.readVarint());\n break;\n case 6: result.message = readOptionalString(r.readString()); break;\n case 7: result.title = readOptionalString(r.readString()); break;\n case 8: result.buttonText = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodePackedVarints(buf) {\n const r = new ProtoReader(buf);\n const values = [];\n while (r.hasMore()) values.push(r.readVarint());\n return values;\n}\n\nfunction decodeRiskPolicy(buf) {\n const r = new ProtoReader(buf);\n const result = { version: 0, rules: [] };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.version = r.readVarint(); break;\n case 2: result.rules.push(decodeRiskPolicyRule(r.readBytes())); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeRiskDetectedConfig(buf) {\n const r = new ProtoReader(buf);\n const result = {\n riskPolicy: { version: 0, rules: [] },\n enabled: false,\n botDetectionEnabled: false,\n otherRiskTypesEnabled: false,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.riskPolicy = decodeRiskPolicy(r.readBytes()); break;\n case 2: result.enabled = r.readBool(); break;\n case 3: result.botDetectionEnabled = r.readBool(); break;\n case 4: result.otherRiskTypesEnabled = r.readBool(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction ipReputationThreatLevelName(value) {\n switch (value) {\n case 1: return \"MEDIUM\";\n case 2: return \"HIGH\";\n case 3: return \"CRITICAL\";\n default: return \"UNSPECIFIED\";\n }\n}\n\nfunction decodeIpReputationPolicyRule(buf) {\n const r = new ProtoReader(buf);\n const result = {\n enabled: false,\n priority: 0,\n threatLevels: [],\n actionIds: [],\n message: null,\n title: null,\n buttonText: null,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.enabled = r.readBool(); break;\n case 2: result.priority = r.readVarint(); break;\n case 3: {\n const values = tag.wireType === 2 ? decodePackedVarints(r.readBytes()) : [r.readVarint()];\n result.threatLevels.push(...values.map(ipReputationThreatLevelName));\n break;\n }\n case 4:\n if (tag.wireType === 2) result.actionIds.push(...decodePackedVarints(r.readBytes()));\n else result.actionIds.push(r.readVarint());\n break;\n case 5: result.message = readOptionalString(r.readString()); break;\n case 6: result.title = readOptionalString(r.readString()); break;\n case 7: result.buttonText = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeIpReputationPolicy(buf) {\n const r = new ProtoReader(buf);\n const result = { version: 0, rules: [] };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.version = r.readVarint(); break;\n case 2: result.rules.push(decodeIpReputationPolicyRule(r.readBytes())); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeIpReputationDetectedConfig(buf) {\n const r = new ProtoReader(buf);\n const result = { riskPolicy: { version: 0, rules: [] } };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.riskPolicy = decodeIpReputationPolicy(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeIpReputationActiveAction(buf) {\n const r = new ProtoReader(buf);\n const result = {\n signature: \"\",\n eventId: \"\",\n threatLevel: \"UNSPECIFIED\",\n riskScore: 0,\n actionIds: [],\n expireAtEpochMillis: 0,\n message: null,\n title: null,\n buttonText: null,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.signature = r.readString(); break;\n case 2: result.eventId = r.readString(); break;\n case 3: result.threatLevel = ipReputationThreatLevelName(r.readVarint()); break;\n case 4: result.riskScore = r.readVarint(); break;\n case 5:\n if (tag.wireType === 2) result.actionIds.push(...decodePackedVarints(r.readBytes()));\n else result.actionIds.push(r.readVarint());\n break;\n case 6: result.expireAtEpochMillis = r.readVarintLong(); break;\n case 7: result.message = readOptionalString(r.readString()); break;\n case 8: result.title = readOptionalString(r.readString()); break;\n case 9: result.buttonText = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeWebPushConfig(buf) {\n const r = new ProtoReader(buf);\n const result = { enabled: false, vapidPublicKey: \"\" };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.enabled = r.readBool(); break;\n case 2: result.vapidPublicKey = r.readString(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeSdkRiskConfig(buf) {\n const r = new ProtoReader(buf);\n const result = {\n httpWhitelist: decodeHttpWhitelistRiskConfig(new Uint8Array()),\n riskDetected: decodeRiskDetectedConfig(new Uint8Array()),\n ipReputationDetected: decodeIpReputationDetectedConfig(new Uint8Array()),\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.httpWhitelist = decodeHttpWhitelistRiskConfig(r.readBytes()); break;\n case 2: result.riskDetected = decodeRiskDetectedConfig(r.readBytes()); break;\n case 3: result.ipReputationDetected = decodeIpReputationDetectedConfig(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Parse a ConfigResponse protobuf message into a plain JavaScript object.\n * @param {Uint8Array} buf - Protobuf-encoded ConfigResponse bytes.\n * @returns {Object} An object with the following properties:\n * - perUserMaxFileSizeLimitInBytes {number}\n * - perUserMinFileSizeLimitInBytes {number}\n * - databaseMaxStorageLimitInBytes {number}\n * - isSDKDisabled {boolean}\n * - isHttpLoggingEnabled {boolean}\n * - isCrashTrackingEnabled {boolean}\n * - httpDomainBlackList {string[]}\n * - sensitiveInfoFilter {string[]}\n * - sslPinning {null}\n * - accessToken {string}\n * - limitType {number} \u2014 0 = DAILY, 1 = MONTHLY\n * - riskConfig {Object|null}\n * - activeIpReputationAction {Object|null}\n * - serverNowEpochMillis {number}\n */\nexport function decodeConfigResponse(buf) {\n const r = new ProtoReader(buf);\n const result = {\n perUserMaxFileSizeLimitInBytes: 0,\n perUserMinFileSizeLimitInBytes: 0,\n databaseMaxStorageLimitInBytes: 0,\n isSDKDisabled: false,\n isHttpLoggingEnabled: false,\n isCrashTrackingEnabled: false,\n isEventTrackingEnabled: false,\n httpDomainBlackList: [],\n sensitiveInfoFilter: [],\n sslPinning: null,\n accessToken: \"\",\n limitType: 0, // DAILY=0, MONTHLY=1\n riskConfig: null,\n activeIpReputationAction: null,\n serverNowEpochMillis: 0,\n webPushConfig: { enabled: false, vapidPublicKey: \"\" }\n };\n\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: result.perUserMaxFileSizeLimitInBytes = r.readVarintLong(); break;\n case 2: result.perUserMinFileSizeLimitInBytes = r.readVarintLong(); break;\n case 3: result.databaseMaxStorageLimitInBytes = r.readVarintLong(); break;\n case 4: result.isSDKDisabled = r.readBool(); break;\n case 5: result.isHttpLoggingEnabled = r.readBool(); break;\n case 6: result.isCrashTrackingEnabled = r.readBool(); break;\n case 7: result.httpDomainBlackList.push(r.readString()); break;\n case 8: result.sensitiveInfoFilter.push(r.readString()); break;\n case 9: r.skip(tag.wireType); break; // SslPinningConfig - skip for web\n case 10: result.accessToken = r.readString(); break;\n case 11: result.limitType = r.readVarint(); break;\n case 12: result.riskConfig = decodeSdkRiskConfig(r.readBytes()); break;\n case 13: result.activeIpReputationAction = decodeIpReputationActiveAction(r.readBytes()); break;\n case 14: result.serverNowEpochMillis = r.readVarintLong(); break;\n case 15: result.isEventTrackingEnabled = r.readBool(); break;\n case 18: result.webPushConfig = decodeWebPushConfig(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Encode a LogRequest message to Protocol Buffers binary.\n *\n * Writes the following fields when present:\n * - field 1: content (bytes)\n * - field 2: deviceUuid (string)\n * - field 4: appVersion (string)\n * - field 5: sdkVersion (string)\n * - field 6: osVersion (string)\n * - field 7: errorCount (string)\n * - field 8: firstRealUserUuid (string)\n * - field 9: uploadId (string)\n * (field 3 is intentionally omitted)\n * @param {{ content: Uint8Array, deviceUuid: string, appVersion?: string, sdkVersion?: string, osVersion?: string, errorCount?: string, firstRealUserUuid?: string, uploadId?: string }} req - Log request payload\n * @returns {Uint8Array} The encoded protobuf message\n */\nexport function encodeLogRequest(req) {\n const w = new ProtoWriter();\n w.writeBytes(1, req.content);\n w.writeString(2, req.deviceUuid);\n // field 3 is skipped in proto (no field 3)\n w.writeString(4, req.appVersion);\n w.writeString(5, req.sdkVersion);\n w.writeString(6, req.osVersion);\n w.writeString(7, req.errorCount);\n w.writeString(8, req.firstRealUserUuid);\n w.writeString(9, req.uploadId);\n return w.finish();\n}\n\n/**\n * Parse a LogResponse protobuf and extract the remaining limit.\n * @param {Uint8Array} buf - The encoded LogResponse message.\n * @returns {{ remainingLimit: number }} An object with `remainingLimit` parsed from the message.\n */\nexport function decodeLogResponse(buf) {\n const r = new ProtoReader(buf);\n const result = { remainingLimit: 0 };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: result.remainingLimit = r.readVarint(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Encode a CrashReportRequest message to protobuf binary format.\n *\n * @param {{ content: Uint8Array, deviceUuid: string, sdkVersion?: string }} req - Request object containing crash report data.\n * - content: Raw crash report payload as bytes.\n * - deviceUuid: Device identifier string.\n * - sdkVersion: Optional SDK version string.\n * @returns {Uint8Array} The serialized CrashReportRequest as a Uint8Array.\n */\nexport function encodeCrashReportRequest(req) {\n const w = new ProtoWriter();\n w.writeBytes(1, req.content);\n w.writeString(2, req.deviceUuid);\n // field 3 is skipped in proto (no field 3)\n w.writeString(4, req.sdkVersion);\n return w.finish();\n}\n\n// \u2500\u2500\u2500 google.protobuf.Struct \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Encodes an arbitrary JSON-serializable object as a google.protobuf.Struct so it\n// can be used for the EventItem.properties field.\n//\n// Struct { map<string, Value> fields = 1; }\n// Value { oneof kind { NullValue null_value=1; double number_value=2;\n// string string_value=3; bool bool_value=4;\n// Struct struct_value=5; ListValue list_value=6; } }\n// ListValue { repeated Value values = 1; }\n\n/**\n * Encode a single google.protobuf.Value into the provided writer.\n * @param {ProtoWriter} w - Writer positioned inside a Value message.\n * @param {*} value - Any JSON-serializable value.\n */\nfunction encodeStructValue(w, value) {\n if (value === null || value === undefined) {\n // null_value = 0 (field 1). Force-write so the value is unambiguous.\n w._writeTag(1, 0);\n w._writeVarint(0);\n return;\n }\n const t = typeof value;\n if (t === \"number\") {\n if (Number.isFinite(value)) {\n w.writeDouble(2, value);\n } else {\n w._writeTag(1, 0);\n w._writeVarint(0);\n }\n return;\n }\n if (t === \"boolean\") {\n w.writeBoolForce(4, value);\n return;\n }\n if (t === \"string\") {\n w.writeStringForce(3, value);\n return;\n }\n if (Array.isArray(value)) {\n // list_value (field 6) = ListValue { repeated Value values = 1; }\n w.writeMessage(6, (lw) => {\n for (const item of value) {\n lw.writeMessage(1, (vw) => encodeStructValue(vw, item));\n }\n });\n return;\n }\n if (t === \"object\") {\n // struct_value (field 5) = Struct\n w.writeMessage(5, (sw) => encodeStruct(sw, value));\n return;\n }\n // Fallback: coerce to string\n w.writeStringForce(3, String(value));\n}\n\n/**\n * Encode a plain object as a google.protobuf.Struct into the provided writer.\n * @param {ProtoWriter} w - Writer positioned inside a Struct message.\n * @param {Object} obj - Object whose enumerable keys become Struct fields.\n */\nfunction encodeStruct(w, obj) {\n for (const key of Object.keys(obj)) {\n // Each map<string,Value> entry is a message: key (1, string), value (2, Value).\n w.writeMessage(1, (entry) => {\n entry.writeStringForce(1, key);\n entry.writeMessage(2, (vw) => encodeStructValue(vw, obj[key]));\n });\n }\n}\n\n// \u2500\u2500\u2500 EventBatchRequest \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Encode an EventItem message.\n * @param {ProtoWriter} w\n * @param {{ eventId: string, eventCode: string, timestamp: number, properties?: Object }} evt\n */\nfunction encodeEventItem(w, evt) {\n w.writeString(1, evt.eventId);\n w.writeString(2, evt.eventCode);\n w.writeInt64Long(3, evt.timestamp);\n if (evt.properties && typeof evt.properties === \"object\" && Object.keys(evt.properties).length > 0) {\n w.writeMessage(4, (pw) => encodeStruct(pw, evt.properties));\n }\n}\n\n/**\n * Encode an EventSession message.\n * @param {ProtoWriter} w\n * @param {{ sessionId: string, userUuid?: string, events?: Array }} session\n */\nfunction encodeEventSession(w, session) {\n w.writeString(1, session.sessionId);\n w.writeString(2, session.userUuid);\n if (Array.isArray(session.events)) {\n for (const evt of session.events) {\n w.writeMessage(3, (ew) => encodeEventItem(ew, evt));\n }\n }\n}\n\n/**\n * Serialize an EventBatchRequest into protobuf binary.\n * @param {{ deviceUuid: string, sessions?: Array, firstRealUserUuid?: string, uploadId?: string }} req\n * @returns {Uint8Array} The encoded protobuf message.\n */\nexport function encodeEventBatchRequest(req) {\n const w = new ProtoWriter();\n w.writeString(1, req.deviceUuid);\n if (Array.isArray(req.sessions)) {\n for (const session of req.sessions) {\n w.writeMessage(2, (sw) => encodeEventSession(sw, session));\n }\n }\n w.writeString(3, req.firstRealUserUuid);\n w.writeString(4, req.uploadId);\n return w.finish();\n}\n\n/**\n * Decode an EventBatchResponse protobuf message.\n * @param {Uint8Array} buf - The encoded EventBatchResponse message.\n * @returns {{ count: number }} Object with `count` parsed from the message.\n */\nexport function decodeEventBatchResponse(buf) {\n const r = new ProtoReader(buf);\n const result = { count: 0 };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: result.count = r.readVarint(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n// \u2500\u2500\u2500 EventBatchRequest / Struct decoders (round-trip / testing) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Decode a google.protobuf.Value message into a JS value.\n * @param {Uint8Array} buf\n * @returns {*}\n */\nfunction decodeStructValue(buf) {\n const r = new ProtoReader(buf);\n let result = null;\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: r.readVarint(); result = null; break; // null_value\n case 2: result = r.readDouble(); break; // number_value\n case 3: result = r.readString(); break; // string_value\n case 4: result = r.readBool(); break; // bool_value\n case 5: result = decodeStruct(r.readBytes()); break; // struct_value\n case 6: result = decodeStructList(r.readBytes()); break; // list_value\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Decode a google.protobuf.ListValue into a JS array.\n * @param {Uint8Array} buf\n * @returns {Array}\n */\nfunction decodeStructList(buf) {\n const r = new ProtoReader(buf);\n const arr = [];\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n if (tag.fieldNumber === 1) arr.push(decodeStructValue(r.readBytes()));\n else r.skip(tag.wireType);\n }\n return arr;\n}\n\n/**\n * Decode a google.protobuf.Struct into a plain JS object.\n * @param {Uint8Array} buf\n * @returns {Object}\n */\nfunction decodeStruct(buf) {\n const r = new ProtoReader(buf);\n const obj = {};\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n if (tag.fieldNumber === 1) {\n const entry = new ProtoReader(r.readBytes());\n let key = \"\";\n let value = null;\n while (entry.hasMore()) {\n const et = entry.readTag();\n if (!et) break;\n if (et.fieldNumber === 1) key = entry.readString();\n else if (et.fieldNumber === 2) value = decodeStructValue(entry.readBytes());\n else entry.skip(et.wireType);\n }\n obj[key] = value;\n } else {\n r.skip(tag.wireType);\n }\n }\n return obj;\n}\n\nfunction decodeEventItem(buf) {\n const r = new ProtoReader(buf);\n const item = { eventId: \"\", eventCode: \"\", timestamp: 0, properties: {} };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: item.eventId = r.readString(); break;\n case 2: item.eventCode = r.readString(); break;\n case 3: item.timestamp = r.readVarintLong(); break;\n case 4: item.properties = decodeStruct(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return item;\n}\n\nfunction decodeEventSession(buf) {\n const r = new ProtoReader(buf);\n const session = { sessionId: \"\", userUuid: \"\", events: [] };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: session.sessionId = r.readString(); break;\n case 2: session.userUuid = r.readString(); break;\n case 3: session.events.push(decodeEventItem(r.readBytes())); break;\n default: r.skip(tag.wireType);\n }\n }\n return session;\n}\n\n/**\n * Decode an EventBatchRequest protobuf message into a plain JS object.\n * @param {Uint8Array} buf\n * @returns {{ deviceUuid: string, sessions: Array, firstRealUserUuid: string, uploadId: string }}\n */\nexport function decodeEventBatchRequest(buf) {\n const r = new ProtoReader(buf);\n const req = { deviceUuid: \"\", sessions: [], firstRealUserUuid: \"\", uploadId: \"\" };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: req.deviceUuid = r.readString(); break;\n case 2: req.sessions.push(decodeEventSession(r.readBytes())); break;\n case 3: req.firstRealUserUuid = r.readString(); break;\n case 4: req.uploadId = r.readString(); break;\n default: r.skip(tag.wireType);\n }\n }\n return req;\n}\n", "// LogDrop EventModule \u2014 internal event tracking\n// Mirrors the lifecycle pattern used by PushModule\n// (constructor config slice, install() / uninstall() / teardown()).\n//\n// Listener coexistence note (REQ-032):\n// This module registers its own visibilitychange and pagehide handlers\n// on document and window respectively. The DOM event model supports\n// multiple listeners per event, so these coexist safely with any other\n// handlers registered on the same DOM events.\n\nimport { LogDropConstants } from \"../constants.js\";\nimport { encodeEventBatchRequest, decodeEventBatchResponse } from \"../protobuf.js\";\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n/**\n * Detects whether a global `window` object is available in the current environment.\n * @returns {boolean} `true` if `window` is defined in the current environment, `false` otherwise.\n */\n\nfunction hasWindow() {\n return typeof window !== \"undefined\";\n}\n\n/**\n * Selects the most appropriate global fetch implementation available in the current environment.\n *\n * Prefers `window.fetch` (bound to `window`) when present so code that stubs `window.fetch` is respected, and otherwise falls back to the global `fetch`.\n * @returns {Function|null} The chosen `fetch` function (with `window.fetch` bound to `window` when used), or `null` if no fetch implementation is available.\n */\nfunction getFetch() {\n if (hasWindow() && typeof window.fetch === \"function\") {\n return window.fetch.bind(window);\n }\n if (typeof fetch === \"function\") {\n return fetch;\n }\n return null;\n}\n\n/**\n * Create a UUID v4 string in dashed format.\n * @returns {string} A UUID v4 formatted string (e.g. `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`). When the Web Crypto API is available the value is produced via `crypto.randomUUID()`, otherwise a Math.random()-based fallback is used.\n */\nfunction generateEventId() {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback\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\n/**\n * Determine whether the browser Navigation API is present and supports event listeners.\n * @returns {boolean} `true` if the global `navigation` object exists and has an `addEventListener` function, `false` otherwise.\n */\nfunction hasNavigationApi() {\n return (\n typeof navigation !== \"undefined\" &&\n typeof navigation.addEventListener === \"function\"\n );\n}\n\n// ---------------------------------------------------------------------------\n// EventModule\n// ---------------------------------------------------------------------------\n\nexport class EventModule {\n /**\n * @param {{\n * deviceId: string,\n * getSessionId: () => string,\n * getUserUuid: () => string|null,\n * release: string|undefined,\n * apiKey: string,\n * apiBase: string,\n * isEventTrackingEnabled: boolean,\n * isFirstVisit: boolean,\n * isSdkUpdated: boolean,\n * previousRelease: string|null,\n * }} config\n */\n constructor(config) {\n const cfg = config ?? {};\n this._deviceId = cfg.deviceId ?? \"\";\n this._getSessionId = typeof cfg.getSessionId === \"function\" ? cfg.getSessionId : () => \"\";\n this._getUserUuid = typeof cfg.getUserUuid === \"function\" ? cfg.getUserUuid : () => null;\n // Resolves the first *real* (identified) user uuid. Returns null while the\n // user is anonymous so first_real_user_uuid stays empty (spec: optional).\n this._getRealUserUuid = typeof cfg.getRealUserUuid === \"function\" ? cfg.getRealUserUuid : () => null;\n // Called for each event after a successful send so the host client can mirror\n // it into the log stream at EVENT level. No-op when not provided.\n this._logEvent = typeof cfg.logEvent === \"function\" ? cfg.logEvent : null;\n // Resolves the per-session access token required by the events/collect\n // endpoint (server rejects requests without x-session-token \u2192 400).\n this._getSessionToken = typeof cfg.getSessionToken === \"function\" ? cfg.getSessionToken : null;\n this._release = cfg.release ?? undefined;\n this._apiKey = cfg.apiKey ?? \"\";\n this._apiBase = cfg.apiBase ?? \"\";\n this._isEventTrackingEnabled = cfg.isEventTrackingEnabled === true;\n this._isFirstVisit = cfg.isFirstVisit === true;\n this._isSdkUpdated = cfg.isSdkUpdated === true;\n this._previousRelease = cfg.previousRelease ?? null;\n this._dbPromise = cfg.dbPromise ?? null;\n\n this._eventQueue = [];\n this._eventPersistPromises = new Set();\n this._activeMemoryBatch = null;\n this._eventFlushInProgress = false;\n this._installed = false;\n this._tornDown = false;\n\n // Listener references (REQ-033)\n this._visibilityHandler = null;\n this._pageHideHandler = null;\n this._navigateHandler = null;\n this._popstateHandler = null;\n\n // For pushState/replaceState fallback restoration\n this._originalPushState = null;\n this._originalReplaceState = null;\n this._usesNavigationApi = false;\n\n // Track last known URL for previousUrl in page-view events\n this._lastUrl = null;\n\n // Permission tracking (REQ-034)\n this._permissionStatuses = [];\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n install() {\n if (this._installed || this._tornDown) return;\n\n this._installed = true;\n\n // Record initial URL\n this._lastUrl = this._getCurrentUrl();\n\n // Enqueue initial lifecycle events unconditionally \u2014 these are captured once\n // at session start and must not be gated by isEventTrackingEnabled, which may\n // not be set until the /logdrop/init response arrives. They will be held in\n // the queue and sent once setEnabled(true) is called and a flush fires.\n this._enqueueEventUnconditional(\"ao\", {});\n\n if (this._isFirstVisit) {\n this._enqueueEventUnconditional(\"ai\", {});\n }\n\n if (this._isSdkUpdated) {\n this._enqueueEventUnconditional(\"au\", {\n pv: this._previousRelease,\n nv: this._release,\n });\n }\n\n // Record session start time for time_in_app tracking\n this._sessionStartTime = Date.now();\n\n // Attach visibility handler (REQ-006, REQ-007)\n this._visibilityHandler = () => {\n try {\n if (typeof document === \"undefined\") return;\n if (document.visibilityState === \"hidden\") {\n this._enqueueEvent(\"ab\", {});\n // time_in_app: elapsed duration since session start or last foreground\n if (this._sessionStartTime != null) {\n this._enqueueEvent(\"ta\", { ed: Date.now() - this._sessionStartTime });\n }\n this._sessionStartTime = null;\n } else if (document.visibilityState === \"visible\") {\n this._enqueueEvent(\"af\", {});\n this._sessionStartTime = Date.now();\n }\n } catch {\n // never break host app\n }\n };\n\n if (typeof document !== \"undefined\" && typeof document.addEventListener === \"function\") {\n document.addEventListener(\"visibilitychange\", this._visibilityHandler);\n }\n\n // Attach pagehide handler for keepalive flush (REQ-021)\n this._pageHideHandler = () => {\n try {\n this._flush(true); // keepalive = true\n } catch {\n // silently swallow (SEC-002)\n }\n };\n\n if (hasWindow() && typeof window.addEventListener === \"function\") {\n window.addEventListener(\"pagehide\", this._pageHideHandler);\n }\n\n // SPA detection (REQ-009, REQ-010)\n this._installSpaDetection();\n\n // Permission tracking (REQ-034)\n void this._installPermissionTracking();\n }\n\n uninstall() {\n if (!this._installed) return;\n\n // Remove visibility handler\n if (\n this._visibilityHandler &&\n typeof document !== \"undefined\" &&\n typeof document.removeEventListener === \"function\"\n ) {\n try {\n document.removeEventListener(\"visibilitychange\", this._visibilityHandler);\n } catch {\n // ignore\n }\n }\n this._visibilityHandler = null;\n\n // Remove pagehide handler\n if (\n this._pageHideHandler &&\n hasWindow() &&\n typeof window.removeEventListener === \"function\"\n ) {\n try {\n window.removeEventListener(\"pagehide\", this._pageHideHandler);\n } catch {\n // ignore\n }\n }\n this._pageHideHandler = null;\n\n // Remove SPA detection\n this._uninstallSpaDetection();\n\n // Remove permission tracking\n this._uninstallPermissionTracking();\n\n this._installed = false;\n }\n\n teardown() {\n this.uninstall();\n this._tornDown = true;\n }\n\n // -------------------------------------------------------------------------\n // Kill switch (REQ-027)\n // -------------------------------------------------------------------------\n\n setEnabled(bool) {\n this._isEventTrackingEnabled = bool === true;\n }\n\n // -------------------------------------------------------------------------\n // Event queue\n // -------------------------------------------------------------------------\n\n _enqueueEvent(eventCode, properties) {\n if (!this._isEventTrackingEnabled || this._tornDown) return;\n this._enqueueEventUnconditional(eventCode, properties);\n }\n\n // Public entry point for callers outside the module (e.g. risk events from\n // LogDropClient). Enqueues an event honoring the isEventTrackingEnabled gate.\n trackEvent(eventCode, properties) {\n this._enqueueEvent(eventCode, properties);\n }\n\n // Validate an event against the server registry: the code must be recognized\n // and every required property must be present and non-empty.\n _isValidEvent(eventCode, properties) {\n if (!LogDropConstants.VALID_EVENT_CODES.includes(eventCode)) {\n return false;\n }\n const required = LogDropConstants.EVENT_REQUIRED_PROPS[eventCode] ?? [];\n const props = properties ?? {};\n for (const key of required) {\n const val = props[key];\n if (val === undefined || val === null || val === \"\") {\n return false;\n }\n }\n return true;\n }\n\n // Enqueue without the isEventTrackingEnabled gate \u2014 used for initial lifecycle\n // events that must be captured before the server config response arrives.\n _enqueueEventUnconditional(eventCode, properties) {\n if (this._tornDown) return;\n\n // Guard: the server rejects the entire batch (HTTP 400) if any event uses an\n // unknown code or omits a required property. Drop such events here so one bad\n // event can never poison a whole batch.\n if (!this._isValidEvent(eventCode, properties)) return;\n\n const event = {\n eventId: generateEventId(),\n eventCode,\n timestamp: Date.now(),\n properties: properties ?? {},\n _sessionId: this._getSessionId(),\n userUuid: this._getUserUuid(),\n };\n this._eventQueue.push(event);\n\n const persistPromise = this._persistEvent(event);\n this._eventPersistPromises.add(persistPromise);\n void persistPromise.finally(() => this._eventPersistPromises.delete(persistPromise));\n\n // Immediate flush at 30 items (REQ-020)\n if (this._eventQueue.length >= 30) {\n this._flush();\n }\n }\n\n // -------------------------------------------------------------------------\n // Flush\n // -------------------------------------------------------------------------\n\n async _persistEvent(event) {\n if (!this._dbPromise) return null;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"events\", \"readwrite\");\n const request = tx.objectStore(\"events\").add({ ...event });\n await new Promise((resolve, reject) => {\n tx.oncomplete = resolve;\n tx.onerror = () => reject(tx.error);\n });\n event._dbId = request.result;\n return request.result;\n } catch {\n return null;\n }\n }\n\n async _readStore(storeName) {\n if (!this._dbPromise) return [];\n const db = await this._dbPromise;\n const tx = db.transaction(storeName, \"readonly\");\n const request = tx.objectStore(storeName).getAll();\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => reject(request.error);\n });\n }\n\n async _replaceEventBatch(batch) {\n const db = await this._dbPromise;\n const tx = db.transaction(\"event_upload_batch\", \"readwrite\");\n const store = tx.objectStore(\"event_upload_batch\");\n store.clear();\n if (batch) store.add(batch);\n await new Promise((resolve, reject) => {\n tx.oncomplete = resolve;\n tx.onerror = () => reject(tx.error);\n });\n }\n\n async _getOrCreateEventBatch() {\n await Promise.all([...this._eventPersistPromises]);\n\n if (this._dbPromise) {\n try {\n const allEvents = await this._readStore(\"events\");\n const storedBatches = await this._readStore(\"event_upload_batch\");\n const storedBatch = storedBatches[0] ?? null;\n\n if (storedBatch) {\n const rows = allEvents.filter((event) => event.id <= storedBatch.lastEventId);\n if (rows.length > 0) {\n return { uploadId: storedBatch.uploadId, events: rows, persisted: true };\n }\n await this._replaceEventBatch(null);\n }\n\n if (allEvents.length > 0) {\n const batch = {\n uploadId: generateEventId(),\n lastEventId: allEvents[allEvents.length - 1].id,\n };\n await this._replaceEventBatch(batch);\n return { uploadId: batch.uploadId, events: allEvents, persisted: true };\n }\n } catch {\n // IndexedDB is best-effort; keep the original in-memory upload path available.\n }\n }\n\n if (!this._activeMemoryBatch && this._eventQueue.length > 0) {\n this._activeMemoryBatch = {\n uploadId: generateEventId(),\n events: [...this._eventQueue],\n persisted: false,\n };\n }\n return this._activeMemoryBatch;\n }\n\n async _acknowledgeEventBatch(batch) {\n const eventIds = new Set(batch.events.map((event) => event.eventId));\n\n if (batch.persisted && this._dbPromise) {\n const db = await this._dbPromise;\n const tx = db.transaction(\"events\", \"readwrite\");\n const store = tx.objectStore(\"events\");\n batch.events.forEach((event) => store.delete(event.id));\n await new Promise((resolve, reject) => {\n tx.oncomplete = resolve;\n tx.onerror = () => reject(tx.error);\n });\n await this._replaceEventBatch(null);\n } else {\n this._activeMemoryBatch = null;\n }\n\n this._eventQueue = this._eventQueue.filter((event) => !eventIds.has(event.eventId));\n }\n\n async _flush(keepalive = false) {\n if (this._tornDown) return;\n if (!this._isEventTrackingEnabled) return;\n if (this._eventFlushInProgress) return;\n if (this._eventQueue.length === 0 && !this._dbPromise) return;\n\n this._eventFlushInProgress = true;\n\n // Resolve fetch before mutating the queue \u2014 if unavailable, bail cleanly\n const fetchFn = getFetch();\n if (!fetchFn) {\n this._eventFlushInProgress = false;\n return;\n }\n\n // Resolve the session token required by the server. Without a valid\n // x-session-token the events/collect endpoint responds with 400.\n let sessionToken = null;\n if (this._getSessionToken) {\n try {\n sessionToken = await this._getSessionToken();\n } catch {\n sessionToken = null;\n }\n }\n if (!sessionToken) {\n // Keep events queued for a later flush once a token is available.\n this._eventFlushInProgress = false;\n return;\n }\n\n try {\n const batch = await this._getOrCreateEventBatch();\n if (!batch || batch.events.length === 0) return;\n const events = batch.events;\n\n // Group events by sessionId (REQ-016)\n const sessionMap = new Map();\n for (const evt of events) {\n const sid = evt._sessionId;\n if (!sessionMap.has(sid)) {\n sessionMap.set(sid, { userUuid: evt.userUuid, events: [] });\n }\n sessionMap.get(sid).events.push({\n eventId: evt.eventId,\n eventCode: evt.eventCode,\n timestamp: evt.timestamp,\n properties: evt.properties,\n });\n }\n\n const sessions = [];\n for (const [sessionId, sessionData] of sessionMap) {\n sessions.push({\n sessionId,\n userUuid: sessionData.userUuid,\n events: sessionData.events,\n });\n }\n\n // Only a real, identified user populates first_real_user_uuid; it stays\n // empty while anonymous (session user_uuid falls back to the deviceUuid).\n const firstRealUserUuid = this._getRealUserUuid() ?? \"\";\n\n const payload = {\n deviceUuid: this._deviceId,\n sessions,\n firstRealUserUuid,\n uploadId: batch.uploadId,\n };\n\n const protoBytes = encodeEventBatchRequest(payload);\n\n const url = `${this._apiBase}${LogDropConstants.EVENTS_PATH}`;\n const fetchOptions = {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-protobuf\",\n \"Accept\": \"application/x-protobuf\",\n \"x-api-key\": this._apiKey,\n \"x-session-token\": sessionToken,\n },\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" }),\n };\n\n if (keepalive) {\n fetchOptions.keepalive = true;\n }\n\n const res = await fetchFn(url, fetchOptions);\n if (res.ok) {\n // Mirror every successfully sent event into the log stream (EVENT level).\n if (this._logEvent) {\n for (const s of payload.sessions) {\n for (const e of s.events) {\n try {\n this._logEvent({\n eventId: e.eventId,\n eventCode: e.eventCode,\n eventName: LogDropConstants.EVENT_NAMES[e.eventCode] ?? e.eventCode,\n timestamp: e.timestamp,\n sessionId: s.sessionId,\n properties: e.properties ?? {},\n });\n } catch {\n // never let logging break the flush\n }\n }\n }\n }\n\n // Best-effort: parse EventBatchResponse (non-critical)\n try {\n const responseBytes = new Uint8Array(await res.arrayBuffer());\n if (responseBytes.length > 0) decodeEventBatchResponse(responseBytes);\n } catch {\n // ignore response decode errors\n }\n await this._acknowledgeEventBatch(batch);\n }\n } catch (err) {\n // Surface the error instead of swallowing it\n throw err;\n } finally {\n this._eventFlushInProgress = false;\n }\n }\n\n // -------------------------------------------------------------------------\n // SPA detection\n // -------------------------------------------------------------------------\n\n _installSpaDetection() {\n if (hasNavigationApi()) {\n // Primary: Navigation API (REQ-009)\n this._usesNavigationApi = true;\n this._navigateHandler = (event) => {\n try {\n // Track the current route internally. No server event is emitted:\n // the LogDrop event registry has no page-view/screen-view code, so\n // SPA navigations are not reported to /events/collect.\n const destUrl = (event && event.destination && event.destination.url)\n ? event.destination.url\n : this._getCurrentUrl();\n queueMicrotask(() => {\n this._lastUrl = destUrl;\n });\n } catch {\n // never break host app\n }\n };\n navigation.addEventListener(\"navigate\", this._navigateHandler);\n } else {\n // Fallback: monkey-patch pushState/replaceState + popstate (REQ-010)\n this._usesNavigationApi = false;\n this._installHistoryPatches();\n }\n }\n\n _uninstallSpaDetection() {\n if (this._usesNavigationApi) {\n // Remove Navigation API listener\n if (\n this._navigateHandler &&\n typeof navigation !== \"undefined\" &&\n typeof navigation.removeEventListener === \"function\"\n ) {\n try {\n navigation.removeEventListener(\"navigate\", this._navigateHandler);\n } catch {\n // ignore\n }\n }\n this._navigateHandler = null;\n } else {\n // Restore monkey-patched history methods (REQ-011)\n this._restoreHistoryPatches();\n }\n\n // Remove popstate listener\n if (\n this._popstateHandler &&\n hasWindow() &&\n typeof window.removeEventListener === \"function\"\n ) {\n try {\n window.removeEventListener(\"popstate\", this._popstateHandler);\n } catch {\n // ignore\n }\n }\n this._popstateHandler = null;\n }\n\n _installHistoryPatches() {\n if (typeof history === \"undefined\") return;\n\n // Store originals for restoration (REQ-011)\n this._originalPushState = history.pushState;\n this._originalReplaceState = history.replaceState;\n\n const self = this;\n\n // Monkey-patch pushState. We still call through to the original so the host\n // app's routing is unaffected, and we keep _lastUrl current, but no server\n // event is emitted (registry has no page-view/screen-view code).\n history.pushState = function (...args) {\n // Call through to original (COR-004)\n self._originalPushState.apply(this, args);\n self._lastUrl = self._getCurrentUrl();\n };\n\n // Monkey-patch replaceState\n history.replaceState = function (...args) {\n // Call through to original (COR-004)\n self._originalReplaceState.apply(this, args);\n self._lastUrl = self._getCurrentUrl();\n };\n\n // popstate listener for back/forward \u2014 track route only, no event emitted.\n this._popstateHandler = () => {\n try {\n this._lastUrl = this._getCurrentUrl();\n } catch {\n // never break host app\n }\n };\n\n if (hasWindow() && typeof window.addEventListener === \"function\") {\n window.addEventListener(\"popstate\", this._popstateHandler);\n }\n }\n\n _restoreHistoryPatches() {\n if (typeof history === \"undefined\") return;\n\n if (this._originalPushState) {\n history.pushState = this._originalPushState;\n this._originalPushState = null;\n }\n if (this._originalReplaceState) {\n history.replaceState = this._originalReplaceState;\n this._originalReplaceState = null;\n }\n }\n\n // -------------------------------------------------------------------------\n // Permission tracking (REQ-034)\n // -------------------------------------------------------------------------\n\n async _installPermissionTracking() {\n const PERMISSIONS = [\n { pt: \"notification\", apiName: \"notifications\" },\n { pt: \"geolocation\", apiName: \"geolocation\" },\n { pt: \"camera\", apiName: \"camera\" },\n { pt: \"microphone\", apiName: \"microphone\" },\n ];\n\n const hasPermissionsApi =\n typeof navigator !== \"undefined\" &&\n navigator.permissions &&\n typeof navigator.permissions.query === \"function\";\n\n if (hasPermissionsApi) {\n for (const { pt, apiName } of PERMISSIONS) {\n try {\n const status = await navigator.permissions.query({ name: apiName });\n this._enqueueEvent(\"ap\", { pt, ps: status.state });\n status.onchange = () => {\n try {\n if (!this._installed) return;\n this._enqueueEvent(\"ap\", { pt, ps: status.state });\n } catch { /* ignore */ }\n };\n this._permissionStatuses.push(status);\n } catch {\n // Query rejected (e.g., Firefox rejecting camera/microphone)\n const ps = pt === \"notification\" ? this._getNotificationPermission() : \"unsupported\";\n this._enqueueEvent(\"ap\", { pt, ps });\n }\n }\n } else {\n // No Permissions API \u2014 use fallbacks\n this._enqueueEvent(\"ap\", { pt: \"notification\", ps: this._getNotificationPermission() });\n for (const pt of [\"geolocation\", \"camera\", \"microphone\"]) {\n this._enqueueEvent(\"ap\", { pt, ps: \"unsupported\" });\n }\n }\n }\n\n _getNotificationPermission() {\n try {\n if (typeof Notification !== \"undefined\" && Notification.permission) {\n const raw = Notification.permission; // \"granted\" | \"denied\" | \"default\"\n return raw === \"default\" ? \"prompt\" : raw;\n }\n } catch { /* ignore */ }\n return \"unsupported\";\n }\n\n _uninstallPermissionTracking() {\n for (const status of this._permissionStatuses) {\n try { status.onchange = null; } catch { /* ignore */ }\n }\n this._permissionStatuses = [];\n }\n\n // -------------------------------------------------------------------------\n // DOM accessors (safe for environments without full browser globals)\n // -------------------------------------------------------------------------\n\n _getCurrentUrl() {\n try {\n if (typeof location !== \"undefined\" && location.href) return location.href;\n } catch {\n // ignore\n }\n return \"\";\n }\n\n _getReferrer() {\n try {\n if (typeof document !== \"undefined\" && document.referrer != null) return document.referrer;\n } catch {\n // ignore\n }\n return \"\";\n }\n\n _getTitle() {\n try {\n if (typeof document !== \"undefined\" && document.title != null) return document.title;\n } catch {\n // ignore\n }\n return \"\";\n }\n}\n", "function hasWindow() {\n return typeof window !== \"undefined\";\n}\n\nexport class HeadlessBrowserSignalProvider {\n detect() {\n if (typeof navigator === \"undefined\") return null;\n\n const indicators = [];\n\n // navigator.webdriver is true in headless/automated browsers\n if (navigator.webdriver === true) {\n indicators.push(\"webdriver\");\n }\n\n // Chrome API object is absent in headless Chromium\n if (\n typeof navigator.userAgent === \"string\" &&\n navigator.userAgent.toLowerCase().includes(\"chrome\") &&\n hasWindow() &&\n !window.chrome\n ) {\n indicators.push(\"missing_chrome_api\");\n }\n\n if (hasWindow()) {\n // Playwright fingerprint\n if (window.__playwright__binding__ !== undefined || window.__pwInitScripts__ !== undefined) {\n indicators.push(\"playwright_binding\");\n }\n\n // CDP / ChromeDriver markers (keys starting with cdc_)\n for (const key of Object.keys(window)) {\n if (key.startsWith(\"cdc_\")) {\n indicators.push(\"cdp_marker\");\n break;\n }\n }\n }\n\n if (indicators.length === 0) return null;\n\n return {\n id: \"headless_browser_detected\",\n weight: 0.90,\n severity: 1.0,\n confidence: 0.90,\n evidence: { indicators: indicators.join(\",\") },\n };\n }\n}\n", "export class AutomationEnvironmentSignalProvider {\n detect() {\n if (typeof window === \"undefined\") return null;\n\n const indicators = [];\n\n // Playwright markers\n if (window.__playwright__binding__ !== undefined || window.__pwInitScripts__ !== undefined) {\n indicators.push(\"playwright\");\n }\n\n // Puppeteer markers\n if (window.__puppeteer_evaluation_script__ !== undefined) {\n indicators.push(\"puppeteer\");\n }\n\n // Selenium / WebDriver markers on document\n if (typeof document !== \"undefined\") {\n if (document.$wdc_ !== undefined || document.__webdriver_evaluate !== undefined) {\n indicators.push(\"selenium\");\n }\n }\n\n if (indicators.length === 0) return null;\n\n return {\n id: \"automation_environment_detected\",\n // Keep the shared automation signal aligned with Android/iOS.\n weight: 0.60,\n severity: 1.0,\n confidence: 1.0,\n evidence: { indicators: indicators.join(\",\") },\n };\n }\n}\n", "const BUFFER_SIZE = 60;\nconst ANALYSIS_WINDOW_MS = 4000;\nconst MIN_SAMPLES = 8;\nconst ROBOTIC_TIMING_STDDEV_MS = 18;\nconst ROBOTIC_TIMING_MEAN_MS = 120;\nconst ROBOTIC_PATH_STRAIGHTNESS = 0.985;\nconst DENSE_BURST_COUNT = 10;\nconst DENSE_BURST_WINDOW_MS = 2500;\n\nfunction stddev(values) {\n if (values.length < 2) return 0;\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\n const variance = values.reduce((s, v) => s + (v - mean) ** 2, 0) / (values.length - 1);\n return Math.sqrt(variance);\n}\n\nfunction mean(values) {\n return values.length === 0 ? 0 : values.reduce((a, b) => a + b, 0) / values.length;\n}\n\nexport class PointerBehaviorSignalProvider {\n constructor() {\n this._samples = [];\n }\n\n recordSample(x, y, time) {\n this._samples.push({ x, y, time });\n if (this._samples.length > BUFFER_SIZE) {\n this._samples.shift();\n }\n }\n\n // Test-only injection hook\n _injectSamples(samples) {\n this._samples = samples.slice(-BUFFER_SIZE);\n }\n\n detect() {\n const now = this._samples.length > 0 ? this._samples[this._samples.length - 1].time : 0;\n const windowStart = now - ANALYSIS_WINDOW_MS;\n const recent = this._samples.filter((s) => s.time >= windowStart);\n\n if (recent.length < MIN_SAMPLES) return null;\n\n // Inter-event timing intervals\n const intervals = [];\n for (let i = 1; i < recent.length; i++) {\n intervals.push(recent[i].time - recent[i - 1].time);\n }\n\n const timingMean = mean(intervals);\n const timingStddev = stddev(intervals);\n const roboticTiming = timingStddev < ROBOTIC_TIMING_STDDEV_MS && timingMean < ROBOTIC_TIMING_MEAN_MS;\n\n // Path analysis\n let pathLength = 0;\n for (let i = 1; i < recent.length; i++) {\n const dx = recent[i].x - recent[i - 1].x;\n const dy = recent[i].y - recent[i - 1].y;\n pathLength += Math.sqrt(dx * dx + dy * dy);\n }\n const first = recent[0];\n const last = recent[recent.length - 1];\n const dx = last.x - first.x;\n const dy = last.y - first.y;\n const straightLine = Math.sqrt(dx * dx + dy * dy);\n const straightness = pathLength > 0 ? straightLine / pathLength : 0;\n const roboticPath = straightness > ROBOTIC_PATH_STRAIGHTNESS;\n\n // Dense burst\n const span = last.time - first.time;\n const denseBurst = recent.length >= DENSE_BURST_COUNT && span < DENSE_BURST_WINDOW_MS;\n const evenlyTimedBurst = timingStddev < 30 && timingMean < 180;\n const linearBurst = denseBurst && roboticPath && evenlyTimedBurst;\n\n const triggered = roboticTiming || linearBurst || (roboticPath && denseBurst);\n if (!triggered) return null;\n\n return {\n id: \"automation_pointer_pattern\",\n weight: 0.60,\n severity: 1.0,\n confidence: 1.0,\n evidence: {\n stddev: timingStddev.toFixed(2),\n mean_interval: timingMean.toFixed(2),\n straight: straightness.toFixed(4),\n span: span.toFixed(0),\n samples: recent.length.toString(),\n },\n };\n }\n}\n", "const BUFFER_SIZE = 20;\nconst MIN_KEYSTROKES = 6;\nconst ROBOTIC_STDDEV_MS = 20;\n\nfunction stddev(values) {\n if (values.length < 2) return 0;\n const m = values.reduce((a, b) => a + b, 0) / values.length;\n const variance = values.reduce((s, v) => s + (v - m) ** 2, 0) / (values.length - 1);\n return Math.sqrt(variance);\n}\n\nexport class KeyboardCadenceSignalProvider {\n constructor() {\n this._timestamps = [];\n }\n\n recordTimestamp(ts) {\n this._timestamps.push(ts);\n if (this._timestamps.length > BUFFER_SIZE) {\n this._timestamps.shift();\n }\n }\n\n // Test-only injection hook\n _injectTimestamps(timestamps) {\n this._timestamps = timestamps.slice(-BUFFER_SIZE);\n }\n\n detect() {\n if (this._timestamps.length < MIN_KEYSTROKES) return null;\n\n const intervals = [];\n for (let i = 1; i < this._timestamps.length; i++) {\n intervals.push(this._timestamps[i] - this._timestamps[i - 1]);\n }\n\n const s = stddev(intervals);\n if (s >= ROBOTIC_STDDEV_MS) return null;\n\n return {\n id: \"keyboard_too_uniform\",\n weight: 0.55,\n severity: 1.0,\n confidence: 0.80,\n evidence: {\n stddev: s.toFixed(2),\n samples: this._timestamps.length.toString(),\n },\n };\n }\n}\n", "function isChromium(ua) {\n return typeof ua === \"string\" && ua.toLowerCase().includes(\"chrome\") && !ua.toLowerCase().includes(\"firefox\");\n}\n\nexport class HardwareConsistencySignalProvider {\n detect() {\n if (typeof navigator === \"undefined\") return null;\n\n const ua = navigator.userAgent;\n const chromium = isChromium(ua);\n const indicators = [];\n\n // Empty plugins on claimed Chromium desktop\n const plugins = navigator.plugins;\n if (chromium && plugins !== undefined && plugins.length === 0) {\n indicators.push(\"empty_plugins\");\n }\n\n // Missing or empty languages\n const languages = navigator.languages;\n if (!languages || languages.length === 0) {\n indicators.push(\"missing_languages\");\n }\n\n // Missing deviceMemory on Chromium (only Chromium supports this API)\n if (chromium && navigator.deviceMemory === undefined) {\n indicators.push(\"missing_device_memory\");\n }\n\n if (indicators.length === 0) return null;\n\n return {\n id: \"hardware_inconsistency\",\n weight: 0.40,\n severity: 0.7,\n confidence: 0.60,\n evidence: { indicators: indicators.join(\",\") },\n };\n }\n}\n", "// Threshold in pixels \u2014 docked DevTools typically adds 300px; 200px avoids\n// false positives from zoom levels and browser chrome on small windows.\nconst SIZE_THRESHOLD = 200;\n\nexport class DevToolsSignalProvider {\n detect() {\n if (typeof window === \"undefined\") return null;\n\n const widthDiff = (window.outerWidth ?? 0) - (window.innerWidth ?? 0);\n const heightDiff = (window.outerHeight ?? 0) - (window.innerHeight ?? 0);\n\n if (widthDiff <= SIZE_THRESHOLD && heightDiff <= SIZE_THRESHOLD) return null;\n\n return {\n id: \"devtools_open\",\n weight: 0.40,\n severity: 0.7,\n confidence: 0.75,\n evidence: {\n width_diff: widthDiff.toString(),\n height_diff: heightDiff.toString(),\n },\n };\n }\n}\n", "// Best-effort detection of *undocked* (separate-window) DevTools.\n//\n// The size-diff heuristic in devToolsSignal.js only works when DevTools is\n// docked to the page (it shrinks the viewport). When the user pops DevTools out\n// into its own OS window, the viewport is unchanged and that heuristic fails.\n//\n// This provider uses the well-known \"console getter\" trick: we log a bait\n// object that has a property getter. When the DevTools Console panel renders a\n// logged value, it eagerly evaluates the object's getters to build a preview \u2014\n// firing our getter. If the getter fires, the Console is being rendered, i.e.\n// DevTools is open (docked OR undocked).\n//\n// Trade-off: `probe()` emits a periodic console.log, so it leaves a small\n// footprint in the console. This is gated by a constant so it can be disabled.\n//\n// The RiskModule drives this provider: it calls `probe()` on a short interval,\n// then reads the result via `detect()`. In Chromium the getter fires\n// synchronously during `console.log`, so the flag set by the most recent\n// `probe()` reflects the current state.\n\nexport class DevToolsConsoleSignalProvider {\n constructor() {\n this._triggered = false;\n this._bait = this._makeBait();\n }\n\n _makeBait() {\n const self = this;\n const bait = {};\n // The Console preview reads own-enumerable property getters. When DevTools\n // renders the bait, this getter runs and flips the flag.\n Object.defineProperty(bait, \"id\", {\n enumerable: true,\n configurable: true,\n get() {\n self._triggered = true;\n return \"\";\n },\n });\n return bait;\n }\n\n // Logs the bait so an open Console panel triggers the getter. Meant to be\n // called on a short interval. Resets the flag first so `detect()` reflects\n // only the current probe.\n probe() {\n if (typeof console === \"undefined\" || typeof console.log !== \"function\") return;\n this._triggered = false;\n try {\n // A zero-size CSS format keeps the visible footprint minimal while still\n // forcing the console to render (and thus preview) the bait object.\n console.log(\"%c%o\", \"font-size:0;color:transparent\", this._bait);\n } catch {\n // never break the host app\n }\n }\n\n detect() {\n if (!this._triggered) return null;\n\n return {\n id: \"devtools_open\",\n weight: 0.40,\n severity: 0.7,\n // Lower than the size-based signal: the console trick is more heuristic\n // and can be defeated by users who disable console preview.\n confidence: 0.6,\n evidence: {\n method: \"console_getter\",\n },\n };\n }\n}\n", "// Chrome 115+ (Aug 2023) changed incognito storage quota from a fixed ~120 MB\n// cap to RAM/10 (~800 MB\u20131.6 GB on typical hardware), making quota-based\n// detection unreliable for modern Chrome. webkitRequestFileSystem \u2014 the\n// previous reliable signal \u2014 was also removed in Chrome 115.\n//\n// Detection coverage:\n// Firefox private \u2192 storage.estimate() returns ~0 quota \u2713\n// Safari private \u2192 localStorage.setItem() throws \u2713\n// Chrome < 115 \u2192 webkitRequestFileSystem error \u2713\n// Chrome 115+ \u2192 not detectable via browser APIs \u2717\n\n// Firefox private mode returns near-zero quota; 10 MB gives a safe margin.\nconst FIREFOX_PRIVATE_QUOTA_THRESHOLD = 10 * 1024 * 1024;\n\nexport class IncognitoSignalProvider {\n constructor() {\n this._detected = null;\n this._method = null;\n this._checkPromise = this._check();\n }\n\n async _check() {\n const win = typeof window !== \"undefined\" ? window : null;\n\n // Method 1: webkitRequestFileSystem \u2014 Chrome < 115 incognito blocks it\n const fs = win && (win.RequestFileSystem || win.webkitRequestFileSystem);\n if (fs) {\n const blocked = await new Promise((resolve) => {\n try {\n fs(0 /* TEMPORARY */, 100, () => resolve(false), () => resolve(true));\n } catch {\n resolve(false);\n }\n });\n if (blocked) {\n this._detected = true;\n this._method = \"filesystem_api\";\n return;\n }\n }\n\n // Method 2: storage.estimate() quota \u2014 Firefox private returns ~0\n if (\n typeof navigator !== \"undefined\" &&\n navigator.storage &&\n typeof navigator.storage.estimate === \"function\"\n ) {\n try {\n const { quota } = await navigator.storage.estimate();\n if (typeof quota === \"number\" && quota < FIREFOX_PRIVATE_QUOTA_THRESHOLD) {\n this._detected = true;\n this._method = \"storage_quota\";\n return;\n }\n // Quota is normal-sized \u2014 not private (or Chrome 115+ incognito which\n // is indistinguishable from normal browsing via this API)\n this._detected = false;\n return;\n } catch {\n // fall through to localStorage check\n }\n }\n\n // Method 3: localStorage throw \u2014 Safari private browsing\n if (typeof localStorage !== \"undefined\") {\n try {\n localStorage.setItem(\"_ld_priv_test\", \"1\");\n localStorage.removeItem(\"_ld_priv_test\");\n this._detected = false;\n } catch {\n this._detected = true;\n this._method = \"localstorage_throw\";\n }\n return;\n }\n\n this._detected = false;\n }\n\n detect() {\n if (!this._detected) return null;\n\n return {\n id: \"private_browsing_detected\",\n weight: 0.30,\n severity: 0.5,\n confidence: 0.70,\n evidence: { method: this._method ?? \"unknown\" },\n };\n }\n}\n", "// Soft signal for Chrome 115+ incognito detection via cross-session localStorage\n// persistence. Normal mode: localStorage survives tab close; incognito: wiped\n// when all private windows close.\n//\n// Flow per page load:\n// - Same session (sessionStorage marker set): skip, return null\n// - New session, localStorage token exists: normal mode \u2014 no signal, increment count\n// - New session, localStorage token absent: possible incognito first visit \u2014 fire signal\n//\n// Caveat: fires on genuine first visits and cleared-cookie users (false positive).\n// Confidence is deliberately low (0.50) to reflect this.\n\nconst LS_KEY = \"_ld_cv\";\nconst SS_KEY = \"_ld_sm\";\n\nfunction hasStorage(key) {\n try {\n return typeof global !== \"undefined\"\n ? global[key] != null\n : typeof window !== \"undefined\" && window[key] != null;\n } catch {\n return false;\n }\n}\n\nfunction getLS() {\n try {\n return typeof localStorage !== \"undefined\" ? localStorage : null;\n } catch {\n return null;\n }\n}\n\nfunction getSS() {\n try {\n return typeof sessionStorage !== \"undefined\" ? sessionStorage : null;\n } catch {\n return null;\n }\n}\n\nexport class SessionPersistenceSignalProvider {\n detect() {\n const ls = getLS();\n const ss = getSS();\n\n if (!ls || !ss) return null;\n\n // Within-session reload: skip entirely\n if (ss.getItem(SS_KEY) === \"1\") return null;\n\n // Mark this session so reloads skip\n ss.setItem(SS_KEY, \"1\");\n\n // Try to read existing cross-session token\n let token = null;\n try {\n const raw = ls.getItem(LS_KEY);\n if (raw) token = JSON.parse(raw);\n } catch {\n // Corrupted token \u2014 treat as absent\n token = null;\n }\n\n const sessionCount = (token?.n ?? 0) + 1;\n ls.setItem(LS_KEY, JSON.stringify({ t: Date.now(), n: sessionCount }));\n\n if (token !== null) {\n // Token existed \u2014 localStorage persisted across sessions \u2192 normal mode\n return null;\n }\n\n // No token found on a new session \u2014 possible incognito\n return {\n id: \"session_not_persistent\",\n weight: 0.25,\n severity: 0.6,\n confidence: 0.50,\n evidence: {\n method: \"localstorage_persistence\",\n sessions: sessionCount,\n },\n };\n }\n}\n", "export const RiskEventIds = Object.freeze({\n JAILBREAK_DETECTED: 1,\n DEBUGGER_ATTACHED: 2,\n HOOKING_SUSPECTED: 3,\n PROXY_CONFIGURED: 4,\n VPN_SUSPECTED: 5,\n SIMULATOR_IN_USE: 6,\n AUTOMATION_ENVIRONMENT_DETECTED: 7,\n AUTOMATION_TOUCH_PATTERN: 8,\n DEVICE_CLOCK_MISMATCH: 9,\n DEVTOOLS_OPEN: 10,\n HEADLESS_BROWSER_DETECTED: 11,\n AUTOMATION_POINTER_PATTERN: 12,\n KEYBOARD_TOO_UNIFORM: 13,\n PRIVATE_BROWSING_DETECTED: 14,\n SESSION_NOT_PERSISTENT: 15,\n HARDWARE_INCONSISTENCY: 16,\n});\n\nexport const RiskActionIds = Object.freeze({\n BLOCK_ALL_NETWORK: 1,\n SHOW_WARNING: 2,\n BLOCK_APP: 3,\n});\n\nconst KNOWN_EVENT_IDS = new Set(Object.values(RiskEventIds));\nconst KNOWN_ACTION_IDS = new Set(Object.values(RiskActionIds));\n\nconst SIGNAL_EVENT_IDS = Object.freeze({\n devtools_open: RiskEventIds.DEVTOOLS_OPEN,\n headless_browser_detected: RiskEventIds.HEADLESS_BROWSER_DETECTED,\n automation_environment_detected: RiskEventIds.AUTOMATION_ENVIRONMENT_DETECTED,\n automation_pointer_pattern: RiskEventIds.AUTOMATION_POINTER_PATTERN,\n keyboard_too_uniform: RiskEventIds.KEYBOARD_TOO_UNIFORM,\n private_browsing_detected: RiskEventIds.PRIVATE_BROWSING_DETECTED,\n session_not_persistent: RiskEventIds.SESSION_NOT_PERSISTENT,\n hardware_inconsistency: RiskEventIds.HARDWARE_INCONSISTENCY,\n});\n\nexport function eventIdForSignal(signalId) {\n return SIGNAL_EVENT_IDS[signalId] ?? null;\n}\n\nexport function actionName(actionId) {\n switch (actionId) {\n case RiskActionIds.BLOCK_ALL_NETWORK: return \"block_all_network\";\n case RiskActionIds.SHOW_WARNING: return \"show_warning\";\n case RiskActionIds.BLOCK_APP: return \"block_app\";\n default: return null;\n }\n}\n\nexport function evaluateRiskPolicy(policy, detectedEventIds) {\n const detected = new Set(detectedEventIds ?? []);\n const rules = Array.isArray(policy?.rules) ? policy.rules : [];\n if (rules.length === 0 || detected.size === 0) return emptyEvaluation();\n\n const matchedRules = rules\n .filter((rule) => rule?.enabled === true)\n .map((rule) => {\n const eventIds = (rule.eventIds ?? []).filter((id) => KNOWN_EVENT_IDS.has(id));\n const actionIds = (rule.actionIds ?? []).filter((id) => KNOWN_ACTION_IDS.has(id));\n return { ...rule, eventIds, actionIds };\n })\n .filter((rule) => {\n if (rule.eventIds.length === 0 || rule.actionIds.length === 0) return false;\n const matchType = String(rule.matchType || \"ANY\").toUpperCase();\n if (matchType === \"ANY\") return rule.eventIds.some((id) => detected.has(id));\n if (matchType === \"ALL\") return rule.eventIds.every((id) => detected.has(id));\n return false;\n })\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n\n if (matchedRules.length === 0) return emptyEvaluation();\n\n const actionIds = [...new Set(matchedRules.flatMap((rule) => rule.actionIds))];\n const firstText = (key) => matchedRules\n .map((rule) => typeof rule[key] === \"string\" ? rule[key].trim() : \"\")\n .find(Boolean) || null;\n\n return {\n matchedRules,\n actionIds,\n title: firstText(\"title\"),\n message: firstText(\"message\"),\n buttonText: firstText(\"buttonText\"),\n };\n}\n\nexport function policyEvaluationSignature(evaluation) {\n if (!evaluation || evaluation.actionIds.length === 0) return null;\n return JSON.stringify({\n actions: [...evaluation.actionIds].sort((a, b) => a - b),\n rules: evaluation.matchedRules.map((rule) => rule.priority ?? 0),\n });\n}\n\nfunction emptyEvaluation() {\n return {\n matchedRules: [],\n actionIds: [],\n title: null,\n message: null,\n buttonText: null,\n };\n}\n", "import { HeadlessBrowserSignalProvider } from \"./signals/headlessBrowserSignal.js\";\nimport { AutomationEnvironmentSignalProvider } from \"./signals/automationEnvironmentSignal.js\";\nimport { PointerBehaviorSignalProvider } from \"./signals/pointerBehaviorSignal.js\";\nimport { KeyboardCadenceSignalProvider } from \"./signals/keyboardCadenceSignal.js\";\nimport { HardwareConsistencySignalProvider } from \"./signals/hardwareConsistencySignal.js\";\nimport { DevToolsSignalProvider } from \"./signals/devToolsSignal.js\";\nimport { DevToolsConsoleSignalProvider } from \"./signals/devToolsConsoleSignal.js\";\nimport { IncognitoSignalProvider } from \"./signals/incognitoSignal.js\";\nimport { SessionPersistenceSignalProvider } from \"./signals/sessionPersistenceSignal.js\";\nimport { LogDropConstants } from \"../constants.js\";\nimport {\n evaluateRiskPolicy,\n eventIdForSignal,\n policyEvaluationSignature,\n} from \"./riskPolicy.js\";\n\n// ---------------------------------------------------------------------------\n// Scoring \u2014 same multiplicative formula as iOS RiskEngine / BotEngine\n// ---------------------------------------------------------------------------\n\nfunction computeScore(signals) {\n let complement = 1;\n for (const s of signals) {\n complement *= 1 - s.weight * s.severity * s.confidence;\n }\n return Math.round(Math.min(100, Math.max(0, 100 * (1 - complement))));\n}\n\nfunction scoreToLabel(score, collecting) {\n if (collecting) return \"collecting\";\n if (score >= 60) return \"automation_suspected\";\n if (score >= 30) return \"uncertain\";\n return \"likely_human\";\n}\n\nfunction scoreToRiskLevel(score) {\n if (score >= 75) return \"critical\";\n if (score >= 50) return \"high\";\n if (score >= 25) return \"medium\";\n return \"low\";\n}\n\n// Same combined session posture contract as Android/iOS SessionThreatManager.\nfunction scoresToPosture(riskScore, botScore) {\n if (riskScore >= 75) return \"critical\";\n if (riskScore >= 50 || botScore >= 60) return \"at_risk\";\n if (riskScore >= 25 || botScore >= 30) return \"elevated\";\n return \"safe\";\n}\n\n// ---------------------------------------------------------------------------\n// Signal categorisation \u2014 bot detection and risk detection are separate.\n// Bot signals \u2192 drive the bot score / label (is this an automated client?)\n// Risk signals \u2192 drive the risk score / posture (environment/integrity risk)\n// A signal in one category must NOT influence the other category's score.\n// ---------------------------------------------------------------------------\n\nconst BOT_SIGNAL_IDS = new Set([\n \"headless_browser_detected\",\n \"automation_environment_detected\",\n \"automation_pointer_pattern\",\n \"keyboard_too_uniform\",\n]);\n\nconst RISK_SIGNAL_IDS = new Set([\n \"devtools_open\",\n \"private_browsing_detected\",\n \"session_not_persistent\",\n \"hardware_inconsistency\",\n]);\n\n// ---------------------------------------------------------------------------\n// RiskModule\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_INTERVAL_MS = 30_000;\n// Require 3s of activity before the first meaningful evaluation\nconst MIN_COLLECT_MS = 3_000;\n// Minimum pointer samples before behavioural signals are considered\nconst MIN_POINTER_SAMPLES = 8;\n// Sticky label: require this many consecutive non-suspected evals to downgrade\nconst STICKY_DOWNGRADE_COUNT = 3;\n\nexport class RiskModule {\n // Static helpers exposed for testing\n static _computeScore = computeScore;\n static _scoreToLabel = scoreToLabel;\n static _scoreToRiskLevel = scoreToRiskLevel;\n static _scoresToPosture = scoresToPosture;\n static _scoreToPosture = scoreToRiskLevel;\n\n constructor(config = {}) {\n const cfg = config ?? {};\n this._onThreatChanged = typeof cfg.onThreatChanged === \"function\" ? cfg.onThreatChanged : null;\n // Fired immediately when a discrete risk event occurs (e.g. DevTools opened),\n // independent of the periodic posture-change callback.\n this._onRiskEvent = typeof cfg.onRiskEvent === \"function\" ? cfg.onRiskEvent : null;\n this._onPolicyChanged = typeof cfg.onPolicyChanged === \"function\" ? cfg.onPolicyChanged : null;\n this._intervalMs = cfg.checkIntervalMs ?? DEFAULT_INTERVAL_MS;\n this._botDetectionEnabled = cfg.botDetectionEnabled !== false;\n this._otherRiskTypesEnabled = cfg.otherRiskTypesEnabled !== false;\n this._riskPolicy = cfg.riskPolicy ?? { version: 0, rules: [] };\n\n this._installed = false;\n this._tornDown = false;\n\n this._snapshot = null;\n this._lastPosture = null;\n this._lastReportedSignals = new Map();\n this._lastPolicySignature = null;\n this._installTime = null;\n\n // DevTools open/close state tracking (for instant risk events)\n this._devtoolsOpen = false;\n\n // Sticky label tracking\n this._stickyLabel = null;\n this._consecutiveNonSuspected = 0;\n\n // Signal providers\n this._headless = new HeadlessBrowserSignalProvider();\n this._automation = new AutomationEnvironmentSignalProvider();\n this._pointer = new PointerBehaviorSignalProvider();\n this._keyboard = new KeyboardCadenceSignalProvider();\n this._hardware = new HardwareConsistencySignalProvider();\n this._devtools = new DevToolsSignalProvider();\n this._devtoolsConsole = new DevToolsConsoleSignalProvider();\n this._incognito = new IncognitoSignalProvider();\n this._sessionPersistence = new SessionPersistenceSignalProvider();\n\n // DOM listener references\n this._mousemoveHandler = null;\n this._keydownHandler = null;\n this._resizeHandler = null;\n this._timer = null;\n // Short-interval timer that drives the console-getter DevTools probe.\n this._devtoolsProbeTimer = null;\n }\n\n install() {\n if (this._installed || this._tornDown) return;\n this._installed = true;\n this._installTime = Date.now();\n\n // Attach behavioural listeners\n if (this._botDetectionEnabled && typeof window !== \"undefined\" && typeof window.addEventListener === \"function\") {\n this._mousemoveHandler = (e) => {\n try {\n const t = typeof performance !== \"undefined\" ? performance.now() : Date.now();\n this._pointer.recordSample(e.clientX, e.clientY, t);\n } catch {\n // never break host app\n }\n };\n window.addEventListener(\"mousemove\", this._mousemoveHandler, { passive: true });\n }\n\n if (this._botDetectionEnabled && typeof document !== \"undefined\" && typeof document.addEventListener === \"function\") {\n this._keydownHandler = (e) => {\n try {\n // Skip modifier-only keys\n if ([\"Shift\", \"Control\", \"Alt\", \"Meta\"].includes(e.key)) return;\n this._keyboard.recordTimestamp(typeof performance !== \"undefined\" ? performance.now() : Date.now());\n } catch {\n // never break host app\n }\n };\n document.addEventListener(\"keydown\", this._keydownHandler, { passive: true });\n }\n\n // Detect DevTools open/close instantly. Docked DevTools changes the\n // inner/outer window size, which fires a \"resize\" event \u2014 this lets us\n // report the risk the moment it happens instead of waiting for the\n // periodic 30s evaluation tick.\n if (this._otherRiskTypesEnabled && typeof window !== \"undefined\" && typeof window.addEventListener === \"function\") {\n this._resizeHandler = () => {\n try { this._checkDevtools(); } catch {}\n };\n window.addEventListener(\"resize\", this._resizeHandler, { passive: true });\n }\n\n // Run initial evaluation and start periodic timer\n this.evaluate();\n\n // Initial DevTools check \u2014 reports if DevTools is already open at load.\n if (this._otherRiskTypesEnabled) this._checkDevtools();\n\n this._timer = setInterval(() => {\n try { this.evaluate(); } catch {}\n }, this._intervalMs);\n\n // Don't keep the Node.js event loop alive (matches other timers in the SDK).\n if (this._timer && typeof this._timer.unref === \"function\") {\n this._timer.unref();\n }\n\n // Console-getter probe \u2014 catches undocked (separate-window) DevTools that\n // the size-diff heuristic and the \"resize\" listener cannot see. Each tick\n // logs the bait then re-checks the DevTools state so the risk event fires\n // promptly when the Console panel starts rendering.\n if (\n LogDropConstants.DEVTOOLS_CONSOLE_PROBE_ENABLED &&\n this._otherRiskTypesEnabled &&\n typeof window !== \"undefined\" &&\n typeof console !== \"undefined\" &&\n typeof console.log === \"function\"\n ) {\n // Prime once immediately, then poll.\n try { this._devtoolsConsole.probe(); this._checkDevtools(); } catch {}\n\n this._devtoolsProbeTimer = setInterval(() => {\n try {\n this._devtoolsConsole.probe();\n this._checkDevtools();\n } catch {}\n }, LogDropConstants.DEVTOOLS_PROBE_INTERVAL_MS);\n\n if (this._devtoolsProbeTimer && typeof this._devtoolsProbeTimer.unref === \"function\") {\n this._devtoolsProbeTimer.unref();\n }\n }\n }\n\n // Returns a single DevTools signal (never both), preferring the reliable\n // size-based signal and falling back to the console-getter signal that also\n // covers undocked DevTools. Returning one signal avoids double-counting the\n // same \"devtools_open\" event in the risk score.\n _detectDevtoolsSignal() {\n return this._devtools.detect() || this._devtoolsConsole.detect();\n }\n\n // Checks the current DevTools open state and refreshes the full evaluation on\n // transitions. Generic evaluation reports the canonical `devtools_open` id.\n _checkDevtools() {\n if (!this._installed || this._tornDown) return;\n\n const signal = this._detectDevtoolsSignal();\n const open = signal !== null;\n\n if (open && !this._devtoolsOpen) {\n this._devtoolsOpen = true;\n this.evaluate();\n } else if (!open && this._devtoolsOpen) {\n this._devtoolsOpen = false;\n this.evaluate();\n }\n }\n\n teardown() {\n if (!this._installed) return;\n this._tornDown = true;\n\n if (this._timer !== null) {\n clearInterval(this._timer);\n this._timer = null;\n }\n\n if (this._devtoolsProbeTimer !== null) {\n clearInterval(this._devtoolsProbeTimer);\n this._devtoolsProbeTimer = null;\n }\n\n if (this._mousemoveHandler && typeof window !== \"undefined\") {\n try { window.removeEventListener(\"mousemove\", this._mousemoveHandler); } catch {}\n this._mousemoveHandler = null;\n }\n\n if (this._keydownHandler && typeof document !== \"undefined\") {\n try { document.removeEventListener(\"keydown\", this._keydownHandler); } catch {}\n this._keydownHandler = null;\n }\n\n if (this._resizeHandler && typeof window !== \"undefined\") {\n try { window.removeEventListener(\"resize\", this._resizeHandler); } catch {}\n this._resizeHandler = null;\n }\n }\n\n evaluate() {\n if (!this._installed) return;\n\n // Run all signal providers\n const rawSignals = [\n ...(this._botDetectionEnabled ? [\n this._headless.detect(),\n this._automation.detect(),\n this._pointer._samples.length >= MIN_POINTER_SAMPLES ? this._pointer.detect() : null,\n this._keyboard._timestamps.length >= 6 ? this._keyboard.detect() : null,\n ] : []),\n ...(this._otherRiskTypesEnabled ? [\n this._hardware.detect(),\n this._detectDevtoolsSignal(),\n this._incognito.detect(),\n this._sessionPersistence.detect(),\n ] : []),\n ].filter(Boolean);\n\n // Split signals into the two independent categories and score each on its own.\n const botSignals = this._botDetectionEnabled\n ? rawSignals.filter((s) => BOT_SIGNAL_IDS.has(s.id))\n : [];\n const riskSignals = this._otherRiskTypesEnabled\n ? rawSignals.filter((s) => RISK_SIGNAL_IDS.has(s.id))\n : [];\n\n const botScore = computeScore(botSignals);\n const riskScore = computeScore(riskSignals);\n\n // Collecting phase: not enough time has passed and no interaction data\n const elapsed = this._installTime != null ? Date.now() - this._installTime : Infinity;\n const hasPointerData = this._pointer._samples.length >= MIN_POINTER_SAMPLES;\n const collecting = elapsed < MIN_COLLECT_MS && !hasPointerData && rawSignals.length === 0;\n\n // Keep the separate mobile contracts: riskLevel comes from risk only,\n // while session posture combines risk and bot scores.\n let label = this._botDetectionEnabled ? scoreToLabel(botScore, collecting) : \"disabled\";\n const riskLevel = scoreToRiskLevel(riskScore);\n const posture = scoresToPosture(riskScore, botScore);\n\n // Label stabilisation \u2014 automation_suspected is sticky\n if (this._botDetectionEnabled && label === \"automation_suspected\") {\n this._stickyLabel = \"automation_suspected\";\n this._consecutiveNonSuspected = 0;\n } else if (this._botDetectionEnabled && this._stickyLabel === \"automation_suspected\") {\n this._consecutiveNonSuspected++;\n if (this._consecutiveNonSuspected < STICKY_DOWNGRADE_COUNT) {\n label = \"automation_suspected\";\n } else {\n this._stickyLabel = null;\n this._consecutiveNonSuspected = 0;\n }\n }\n\n // Build evidence map from all fired signals\n const evidence = {};\n for (const s of rawSignals) {\n for (const [k, v] of Object.entries(s.evidence ?? {})) {\n evidence[`${s.id}.${k}`] = v;\n }\n }\n\n const reasons = riskSignals.map((signal) => signal.id);\n if (label === \"automation_suspected\" || label === \"uncertain\") reasons.push(label);\n if (reasons.length === 0) {\n reasons.push(posture === \"safe\" ? \"no_local_threats_detected\" : \"local_heuristics_triggered\");\n }\n\n this._snapshot = {\n botScore,\n riskScore,\n label,\n riskLevel,\n posture,\n reasons,\n riskSignals: riskSignals.map((signal) => signal.id),\n botSignals: botSignals.map((signal) => signal.id),\n evidence,\n timestamp: Date.now(),\n };\n\n this._evaluatePolicy([...riskSignals, ...botSignals]);\n this._reportDetectedSignals(riskSignals, botSignals);\n\n // Fire callback only when posture changes\n if (posture !== this._lastPosture) {\n this._lastPosture = posture;\n if (this._onThreatChanged) {\n try { this._onThreatChanged(this.getSessionThreat()); } catch {}\n }\n }\n }\n\n _reportDetectedSignals(riskSignals, botSignals) {\n if (!this._onRiskEvent) return;\n\n const report = (signal, score, category) => {\n if (category === \"bot\" && score < 30) return;\n if (category === \"risk\" && score <= 0) return;\n\n const key = `${category}:${signal.id}`;\n if (this._lastReportedSignals.get(key) === score) return;\n this._lastReportedSignals.set(key, score);\n\n try {\n this._onRiskEvent({\n type: signal.id,\n score,\n category,\n evidence: signal.evidence ?? {},\n snapshot: this.getBotSnapshot(),\n });\n } catch {\n // never break the host app\n }\n };\n\n for (const signal of riskSignals) report(signal, this._snapshot.riskScore, \"risk\");\n for (const signal of botSignals) report(signal, this._snapshot.botScore, \"bot\");\n }\n\n _evaluatePolicy(activeSignals) {\n const detectedEventIds = activeSignals\n .map((signal) => eventIdForSignal(signal.id))\n .filter((eventId) => eventId !== null);\n const evaluation = evaluateRiskPolicy(this._riskPolicy, detectedEventIds);\n const signature = policyEvaluationSignature(evaluation);\n if (signature === this._lastPolicySignature) return;\n this._lastPolicySignature = signature;\n if (this._onPolicyChanged) {\n try { this._onPolicyChanged(evaluation); } catch {}\n }\n }\n\n getBotSnapshot() {\n if (!this._installed) return null;\n return this._snapshot\n ? { ...this._snapshot }\n : {\n botScore: 0,\n riskScore: 0,\n label: \"collecting\",\n riskLevel: \"low\",\n posture: \"safe\",\n reasons: [\"no_local_threats_detected\"],\n riskSignals: [],\n botSignals: [],\n evidence: {},\n timestamp: Date.now(),\n };\n }\n\n getSessionThreat() {\n if (!this._installed) return null;\n const snap = this.getBotSnapshot();\n return {\n botScore: snap.botScore,\n botLabel: snap.label,\n riskScore: snap.riskScore,\n riskLevel: snap.riskLevel,\n posture: snap.posture,\n reasons: [...snap.reasons],\n timestamp: snap.timestamp,\n };\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["// LogDrop Web SDK (minimal, local-dev oriented)\n// Public API is intentionally close to the Swift facade (levels + basic flush behavior).\n\nimport { LogDropConstants } from \"./constants.js\";\nimport { NetworkInstrumentation } from \"./instrumentation/networkInstrumentation.js\";\nimport { PushModule } from \"./push/pushModule.js\";\nimport { InAppMessagePresenter } from \"./push/inAppMessagePresenter.js\";\nimport { EventModule } from \"./events/eventModule.js\";\nimport { RiskModule } from \"./risk/riskModule.js\";\nimport { actionName, RiskActionIds } from \"./risk/riskPolicy.js\";\nimport {\n encodeUserUpdateRequest,\n decodeSdkTokenResponse,\n encodeInitRequest,\n decodeConfigResponse,\n encodeLogRequest,\n decodeLogResponse,\n encodeCrashReportRequest\n} from \"./protobuf.js\";\n\nexport const LogLevel = Object.freeze({\n ERROR: \"ERROR\",\n WARNING: \"WARNING\",\n INFO: \"INFO\",\n DEBUG: \"DEBUG\",\n CRASH: \"CRASH\",\n DEVICEINFO: \"DEVICEINFO\",\n NETWORK_ACTIVITY: \"NETWORK_ACTIVITY\",\n REMOTE_MESSAGE: \"REMOTE_MESSAGE\",\n EVENT: \"EVENT\"\n});\n\n// Cached once at module scope \u2014 LogLevel is frozen so this never changes\nconst _logLevelValues = Object.values(LogLevel);\n\n/**\n * LogFlow - Used to group related logs together\n * @param {string} name - Flow name (e.g., \"checkout\", \"login\")\n * @param {string} id - Unique flow instance ID\n * @param {Object} [customAttributes] - Optional custom key-value pairs\n */\nexport class LogFlow {\n constructor(name, id, customAttributes = null) {\n this.name = String(name || \"\");\n this.id = String(id || \"\");\n this.customAttributes = customAttributes || null;\n }\n}\n\nconst LOGDROP_DOMAIN_EXCLUDE = /(^https?:\\/\\/([^/]+\\.)?logdrop\\.io(\\/|$))/i;\nconst LOGDROP_INIT_CACHE_KEY = \"logdrop_init_cache\";\nconst LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY = \"logdrop_token_recovery_identity\";\nconst LOGDROP_IP_REPUTATION_ACTION_KEY = \"logdrop_ip_reputation_active_action\";\nconst LOGDROP_IP_REPUTATION_SIGNATURES_KEY = \"logdrop_ip_reputation_processed_signatures\";\nconst LOGDROP_LAST_USER_UPDATE_KEY = \"logdrop_last_user_update\";\nconst REDACTED_PROTO_PLACEHOLDER = \"[REDACTED]\";\nconst SENSITIVE_PROTO_FIELD_NAMES = new Set([\n \"accesstoken\",\n \"refreshtoken\",\n \"token\",\n \"auth\"\n]);\n\nfunction nowIso() {\n // Backend expects: \"YYYY-MM-DD HH:MM:SS:ms\"\n // Example: \"2026-02-10 11:48:13:200\"\n const d = new Date();\n\n const pad2 = (n) => String(n).padStart(2, \"0\");\n const pad3 = (n) => String(n).padStart(3, \"0\");\n\n // Use UTC to be consistent; backend treats it as \"local\" anyway.\n const yyyy = d.getUTCFullYear();\n const mm = pad2(d.getUTCMonth() + 1);\n const dd = pad2(d.getUTCDate());\n\n const HH = pad2(d.getUTCHours());\n const MM = pad2(d.getUTCMinutes());\n const SS = pad2(d.getUTCSeconds());\n const ms = pad3(d.getUTCMilliseconds());\n\n return `${yyyy}-${mm}-${dd} ${HH}:${MM}:${SS}:${ms}`;\n}\n\nfunction safeStringify(obj) {\n try {\n if (obj instanceof Error) {\n return JSON.stringify({ name: obj.name, message: obj.message, stack: obj.stack });\n }\n return JSON.stringify(obj);\n } catch {\n return \"\\\"[unserializable]\\\"\";\n }\n}\n\nfunction hasWindow() {\n return typeof window !== \"undefined\";\n}\n\nfunction getBaseHref() {\n if (hasWindow() && window.location && typeof window.location.href === \"string\") return window.location.href;\n return \"http://localhost/\";\n}\n\n/**\n * Normalize an input base URL to a canonical SDK endpoint base.\n *\n * Trims whitespace and trailing slashes, applies a fallback when `baseUrl` is empty, and ensures the result targets the `/api/v2/sdk` path.\n * @param {string} baseUrl - The user-provided base URL (may be empty or already include a path).\n * @returns {string} A base URL string that ends with `/api/v2/sdk`, using `LogDropConstants.DEFAULT_BASE_URL` when `baseUrl` is falsy.\n */\nfunction normalizeBaseUrl(baseUrl) {\n const trimmed = String(baseUrl || \"\").trim();\n const normalized = trimmed.replace(/\\/+$/, \"\");\n const fallback = LogDropConstants.DEFAULT_BASE_URL;\n const base = normalized || fallback;\n // V2: base URL points to /api/v2/sdk\n if (base.endsWith(\"/api/v2/sdk\")) return base;\n if (base.endsWith(\"/api\")) return `${base}/v2/sdk`;\n return `${base}/api/v2/sdk`;\n}\n\n/**\n * Concatenates multiple Uint8Array instances into a single contiguous Uint8Array in the order provided.\n * @param {Uint8Array[]} chunks - Array of byte chunks to concatenate.\n * @returns {Uint8Array} The combined Uint8Array containing all input bytes.\n */\nfunction concatUint8Arrays(chunks) {\n const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const out = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.length;\n }\n return out;\n}\n\n/**\n * Compute the CRC32 checksum of the provided bytes.\n * @param {Uint8Array} bytes - The input byte sequence to checksum.\n * @returns {number} CRC32 checksum as an unsigned 32-bit integer.\n */\nfunction crc32(bytes) {\n let crc = 0xffffffff;\n for (let i = 0; i < bytes.length; i += 1) {\n let c = (crc ^ bytes[i]) & 0xff;\n for (let k = 0; k < 8; k += 1) {\n c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1);\n }\n crc = (crc >>> 8) ^ c;\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n/**\n * Generate a version-4 (random) UUID string.\n *\n * Uses secure browser crypto APIs when available and falls back to a Math.random-based generator in legacy environments.\n * @returns {string} A v4 UUID in the standard 8-4-4-4-12 dashed hexadecimal format (lowercase).\n */\nexport function generateUUID() {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4\n bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10xx\n const hex = Array.from(bytes).map(b => b.toString(16).padStart(2, '0'));\n return `${hex.slice(0,4).join('')}-${hex.slice(4,6).join('')}-${hex.slice(6,8).join('')}-${hex.slice(8,10).join('')}-${hex.slice(10).join('')}`;\n }\n // Math.random fallback (last resort for legacy environments)\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\n/**\n * Compute a compact fingerprint for a stack trace to identify similar crashes.\n *\n * Extracts the error type (first line) and up to the first five stack-frame function names,\n * supporting common V8/Chrome and Firefox/Safari stack formats, concatenates them into a key,\n * and returns its CRC32 checksum.\n *\n * @param {string} stack - The stack trace text to fingerprint; non-string values are treated as empty string.\n * @returns {number} CRC32 checksum of the derived key to use as a crash fingerprint.\n */\nexport function fingerprintStack(stack) {\n const s = typeof stack === 'string' ? stack : '';\n const lines = s.trim().split('\\n');\n const errorType = lines[0] ? lines[0].trim() : '';\n // V8/Chrome: \" at funcName (file:line:col)\" | Firefox/Safari: \"funcName@file:line:col\"\n const frameLines = lines.slice(1).filter(l => /^\\s*at /.test(l) || /@/.test(l));\n const top5 = frameLines.slice(0, 5);\n const frameNames = top5.map(line => {\n if (/^\\s*at /.test(line)) {\n // V8/Chrome format\n const m = line.trim().match(/^at\\s+([^\\s(]+)/);\n const raw = m ? m[1] : '';\n return raw.split('/').pop() || 'anonymous';\n } else {\n // Firefox/Safari format: \"funcName@file:line:col\"\n const m = line.match(/^([^@]*)@/);\n const raw = m ? m[1].trim() : '';\n return raw.split('/').pop() || 'anonymous';\n }\n });\n const key = errorType + ':' + frameNames.join(',');\n const bytes = new TextEncoder().encode(key);\n return crc32(bytes);\n}\n\n/**\n * Capture a best-effort snapshot of the current page and runtime state for diagnostic and crash reports.\n *\n * @returns {{url: string, referrer: string, visibilityState: string, onLine: boolean, viewportWidth: number, viewportHeight: number, heapUsed: number|null}} An object containing:\n * - `url`: current page URL or empty string,\n * - `referrer`: document referrer or empty string,\n * - `visibilityState`: document visibility state (defaults to `\"visible\"`),\n * - `onLine`: navigator online status (defaults to `true` when unavailable),\n * - `viewportWidth`: window inner width or `0`,\n * - `viewportHeight`: window inner height or `0`,\n * - `heapUsed`: `performance.memory.usedJSHeapSize` when available, otherwise `null`.\n */\nexport function capturePageState() {\n return {\n url: (typeof location !== 'undefined' && location.href) || '',\n referrer: (typeof document !== 'undefined' && document.referrer) || '',\n visibilityState: (typeof document !== 'undefined' && document.visibilityState) || 'visible',\n onLine: (typeof navigator !== 'undefined' && typeof navigator.onLine === 'boolean') ? navigator.onLine : true,\n viewportWidth: (typeof window !== 'undefined' && window.innerWidth) || 0,\n viewportHeight: (typeof window !== 'undefined' && window.innerHeight) || 0,\n heapUsed: (typeof performance !== 'undefined' && performance.memory)\n ? performance.memory.usedJSHeapSize\n : null,\n };\n}\n\n/**\n * Build a minimal ZIP archive (single file) containing the given text content.\n *\n * Produces a byte array representing a valid ZIP file with one entry named by `filename`\n * whose contents are `textContent`.\n *\n * @param {string} filename - The file name to store inside the ZIP archive.\n * @param {string} textContent - The UTF-8 text content to place into the file entry.\n * @returns {Uint8Array} A contiguous Uint8Array containing the ZIP file bytes.\n */\nfunction buildZipBytes(filename, textContent) {\n const encoder = new TextEncoder();\n const fileNameBytes = encoder.encode(filename);\n const fileBytes = encoder.encode(textContent);\n const fileCrc = crc32(fileBytes);\n const localHeader = new Uint8Array(30 + fileNameBytes.length);\n const localView = new DataView(localHeader.buffer);\n localView.setUint32(0, 0x04034b50, true);\n localView.setUint16(4, 20, true);\n localView.setUint16(6, 0, true);\n localView.setUint16(8, 0, true);\n localView.setUint16(10, 0, true);\n localView.setUint16(12, 0, true);\n localView.setUint32(14, fileCrc, true);\n localView.setUint32(18, fileBytes.length, true);\n localView.setUint32(22, fileBytes.length, true);\n localView.setUint16(26, fileNameBytes.length, true);\n localView.setUint16(28, 0, true);\n localHeader.set(fileNameBytes, 30);\n\n const centralHeader = new Uint8Array(46 + fileNameBytes.length);\n const centralView = new DataView(centralHeader.buffer);\n centralView.setUint32(0, 0x02014b50, true);\n centralView.setUint16(4, 20, true);\n centralView.setUint16(6, 20, true);\n centralView.setUint16(8, 0, true);\n centralView.setUint16(10, 0, true);\n centralView.setUint16(12, 0, true);\n centralView.setUint16(14, 0, true);\n centralView.setUint32(16, fileCrc, true);\n centralView.setUint32(20, fileBytes.length, true);\n centralView.setUint32(24, fileBytes.length, true);\n centralView.setUint16(28, fileNameBytes.length, true);\n centralView.setUint16(30, 0, true);\n centralView.setUint16(32, 0, true);\n centralView.setUint16(34, 0, true);\n centralView.setUint16(36, 0, true);\n centralView.setUint32(38, 0, true);\n centralView.setUint32(42, 0, true);\n centralHeader.set(fileNameBytes, 46);\n\n const endHeader = new Uint8Array(22);\n const endView = new DataView(endHeader.buffer);\n endView.setUint32(0, 0x06054b50, true);\n endView.setUint16(4, 0, true);\n endView.setUint16(6, 0, true);\n endView.setUint16(8, 1, true);\n endView.setUint16(10, 1, true);\n endView.setUint32(12, centralHeader.length, true);\n endView.setUint32(16, localHeader.length + fileBytes.length, true);\n endView.setUint16(20, 0, true);\n\n return concatUint8Arrays([localHeader, fileBytes, centralHeader, endHeader]);\n}\n\n\nexport class LogDropClient {\n constructor() {\n this._config = null;\n this._debugLogEnabled = false;\n this._queue = [];\n this._flushTimer = null;\n this._fileFlushTimer = null;\n this._fileFlushInProgress = false;\n this._crashFlushTimer = null;\n this._crashFlushDelayMs = 5000;\n this._crashFlushInProgress = false;\n this._deviceInfoTimer = null;\n this._storageCheckTimer = null;\n this._dbPromise = null;\n this._initialized = false;\n this._initResponse = null;\n this._tokenRecoveryPromise = null;\n this._tokenValidationState = {\n logdrop_access_token: null,\n logdrop_refresh_token: null\n };\n\n // Session info\n this._sessionId = this._generateUUID();\n this._sessionCreateDate = nowIso();\n\n // Device ID (persistent across sessions)\n this._deviceId = this._getOrCreateDeviceId();\n\n // Server config from init response. These are pre-init defaults; the real\n // values come from the ConfigResponse (see _applyServerConfig). Event\n // tracking stays off until the server enables it via isEventTrackingEnabled.\n this._serverConfig = {\n isSDKDisabled: false,\n isHttpLoggingEnabled: true,\n isCrashTrackingEnabled: true,\n isEventTrackingEnabled: false,\n riskConfig: null,\n webPushConfig: null,\n };\n\n this._activeIpReputationAction = this._loadStoredIpReputationAction();\n this._ipReputationExpiryTimer = null;\n\n // Try to load cached server config\n this._loadCachedServerConfig();\n\n // Restore a previously identified user (via updateUser). Until updateUser is\n // called, _user stays null and the deviceUuid is used as the effective userUuid.\n this._user = this._loadPersistedExternalUser();\n\n // Prevent duplicate listeners across re-init\n this._errorHandlersInstalled = false;\n\n // Network instrumentation\n this._net = null;\n\n // Push notifications\n this._pushModule = null;\n this._inAppMessagePresenter = null;\n this.push = null;\n this._desiredWebPushSubscription = undefined;\n\n // User/device updates follow the same shape as the mobile SDKs: retain the\n // last successful snapshot, coalesce newer changes while one request is in\n // flight, and never run overlapping users/update requests.\n this._lastSentUserUpdate = this._loadLastSentUserUpdate();\n this._activeUserUpdate = null;\n this._pendingUserUpdate = null;\n this._drainingUserUpdates = false;\n\n // Event tracking\n this._eventModule = null;\n this._eventFlushTimer = null;\n\n // Risk & bot detection\n this._riskModule = null;\n this._activeRiskPolicyEvaluation = null;\n this._riskPolicyOverlay = null;\n\n this._seenCrashes = new Set();\n this._crashTrackingOverride = null;\n\n this._originalFetch = null;\n }\n\n _generateUUID() {\n // General-purpose UUID (session IDs may keep the standard dashed form).\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older browsers\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\n _isInternalLoggingEnabled() {\n return this._debugLogEnabled === true;\n }\n\n _logInternal(...args) {\n if (!this._isInternalLoggingEnabled()) return;\n // eslint-disable-next-line no-console\n console.log(...args);\n }\n\n _warnInternal(...args) {\n if (!this._isInternalLoggingEnabled()) return;\n // eslint-disable-next-line no-console\n console.warn(...args);\n }\n\n _errorInternal(...args) {\n if (!this._isInternalLoggingEnabled()) return;\n // eslint-disable-next-line no-console\n console.error(...args);\n }\n\n _getProtoHexPreview(bytes, limit = 64) {\n if (!(bytes instanceof Uint8Array) || bytes.length === 0) return \"empty\";\n\n const preview = Array.from(bytes.slice(0, limit))\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\" \");\n\n return bytes.length > limit ? `${preview} ...` : preview;\n }\n\n _isSensitiveProtoFieldName(fieldName) {\n if (typeof fieldName !== \"string\" || fieldName.length === 0) return false;\n\n const normalizedFieldName = fieldName.replace(/[^a-z0-9]/gi, \"\").toLowerCase();\n return SENSITIVE_PROTO_FIELD_NAMES.has(normalizedFieldName);\n }\n\n _summarizeProtoPayloadEntry(value, fieldName = null) {\n if (this._isSensitiveProtoFieldName(fieldName)) {\n return {\n containsSensitiveData: true,\n summary: REDACTED_PROTO_PLACEHOLDER\n };\n }\n\n if (value instanceof Uint8Array) {\n return {\n containsSensitiveData: false,\n summary: {\n byteLength: value.length,\n hexPreview: this._getProtoHexPreview(value)\n }\n };\n }\n\n if (Array.isArray(value)) {\n let containsSensitiveData = false;\n const summary = value.map((entry) => {\n const summarizedEntry = this._summarizeProtoPayloadEntry(entry);\n containsSensitiveData = containsSensitiveData || summarizedEntry.containsSensitiveData;\n return summarizedEntry.summary;\n });\n\n return { containsSensitiveData, summary };\n }\n\n if (value && typeof value === \"object\") {\n const summary = {};\n let containsSensitiveData = false;\n for (const [key, entry] of Object.entries(value)) {\n const summarizedEntry = this._summarizeProtoPayloadEntry(entry, key);\n summary[key] = summarizedEntry.summary;\n containsSensitiveData = containsSensitiveData || summarizedEntry.containsSensitiveData;\n }\n\n return { containsSensitiveData, summary };\n }\n\n return {\n containsSensitiveData: false,\n summary: value\n };\n }\n\n _summarizeProtoPayload(value) {\n return this._summarizeProtoPayloadEntry(value).summary;\n }\n\n _debugLogProtoBody(label, payload, protoBytes) {\n if (!this._isInternalLoggingEnabled()) return;\n\n const payloadSummary = this._summarizeProtoPayloadEntry(payload);\n\n this._logInternal(`[LogDrop DEBUG] ${label} payload:`, payloadSummary.summary);\n this._logInternal(\n `[LogDrop DEBUG] ${label} protobuf bytes (${protoBytes.length} B): ${payloadSummary.containsSensitiveData ? REDACTED_PROTO_PLACEHOLDER : this._getProtoHexPreview(protoBytes)}`\n );\n }\n\n _debugLogProtoResponse(label, responseBytes, decoder = null) {\n if (!this._isInternalLoggingEnabled()) return;\n\n if (!(responseBytes instanceof Uint8Array) || responseBytes.length === 0) {\n this._logInternal(`[LogDrop DEBUG] ${label} response body: empty`);\n return;\n }\n\n let containsSensitiveData = false;\n\n if (typeof decoder === \"function\") {\n try {\n const decodedSummary = this._summarizeProtoPayloadEntry(decoder(responseBytes));\n containsSensitiveData = decodedSummary.containsSensitiveData;\n this._logInternal(`[LogDrop DEBUG] ${label} decoded response:`, decodedSummary.summary);\n } catch (err) {\n this._warnInternal(`[LogDrop DEBUG] ${label} response decode failed:`, err?.message || err);\n }\n }\n\n this._logInternal(\n `[LogDrop DEBUG] ${label} response protobuf bytes (${responseBytes.length} B): ${containsSensitiveData ? REDACTED_PROTO_PLACEHOLDER : this._getProtoHexPreview(responseBytes)}`\n );\n }\n\n _getOrCreateDeviceId() {\n this._isNewDevice = false;\n if (!hasWindow() || typeof localStorage === \"undefined\") {\n this._isNewDevice = true;\n return this._generateUUID().replace(/-/g, \"\");\n }\n const key = \"logdrop_device_id\";\n let deviceId = localStorage.getItem(key);\n const normalizedDeviceId = deviceId ? deviceId.replace(/-/g, \"\") : \"\";\n if (normalizedDeviceId.length === 32) {\n if (normalizedDeviceId !== deviceId) {\n deviceId = normalizedDeviceId;\n this._isNewDevice = true;\n try {\n localStorage.setItem(key, deviceId);\n localStorage.removeItem(\"logdrop_access_token\");\n localStorage.removeItem(\"logdrop_refresh_token\");\n localStorage.removeItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n localStorage.removeItem(LOGDROP_LAST_USER_UPDATE_KEY);\n } catch {\n // ignore storage errors\n }\n }\n return deviceId;\n }\n\n deviceId = this._generateUUID().replace(/-/g, \"\");\n this._isNewDevice = true;\n try {\n localStorage.setItem(key, deviceId);\n if (normalizedDeviceId) {\n localStorage.removeItem(\"logdrop_access_token\");\n localStorage.removeItem(\"logdrop_refresh_token\");\n localStorage.removeItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n localStorage.removeItem(LOGDROP_LAST_USER_UPDATE_KEY);\n }\n } catch {\n // ignore storage errors\n }\n return deviceId;\n }\n\n // Effective userUuid for events / logs / device info:\n // - the external user id once updateUser() has been called (persisted), or\n // - the deviceUuid until then (so the user is never truly \"anonymous\").\n _getEffectiveUserUuid() {\n return this._user?.userUuid ?? this._deviceId;\n }\n\n // Load the persisted external user id (set via updateUser) so it survives\n // page reloads/restarts until the host app calls updateUser again.\n _loadPersistedExternalUser() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n try {\n const uuid = localStorage.getItem(\"logdrop_external_user_uuid\");\n return uuid ? { userUuid: uuid } : null;\n } catch {\n return null;\n }\n }\n\n _persistExternalUser(userUuid) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(\"logdrop_external_user_uuid\", userUuid);\n } catch {\n // ignore storage errors\n }\n }\n\n _clearPersistedExternalUser() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.removeItem(\"logdrop_external_user_uuid\");\n } catch {\n // ignore storage errors\n }\n }\n\n _isUserRegistered() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return false;\n return localStorage.getItem(\"logdrop_user_registered\") === \"true\";\n }\n\n _markUserRegistered() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(\"logdrop_user_registered\", \"true\");\n } catch {\n // ignore storage errors\n }\n }\n\n _loadLastSentUserUpdate() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(LOGDROP_LAST_USER_UPDATE_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? parsed : null;\n } catch {\n return null;\n }\n }\n\n _saveLastSentUserUpdate(snapshot) {\n this._lastSentUserUpdate = snapshot;\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(LOGDROP_LAST_USER_UPDATE_KEY, JSON.stringify(snapshot));\n } catch {\n // A failed optimization cache must never fail the actual user update.\n }\n }\n\n _normalizeWebPushSubscription(subscription) {\n if (subscription == null) return null;\n const keys = subscription.keys || {};\n const endpoint = String(subscription.endpoint || \"\").trim();\n const p256dh = String(keys.p256dh || subscription.p256dh || \"\").trim();\n const auth = String(keys.auth || subscription.auth || \"\").trim();\n if (!endpoint || !p256dh || !auth) return null;\n const expirationTime = Number(subscription.expirationTime);\n return {\n endpoint,\n p256dh,\n auth,\n expirationTime: Number.isSafeInteger(expirationTime) && expirationTime > 0\n ? expirationTime\n : null,\n };\n }\n\n _webPushSubscriptionFingerprint(subscription) {\n return subscription == null ? null : JSON.stringify(subscription);\n }\n\n _handleWebPushSubscriptionChanged(subscription) {\n if (subscription == null) {\n this._desiredWebPushSubscription = null;\n return Promise.resolve(true);\n }\n const normalizedSubscription = this._normalizeWebPushSubscription(subscription);\n if (normalizedSubscription == null) {\n console.warn(\"[LogDrop] Ignoring invalid Web Push subscription\");\n return Promise.resolve(false);\n }\n this._desiredWebPushSubscription = normalizedSubscription;\n return this._sendUserUpdate(this._getEffectiveUserUuid(), !!this._user, {\n reason: \"web_push_subscription_changed\",\n });\n }\n\n // \u2500\u2500 V2 Token Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n _normalizeTokenValue(value) {\n if (typeof value !== \"string\") return null;\n const normalized = value.trim();\n if (!normalized || normalized === \"null\" || normalized === \"undefined\") {\n return null;\n }\n return normalized;\n }\n\n _normalizeTokenRecoveryIdentity(recoveryIdentity) {\n if (!recoveryIdentity || typeof recoveryIdentity !== \"object\") return null;\n\n const userUuid = this._normalizeTokenValue(recoveryIdentity.userUuid);\n if (!userUuid) return null;\n\n return {\n userUuid,\n isExternalUser: recoveryIdentity.isExternalUser === true\n };\n }\n\n _getPersistedTokenRecoveryIdentity() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n\n const rawValue = localStorage.getItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n if (rawValue == null) return null;\n\n try {\n const persistedIdentity = this._normalizeTokenRecoveryIdentity(JSON.parse(rawValue));\n if (persistedIdentity) {\n return persistedIdentity;\n }\n } catch {\n // Fall through to cleanup.\n }\n\n try {\n localStorage.removeItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n } catch {\n // ignore storage cleanup errors\n }\n\n return null;\n }\n\n _clearPersistedTokenRecoveryIdentity() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n\n try {\n localStorage.removeItem(LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY);\n } catch {\n // ignore storage cleanup errors\n }\n }\n\n _clearStoredTokens() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n\n try {\n localStorage.removeItem(\"logdrop_access_token\");\n localStorage.removeItem(\"logdrop_refresh_token\");\n this._clearPersistedTokenRecoveryIdentity();\n this._tokenValidationState.logdrop_access_token = null;\n this._tokenValidationState.logdrop_refresh_token = null;\n } catch (err) {\n this._warnInternal(\"[LogDrop] Failed to clear stored auth state:\", err?.message || err);\n }\n }\n\n _getTokenRecoveryTarget() {\n if (this._user?.userUuid) {\n return { userUuid: this._user.userUuid, isExternalUser: true };\n }\n const persistedRecoveryIdentity = this._getPersistedTokenRecoveryIdentity();\n if (persistedRecoveryIdentity) {\n return persistedRecoveryIdentity;\n }\n if (this._deviceId) {\n return { userUuid: this._deviceId, isExternalUser: false };\n }\n return null;\n }\n\n async _recoverSessionTokens(reason) {\n if (!this._config) {\n this._warnInternal(`[LogDrop] ${reason}; cannot recover tokens before init`);\n return false;\n }\n\n if (!this._config.webSecretKey) {\n this._warnInternal(`[LogDrop] ${reason}; cannot recover tokens without webSecretKey`);\n return false;\n }\n\n const recoveryTarget = this._getTokenRecoveryTarget();\n if (!recoveryTarget) {\n this._warnInternal(`[LogDrop] ${reason}; no recovery identity is available`);\n return false;\n }\n\n if (this._tokenRecoveryPromise) {\n return this._tokenRecoveryPromise;\n }\n\n this._warnInternal(`[LogDrop] ${reason}; attempting signature-based re-auth`);\n\n this._tokenRecoveryPromise = (async () => {\n const recovered = await this._sendUserUpdate(\n recoveryTarget.userUuid,\n recoveryTarget.isExternalUser\n );\n\n if (!recovered) {\n this._warnInternal(\"[LogDrop] Signature-based re-auth did not recover session tokens\");\n }\n\n return recovered;\n })();\n\n try {\n return await this._tokenRecoveryPromise;\n } finally {\n this._tokenRecoveryPromise = null;\n }\n }\n\n _getStoredToken(storageKey, tokenName) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n\n const rawValue = localStorage.getItem(storageKey);\n const normalizedValue = this._normalizeTokenValue(rawValue);\n if (normalizedValue) {\n this._tokenValidationState[storageKey] = null;\n return normalizedValue;\n }\n\n const reason = rawValue == null ? \"missing\" : \"invalid\";\n if (rawValue != null) {\n try {\n localStorage.removeItem(storageKey);\n } catch {\n // ignore storage cleanup errors\n }\n }\n\n if (this._tokenValidationState[storageKey] !== reason) {\n this._tokenValidationState[storageKey] = reason;\n this._warnInternal(`[LogDrop] Stored ${tokenName} is ${reason}; treating it as a deleted token`);\n }\n\n return null;\n }\n\n async _ensureSessionToken(reason) {\n let sessionToken = this._getAccessToken();\n if (sessionToken) return sessionToken;\n\n const recovered = await this._recoverSessionTokens(reason);\n if (!recovered) return null;\n\n sessionToken = this._getAccessToken();\n if (!sessionToken) {\n this._warnInternal(`[LogDrop] ${reason}; re-auth succeeded but no access token was persisted`);\n }\n\n return sessionToken;\n }\n\n _getAccessToken() {\n return this._getStoredToken(\"logdrop_access_token\", \"access token\");\n }\n\n _getRefreshToken() {\n return this._getStoredToken(\"logdrop_refresh_token\", \"refresh token\");\n }\n\n _saveTokens(accessToken, refreshToken, recoveryIdentity = null) {\n if (!hasWindow() || typeof localStorage === \"undefined\") {\n this._warnInternal(\"[LogDrop] Failed to persist session tokens: localStorage is unavailable\");\n return false;\n }\n\n const normalizedAccessToken = this._normalizeTokenValue(accessToken);\n const normalizedRefreshToken = this._normalizeTokenValue(refreshToken);\n const normalizedRecoveryIdentity = this._normalizeTokenRecoveryIdentity(\n recoveryIdentity || this._getTokenRecoveryTarget()\n );\n if (!normalizedAccessToken && !normalizedRefreshToken) {\n this._warnInternal(\"[LogDrop] Failed to persist session tokens: no valid tokens were provided\");\n return false;\n }\n\n try {\n if (normalizedRecoveryIdentity) {\n localStorage.setItem(\n LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY,\n JSON.stringify(normalizedRecoveryIdentity)\n );\n } else {\n this._clearPersistedTokenRecoveryIdentity();\n }\n if (normalizedAccessToken) {\n localStorage.setItem(\"logdrop_access_token\", normalizedAccessToken);\n this._tokenValidationState.logdrop_access_token = null;\n }\n if (normalizedRefreshToken) {\n localStorage.setItem(\"logdrop_refresh_token\", normalizedRefreshToken);\n this._tokenValidationState.logdrop_refresh_token = null;\n }\n return true;\n } catch (err) {\n this._warnInternal(\"[LogDrop] Failed to persist session tokens:\", err?.message || err);\n return false;\n }\n }\n\n /**\n * Compute SHA-256 signature: SHA256(webSecretKey + deviceUuid)\n * Used as fallback auth when no session token is available.\n */\n async _computeSignature(webSecretKey, deviceUuid) {\n const data = new TextEncoder().encode(webSecretKey + deviceUuid);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map(b => b.toString(16).padStart(2, \"0\")).join(\"\");\n }\n\n _getOsInfo() {\n if (!hasWindow() || !navigator) return { osName: \"Unknown\", osVersion: \"Unknown\" };\n\n const ua = navigator.userAgent;\n let osName = \"Unknown\";\n let osVersion = \"Unknown\";\n\n if (ua.includes(\"Windows\")) {\n osName = \"Windows\";\n const match = ua.match(/Windows NT (\\d+\\.\\d+)/);\n if (match) osVersion = match[1];\n } else if (ua.includes(\"iPhone\") || ua.includes(\"iPad\")) {\n // Must come before \"Mac OS X\" \u2014 real iOS UAs contain both \"iPhone\" and \"Mac OS X\"\n osName = \"iOS\";\n const match = ua.match(/OS (\\d+[._]\\d+)/);\n if (match) osVersion = match[1].replace(/_/g, \".\");\n } else if (ua.includes(\"Mac OS X\")) {\n osName = \"macOS\";\n const match = ua.match(/Mac OS X (\\d+[._]\\d+[._]?\\d*)/);\n if (match) osVersion = match[1].replace(/_/g, \".\");\n } else if (ua.includes(\"Android\")) {\n osName = \"Android\";\n const match = ua.match(/Android (\\d+(\\.\\d+)?)/);\n if (match) osVersion = match[1];\n } else if (ua.includes(\"Linux\")) {\n osName = \"Linux\";\n }\n\n return { osName, osVersion };\n }\n\n\n\n _getDeviceBrand() {\n if (!hasWindow() || !navigator) return \"Unknown\";\n\n const ua = navigator.userAgent;\n\n // Mobile brands\n if (ua.includes(\"Samsung\")) return \"Samsung\";\n if (ua.includes(\"Huawei\")) return \"Huawei\";\n if (ua.includes(\"Xiaomi\") || ua.includes(\"Redmi\")) return \"Xiaomi\";\n if (ua.includes(\"OPPO\")) return \"OPPO\";\n if (ua.includes(\"Vivo\")) return \"Vivo\";\n if (ua.includes(\"OnePlus\")) return \"OnePlus\";\n if (ua.includes(\"LG\")) return \"LG\";\n if (ua.includes(\"Sony\")) return \"Sony\";\n if (ua.includes(\"HTC\")) return \"HTC\";\n if (ua.includes(\"Motorola\")) return \"Motorola\";\n if (ua.includes(\"Nokia\")) return \"Nokia\";\n if (ua.includes(\"Google\") || ua.includes(\"Pixel\")) return \"Google\";\n if (ua.includes(\"iPhone\") || ua.includes(\"iPad\") || ua.includes(\"Macintosh\")) return \"Apple\";\n\n // Desktop browsers as \"brand\"\n if (ua.includes(\"Chrome\")) return \"Google\";\n if (ua.includes(\"Firefox\")) return \"Mozilla\";\n if (ua.includes(\"Safari\")) return \"Apple\";\n if (ua.includes(\"Edge\")) return \"Microsoft\";\n\n return \"Unknown\";\n }\n\n _createUserUpdateTask(userUuid, isExternalUser, options = {}) {\n const subscription = this._desiredWebPushSubscription === undefined\n ? undefined\n : this._normalizeWebPushSubscription(this._desiredWebPushSubscription);\n const descriptor = {\n userUuid: String(userUuid || this._deviceId),\n isExternalUser: isExternalUser === true,\n webPushSubscription: subscription,\n reason: options.reason || \"user_update\",\n };\n return {\n ...descriptor,\n key: JSON.stringify(descriptor),\n waiters: [],\n };\n }\n\n _sendUserUpdate(userUuid, isExternalUser = false, options = {}) {\n if (!this._config) return Promise.resolve(false);\n const task = this._createUserUpdateTask(userUuid, isExternalUser, options);\n\n return new Promise((resolve) => {\n if (this._activeUserUpdate?.key === task.key) {\n this._activeUserUpdate.waiters.push(resolve);\n return;\n }\n\n if (this._pendingUserUpdate?.key === task.key) {\n this._pendingUserUpdate.waiters.push(resolve);\n } else if (this._pendingUserUpdate) {\n // Keep only the newest desired state, but resolve callers waiting on\n // the superseded state when that newest state has been persisted.\n task.waiters.push(...this._pendingUserUpdate.waiters, resolve);\n this._pendingUserUpdate = task;\n } else {\n task.waiters.push(resolve);\n this._pendingUserUpdate = task;\n }\n\n void this._drainUserUpdates();\n });\n }\n\n async _drainUserUpdates() {\n if (this._drainingUserUpdates) return;\n this._drainingUserUpdates = true;\n try {\n while (this._pendingUserUpdate) {\n const task = this._pendingUserUpdate;\n this._pendingUserUpdate = null;\n this._activeUserUpdate = task;\n let result = false;\n try {\n result = await this._performUserUpdate(task);\n } catch (err) {\n console.warn(\"[LogDrop] User update failed:\", err?.message || err);\n }\n for (const resolve of task.waiters) resolve(result);\n this._activeUserUpdate = null;\n }\n } finally {\n this._activeUserUpdate = null;\n this._drainingUserUpdates = false;\n if (this._pendingUserUpdate) void this._drainUserUpdates();\n }\n }\n\n async _performUserUpdate(task) {\n const config = this._config;\n if (!config) return false;\n const fetchFn = hasWindow() ? window.fetch : (typeof fetch !== \"undefined\" ? fetch : null);\n if (typeof fetchFn !== \"function\") return false;\n\n const osInfo = this._getOsInfo();\n const last = this._lastSentUserUpdate?.apiKey === config.apiKey\n ? this._lastSentUserUpdate\n : null;\n const runtime = {\n apiKey: config.apiKey,\n userUuid: task.userUuid,\n osName: osInfo.osName,\n osVersion: osInfo.osVersion,\n deviceBrand: this._getDeviceBrand(),\n deviceModel: this._parseDeviceModel(navigator?.userAgent || \"\") || \"Web Browser\",\n appVersion: config.release || \"1.0\",\n sdkVersion: LogDropConstants.SDK_VERSION,\n webPushFingerprint: task.webPushSubscription === undefined\n ? last?.webPushFingerprint\n : this._webPushSubscriptionFingerprint(task.webPushSubscription),\n };\n const device = { deviceUuid: this._deviceId, sdkType: \"WEB\" };\n const deltaFields = [\"osName\", \"osVersion\", \"deviceBrand\", \"deviceModel\", \"appVersion\", \"sdkVersion\"];\n for (const field of deltaFields) {\n if (!last || runtime[field] !== last[field]) device[field] = runtime[field];\n }\n\n const subscriptionChanged = task.webPushSubscription !== undefined &&\n (!last || runtime.webPushFingerprint !== last.webPushFingerprint);\n if (task.webPushSubscription && subscriptionChanged) {\n device.webPushSubscription = task.webPushSubscription;\n }\n\n const identityChanged = !last || runtime.userUuid !== last.userUuid;\n const hasDeviceDelta = Object.keys(device).some((key) => ![\"deviceUuid\", \"sdkType\"].includes(key));\n const sessionToken = this._getAccessToken();\n const refreshToken = this._getRefreshToken();\n if (!identityChanged && !hasDeviceDelta && sessionToken && refreshToken) {\n this._logInternal(`[LogDrop] User update skipped; no changes (${task.reason})`);\n return true;\n }\n\n const headers = {\n \"content-type\": \"application/x-protobuf\",\n \"accept\": \"application/x-protobuf\",\n \"x-api-key\": config.apiKey,\n };\n let usedSignatureAuth = false;\n if (sessionToken) {\n headers[\"x-session-token\"] = sessionToken;\n } else if (config.webSecretKey) {\n headers[\"x-logdrop-signature\"] = await this._computeSignature(\n config.webSecretKey,\n this._deviceId\n );\n usedSignatureAuth = true;\n } else {\n return false;\n }\n\n const requestPayload = { userUuid: task.userUuid, device };\n const protoBytes = encodeUserUpdateRequest(requestPayload);\n this._debugLogProtoBody(\"User update request\", requestPayload, protoBytes);\n\n try {\n // init() may disable and tear down the SDK while signature creation is\n // awaiting Web Crypto. Do not send a request for an obsolete config.\n if (this._config !== config) return false;\n const url = `${config.baseUrl}${LogDropConstants.USERS_UPDATE_PATH}`;\n const res = await fetchFn(url, {\n method: \"POST\",\n headers,\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" }),\n });\n if (!res.ok) return false;\n if (this._config !== config) return false;\n\n if (usedSignatureAuth) {\n try {\n const responseBytes = new Uint8Array(await res.arrayBuffer());\n this._debugLogProtoResponse(\"User update\", responseBytes, decodeSdkTokenResponse);\n if (responseBytes.length > 0) {\n const tokenResponse = decodeSdkTokenResponse(responseBytes);\n this._saveTokens(tokenResponse.accessToken, tokenResponse.refreshToken, {\n userUuid: task.userUuid,\n isExternalUser: task.isExternalUser,\n });\n }\n } catch {\n // Token parsing failed, non-critical for an otherwise successful update.\n }\n }\n\n this._saveLastSentUserUpdate(runtime);\n if (!task.isExternalUser) this._markUserRegistered();\n this._logInternal(`[LogDrop] User update successful (${task.reason})`);\n\n // A first signed registration may be what made automatic push\n // reconciliation possible. Trigger it only before a subscription state\n // has been observed, avoiding a subscribe -> update loop.\n if (usedSignatureAuth && this._desiredWebPushSubscription === undefined) {\n void this._pushModule?.reconcileGrantedSubscription();\n }\n return true;\n } catch (err) {\n // Preserve the existing user-update diagnostic even when SDK debug logs\n // are disabled; authentication/registration failures must be visible.\n // eslint-disable-next-line no-console\n console.warn(\"[LogDrop] User update failed:\", err.message || err);\n this._warnInternal(\"[LogDrop] User update failed:\", err.message || err);\n return false;\n }\n }\n\n async _getDeviceInfo() {\n const info = {\n sessionID: this._sessionId,\n session_create_date: this._sessionCreateDate,\n device_id: this._deviceId,\n userUuid: this._getEffectiveUserUuid(),\n gmt: -(new Date().getTimezoneOffset()), // Convert to GMT offset in minutes (positive = east of UTC)\n };\n\n if (this._riskModule) {\n const snap = this._riskModule.getBotSnapshot();\n if (snap) {\n info.bot_score = snap.botScore;\n info.bot_label = snap.label;\n info.risk_score = snap.riskScore;\n info.posture = snap.posture;\n }\n }\n\n // OS and browser info from userAgent\n if (hasWindow() && navigator) {\n // Locale\n if (navigator.language) {\n info.locale = navigator.language;\n }\n\n // Network available\n if (typeof navigator.onLine === \"boolean\") {\n info.network_available = navigator.onLine;\n }\n\n // RAM size (approximate, in GB)\n if (navigator.deviceMemory) {\n info.ram_size = `${navigator.deviceMemory} GB`;\n }\n\n // CPU cores\n if (navigator.hardwareConcurrency) {\n info.cpu_cores = navigator.hardwareConcurrency;\n }\n\n // Platform/OS\n if (navigator.platform) {\n info.os_version = navigator.platform;\n }\n\n // User agent for device model approximation\n if (navigator.userAgent) {\n info.user_agent = navigator.userAgent;\n // Try to extract device model from userAgent\n const model = this._parseDeviceModel(navigator.userAgent);\n if (model) {\n info.device_model = model;\n }\n }\n\n // Connection info (Network Information API)\n if (navigator.connection) {\n if (navigator.connection.effectiveType) {\n info.connection_type = navigator.connection.effectiveType;\n }\n if (typeof navigator.connection.downlink === \"number\") {\n info.connection_downlink_mbps = navigator.connection.downlink;\n }\n if (typeof navigator.connection.rtt === \"number\") {\n info.connection_rtt_ms = navigator.connection.rtt;\n }\n if (typeof navigator.connection.saveData === \"boolean\") {\n info.save_data_mode = navigator.connection.saveData;\n }\n }\n\n // Battery info (async)\n try {\n if (navigator.getBattery) {\n const battery = await navigator.getBattery();\n if (typeof battery.level === \"number\") {\n info.battery_level = `${Math.round(battery.level * 100)}%`;\n }\n if (typeof battery.charging === \"boolean\") {\n info.low_power_mode = !battery.charging && battery.level < 0.2;\n info.is_charging = battery.charging;\n }\n }\n } catch {\n // Battery API not available or failed\n }\n\n // Storage estimate (async)\n try {\n if (navigator.storage && navigator.storage.estimate) {\n const estimate = await navigator.storage.estimate();\n if (estimate.quota && estimate.usage) {\n const freeBytes = estimate.quota - estimate.usage;\n info.free_disk_space = this._formatBytes(freeBytes);\n info.total_disk_quota = this._formatBytes(estimate.quota);\n }\n }\n } catch {\n // Storage API not available or failed\n }\n }\n\n // Screen info\n if (hasWindow() && window.screen) {\n info.screen_width = window.screen.width;\n info.screen_height = window.screen.height;\n info.screen_color_depth = window.screen.colorDepth;\n if (window.devicePixelRatio) {\n info.device_pixel_ratio = window.devicePixelRatio;\n }\n }\n\n // Document visibility\n if (hasWindow() && document.visibilityState) {\n info.visibility_state = document.visibilityState;\n }\n\n // Page info\n if (hasWindow() && window.location) {\n info.page_url = window.location.href;\n if (document.referrer) {\n info.referrer = document.referrer;\n }\n }\n\n // App version from config\n if (this._config && this._config.release) {\n info.app_version = this._config.release;\n }\n\n return info;\n }\n\n _getUserAgentData() {\n if (!hasWindow() || !navigator) return null;\n\n const uaData = navigator[\"userAgentData\"]; // avoids \"unresolved\" in some toolchains\n if (!uaData || typeof uaData !== \"object\") return null;\n\n return uaData;\n }\n\n _parseDeviceModel(userAgent) {\n if (!hasWindow() || !navigator) return null;\n\n const uaData = this._getUserAgentData();\n if (uaData && typeof uaData.model === \"string\" && uaData.model.trim()) {\n return uaData.model.trim();\n }\n\n // 2) Android model extraction from UA parens\n const mobileMatch = userAgent.match(/\\(([^)]+)\\)/);\n if (mobileMatch) {\n const parts = mobileMatch[1].split(\";\").map(s => s.trim());\n // Android: \"Linux; Android 10; SM-G970F\"\n const androidDevice = parts.find(p => /^(SM-|Pixel|Nexus|LG-|HTC|Huawei|Xiaomi|OPPO|Vivo|OnePlus)/i.test(p));\n if (androidDevice) return androidDevice;\n // iOS: \"iPhone; CPU iPhone OS 14_0\"\n if (parts.some(p => p.includes(\"iPhone\"))) return \"iPhone\";\n if (parts.some(p => p.includes(\"iPad\"))) return \"iPad\";\n }\n\n // 3) Desktop fallback: OS + Browser + major version\n const os = this._getOsInfo();\n const browser = this._getBrowserInfo();\n\n // Example: \"macOS 10.15.7 - Chrome 144\"\n const osPart = `${os.osName} ${os.osVersion}`.trim();\n const brPart = `${browser.name} ${browser.version}`.trim();\n\n return `${osPart} - ${brPart}`.trim();\n }\n\n _getBrowserInfo() {\n if (!hasWindow() || !navigator) return { name: \"Unknown\", version: \"Unknown\" };\n\n const uaData = this._getUserAgentData();\n if (uaData && Array.isArray(uaData.brands)) {\n const preferred =\n uaData.brands.find(b => /Chrome/i.test(b.brand)) ||\n uaData.brands.find(b => /Chromium/i.test(b.brand)) ||\n uaData.brands[0];\n\n return {\n name: preferred?.brand || \"Unknown\",\n version: preferred?.version || \"Unknown\"\n };\n }\n\n const ua = navigator.userAgent;\n\n // Very lightweight UA parsing\n const edge = ua.match(/Edg\\/(\\d+)/);\n if (edge) return { name: \"Edge\", version: edge[1] };\n\n const chrome = ua.match(/Chrome\\/(\\d+)/);\n if (chrome) return { name: \"Chrome\", version: chrome[1] };\n\n const firefox = ua.match(/Firefox\\/(\\d+)/);\n if (firefox) return { name: \"Firefox\", version: firefox[1] };\n\n // Safari (but not Chrome)\n const safari = ua.match(/Version\\/(\\d+).+Safari/);\n if (safari && !ua.includes(\"Chrome\")) return { name: \"Safari\", version: safari[1] };\n\n return { name: \"Unknown\", version: \"Unknown\" };\n }\n\n _formatBytes(bytes) {\n if (bytes === 0) return \"0 Bytes\";\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n }\n\n _scheduleDeviceInfoCollection() {\n if (this._deviceInfoTimer) clearInterval(this._deviceInfoTimer);\n\n // Collect immediately on start\n this._collectAndLogDeviceInfo();\n\n // Then collect every DEVICE_INFO_INTERVAL_MS\n this._deviceInfoTimer = setInterval(() => {\n this._collectAndLogDeviceInfo();\n }, LogDropConstants.DEVICE_INFO_INTERVAL_MS);\n\n if (this._deviceInfoTimer && typeof this._deviceInfoTimer.unref === \"function\") {\n this._deviceInfoTimer.unref();\n }\n }\n\n async _collectAndLogDeviceInfo() {\n if (!this._config) return;\n try {\n const deviceInfo = await this._getDeviceInfo();\n this._enqueue(LogLevel.DEVICEINFO, deviceInfo);\n } catch {\n // best-effort only\n }\n }\n\n _loadCachedServerConfig() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n const cached = localStorage.getItem(LOGDROP_INIT_CACHE_KEY);\n if (cached) {\n const parsed = JSON.parse(cached);\n if (parsed && parsed.data) {\n // Only apply isSDKDisabled from cache to block init if needed\n // isHttpLoggingEnabled stays true until fresh response arrives\n // This ensures all logs are captured while waiting for init response\n if (typeof parsed.data.isSDKDisabled === \"boolean\") {\n this._serverConfig.isSDKDisabled = parsed.data.isSDKDisabled;\n }\n }\n }\n } catch {\n // ignore parse errors\n }\n }\n\n _saveServerConfigToCache(response) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(LOGDROP_INIT_CACHE_KEY, JSON.stringify(response));\n } catch {\n // ignore storage errors (quota exceeded, etc.)\n }\n }\n\n _applyServerConfig(data, applyNetworkChange = false) {\n if (!data) return;\n\n const prevHttpLogging = this._serverConfig.isHttpLoggingEnabled;\n\n // isSDKDisabled\n if (typeof data.isSDKDisabled === \"boolean\") {\n this._serverConfig.isSDKDisabled = data.isSDKDisabled;\n }\n\n // isHttpLoggingEnabled\n if (typeof data.isHttpLoggingEnabled === \"boolean\") {\n this._serverConfig.isHttpLoggingEnabled = data.isHttpLoggingEnabled;\n }\n\n // isCrashTrackingEnabled \u2014 local override from init config takes precedence\n if (typeof data.isCrashTrackingEnabled === \"boolean\" && this._crashTrackingOverride === null) {\n this._serverConfig.isCrashTrackingEnabled = data.isCrashTrackingEnabled;\n }\n\n // isPushEnabled \u2014 forward remote flag to PushModule (REQ-005)\n if (this._pushModule && typeof data.isPushEnabled === \"boolean\") {\n this._pushModule.isPushEnabled = data.isPushEnabled;\n }\n\n // isEventTrackingEnabled \u2014 forward remote flag to EventModule (REQ-025)\n if (typeof data.isEventTrackingEnabled === \"boolean\") {\n this._serverConfig.isEventTrackingEnabled = data.isEventTrackingEnabled;\n this._eventModule?.setEnabled(data.isEventTrackingEnabled);\n }\n\n if (data.riskConfig && typeof data.riskConfig === \"object\") {\n this._serverConfig.riskConfig = data.riskConfig;\n }\n\n if (data.webPushConfig && typeof data.webPushConfig === \"object\") {\n this._serverConfig.webPushConfig = data.webPushConfig;\n if (this._pushModule) {\n this._pushModule.updateServerConfig({\n isPushEnabled: data.webPushConfig.enabled === true,\n vapidPublicKey: data.webPushConfig.vapidPublicKey || null,\n });\n }\n }\n\n // Check if SDK should be disabled after fresh init response\n if (this._serverConfig.isSDKDisabled && this._initialized) {\n this._warnInternal(\"[LogDrop] SDK disabled by server, clearing all logs and shutting down\");\n // Clear all stored logs before shutting down\n void this._clearLogs().catch(() => {});\n this._initialized = false;\n this._config = null;\n this.teardown();\n return; // Don't process further\n }\n\n if (data.riskConfig && typeof data.riskConfig === \"object\") {\n this._syncRiskModuleFromServerConfig();\n }\n\n // Apply the IP reputation action after rebuilding the risk module. Risk\n // module sync clears stale risk-policy UI, so doing this first would also\n // remove a newly displayed IP reputation warning.\n if (Object.prototype.hasOwnProperty.call(data, \"activeIpReputationAction\")) {\n this._applyIpReputationActionFromInit(\n data.activeIpReputationAction,\n data.serverNowEpochMillis\n );\n }\n\n // Apply network tracking change dynamically if requested\n if (applyNetworkChange && this._config) {\n if (this._serverConfig.isHttpLoggingEnabled && !prevHttpLogging) {\n // Enable network tracking\n this._installNetworkInstrumentation();\n } else if (!this._serverConfig.isHttpLoggingEnabled && prevHttpLogging) {\n // Disable network tracking and clear all network logs from DB\n this._logInternal(\"[LogDrop] HTTP logging disabled by server, clearing network logs\");\n this._uninstallNetworkInstrumentation();\n void this._clearNetworkLogs();\n }\n if (this._activeRiskPolicyEvaluation?.actionIds?.includes(RiskActionIds.BLOCK_ALL_NETWORK)) {\n this._refreshNetworkInstrumentationForRiskPolicy();\n }\n }\n }\n\n _installNetworkInstrumentation(forceRiskGuard = false) {\n if (!this._config || this._net) return;\n\n this._net = new NetworkInstrumentation({\n onEvent: (eventName, payload) => {\n if (eventName !== \"network_activity\") return;\n if (!this._serverConfig.isHttpLoggingEnabled || !this._config?.network?.enabled) return;\n this._enqueue(LogLevel.NETWORK_ACTIVITY, payload, new LogFlow(\"NetworkActivity\", payload.uuid));\n },\n getBaseHref,\n excludeUrls: this._config.network.excludeUrls,\n shouldBlockRequest: (url) => this._shouldBlockNetworkRequest(url),\n redaction: { stripQuery: this._config.network.stripQuery, stripHash: this._config.network.stripHash },\n sampling: {\n rate: this._config.network.sampleRate,\n onlyErrors: this._config.network.onlyErrors,\n slowThresholdMs: this._config.network.slowThresholdMs\n },\n capture: {\n fetch: forceRiskGuard || this._config.network.captureFetch,\n xhr: forceRiskGuard || this._config.network.captureXHR,\n headersAllowlist: this._config.network.headersAllowlist\n }\n });\n\n this._net.install();\n }\n\n _uninstallNetworkInstrumentation() {\n if (this._net) {\n this._net.uninstall();\n this._net = null;\n }\n }\n\n _shouldBlockNetworkRequest(rawUrl) {\n const riskPolicyBlocks = this._activeRiskPolicyEvaluation?.actionIds?.includes(\n RiskActionIds.BLOCK_ALL_NETWORK\n ) === true;\n const ipReputationBlocks = this._getActiveIpReputationAction()?.actionIds?.includes(\n RiskActionIds.BLOCK_ALL_NETWORK\n ) === true;\n if (!riskPolicyBlocks && !ipReputationBlocks) return false;\n\n try {\n const requestUrl = new URL(rawUrl, getBaseHref());\n const sdkUrl = new URL(this._config?.baseUrl ?? LogDropConstants.DEFAULT_BASE_URL);\n if (requestUrl.origin.toLowerCase() !== sdkUrl.origin.toLowerCase()) return true;\n\n // On Web, the host alone is not enough: the application and LogDrop may\n // share an origin through a reverse proxy. Exempt only the SDK base path,\n // not every request on the same host/origin.\n const sdkPath = sdkUrl.pathname.replace(/\\/+$/, \"\");\n const requestPath = requestUrl.pathname.replace(/\\/+$/, \"\");\n const isSdkEndpoint = requestPath === sdkPath || requestPath.startsWith(`${sdkPath}/`);\n return !isSdkEndpoint;\n } catch {\n return true;\n }\n }\n\n _loadStoredIpReputationAction() {\n if (!hasWindow() || typeof localStorage === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(LOGDROP_IP_REPUTATION_ACTION_KEY);\n const action = raw ? JSON.parse(raw) : null;\n return action && typeof action.signature === \"string\" && action.signature\n ? action\n : null;\n } catch {\n return null;\n }\n }\n\n _persistIpReputationAction(action) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return;\n try {\n if (action) localStorage.setItem(LOGDROP_IP_REPUTATION_ACTION_KEY, JSON.stringify(action));\n else localStorage.removeItem(LOGDROP_IP_REPUTATION_ACTION_KEY);\n } catch {\n // best effort only\n }\n }\n\n _trustedNowForIpReputation(action) {\n const serverNow = Number(action?.receivedServerEpochMillis);\n const receivedAt = Number(action?.receivedAtClientEpochMillis);\n const receivedMonotonic = Number(action?.receivedAtMonotonicMillis);\n const receivedTimeOrigin = Number(action?.receivedPerformanceTimeOrigin);\n const currentMonotonic = typeof performance !== \"undefined\" ? Number(performance.now?.()) : NaN;\n const currentTimeOrigin = typeof performance !== \"undefined\" ? Number(performance.timeOrigin) : NaN;\n if (Number.isFinite(serverNow) && serverNow > 0 &&\n Number.isFinite(receivedMonotonic) && Number.isFinite(currentMonotonic) &&\n Number.isFinite(receivedTimeOrigin) && receivedTimeOrigin === currentTimeOrigin) {\n return serverNow + Math.max(0, currentMonotonic - receivedMonotonic);\n }\n if (Number.isFinite(serverNow) && serverNow > 0 && Number.isFinite(receivedAt) && receivedAt > 0) {\n return serverNow + Math.max(0, Date.now() - receivedAt);\n }\n return Date.now();\n }\n\n _isIpReputationActionExpired(action) {\n const expiresAt = Number(action?.expireAtEpochMillis);\n return !Number.isFinite(expiresAt) || expiresAt <= this._trustedNowForIpReputation(action);\n }\n\n _getActiveIpReputationAction() {\n const action = this._activeIpReputationAction;\n if (!action) return null;\n if (this._isIpReputationActionExpired(action)) {\n this._clearIpReputationAction(\"expired\");\n return null;\n }\n return action;\n }\n\n _resolveIpReputationPresentation(action) {\n const policyRules = this._serverConfig.riskConfig?.ipReputationDetected?.riskPolicy?.rules ?? [];\n const matchingRule = policyRules\n .filter((rule) => rule?.enabled === true && (rule.threatLevels ?? []).includes(action.threatLevel))\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0))[0];\n return {\n ...action,\n title: action.title || matchingRule?.title || null,\n message: action.message || matchingRule?.message || null,\n buttonText: action.buttonText || matchingRule?.buttonText || null,\n };\n }\n\n _hasProcessedIpReputationSignature(signature) {\n if (!hasWindow() || typeof localStorage === \"undefined\") return false;\n try {\n const values = JSON.parse(localStorage.getItem(LOGDROP_IP_REPUTATION_SIGNATURES_KEY) || \"[]\");\n return Array.isArray(values) && values.includes(signature);\n } catch {\n return false;\n }\n }\n\n _markIpReputationSignatureProcessed(signature) {\n if (!hasWindow() || typeof localStorage === \"undefined\" || !signature) return;\n try {\n const parsed = JSON.parse(localStorage.getItem(LOGDROP_IP_REPUTATION_SIGNATURES_KEY) || \"[]\");\n const values = Array.isArray(parsed) ? parsed.filter((value) => typeof value === \"string\") : [];\n const next = [...values.filter((value) => value !== signature), signature].slice(-100);\n localStorage.setItem(LOGDROP_IP_REPUTATION_SIGNATURES_KEY, JSON.stringify(next));\n } catch {\n // best effort only\n }\n }\n\n _scheduleIpReputationExpiry() {\n if (this._ipReputationExpiryTimer) clearTimeout(this._ipReputationExpiryTimer);\n this._ipReputationExpiryTimer = null;\n const action = this._activeIpReputationAction;\n if (!action) return;\n const remaining = Number(action.expireAtEpochMillis) - this._trustedNowForIpReputation(action);\n if (remaining <= 0) {\n this._clearIpReputationAction(\"expired\");\n return;\n }\n this._ipReputationExpiryTimer = setTimeout(\n () => this._scheduleIpReputationExpiry(),\n Math.min(remaining, 2_147_000_000)\n );\n if (typeof this._ipReputationExpiryTimer?.unref === \"function\") {\n this._ipReputationExpiryTimer.unref();\n }\n }\n\n _applyIpReputationActionFromInit(action, serverNowEpochMillis) {\n if (!action || typeof action.signature !== \"string\" || !action.signature.trim()) {\n this._clearIpReputationAction(\"cleared\");\n return;\n }\n const receivedAtClientEpochMillis = Date.now();\n const normalized = this._resolveIpReputationPresentation({\n ...action,\n signature: action.signature.trim(),\n eventId: String(action.eventId || action.signature),\n actionIds: [...new Set((action.actionIds ?? []).filter((id) => actionName(id)))],\n receivedServerEpochMillis: Number(serverNowEpochMillis) || receivedAtClientEpochMillis,\n receivedAtClientEpochMillis,\n receivedAtMonotonicMillis: typeof performance !== \"undefined\" ? Number(performance.now?.()) : null,\n receivedPerformanceTimeOrigin: typeof performance !== \"undefined\" ? Number(performance.timeOrigin) : null,\n });\n if (this._isIpReputationActionExpired(normalized)) {\n this._clearIpReputationAction(\"expired\");\n return;\n }\n const showWarning = !this._hasProcessedIpReputationSignature(normalized.signature);\n this._activeIpReputationAction = normalized;\n this._persistIpReputationAction(normalized);\n this._markIpReputationSignatureProcessed(normalized.signature);\n this._scheduleIpReputationExpiry();\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(this._activeRiskPolicyEvaluation, showWarning);\n }\n\n _restoreIpReputationActionIfNeeded() {\n const action = this._getActiveIpReputationAction();\n if (!action) return;\n this._scheduleIpReputationExpiry();\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(this._activeRiskPolicyEvaluation, false);\n }\n\n _clearIpReputationAction(clearReason = \"cleared\") {\n const previous = this._activeIpReputationAction;\n if (this._ipReputationExpiryTimer) clearTimeout(this._ipReputationExpiryTimer);\n this._ipReputationExpiryTimer = null;\n this._activeIpReputationAction = null;\n this._persistIpReputationAction(null);\n if (previous && this._eventModule) {\n const actionIds = previous.actionIds ?? [];\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.SDK_ACTION_CLEARED, {\n as: \"ip_reputation\",\n cr: clearReason,\n bl: actionIds.includes(RiskActionIds.BLOCK_APP) || actionIds.includes(RiskActionIds.BLOCK_ALL_NETWORK),\n sig: previous.signature,\n saa: actionIds.map(actionName).filter(Boolean).join(\",\") || \"none\",\n });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n if (this._config) {\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(this._activeRiskPolicyEvaluation);\n }\n }\n\n _syncRiskModuleFromServerConfig() {\n const riskDetected = this._serverConfig.riskConfig?.riskDetected;\n const enabled = riskDetected?.enabled === true && (\n riskDetected.botDetectionEnabled === true ||\n riskDetected.otherRiskTypesEnabled === true\n );\n\n this._riskModule?.teardown();\n this._riskModule = null;\n if (this._activeRiskPolicyEvaluation) {\n this._handleRiskPolicyChanged({\n matchedRules: [], actionIds: [], title: null, message: null, buttonText: null,\n });\n } else {\n this._activeRiskPolicyEvaluation = null;\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(null);\n }\n\n if (!enabled || !this._initialized || !this._config) return;\n\n this._riskModule = new RiskModule({\n botDetectionEnabled: riskDetected.botDetectionEnabled === true,\n otherRiskTypesEnabled: riskDetected.otherRiskTypesEnabled === true,\n riskPolicy: riskDetected.riskPolicy,\n onThreatChanged: this._config.onSessionThreatChanged ?? null,\n onRiskEvent: (evt) => this._handleRiskEvent(evt),\n onPolicyChanged: (evaluation) => this._handleRiskPolicyChanged(evaluation),\n checkIntervalMs: 30_000,\n });\n this._riskModule.install();\n }\n\n init(config) {\n this._debugLogEnabled = config?.debugLogEnabled === true || config?.isDebugLogEnabled === true;\n\n if (this._initialized) return;\n\n // Check if SDK is disabled from cached server config\n if (this._serverConfig.isSDKDisabled) {\n this._warnInternal(\"[LogDrop] SDK is disabled by server configuration\");\n return;\n }\n\n if (!config || !config.appId) throw new Error(\"LogDrop.init requires config.appId\");\n const apiKey = String(config.apiKey || \"\").trim();\n if (!apiKey) throw new Error(\"LogDrop.init requires config.apiKey\");\n const defaultWebSecretKey =\n config.webSecretKey == null ? LogDropConstants.DEFAULT_WEB_SECRET_KEY : config.webSecretKey;\n const webSecretKey = String(defaultWebSecretKey || \"\").trim() || null;\n\n // Build config - use provided baseUrl or fall back to default from constants\n const baseUrl = normalizeBaseUrl(config.baseUrl);\n const endpoint = baseUrl;\n\n // NEW: unified network config\n const networkCfg = {\n enabled: config.network?.enabled !== false,\n\n captureFetch: config.network?.captureFetch !== false,\n captureXHR: config.network?.captureXHR !== false,\n\n // Safe defaults\n stripQuery: config.network?.stripQuery !== false,\n stripHash: config.network?.stripHash !== false,\n\n // Sampling defaults\n sampleRate: typeof config.network?.sampleRate === \"number\" ? config.network.sampleRate : 1,\n onlyErrors: config.network?.onlyErrors === true,\n slowThresholdMs:\n typeof config.network?.slowThresholdMs === \"number\" ? config.network.slowThresholdMs : undefined,\n\n // Header capture (default none)\n headersAllowlist: Array.isArray(config.network?.headersAllowlist) ? config.network.headersAllowlist : [],\n\n excludeUrls: [\n LOGDROP_DOMAIN_EXCLUDE,\n baseUrl,\n endpoint,\n LogDropConstants.DEFAULT_BASE_URL,\n ...(Array.isArray(config.network?.excludeUrls) ? config.network.excludeUrls : [])\n ]\n };\n\n this._config = {\n appId: String(config.appId),\n apiKey,\n webSecretKey,\n baseUrl,\n endpoint,\n env: config.env ? String(config.env) : \"prod\",\n release: config.release ? String(config.release) : undefined,\n debugLogEnabled: this._debugLogEnabled,\n flushIntervalMs: typeof config.flushIntervalMs === \"number\" ? config.flushIntervalMs : 60000,\n maxBatchSize: typeof config.maxBatchSize === \"number\" ? config.maxBatchSize : 50,\n\n // NEW\n network: networkCfg,\n\n // Push notifications\n vapidPublicKey: config.vapidPublicKey ? String(config.vapidPublicKey) : null,\n manualServiceWorkerRegistration: config.manualServiceWorkerRegistration === true,\n serviceWorkerUrl: config.serviceWorkerUrl ? String(config.serviceWorkerUrl) : LogDropConstants.PUSH_SW_PATH,\n serviceWorkerScope: config.serviceWorkerScope ? String(config.serviceWorkerScope) : LogDropConstants.PUSH_SW_SCOPE,\n serviceWorkerRegistration: config.serviceWorkerRegistration ?? null,\n onRemoteMessageReceived: typeof config.onRemoteMessageReceived === \"function\" ? config.onRemoteMessageReceived : null,\n\n // Risk & bot detection\n onSessionThreatChanged: typeof config.onSessionThreatChanged === \"function\" ? config.onSessionThreatChanged : null,\n onRiskPolicyActionTaken: typeof config.onRiskPolicyActionTaken === \"function\" ? config.onRiskPolicyActionTaken : null,\n };\n\n // If crashTracking is explicitly set in config, apply it as a local override\n // that takes precedence over whatever the server returns in the init response.\n if (typeof config.crashTracking === \"boolean\") {\n this._serverConfig.isCrashTrackingEnabled = config.crashTracking;\n this._crashTrackingOverride = config.crashTracking;\n } else {\n this._crashTrackingOverride = null;\n }\n\n // Enable debug logs for non-production environments\n LogDropConstants.DEBUG_LOGS_ENABLED = ![\"prod\", \"production\"].includes(this._config.env);\n\n // Global JS error capture (idempotent)\n this._installGlobalErrorHandlers();\n\n // Init persistent log storage (best-effort)\n this._initDb();\n\n this._inAppMessagePresenter = new InAppMessagePresenter({\n onAction: (payload) => this._handleWebPushClick(payload),\n });\n\n // Instantiate PushModule (install lifecycle mirrors NetworkInstrumentation)\n this._pushModule = new PushModule({\n vapidPublicKey: this._config.vapidPublicKey,\n manualServiceWorkerRegistration: this._config.manualServiceWorkerRegistration,\n serviceWorkerUrl: this._config.serviceWorkerUrl,\n serviceWorkerScope: this._config.serviceWorkerScope,\n serviceWorkerRegistration: this._config.serviceWorkerRegistration,\n isPushEnabled: true, // default; overridden by server config in _applyServerConfig\n onRemoteMessageReceived: this._config.onRemoteMessageReceived,\n apiKey: this._config.apiKey,\n apiBase: this._config.baseUrl,\n deviceId: this._deviceId,\n getSessionToken: () => this._getAccessToken(),\n onPushReceived: (payload) => this._handleWebPushReceived(payload),\n onNotificationClick: (payload) => this._handleWebPushClick(payload),\n onSubscriptionChanged: (subscription) => this._handleWebPushSubscriptionChanged(subscription),\n });\n this._pushModule.install();\n this.push = {\n subscribe: () => this._pushModule.subscribe(),\n unsubscribe: () => this._pushModule.unsubscribe(),\n getPermissionState: () => this._pushModule.getPermissionState(),\n };\n\n // Compute release comparison for event tracking (REQ-030)\n const storedRelease = hasWindow() && localStorage\n ? localStorage.getItem(\"logdrop_last_release\")\n : null;\n const isSdkUpdated = !!(this._config.release && storedRelease && this._config.release !== storedRelease);\n const previousRelease = storedRelease;\n if (this._config.release && hasWindow() && localStorage) {\n try { localStorage.setItem(\"logdrop_last_release\", this._config.release); } catch {}\n }\n\n // Instantiate EventModule (lifecycle mirrors PushModule)\n this._eventModule = new EventModule({\n deviceId: this._deviceId,\n getSessionId: () => this._sessionId,\n getUserUuid: () => this._getEffectiveUserUuid(),\n // firstRealUserUuid must reflect the first *real* (identified) user only \u2014\n // it stays empty while the user is anonymous (deviceUuid fallback).\n getRealUserUuid: () => this._user?.userUuid ?? null,\n getSessionToken: () => this._ensureSessionToken(\"Event upload requires a valid access token\"),\n // Mirror every successfully sent event into the log stream at EVENT level.\n logEvent: (eventLog) => this._enqueue(LogLevel.EVENT, eventLog),\n release: this._config.release,\n apiKey: this._config.apiKey,\n apiBase: this._config.baseUrl,\n isEventTrackingEnabled: this._serverConfig.isEventTrackingEnabled,\n isFirstVisit: this._isNewDevice,\n isSdkUpdated,\n previousRelease,\n dbPromise: this._dbPromise,\n });\n this._eventModule.install();\n this._pushModule?.requestPendingMessages();\n this._scheduleEventFlush();\n\n // Init handshake (best-effort, fire-and-forget)\n this._initialized = true;\n void this._sendInitRequest();\n\n // Ensure any previous instrumentation is cleaned up on re-init\n this._uninstallNetworkInstrumentation();\n\n // NEW: Install network instrumentation (preferred path)\n // Only install if both config and server allow it\n if (this._config.network.enabled && this._serverConfig.isHttpLoggingEnabled) {\n this._installNetworkInstrumentation();\n }\n\n // Restore an unexpired server-issued IP reputation action immediately;\n // the fresh init response will confirm, replace, or clear it.\n this._restoreIpReputationActionIfNeeded();\n\n // periodic flush (mirrors Swift's delayed sendLogs behavior)\n this._scheduleFlush();\n this._scheduleFileFlush();\n\n // Start device info collection (every 10 seconds)\n this._scheduleDeviceInfoCollection();\n\n // Start storage monitoring (every 2 minutes)\n this._scheduleStorageCheck();\n\n this.i(\"LogDrop initialized\", {\n appId: this._config.appId,\n env: this._config.env,\n release: this._config.release,\n networkEnabled: this._config.network.enabled\n });\n }\n\n async updateUser(externalId, completion) {\n if (!externalId) {\n this._user = null;\n this._clearPersistedExternalUser();\n this._clearStoredTokens();\n this.i(\"User cleared\");\n if (typeof completion === \"function\") completion(true);\n return;\n }\n\n const userUuid = String(externalId);\n\n // Rotate session when switching from one identified user to a different identified user.\n // Do NOT rotate when going from anonymous (null) to an identified user.\n if (this._user?.userUuid && this._user.userUuid !== userUuid) {\n this._sessionId = this._generateUUID();\n this._sessionCreateDate = nowIso();\n }\n\n this._user = { userUuid };\n // Persist so the identified user survives reloads/restarts until changed.\n this._persistExternalUser(userUuid);\n\n // Send user update request with external ID\n const success = await this._sendUserUpdate(userUuid, true, { reason: \"developer_user_update\" });\n\n this.i(\"User updated\", { userUuid, success });\n if (typeof completion === \"function\") completion(success);\n }\n\n // Severity helpers - with optional LogFlow support\n e(arg0, arg1, logFlow = null) {\n const tagged = typeof arg0 === 'string' && typeof arg1 === 'string' && !_logLevelValues.includes(arg0);\n this._enqueue(LogLevel.ERROR, tagged ? arg1 : arg0, tagged ? logFlow : arg1 instanceof LogFlow ? arg1 : null, tagged ? arg0 : null);\n }\n w(arg0, arg1, logFlow = null) {\n const tagged = typeof arg0 === 'string' && typeof arg1 === 'string' && !_logLevelValues.includes(arg0);\n this._enqueue(LogLevel.WARNING, tagged ? arg1 : arg0, tagged ? logFlow : arg1 instanceof LogFlow ? arg1 : null, tagged ? arg0 : null);\n }\n i(arg0, arg1, logFlow = null) {\n const tagged = typeof arg0 === 'string' && typeof arg1 === 'string' && !_logLevelValues.includes(arg0);\n this._enqueue(LogLevel.INFO, tagged ? arg1 : arg0, tagged ? logFlow : arg1 instanceof LogFlow ? arg1 : null, tagged ? arg0 : null);\n }\n d(arg0, arg1, logFlow = null) {\n const tagged = typeof arg0 === 'string' && typeof arg1 === 'string' && !_logLevelValues.includes(arg0);\n this._enqueue(LogLevel.DEBUG, tagged ? arg1 : arg0, tagged ? logFlow : arg1 instanceof LogFlow ? arg1 : null, tagged ? arg0 : null);\n }\n\n log(tag, message, level, logFlow = null) {\n this._enqueue(level, message, logFlow, tag);\n }\n\n onRemoteMessageReceived(userInfo) {\n // Primary path is now SW \u2192 postMessage \u2192 PushModule \u2192 registered callback.\n // This method remains as a thin delegator for back-compat.\n if (this._config && typeof this._config.onRemoteMessageReceived === \"function\") {\n this._config.onRemoteMessageReceived(userInfo);\n }\n }\n\n saveCustomCrashReport(threadName, stackTrace, crashType = \"CUSTOM\") {\n if (!this._serverConfig.isCrashTrackingEnabled) return;\n this._recordCrash({\n threadName: threadName || \"MainThread\",\n stackTrace: String(stackTrace || \"\"),\n crashType: crashType || \"CUSTOM\",\n isCustomCrash: true\n });\n }\n\n // Emits a discrete risk event (e.g. DevTools opened) as an internal event to\n // the /events/collect endpoint (protobuf) and flushes promptly.\n _handleRiskEvent(evt) {\n if (!this._config || !evt || !this._eventModule) return;\n // Map SDK risk events onto the server's `rd` (risk_detected) event.\n // Required properties: rt (risk_type), rs (risk_score).\n const riskScore = evt.score ?? evt.snapshot?.riskScore ?? evt.snapshot?.score ?? 0;\n const actionIds = this._activeRiskPolicyEvaluation?.actionIds ?? [];\n const actionsApplied = actionIds.map(actionName).filter(Boolean);\n const blocked = actionIds.includes(RiskActionIds.BLOCK_APP) ||\n actionIds.includes(RiskActionIds.BLOCK_ALL_NETWORK);\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.RISK_DETECTED, {\n rt: evt.type,\n rs: riskScore,\n bl: blocked,\n ev: evt.evidence ?? {},\n saa: actionsApplied.join(\",\") || \"none\",\n });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n\n _webPushData(payload) {\n if (!payload || typeof payload !== \"object\") return {};\n return payload.data && typeof payload.data === \"object\" ? payload.data : payload;\n }\n\n _handleWebPushReceived(payload) {\n const data = this._webPushData(payload);\n const action = typeof data.action === \"string\" ? data.action : data.rawExtras?.action;\n const notificationId = String(\n data.notificationId || data.receiveEvent?.properties?.pn || \"\"\n ).trim();\n if (notificationId && this._eventModule) {\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.PUSH_RECEIVED, { pn: notificationId });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n\n this._inAppMessagePresenter?.enqueue(payload);\n\n if (action === \"ip_reputation_action\") {\n this._applyIpReputationActionFromInit({\n signature: data.signature || \"\",\n eventId: data.eventId || data.signature || \"\",\n threatLevel: data.threatLevel || \"UNSPECIFIED\",\n riskScore: Number(data.riskScore) || 0,\n actionIds: String(data.actionIds || \"\")\n .split(\",\")\n .map((value) => Number(value.trim()))\n .filter(Number.isInteger),\n expireAtEpochMillis: Number(data.expireAt) || 0,\n title: data.title || null,\n message: data.message || null,\n buttonText: data.buttonText || null,\n }, Number(data.serverNow) || Date.now());\n } else if (action === \"send_log\") {\n void this.sendLogs().catch(() => {});\n Promise.resolve(this._eventModule?._flush()).catch(() => {});\n }\n\n if (typeof this._config?.onRemoteMessageReceived === \"function\") {\n try { this._config.onRemoteMessageReceived(payload); } catch {}\n }\n }\n\n _handleWebPushClick(payload) {\n const data = this._webPushData(payload);\n const notificationId = String(\n data.notificationId || data.clickEvent?.properties?.pn || \"\"\n ).trim();\n if (notificationId && this._eventModule) {\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.PUSH_CLICK, { pn: notificationId });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n if (typeof this._config?.onRemoteMessageReceived === \"function\") {\n try { this._config.onRemoteMessageReceived(payload); } catch {}\n }\n }\n\n _handleRiskPolicyChanged(evaluation) {\n const previous = this._activeRiskPolicyEvaluation;\n this._activeRiskPolicyEvaluation = evaluation?.actionIds?.length ? evaluation : null;\n if (previous && !this._activeRiskPolicyEvaluation && this._eventModule) {\n const previousNames = previous.actionIds.map(actionName).filter(Boolean);\n this._eventModule.trackEvent(LogDropConstants.EVENT_CODES.SDK_ACTION_CLEARED, {\n as: \"risk_detected\",\n cr: \"cleared\",\n bl: previous.actionIds.includes(RiskActionIds.BLOCK_APP) ||\n previous.actionIds.includes(RiskActionIds.BLOCK_ALL_NETWORK),\n saa: previousNames.join(\",\") || \"none\",\n });\n Promise.resolve(this._eventModule._flush()).catch(() => {});\n }\n this._refreshNetworkInstrumentationForRiskPolicy();\n this._applyRiskPolicyUi(this._activeRiskPolicyEvaluation);\n if (!this._activeRiskPolicyEvaluation || !this._config?.onRiskPolicyActionTaken) return;\n\n const matchedEventIds = [...new Set(\n evaluation.matchedRules.flatMap((rule) => rule.eventIds ?? [])\n )];\n try {\n this._config.onRiskPolicyActionTaken({\n actionIds: [...evaluation.actionIds],\n actionNames: evaluation.actionIds.map(actionName).filter(Boolean),\n matchedEventIds,\n matchedRulePriorities: evaluation.matchedRules.map((rule) => rule.priority ?? 0),\n title: evaluation.title,\n message: evaluation.message,\n buttonText: evaluation.buttonText,\n });\n } catch {\n // never break the host app\n }\n }\n\n _refreshNetworkInstrumentationForRiskPolicy() {\n if (!this._config) return;\n const riskPolicyBlock = this._activeRiskPolicyEvaluation?.actionIds?.includes(\n RiskActionIds.BLOCK_ALL_NETWORK\n ) === true;\n const ipReputationBlock = this._getActiveIpReputationAction()?.actionIds?.includes(\n RiskActionIds.BLOCK_ALL_NETWORK\n ) === true;\n const blockAll = riskPolicyBlock || ipReputationBlock;\n const normalCapture = this._config.network?.enabled === true && this._serverConfig.isHttpLoggingEnabled;\n\n this._uninstallNetworkInstrumentation();\n if (normalCapture || blockAll) this._installNetworkInstrumentation(blockAll);\n }\n\n _applyRiskPolicyUi(evaluation, showIpReputationWarning = false) {\n if (this._riskPolicyOverlay?.parentNode) {\n try { this._riskPolicyOverlay.parentNode.removeChild(this._riskPolicyOverlay); } catch {}\n }\n this._riskPolicyOverlay = null;\n\n const ipAction = this._activeIpReputationAction;\n const ipBlocksApp = ipAction?.actionIds?.includes(RiskActionIds.BLOCK_APP) === true;\n const policyBlocksApp = evaluation?.actionIds?.includes(RiskActionIds.BLOCK_APP) === true;\n if (ipBlocksApp) {\n evaluation = ipAction;\n } else if (!policyBlocksApp && showIpReputationWarning &&\n ipAction?.actionIds?.includes(RiskActionIds.SHOW_WARNING)) {\n evaluation = ipAction;\n }\n\n if (!evaluation || typeof document === \"undefined\" || !document.body ||\n typeof document.createElement !== \"function\") return;\n\n const blockApp = evaluation.actionIds.includes(RiskActionIds.BLOCK_APP);\n const showWarning = evaluation.actionIds.includes(RiskActionIds.SHOW_WARNING);\n if (!blockApp && !showWarning) return;\n\n const overlay = document.createElement(\"div\");\n overlay.setAttribute(\"role\", \"alertdialog\");\n overlay.setAttribute(\"aria-modal\", \"true\");\n overlay.style.cssText = [\n \"position:fixed\", \"inset:0\", \"z-index:2147483647\", \"display:flex\",\n \"align-items:center\", \"justify-content:center\", \"padding:24px\",\n \"background:rgba(15,23,42,.72)\", \"font-family:system-ui,sans-serif\",\n ].join(\";\");\n\n const panel = document.createElement(\"div\");\n panel.style.cssText = \"max-width:520px;width:100%;background:white;border-radius:12px;padding:24px;box-shadow:0 24px 64px rgba(0,0,0,.35);color:#111827\";\n const title = document.createElement(\"h2\");\n title.textContent = evaluation.title || (blockApp ? \"Security block\" : \"Security warning\");\n title.style.cssText = \"margin:0 0 12px;font-size:20px\";\n const message = document.createElement(\"p\");\n message.textContent = evaluation.message || \"A security risk was detected.\";\n message.style.cssText = \"margin:0;line-height:1.5\";\n panel.append(title, message);\n\n if (!blockApp) {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = evaluation.buttonText || \"OK\";\n button.style.cssText = \"margin-top:20px;padding:9px 16px;border:0;border-radius:8px;background:#111827;color:white;cursor:pointer\";\n button.addEventListener(\"click\", () => {\n try { overlay.remove(); } catch {}\n if (this._riskPolicyOverlay === overlay) this._riskPolicyOverlay = null;\n }, { once: true });\n panel.appendChild(button);\n }\n\n overlay.appendChild(panel);\n document.body.appendChild(overlay);\n this._riskPolicyOverlay = overlay;\n }\n\n getBotSnapshot() {\n return this._riskModule?.getBotSnapshot() ?? null;\n }\n\n refreshBotSnapshot() {\n this._riskModule?.evaluate();\n return this._riskModule?.getBotSnapshot() ?? null;\n }\n\n getSessionThreat() {\n return this._riskModule?.getSessionThreat() ?? null;\n }\n\n async sendLogs(completion) {\n // Public API - delegates to the new flush system\n if (!this._config) {\n if (typeof completion === \"function\") completion(false);\n return;\n }\n\n const [logsSuccess, crashesSuccess] = await Promise.all([\n this._flushLogs(),\n this._flushCrashes()\n ]);\n const success = logsSuccess && crashesSuccess;\n if (typeof completion === \"function\") completion(success);\n }\n\n _enqueue(level, message, logFlow = null, tag = null) {\n if (!this._config) return;\n\n const entry = {\n ts: nowIso(),\n level,\n // IMPORTANT: if message object convert => JSON string\n message: typeof message === \"string\" ? message : safeStringify(message)\n };\n\n if (tag) {\n entry.tag = tag;\n }\n\n // Add flow info if provided\n if (logFlow && logFlow instanceof LogFlow) {\n entry.flowId = logFlow.id;\n entry.flowName = logFlow.name;\n if (logFlow.customAttributes) {\n entry.flowAttributes = logFlow.customAttributes;\n }\n }\n\n this._queue.push(entry);\n const persistPromise = this._persistLogEntry(entry, logFlow);\n\n // Avoid unbounded memory growth\n if (this._queue.length > 2000) this._queue.splice(0, this._queue.length - 2000);\n\n // Auto-flush when batch is large\n if (this._queue.length >= this._config.maxBatchSize) this.sendLogs();\n\n // Mirror to console only when internal debug logging is enabled.\n this._logInternal(`[LogDrop:${level}] ${entry.message}`);\n return persistPromise;\n \n }\n\n _scheduleFlush() {\n if (!this._config) return;\n\n if (this._flushTimer) clearInterval(this._flushTimer);\n\n this._flushTimer = setInterval(() => this.sendLogs(), this._config.flushIntervalMs);\n\n // In Node dev environments, avoid keeping the process alive\n if (this._flushTimer && typeof this._flushTimer.unref === \"function\") {\n this._flushTimer.unref();\n }\n }\n\n _scheduleEventFlush() {\n if (this._eventFlushTimer) clearInterval(this._eventFlushTimer);\n\n this._eventFlushTimer = setInterval(() => {\n this._eventModule?._flush();\n }, LogDropConstants.EVENT_FLUSH_INTERVAL_MS);\n\n // PERF-002: unref to avoid keeping Node.js process alive in tests\n if (this._eventFlushTimer && typeof this._eventFlushTimer.unref === \"function\") {\n this._eventFlushTimer.unref();\n }\n }\n\n _scheduleFileFlush() {\n if (!this._config) return;\n if (this._fileFlushTimer) clearInterval(this._fileFlushTimer);\n\n this._fileFlushTimer = setInterval(() => {\n this._flushDbToZip();\n }, LogDropConstants.FILE_EXPORT_INTERVAL_MS);\n\n if (this._fileFlushTimer && typeof this._fileFlushTimer.unref === \"function\") {\n this._fileFlushTimer.unref();\n }\n }\n\n _initDb() {\n if (!hasWindow() || !window.indexedDB) return;\n if (this._dbPromise) return;\n\n this._dbPromise = new Promise((resolve, reject) => {\n const request = window.indexedDB.open(\"logdrop\", 3);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(\"logs\")) {\n db.createObjectStore(\"logs\", { keyPath: \"id\", autoIncrement: true });\n }\n if (!db.objectStoreNames.contains(\"crashes\")) {\n db.createObjectStore(\"crashes\", { keyPath: \"id\", autoIncrement: true });\n }\n if (!db.objectStoreNames.contains(\"events\")) {\n db.createObjectStore(\"events\", { keyPath: \"id\", autoIncrement: true });\n }\n if (!db.objectStoreNames.contains(\"event_upload_batch\")) {\n db.createObjectStore(\"event_upload_batch\", { keyPath: \"id\", autoIncrement: true });\n }\n if (!db.objectStoreNames.contains(\"log_upload_batch\")) {\n db.createObjectStore(\"log_upload_batch\", { keyPath: \"id\", autoIncrement: true });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async _persistLogEntry(entry, logFlow = null) {\n if (!this._dbPromise) return;\n try {\n // Check storage size before adding\n await this._enforceStorageLimit();\n\n const db = await this._dbPromise;\n const tx = db.transaction(\"logs\", \"readwrite\");\n\n const logRecord = {\n sessionId: this._sessionId,\n userUuid: this._getEffectiveUserUuid(),\n ts: entry.ts,\n level: entry.level,\n message: entry.message\n };\n\n if (entry.tag) logRecord.tag = entry.tag;\n\n // Add flow info if provided\n if (logFlow && logFlow instanceof LogFlow) {\n logRecord.flowId = logFlow.id;\n logRecord.flowName = logFlow.name;\n if (logFlow.customAttributes) {\n logRecord.flowAttributes = logFlow.customAttributes;\n }\n }\n\n await new Promise((resolve, reject) => {\n tx.objectStore(\"logs\").add(logRecord);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n } catch {\n // best-effort only\n }\n }\n\n async _readAllLogs() {\n if (!this._dbPromise) return [];\n const db = await this._dbPromise;\n return new Promise((resolve, reject) => {\n const tx = db.transaction(\"logs\", \"readonly\");\n const store = tx.objectStore(\"logs\");\n const request = store.getAll();\n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => reject(request.error);\n });\n }\n\n async _readLogUploadBatch() {\n if (!this._dbPromise) return null;\n const db = await this._dbPromise;\n const tx = db.transaction(\"log_upload_batch\", \"readonly\");\n const request = tx.objectStore(\"log_upload_batch\").getAll();\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve((request.result || [])[0] ?? null);\n request.onerror = () => reject(request.error);\n });\n }\n\n async _replaceLogUploadBatch(batch) {\n if (!this._dbPromise) return;\n const db = await this._dbPromise;\n const tx = db.transaction(\"log_upload_batch\", \"readwrite\");\n const store = tx.objectStore(\"log_upload_batch\");\n store.clear();\n if (batch) store.add(batch);\n await new Promise((resolve, reject) => {\n tx.oncomplete = resolve;\n tx.onerror = () => reject(tx.error);\n });\n }\n\n async _persistCrash(crash) {\n if (!this._dbPromise) return;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"crashes\", \"readwrite\");\n tx.objectStore(\"crashes\").add(crash);\n await new Promise((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n } catch {\n // Best effort. The matching CRASH log is still persisted separately.\n }\n }\n\n async _readAllCrashes() {\n if (!this._dbPromise) return [];\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"crashes\", \"readonly\");\n const request = tx.objectStore(\"crashes\").getAll();\n return await new Promise((resolve, reject) => {\n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => reject(request.error);\n });\n } catch {\n return [];\n }\n }\n\n async _deleteCrashesByIds(ids) {\n if (!this._dbPromise || !ids.length) return;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"crashes\", \"readwrite\");\n const store = tx.objectStore(\"crashes\");\n ids.forEach(id => store.delete(id));\n await new Promise((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n } catch {\n // Retry on the next flush.\n }\n }\n\n _buildCrashData({ threadName, stackTrace, crashType, isCustomCrash, sourceUrl = \"\", line = 0, column = 0 }) {\n const pageState = capturePageState();\n const sessionStartedAt = Date.parse(this._sessionCreateDate);\n return {\n timestamp: Date.now(),\n threadName,\n stackTrace: stackTrace.slice(0, 500000),\n sessionId: this._sessionId,\n userUuid: this._getEffectiveUserUuid(),\n crashType,\n appVersion: this._config?.release || \"UNKNOWN\",\n buildNumber: \"\",\n isAppOnBackground: pageState.visibilityState !== \"visible\",\n sessionTime: Number.isFinite(sessionStartedAt) ? Math.max(0, Date.now() - sessionStartedAt) : 0,\n uuid: generateUUID().replace(/-/g, \"\"),\n isCustomCrash,\n url: pageState.url,\n sourceUrl,\n line,\n column\n };\n }\n\n _recordCrash(crashInput) {\n const stackTrace = String(crashInput.stackTrace || \"\");\n const errorIdentity = crashInput.errorIdentity;\n if (errorIdentity && (typeof errorIdentity === \"object\" || typeof errorIdentity === \"function\")) {\n if (this._seenCrashes.has(errorIdentity)) return;\n this._seenCrashes.add(errorIdentity);\n }\n\n const crash = this._buildCrashData({ ...crashInput, stackTrace });\n const logPromise = this._enqueue(\n LogLevel.CRASH,\n stackTrace,\n new LogFlow(\"Crash\", crash.uuid),\n \"LogDropCrashTracker\"\n );\n const crashPromise = this._persistCrash(crash);\n Promise.allSettled([Promise.resolve(logPromise), crashPromise])\n .then(() => this._scheduleCrashFlush())\n .catch(() => {});\n }\n\n _scheduleCrashFlush() {\n if (this._crashFlushTimer) clearTimeout(this._crashFlushTimer);\n\n this._crashFlushTimer = setTimeout(() => {\n this._crashFlushTimer = null;\n void this._flushCrashes().catch(() => {});\n }, this._crashFlushDelayMs);\n\n if (this._crashFlushTimer && typeof this._crashFlushTimer.unref === \"function\") {\n this._crashFlushTimer.unref();\n }\n }\n\n async _clearLogs() {\n if (!this._dbPromise) return;\n const db = await this._dbPromise;\n return new Promise((resolve, reject) => {\n const tx = db.transaction(\"logs\", \"readwrite\");\n const store = tx.objectStore(\"logs\");\n const request = store.clear();\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n });\n }\n\n async _clearNetworkLogs() {\n if (!this._dbPromise) return;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"logs\", \"readwrite\");\n const store = tx.objectStore(\"logs\");\n const request = store.openCursor();\n\n return new Promise((resolve, reject) => {\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n if (cursor.value && cursor.value.level === LogLevel.NETWORK_ACTIVITY) {\n cursor.delete();\n }\n cursor.continue();\n } else {\n resolve();\n }\n };\n request.onerror = () => reject(request.error);\n });\n } catch {\n // best-effort only\n }\n }\n\n async _getStorageSize() {\n if (!this._dbPromise) return 0;\n try {\n const logs = await this._readAllLogs();\n // Estimate size by stringifying\n const jsonStr = JSON.stringify(logs);\n return new Blob([jsonStr]).size;\n } catch {\n return 0;\n }\n }\n\n _getMaxStorageLimit() {\n // V2: Get from init response or use default\n const initData = this._initResponse;\n return initData?.databaseMaxStorageLimitInBytes ?? LogDropConstants.DATABASE_MAX_STORAGE_LIMIT;\n }\n\n async _enforceStorageLimit() {\n if (!this._dbPromise) return;\n\n try {\n const currentSize = await this._getStorageSize();\n const maxLimit = this._getMaxStorageLimit();\n\n if (currentSize >= maxLimit) {\n // Try to upload first\n const uploadSuccess = await this._flushLogs();\n\n if (!uploadSuccess) {\n // Upload failed, need to delete oldest logs (FIFO)\n await this._deleteOldestLogs(currentSize - maxLimit + LogDropConstants.MAX_LOCAL_STORAGE_SIZE);\n }\n }\n } catch {\n // best-effort only\n }\n }\n\n async _deleteOldestLogs(bytesToFree) {\n if (!this._dbPromise || bytesToFree <= 0) return;\n\n try {\n const logs = await this._readAllLogs();\n if (!logs.length) return;\n\n // Sort by timestamp (oldest first)\n logs.sort((a, b) => new Date(a.ts) - new Date(b.ts));\n\n const idsToDelete = [];\n let freedBytes = 0;\n\n for (const log of logs) {\n if (freedBytes >= bytesToFree) break;\n\n const logSize = new Blob([JSON.stringify(log)]).size;\n idsToDelete.push(log.id);\n freedBytes += logSize;\n }\n\n if (idsToDelete.length > 0) {\n await this._deleteLogsByIds(idsToDelete);\n this._logInternal(`[LogDrop] Deleted ${idsToDelete.length} oldest logs to free storage`);\n }\n } catch {\n // best-effort only\n }\n }\n\n _scheduleStorageCheck() {\n if (this._storageCheckTimer) clearInterval(this._storageCheckTimer);\n\n this._storageCheckTimer = setInterval(async () => {\n await this._checkStorageAndFlush();\n }, LogDropConstants.STORAGE_CHECK_INTERVAL_MS);\n\n if (this._storageCheckTimer && typeof this._storageCheckTimer.unref === \"function\") {\n this._storageCheckTimer.unref();\n }\n }\n\n async _checkStorageAndFlush() {\n if (!this._config) return;\n\n try {\n const currentSize = await this._getStorageSize();\n\n // If storage exceeds 5MB, trigger upload\n if (currentSize >= LogDropConstants.MAX_LOCAL_STORAGE_SIZE) {\n this._logInternal(`[LogDrop] Storage size ${this._formatBytes(currentSize)} exceeds limit, triggering upload`);\n await this._flushLogs();\n }\n } catch {\n // best-effort only\n }\n }\n\n // V2: _getRemainingLimit is no longer needed as a separate API call.\n // The remaining limit is returned in the LogResponse from the /logs endpoint.\n // We keep a cached value from the last init or log response.\n _getCachedRemainingLimit() {\n if (this._cachedRemainingLimit != null) return this._cachedRemainingLimit;\n return LogDropConstants.DEFAULT_INITIAL_REMAINING_LIMIT;\n }\n\n _getMaxFileSize() {\n // V2: Get from init response (now a direct ConfigResponse, not nested under .data)\n const initData = this._initResponse;\n return initData?.perUserMaxFileSizeLimitInBytes ?? 5242880;\n }\n\n _getMinFileSize() {\n // V2: Get minimum file size from init response\n const initData = this._initResponse;\n return initData?.perUserMinFileSizeLimitInBytes ?? 524288;\n }\n\n _groupLogsBySession(logs) {\n const groups = {};\n for (const log of logs) {\n const sessionId = log.sessionId || \"unknown\";\n if (!groups[sessionId]) {\n groups[sessionId] = [];\n }\n groups[sessionId].push(log);\n }\n return groups;\n }\n\n async _getDeviceInfoForSession(sessionId) {\n // Find the most recent device_info for this session\n const logs = await this._readAllLogs();\n const deviceInfoLogs = logs.filter(\n (log) => log.sessionId === sessionId && log.level === LogLevel.DEVICEINFO\n );\n\n if (deviceInfoLogs.length > 0) {\n const last = deviceInfoLogs[deviceInfoLogs.length - 1];\n const msg = last?.message;\n\n if (typeof msg === \"string\" && msg.trim()) {\n try {\n const parsed = JSON.parse(msg);\n if (parsed && typeof parsed === \"object\") return parsed;\n } catch {\n }\n }\n }\n\n // Fallback: generate current device info\n return await this._getDeviceInfo();\n }\n\n _buildLogChunk(sessionGroups, maxFileSize, remainingLimit) {\n const effectiveMaxSize = Math.min(maxFileSize, remainingLimit);\n\n if (effectiveMaxSize <= 0) {\n return null;\n }\n\n const chunk = { sessions: [], size: 0, logIds: [], droppedLogIds: [] };\n\n const appendSessionLogs = (sessionId, sessionLogs) => {\n if (!sessionLogs.length) return;\n chunk.sessions.push({ sessionId, logs: sessionLogs });\n };\n\n for (const [sessionId, logs] of Object.entries(sessionGroups)) {\n const sessionLogs = [];\n\n for (const log of logs) {\n const logEntry = {\n id: log.id,\n ts: log.ts,\n level: log.level,\n message: log.message,\n flowId: log.flowId,\n flowName: log.flowName,\n flowAttributes: log.flowAttributes\n };\n\n const entrySize = JSON.stringify(logEntry).length;\n\n if (entrySize > effectiveMaxSize) {\n chunk.droppedLogIds.push(log.id);\n this._warnInternal(\n `[LogDrop] Dropping oversized log ${log.id} for session ${sessionId}; entry size ${this._formatBytes(entrySize)} exceeds chunk limit ${this._formatBytes(effectiveMaxSize)}`\n );\n continue;\n }\n\n if (chunk.size + entrySize > effectiveMaxSize && chunk.size > 0) {\n appendSessionLogs(sessionId, sessionLogs);\n return chunk.sessions.length > 0 || chunk.droppedLogIds.length > 0 ? chunk : null;\n }\n\n sessionLogs.push(logEntry);\n chunk.logIds.push(log.id);\n chunk.size += entrySize;\n }\n\n appendSessionLogs(sessionId, sessionLogs);\n }\n\n return chunk.sessions.length > 0 || chunk.droppedLogIds.length > 0 ? chunk : null;\n }\n\n async _compressToGzip(data) {\n const jsonString = JSON.stringify(data);\n const encoder = new TextEncoder();\n const uint8Array = encoder.encode(jsonString);\n\n // Try CompressionStream API (modern browsers)\n if (typeof CompressionStream !== \"undefined\") {\n try {\n const stream = new Blob([uint8Array]).stream();\n const compressedStream = stream.pipeThrough(new CompressionStream(\"gzip\"));\n const compressedBlob = await new Response(compressedStream).blob();\n return new Uint8Array(await compressedBlob.arrayBuffer());\n } catch {\n // Fall through to uncompressed\n }\n }\n\n // Fallback: return uncompressed JSON as Uint8Array\n return uint8Array;\n }\n\n async _sendLogFile(gzipBytes, uploadId = \"\") {\n if (!this._config) {\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n }\n\n const fetchFn = hasWindow() ? window.fetch : (typeof fetch !== \"undefined\" ? fetch : null);\n if (typeof fetchFn !== \"function\") {\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n }\n\n const sessionToken = await this._ensureSessionToken(\"Log upload requires a valid access token\");\n if (!sessionToken) {\n this._warnInternal(\"[LogDrop] No valid session token after recovery attempt, skipping log upload\");\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n }\n\n try {\n const osInfo = this._getOsInfo();\n let remainingLimit = this._cachedRemainingLimit;\n\n // V2: Wrap gzipped content in a LogRequest protobuf\n const requestPayload = {\n content: gzipBytes,\n deviceUuid: this._deviceId,\n appVersion: this._config.release || \"1.0\",\n sdkVersion: LogDropConstants.SDK_VERSION,\n osVersion: osInfo.osVersion,\n errorCount: \"0\",\n uploadId,\n };\n const protoBytes = encodeLogRequest(requestPayload);\n this._debugLogProtoBody(\"Log upload request\", requestPayload, protoBytes);\n\n const url = `${this._config.baseUrl}${LogDropConstants.LOGS_PATH}`;\n const res = await fetchFn(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-protobuf\",\n \"accept\": \"application/x-protobuf\",\n \"x-api-key\": this._config.apiKey,\n \"x-session-token\": sessionToken\n },\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" })\n });\n\n if (res.ok) {\n // Parse LogResponse to get remaining limit\n try {\n const responseBytes = new Uint8Array(await res.arrayBuffer());\n this._debugLogProtoResponse(\"Log upload\", responseBytes, decodeLogResponse);\n if (responseBytes.length > 0) {\n const logResponse = decodeLogResponse(responseBytes);\n this._cachedRemainingLimit = logResponse.remainingLimit;\n remainingLimit = this._cachedRemainingLimit;\n }\n } catch {\n // Non-critical, response parsing failed\n }\n return { success: true, remainingLimit };\n }\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n } catch {\n return { success: false, remainingLimit: this._cachedRemainingLimit };\n }\n }\n\n async _sendCrashReport(gzipBytes) {\n if (!this._config) return false;\n\n const fetchFn = hasWindow() ? window.fetch : (typeof fetch !== \"undefined\" ? fetch : null);\n if (typeof fetchFn !== \"function\") return false;\n\n const sessionToken = await this._ensureSessionToken(\"Crash upload requires a valid access token\");\n if (!sessionToken) {\n this._warnInternal(\"[LogDrop] No valid session token after recovery attempt, skipping crash upload\");\n return false;\n }\n\n try {\n const requestPayload = {\n content: gzipBytes,\n deviceUuid: this._deviceId,\n sdkVersion: LogDropConstants.SDK_VERSION\n };\n const protoBytes = encodeCrashReportRequest(requestPayload);\n this._debugLogProtoBody(\"Crash upload request\", requestPayload, protoBytes);\n\n const url = `${this._config.baseUrl}${LogDropConstants.CRASH_PATH}`;\n const res = await fetchFn(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-protobuf\",\n \"accept\": \"application/x-protobuf\",\n \"x-api-key\": this._config.apiKey,\n \"x-session-token\": sessionToken\n },\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" })\n });\n\n return res.ok;\n } catch {\n return false;\n }\n }\n\n async _flushCrashes() {\n if (!this._config || !this._dbPromise || this._crashFlushInProgress) return false;\n this._crashFlushInProgress = true;\n try {\n const crashes = await this._readAllCrashes();\n if (!crashes.length) {\n this._seenCrashes.clear();\n return true;\n }\n\n const crashIds = crashes.map(crash => crash.id).filter(id => id !== undefined);\n const payload = {\n crashes: crashes.map(({ id, ...crash }) => crash)\n };\n const gzipBytes = await this._compressToGzip(payload);\n const success = await this._sendCrashReport(gzipBytes);\n if (success) {\n await this._deleteCrashesByIds(crashIds);\n this._seenCrashes.clear();\n }\n return success;\n } finally {\n this._crashFlushInProgress = false;\n }\n }\n\n async _deleteLogsByIds(ids) {\n if (!this._dbPromise || !ids.length) return;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"logs\", \"readwrite\");\n const store = tx.objectStore(\"logs\");\n\n for (const id of ids) {\n store.delete(id);\n }\n\n return new Promise((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n } catch {\n // best-effort only\n }\n }\n\n _formatLogForExport(log) {\n // Format log entry for export\n // Required: level, message, timestamp, file_and_line\n // Optional: id (flowId), flow_name\n const formatted = {\n level: log.level || \"\",\n message: log.message || \"\",\n timestamp: log.ts || \"\",\n file_and_line: \"\" // Web SDK doesn't have file/line info\n };\n\n // Add flow info if present\n if (log.flowId) {\n formatted.id = log.flowId;\n }\n if (log.flowName) {\n formatted.flow_name = log.flowName;\n }\n\n if (log.tag) {\n formatted.tag = log.tag;\n }\n\n return formatted;\n }\n\n _formatDeviceInfoForExport(deviceInfo) {\n const di = deviceInfo && typeof deviceInfo === \"object\" ? deviceInfo : {};\n\n return {\n sessionID: di.sessionID || \"\",\n session_create_date: di.session_create_date || \"\",\n os_version: di.os_version || \"\",\n app_version: di.app_version || \"\",\n device_model: di.device_model || \"\",\n locale: di.locale || \"\",\n free_disk_space: di.free_disk_space || \"\",\n battery_level: di.battery_level || \"\",\n low_power_mode: di.low_power_mode || \"\",\n ram_size: di.ram_size || \"\",\n device_id: di.device_id || \"\",\n userUuid: di.userUuid ?? null,\n sim_operator_name: \"\",\n network_available: di.network_available ?? true,\n gmt: di.gmt ?? 0,\n ...(di.bot_score !== undefined && {\n bot_score: di.bot_score,\n bot_label: di.bot_label,\n posture: di.posture,\n }),\n };\n }\n\n async _flushLogs() {\n if (!this._config || this._fileFlushInProgress) return false;\n if (!this._dbPromise) return false;\n this._fileFlushInProgress = true;\n\n try {\n // Step 1: Check if there are any logs to send BEFORE making API calls\n const allLogs = await this._readAllLogs();\n\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n this._logInternal(`[LogDrop DEBUG] _flushLogs called. DB log count: ${allLogs.length}`);\n }\n\n if (!allLogs.length) {\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n this._logInternal(\"[LogDrop DEBUG] No logs in DB, skipping flush (no API call made)\");\n }\n // Nothing to send, skip API calls\n return true;\n }\n\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n this._logInternal(\"[LogDrop DEBUG] Logs from DB:\", allLogs);\n }\n\n if (this._cachedRemainingLimit == null) {\n this._logInternal(\n `[LogDrop] Remaining upload quota unknown; using conservative default limit of ${this._formatBytes(LogDropConstants.DEFAULT_INITIAL_REMAINING_LIMIT)} until a successful upload response updates the cache`\n );\n }\n\n // Step 2: Get max file size from init response\n const maxFileSize = this._getMaxFileSize();\n\n // Step 3: Build and send chunks one at a time using the latest cached quota.\n let pendingLogs = allLogs;\n let anySuccess = false;\n\n while (pendingLogs.length > 0) {\n const remainingLimit = this._getCachedRemainingLimit();\n if (remainingLimit <= 0) {\n this._logInternal(\"[LogDrop] Remaining limit reached, stopping upload\");\n break;\n }\n\n const activeBatch = await this._readLogUploadBatch();\n let uploadId = activeBatch?.uploadId ?? null;\n let chunk;\n\n if (activeBatch) {\n const activeIds = new Set(activeBatch.logIds || []);\n const activeLogs = pendingLogs.filter((log) => activeIds.has(log.id));\n if (activeLogs.length === 0) {\n await this._replaceLogUploadBatch(null);\n continue;\n }\n chunk = this._buildLogChunk(\n this._groupLogsBySession(activeLogs),\n Number.MAX_SAFE_INTEGER,\n Number.MAX_SAFE_INTEGER,\n );\n } else {\n const sessionGroups = this._groupLogsBySession(pendingLogs);\n chunk = this._buildLogChunk(sessionGroups, maxFileSize, remainingLimit);\n }\n if (!chunk) {\n break;\n }\n\n if (chunk.droppedLogIds.length > 0) {\n await this._deleteLogsByIds(chunk.droppedLogIds);\n const droppedLogIds = new Set(chunk.droppedLogIds);\n pendingLogs = pendingLogs.filter(log => !droppedLogIds.has(log.id));\n anySuccess = true;\n }\n\n if (!chunk.sessions.length) {\n continue;\n }\n\n if (!uploadId) {\n uploadId = this._generateUUID();\n await this._replaceLogUploadBatch({ uploadId, logIds: chunk.logIds });\n }\n\n // Build the payload in the required format:\n // [{ device_info: {...}, logs: [...] }, ...]\n const payload = [];\n\n for (const session of chunk.sessions) {\n const rawDeviceInfo = await this._getDeviceInfoForSession(session.sessionId);\n const deviceInfo = this._formatDeviceInfoForExport(rawDeviceInfo);\n\n const formattedLogs = session.logs.map(log => this._formatLogForExport(log));\n\n payload.push({\n device_info: deviceInfo,\n logs: formattedLogs\n });\n }\n\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n const payloadJson = JSON.stringify(payload);\n const payloadSize = new Blob([payloadJson]).size;\n this._logInternal(`[LogDrop DEBUG] Payload before gzip - Size: ${this._formatBytes(payloadSize)}, Log IDs: ${chunk.logIds.join(\", \")}`);\n this._logInternal(\"[LogDrop DEBUG] Payload content:\", payload);\n }\n\n // Step 7: Compress to gzip\n const gzipBlob = await this._compressToGzip(payload);\n\n // === DEBUG LOG ===\n if (this._isInternalLoggingEnabled()) {\n this._logInternal(`[LogDrop DEBUG] After gzip - Size: ${this._formatBytes(gzipBlob.length)}`);\n }\n\n // Step 8: Send to backend\n const uploadResult = await this._sendLogFile(gzipBlob, uploadId);\n\n if (uploadResult.success) {\n this._logInternal(`[LogDrop] Successfully sent ${chunk.logIds.length} logs`);\n\n // Step 9: Delete sent logs from DB\n await this._deleteLogsByIds(chunk.logIds);\n await this._replaceLogUploadBatch(null);\n const sentLogIds = new Set(chunk.logIds);\n pendingLogs = pendingLogs.filter(log => !sentLogIds.has(log.id));\n anySuccess = true;\n\n if (uploadResult.remainingLimit != null && uploadResult.remainingLimit <= 0) {\n this._logInternal(\"[LogDrop] Remaining limit exhausted after upload, stopping flush\");\n break;\n }\n } else {\n this._warnInternal(\"[LogDrop] Failed to send log chunk, will retry later\");\n // Don't delete logs, they'll be retried\n break;\n }\n }\n\n return anySuccess;\n } catch (err) {\n this._warnInternal(\"[LogDrop] Flush failed:\", err.message || err);\n return false;\n } finally {\n this._fileFlushInProgress = false;\n }\n }\n\n // Legacy method - kept for backward compatibility\n async _flushDbToZip() {\n return this._flushLogs();\n }\n\n async _sendInitRequest(attempt = 1) {\n const MAX_ATTEMPTS = 3;\n\n if (!this._config) {\n this._failInit(\"LogDrop init failed: no config\");\n return;\n }\n\n const fetchFn = hasWindow() ? window.fetch : (typeof fetch !== \"undefined\" ? fetch : null);\n if (typeof fetchFn !== \"function\") {\n this._failInit(\"LogDrop init failed: fetch not available\");\n return;\n }\n\n try {\n const headers = {\n \"content-type\": \"application/x-protobuf\",\n \"accept\": \"application/x-protobuf\",\n \"x-api-key\": this._config.apiKey\n };\n\n const sessionToken = this._getAccessToken();\n const refreshToken = this._getRefreshToken();\n\n if (!sessionToken || !refreshToken) {\n const recoveryReasons = [];\n if (!sessionToken) {\n recoveryReasons.push(\n `Stored access token is ${this._tokenValidationState.logdrop_access_token || \"unavailable\"}`\n );\n }\n if (!refreshToken) {\n recoveryReasons.push(\n `Stored refresh token is ${this._tokenValidationState.logdrop_refresh_token || \"unavailable\"}`\n );\n }\n void this._recoverSessionTokens(recoveryReasons.join(\"; \"));\n }\n\n // Add session token if available\n if (sessionToken) {\n headers[\"x-session-token\"] = sessionToken;\n }\n\n const requestPayload = {\n refreshToken: refreshToken || \"\",\n deviceUuid: this._deviceId\n };\n const protoBytes = encodeInitRequest(requestPayload);\n this._debugLogProtoBody(\"Init request\", requestPayload, protoBytes);\n\n const url = `${this._config.baseUrl}${LogDropConstants.INIT_PATH}`;\n const res = await fetchFn(url, {\n method: \"POST\",\n headers,\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" })\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n // V2: Decode protobuf ConfigResponse\n const responseBytes = new Uint8Array(await res.arrayBuffer());\n this._debugLogProtoResponse(\"Init\", responseBytes, decodeConfigResponse);\n if (responseBytes.length > 0) {\n this._initResponse = decodeConfigResponse(responseBytes);\n\n // Cache the response in localStorage (as JSON for simplicity)\n this._saveServerConfigToCache({ data: this._initResponse });\n\n // If a new access token was returned, save it\n if (this._initResponse.accessToken) {\n this._saveTokens(this._initResponse.accessToken, null, this._getTokenRecoveryTarget());\n }\n\n // Apply server config (with dynamic network change)\n this._applyServerConfig(this._initResponse, true);\n }\n\n this._logInternal(\"[LogDrop] Init successful\");\n\n // Auto-register user if this is a new device and user not yet registered\n if (this._isNewDevice && !this._isUserRegistered()) {\n // Use device UUID as userUuid for automatic registration\n void this._sendUserUpdate(this._deviceId, false, { reason: \"automatic_device_registration\" });\n }\n } catch (err) {\n if (attempt < MAX_ATTEMPTS) {\n this._warnInternal(`[LogDrop] Init attempt ${attempt} failed, retrying... (${err.message || err})`);\n // Wait before retry (exponential backoff: 1s, 2s)\n await new Promise(r => setTimeout(r, attempt * 1000));\n return this._sendInitRequest(attempt + 1);\n }\n\n this._failInit(`LogDrop init failed after ${MAX_ATTEMPTS} attempts: ${err.message || err}`);\n }\n }\n\n _failInit(message) {\n this._errorInternal(message);\n this._initialized = false;\n this._config = null;\n this.teardown();\n }\n\n _installGlobalErrorHandlers() {\n if (!hasWindow()) return;\n if (this._errorHandlersInstalled) return;\n this._errorHandlersInstalled = true;\n\n window.addEventListener(\"error\", (event) => {\n if (!this._serverConfig.isCrashTrackingEnabled) return;\n const err = event.error;\n const stack = (err && err.stack) ? String(err.stack) : (event.message || \"\");\n this._recordCrash({\n threadName: \"window\",\n stackTrace: stack,\n crashType: err?.name || \"Error\",\n isCustomCrash: false,\n sourceUrl: event.filename || \"\",\n line: event.lineno || 0,\n column: event.colno || 0,\n errorIdentity: err\n });\n });\n\n window.addEventListener(\"unhandledrejection\", (event) => {\n if (!this._serverConfig.isCrashTrackingEnabled) return;\n const reason = event.reason;\n const stack = (reason instanceof Error && reason.stack) ? String(reason.stack) : String(reason || \"\");\n this._recordCrash({\n threadName: \"unhandledrejection\",\n stackTrace: stack,\n crashType: reason instanceof Error ? reason.name : \"UnhandledRejection\",\n isCustomCrash: false,\n errorIdentity: reason instanceof Error ? reason : null\n });\n });\n }\n\n // Optional: restore original fetch (useful for teardown/debug)\n restoreFetch() {\n if (!hasWindow()) return;\n if (this._originalFetch) window.fetch = this._originalFetch;\n this._fetchInstrumented = false;\n this._originalFetch = null;\n }\n\n // Optional: teardown everything (recommended for tests / hot reload)\n teardown() {\n if (this._flushTimer) clearInterval(this._flushTimer);\n this._flushTimer = null;\n if (this._fileFlushTimer) clearInterval(this._fileFlushTimer);\n this._fileFlushTimer = null;\n if (this._crashFlushTimer) clearTimeout(this._crashFlushTimer);\n this._crashFlushTimer = null;\n if (this._deviceInfoTimer) clearInterval(this._deviceInfoTimer);\n this._deviceInfoTimer = null;\n if (this._storageCheckTimer) clearInterval(this._storageCheckTimer);\n this._storageCheckTimer = null;\n\n this._seenCrashes.clear();\n this._uninstallNetworkInstrumentation();\n\n // Push module teardown (REQ-014)\n this._pushModule?.teardown();\n this._pushModule = null;\n this._inAppMessagePresenter?.teardown();\n this._inAppMessagePresenter = null;\n this.push = null;\n\n // Event module teardown (REQ-031)\n if (this._eventFlushTimer) clearInterval(this._eventFlushTimer);\n this._eventFlushTimer = null;\n this._eventModule?.teardown();\n this._eventModule = null;\n\n this._riskModule?.teardown();\n this._riskModule = null;\n this._activeRiskPolicyEvaluation = null;\n if (this._ipReputationExpiryTimer) clearTimeout(this._ipReputationExpiryTimer);\n this._ipReputationExpiryTimer = null;\n if (this._riskPolicyOverlay?.parentNode) {\n try { this._riskPolicyOverlay.parentNode.removeChild(this._riskPolicyOverlay); } catch {}\n }\n this._riskPolicyOverlay = null;\n\n // Deprecated path cleanup\n this.restoreFetch();\n this._debugLogEnabled = false;\n }\n}\n\n// Singleton facade\nexport const LogDrop = new LogDropClient();\n", "export class LogDropConstants {}\n\n/**\n * Default base URL for the LogDrop API.\n *\n * This points to the development/staging server. Production applications\n * should override this by passing a `baseUrl` option to `LogDrop.init()`.\n *\n * The SDK's `normalizeBaseUrl()` function automatically appends `/api/v2/sdk`\n * to this value, so the effective base for all requests becomes:\n * `https://server.logdrop.io/api/v2/sdk`\n */\nLogDropConstants.DEFAULT_BASE_URL = \"https://server.logdrop.io\";\nLogDropConstants.DEFAULT_WEB_SECRET_KEY = \"xuM9w0BAQEFx\";\nLogDropConstants.FILE_EXPORT_INTERVAL_MS = 300000;\nLogDropConstants.DEVICE_INFO_INTERVAL_MS = 10000;\nLogDropConstants.SDK_VERSION =\n typeof __LOGDROP_SDK_VERSION__ !== \"undefined\" ? __LOGDROP_SDK_VERSION__ : \"1.0.0\";\n\n// Storage management\nLogDropConstants.STORAGE_CHECK_INTERVAL_MS = 120000; // 2 minutes\nLogDropConstants.MAX_LOCAL_STORAGE_SIZE = 5242880; // 5MB\nLogDropConstants.DATABASE_MAX_STORAGE_LIMIT = 16000000; // 16MB (from init response default)\n\n// Off by default. init() sets this to true when config.env is not \"prod\" or \"production\".\nLogDropConstants.DEBUG_LOGS_ENABLED = true;\n\n// DevTools detection \u2014 the size-diff heuristic only catches *docked* DevTools.\n// The console-getter probe can additionally detect DevTools opened in a\n// separate (undocked) window, but every probe is necessarily visible in the\n// browser console. Keep it opt-in so the SDK never pollutes host-app logs.\nLogDropConstants.DEVTOOLS_CONSOLE_PROBE_ENABLED = false;\nLogDropConstants.DEVTOOLS_PROBE_INTERVAL_MS = 1500;\n\n// Endpoint paths \u2014 all SDK HTTP calls construct URLs using these constants\nLogDropConstants.INIT_PATH = \"/logdrop/init\";\nLogDropConstants.LOGS_PATH = \"/logs\";\nLogDropConstants.CRASH_PATH = \"/crash\";\nLogDropConstants.USERS_UPDATE_PATH = \"/users/update\";\n\n// Push notification paths\nLogDropConstants.PUSH_SW_PATH = \"/_logdrop/logdrop-sw.js\";\nLogDropConstants.PUSH_SW_SCOPE = \"/\";\n\n// Event tracking paths\nLogDropConstants.EVENTS_PATH = \"/events/collect\";\nLogDropConstants.EVENT_FLUSH_INTERVAL_MS = 10000;\n\n// Server-recognized event short codes (from the LogDrop event registry).\n// The /events/collect endpoint rejects the ENTIRE batch with HTTP 400 if it\n// contains any event whose code is not in this set, so events with unknown\n// codes must be dropped before batching. Each code also has required property\n// keys the server enforces (see EVENT_REQUIRED_PROPS).\nLogDropConstants.EVENT_CODES = Object.freeze({\n APP_INSTALL: \"ai\",\n APP_OPEN: \"ao\",\n APP_FOREGROUNDED: \"af\",\n APP_BACKGROUNDED: \"ab\",\n APP_PERMISSIONS: \"ap\",\n APP_UPDATE: \"au\",\n DEEPLINK_OPEN: \"do\",\n TIME_IN_APP: \"ta\",\n PUSH_RECEIVED: \"pr\",\n PUSH_CLICK: \"pc\",\n WHITELIST_DOMAIN_DETECTED: \"wd\",\n RISK_DETECTED: \"rd\",\n SDK_ACTION_CLEARED: \"sac\",\n});\n\nLogDropConstants.VALID_EVENT_CODES = Object.freeze(\n Object.values(LogDropConstants.EVENT_CODES)\n);\n\n// Human-readable event names keyed by short code. Used when mirroring a sent\n// event into the log stream (LogLevel.EVENT) so log payloads carry eventName.\nLogDropConstants.EVENT_NAMES = Object.freeze({\n ai: \"app_install\",\n ao: \"app_open\",\n af: \"app_foregrounded\",\n ab: \"app_backgrounded\",\n ap: \"app_permissions\",\n au: \"app_update\",\n do: \"deeplink_open\",\n ta: \"time_in_app\",\n pr: \"push_received\",\n pc: \"push_click\",\n wd: \"whitelist_domain_detected\",\n rd: \"risk_detected\",\n sac: \"sdk_action_cleared\",\n});\n\n// Required property keys per event code. The server returns HTTP 400 (empty\n// body) when a valid code is missing any of its required properties.\nLogDropConstants.EVENT_REQUIRED_PROPS = Object.freeze({\n ai: [],\n ao: [],\n af: [],\n ab: [],\n ap: [\"pt\", \"ps\"],\n au: [\"pv\", \"nv\"],\n do: [\"ol\"],\n ta: [\"ed\"],\n pr: [\"pn\"],\n pc: [\"pn\"],\n wd: [\"rs\", \"dm\"],\n rd: [\"rt\", \"rs\"],\n sac: [\"as\", \"cr\"],\n});\nLogDropConstants.DEFAULT_INITIAL_REMAINING_LIMIT = 15728640; // 15MB conservative upload cap before quota is known\n", "// instrumentation/networkInstrumentation.js\n// Fetch + XHR instrumentation with recursion guard, redaction, and optional sampling.\n// Updated: exclude checks now evaluate both raw and absolute URLs (so domain rules like /logdrop\\.io/ work even for relative URLs).\n\nfunction genId() {\n return Math.random().toString(16).slice(2) + Date.now().toString(16);\n}\n\nfunction hasWindow() {\n return typeof window !== \"undefined\";\n}\n\nfunction perfNow() {\n if (hasWindow() && window.performance && typeof window.performance.now === \"function\") {\n return window.performance.now();\n }\n return Date.now();\n}\n\nfunction safeUrlToString(input) {\n try {\n if (typeof input === \"string\") return input;\n if (input && typeof input.url === \"string\") return input.url;\n return String(input ?? \"unknown\");\n } catch {\n return \"unknown\";\n }\n}\n\nfunction safeJsonParse(str) {\n try {\n return JSON.parse(str);\n } catch {\n return null;\n }\n}\n\nfunction parseXhrResponseHeaders(raw) {\n try {\n if (!raw || typeof raw !== \"string\") return null;\n const out = {};\n const lines = raw.trim().split(/[\\r\\n]+/);\n for (const line of lines) {\n const idx = line.indexOf(\":\");\n if (idx === -1) continue;\n const k = line.slice(0, idx).trim().toLowerCase();\n const v = line.slice(idx + 1).trim();\n if (k) out[k] = v;\n }\n return Object.keys(out).length ? out : null;\n } catch {\n return null;\n }\n}\n\nfunction normalizeBody(body) {\n if (body == null) return null;\n\n // fetch init.body can be string/Blob/FormData/etc.\n if (typeof body === \"string\") {\n const asJson = safeJsonParse(body);\n return asJson ?? body;\n }\n\n // XHR body can be string/Document/FormData/etc.\n if (typeof body === \"object\") {\n // Don't try to serialize FormData/Blob/ArrayBuffer aggressively\n if (typeof FormData !== \"undefined\" && body instanceof FormData) return \"[FormData]\";\n if (typeof Blob !== \"undefined\" && body instanceof Blob) return `[Blob ${body.type || \"unknown\"} ${body.size} bytes]`;\n if (typeof ArrayBuffer !== \"undefined\" && body instanceof ArrayBuffer) return `[ArrayBuffer ${body.byteLength} bytes]`;\n }\n\n try {\n return String(body);\n } catch {\n return \"[unserializable]\";\n }\n}\n\nfunction buildFinalNetworkPayload({requestId, method, url, status, tookMs, requestHeaders, requestBody, responseHeaders, responseBody, errorType, errorMessage, didComplete}) {\n // didComplete = \"a response lifecycle completed\" (fetch resolved or XHR loadend)\n // isSuccess = transport success (request completed), NOT \"2xx\"\n const isSuccess = didComplete === true;\n\n const payload = {\n isSuccess,\n uuid: String(requestId || \"\"),\n method: String(method || \"\"),\n url: String(url || \"\"),\n requestHeaders: requestHeaders || {},\n requestBody: requestBody ?? null,\n status: typeof status === \"number\" ? status : 0,\n responseHeaders: responseHeaders || {},\n responseBody: responseBody ?? null,\n tookMs: typeof tookMs === \"number\" ? tookMs : 0\n };\n\n // Only attach error fields when transport failed.\n // This matches your iOS example behavior: responseBody can contain error details while isSuccess stays true.\n if (!isSuccess) {\n payload.errorType = errorType ?? \"network_error\";\n payload.errorMessage = errorMessage ?? \"network_error\";\n }\n\n return payload;\n}\n\n\n\nfunction normalizeUrl(rawUrl, baseHref, {stripQuery = true, stripHash = true} = {}) {\n try {\n const u = new URL(rawUrl, baseHref);\n if (stripQuery) u.search = \"\";\n if (stripHash) u.hash = \"\";\n return u.toString();\n } catch {\n // rawUrl may be relative or malformed; best-effort\n return String(rawUrl || \"unknown\");\n }\n}\n\nfunction toAbsoluteUrl(rawUrl, baseHref) {\n try {\n return new URL(String(rawUrl || \"\"), baseHref).toString();\n } catch {\n return String(rawUrl || \"\");\n }\n}\n\nfunction matchExclude(url, exclude = []) {\n const s = String(url || \"\");\n return exclude.some((rule) => {\n if (!rule) return false;\n if (rule instanceof RegExp) return rule.test(s);\n return s.includes(String(rule));\n });\n}\n\nfunction shouldSample(sampleRate) {\n // sampleRate: 0..1\n if (typeof sampleRate !== \"number\") return true;\n if (sampleRate <= 0) return false;\n if (sampleRate >= 1) return true;\n return Math.random() < sampleRate;\n}\n\nfunction extractFetchMethod(input, init) {\n // fetch(input, init)\n // input may be Request\n try {\n if (init && init.method) return String(init.method).toUpperCase();\n if (input && typeof input.method === \"string\") return String(input.method).toUpperCase();\n } catch {\n }\n return \"GET\";\n}\n\nfunction extractResponseHeaders(res) {\n try {\n if (!res || !res.headers) return null;\n const out = {};\n // Headers.forEach is supported widely\n res.headers.forEach((v, k) => { out[String(k).toLowerCase()] = String(v); });\n return Object.keys(out).length ? out : null;\n } catch {\n return null;\n }\n}\n\nfunction extractFetchHeaders(input, init) {\n const out = {};\n const source = init?.headers ?? input?.headers;\n\n try {\n if (!source) return null;\n\n if (typeof Headers !== \"undefined\" && source instanceof Headers) {\n source.forEach((v, k) => { out[String(k).toLowerCase()] = String(v); });\n return Object.keys(out).length ? out : null;\n }\n\n if (Array.isArray(source)) {\n for (const [k, v] of source) out[String(k).toLowerCase()] = String(v);\n return Object.keys(out).length ? out : null;\n }\n\n if (typeof source === \"object\") {\n for (const k of Object.keys(source)) out[String(k).toLowerCase()] = String(source[k]);\n return Object.keys(out).length ? out : null;\n }\n } catch {}\n\n return null;\n}\n\nexport class NetworkInstrumentation {\n /**\n * @param {{\n * onEvent: (eventName: string, meta: any) => void,\n * getBaseHref?: () => string,\n * excludeUrls?: (string|RegExp)[],\n * redaction?: { stripQuery?: boolean, stripHash?: boolean },\n * sampling?: { rate?: number, onlyErrors?: boolean, slowThresholdMs?: number },\n * capture?: { fetch?: boolean, xhr?: boolean },\n * shouldBlockRequest?: (url: string) => boolean\n * }} opts\n */\n constructor(opts) {\n this._onEvent = opts.onEvent;\n this._getBaseHref = opts.getBaseHref || (() => (hasWindow() ? window.location.href : \"http://localhost/\"));\n this._excludeUrls = opts.excludeUrls || [];\n this._redaction = opts.redaction || {stripQuery: true, stripHash: true};\n this._sampling = opts.sampling || {rate: 1, onlyErrors: false, slowThresholdMs: undefined};\n this._capture = opts.capture || {fetch: true, xhr: true};\n this._shouldBlockRequest = typeof opts.shouldBlockRequest === \"function\"\n ? opts.shouldBlockRequest\n : () => false;\n\n // Fetch state\n this._fetchInstalled = false;\n this._originalFetch = null;\n\n // XHR state\n this._xhrInstalled = false;\n this._xhrProto = null;\n this._xhrOrigOpen = null;\n this._xhrOrigSend = null;\n this._xhrOrigSetHeader = null;\n }\n\n install() {\n if (!hasWindow()) return;\n\n if (this._capture.fetch) this._installFetch();\n if (this._capture.xhr) this._installXHR();\n }\n\n uninstall() {\n if (!hasWindow()) return;\n\n this._uninstallFetch();\n this._uninstallXHR();\n }\n\n _shouldExclude(rawUrl) {\n const baseHref = this._getBaseHref();\n const absUrl = toAbsoluteUrl(rawUrl, baseHref);\n\n // Check both raw and absolute form to support:\n // - relative URLs (/api/x)\n // - domain-based excludes (e.g., /logdrop\\.io/i)\n return matchExclude(rawUrl, this._excludeUrls) || matchExclude(absUrl, this._excludeUrls);\n }\n\n _shouldBlock(rawUrl) {\n try { return this._shouldBlockRequest(String(rawUrl || \"\")) === true; }\n catch { return false; }\n }\n\n _emit(eventName, meta) {\n try {\n this._onEvent(eventName, meta);\n } catch {\n // never break host app\n }\n }\n\n _installFetch() {\n if (this._fetchInstalled) return;\n if (typeof window.fetch !== \"function\") return;\n\n this._fetchInstalled = true;\n this._originalFetch = window.fetch.bind(window);\n\n window.fetch = async (input, init) => {\n const method = extractFetchMethod(input, init);\n const rawUrl = safeUrlToString(input);\n\n if (this._shouldBlock(rawUrl)) {\n throw new TypeError(\"Request blocked by LogDrop risk policy\");\n }\n // recursion guard / logging exclusions\n if (this._shouldExclude(rawUrl)) {\n return this._originalFetch(input, init);\n }\n\n const baseHref = this._getBaseHref();\n const url = normalizeUrl(rawUrl, baseHref, this._redaction);\n\n const requestId = genId();\n const start = perfNow();\n\n let headers = {};\n try {\n // This merges input(Request) + init headers like the browser will\n const req = new Request(input, init);\n const h = {};\n req.headers.forEach((v, k) => { h[String(k).toLowerCase()] = String(v); });\n headers = h;\n } catch {\n // fallback (still better than empty)\n headers = extractFetchHeaders(input, init) || {};\n }\n\n try {\n const reqBody = normalizeBody(init?.body);\n\n const res = await this._originalFetch(input, init);\n\n const tookMs = Math.round(perfNow() - start);\n const status = res?.status ?? 0;\n\n const isError = !res || status >= 400 || status === 0;\n const isSlow =\n typeof this._sampling.slowThresholdMs === \"number\" &&\n tookMs >= this._sampling.slowThresholdMs;\n\n if (!this._sampling.onlyErrors || isError || isSlow) {\n if (shouldSample(this._sampling.rate)) {\n // best-effort response body (clone)\n let responseBody = null;\n try {\n const ct = res?.headers?.get?.(\"content-type\") || \"\";\n const cloned = res.clone();\n const text = await cloned.text();\n const asJson = ct.includes(\"application/json\") ? safeJsonParse(text) : null;\n responseBody = asJson ?? text;\n } catch {\n // ignore\n }\n\n const respHeaders = extractResponseHeaders(res) || {};\n\n const payload = buildFinalNetworkPayload({\n requestId,\n method,\n url,\n status,\n tookMs,\n requestHeaders: headers,\n requestBody: reqBody,\n responseHeaders: respHeaders,\n responseBody,\n errorType: null,\n errorMessage: null,\n didComplete: true\n });\n\n this._emit(\"network_activity\", payload);\n }\n }\n\n return res;\n } catch (err) {\n const tookMs = Math.round(perfNow() - start);\n\n if (shouldSample(this._sampling.rate)) {\n const reqBody = normalizeBody(init?.body);\n\n const payload = buildFinalNetworkPayload({\n requestId,\n method,\n url,\n status: 0,\n tookMs,\n requestHeaders: headers,\n requestBody: reqBody,\n responseHeaders: {},\n responseBody: null,\n errorType: err?.name ?? \"fetch_error\",\n errorMessage: String(err),\n didComplete: false\n });\n\n this._emit(\"network_activity\", payload);\n }\n\n throw err;\n }\n };\n }\n\n _uninstallFetch() {\n if (!this._fetchInstalled) return;\n if (!this._originalFetch) return;\n window.fetch = this._originalFetch;\n this._fetchInstalled = false;\n this._originalFetch = null;\n }\n\n _installXHR() {\n if (this._xhrInstalled) return;\n if (typeof window.XMLHttpRequest !== \"function\") return;\n\n this._xhrInstalled = true;\n\n const proto = window.XMLHttpRequest.prototype;\n this._xhrProto = proto;\n\n this._xhrOrigOpen = proto.open;\n this._xhrOrigSend = proto.send;\n this._xhrOrigSetHeader = proto.setRequestHeader;\n\n // Preserve originals for our overrides\n proto.__ld_open_orig = this._xhrOrigOpen;\n proto.__ld_send_orig = this._xhrOrigSend;\n proto.__ld_setheader_orig = this._xhrOrigSetHeader;\n\n // Attach metadata to each XHR instance\n proto.open = function (method, url, async, user, password) {\n this.__ld = {\n requestId: genId(),\n method: String(method || \"GET\").toUpperCase(),\n rawUrl: String(url || \"unknown\"),\n start: 0,\n headers: {}\n };\n return proto.__ld_open_orig.call(this, method, url, async, user, password);\n };\n\n proto.setRequestHeader = function (name, value) {\n try {\n if (this.__ld && name) this.__ld.headers[String(name).toLowerCase()] = String(value);\n } catch {\n }\n return proto.__ld_setheader_orig.call(this, name, value);\n };\n\n const client = this; // capture instrumentation instance\n\n proto.send = function (body) {\n const ld = this.__ld;\n if (!ld) return proto.__ld_send_orig.call(this, body);\n\n if (client._shouldBlock(ld.rawUrl)) {\n try { this.abort(); } catch {}\n return;\n }\n if (client._shouldExclude(ld.rawUrl)) {\n return proto.__ld_send_orig.call(this, body);\n }\n\n const baseHref = client._getBaseHref();\n const url = normalizeUrl(ld.rawUrl, baseHref, client._redaction);\n\n const headers = ld.headers || {};\n\n ld.start = perfNow();\n\n const finalize = async (eventName) => {\n const tookMs = Math.round(perfNow() - ld.start);\n const status = this.status ?? 0;\n\n const isError = eventName !== \"loadend\" || status >= 400 || status === 0;\n const isSlow =\n typeof client._sampling.slowThresholdMs === \"number\" &&\n tookMs >= client._sampling.slowThresholdMs;\n\n if (!client._sampling.onlyErrors || isError || isSlow) {\n if (shouldSample(client._sampling.rate)) {\n\n // request body best-effort\n const requestBody = normalizeBody(body);\n\n // response body best-effort\n let responseBody = null;\n try {\n // NOTE: responseType \"\" or \"text\" -> use responseText, otherwise use response\n if (!this.responseType || this.responseType === \"text\") {\n const txt = this.responseText;\n const asJson = safeJsonParse(txt);\n responseBody = asJson ?? txt;\n } else {\n responseBody = this.response ?? null;\n }\n } catch {\n // ignore\n }\n\n let responseHeaders = {};\n try {\n const raw = this.getAllResponseHeaders?.();\n const parsed = parseXhrResponseHeaders(raw);\n if (parsed) responseHeaders = parsed;\n } catch {\n // ignore\n }\n\n const didComplete = eventName === \"loadend\";\n\n const payload = buildFinalNetworkPayload({\n requestId: ld.requestId,\n method: ld.method,\n url,\n status: didComplete ? status : 0,\n tookMs,\n requestHeaders: headers,\n requestBody,\n responseHeaders: responseHeaders,\n responseBody: didComplete ? responseBody : null,\n errorType: didComplete ? null : eventName,\n errorMessage: didComplete ? null : eventName,\n didComplete\n });\n\n client._emit(\"network_activity\", payload);\n }\n }\n };\n\n // Use loadend as \"finished\" signal; plus error/abort/timeout\n this.addEventListener(\"loadend\", () => { void finalize(\"loadend\"); }, { once: true });\n this.addEventListener(\"error\", () => { void finalize(\"error\"); }, { once: true });\n this.addEventListener(\"abort\", () => { void finalize(\"abort\"); }, { once: true });\n this.addEventListener(\"timeout\", () => { void finalize(\"timeout\"); }, { once: true });\n\n return proto.__ld_send_orig.call(this, body);\n };\n }\n\n _uninstallXHR() {\n if (!this._xhrInstalled) return;\n if (!this._xhrProto) return;\n\n // Restore originals (best-effort)\n if (this._xhrOrigOpen) this._xhrProto.open = this._xhrOrigOpen;\n if (this._xhrOrigSend) this._xhrProto.send = this._xhrOrigSend;\n if (this._xhrOrigSetHeader) this._xhrProto.setRequestHeader = this._xhrOrigSetHeader;\n\n // Cleanup helper refs\n try {\n delete this._xhrProto.__ld_open_orig;\n delete this._xhrProto.__ld_send_orig;\n delete this._xhrProto.__ld_setheader_orig;\n } catch {\n }\n\n this._xhrInstalled = false;\n this._xhrProto = null;\n this._xhrOrigOpen = null;\n this._xhrOrigSend = null;\n this._xhrOrigSetHeader = null;\n }\n}\n", "// LogDrop PushModule \u2014 full implementation\n// Mirrors the lifecycle pattern used by NetworkInstrumentation\n// (constructor config slice, install() / uninstall() / teardown()).\n//\n// Scope notes:\n// - This module ONLY touches push-specific APIs (navigator.serviceWorker,\n// PushManager, Notification) and delegates config plumbing to the caller.\n// - It does NOT patch global fetch/XHR. The SDK-wide recursion guard for\n// instrumentation lives in networkInstrumentation.js.\n//\n// Requirements covered: REQ-001, REQ-003, REQ-005, REQ-007, REQ-011, REQ-012,\n// REQ-013, REQ-014, REQ-015, REQ-026.\n\nimport { LogDropConstants } from \"../constants.js\";\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n/**\n * Detects whether a global browser `window` object is available.\n * @returns {boolean} `true` if a global `window` object is defined, `false` otherwise.\n */\n\nfunction hasWindow() {\n return typeof window !== \"undefined\";\n}\n\n/**\n * Selects the best available fetch implementation for the current environment.\n * Prefers a `window.fetch` bound to `window` when present, falls back to the global `fetch`, and yields `null` if none exist.\n * @returns {Function|null} The chosen `fetch` function (bound to `window` when applicable), or `null` if no fetch is available.\n */\n/**\n * Decode a base64url-encoded VAPID public key into a byte array for PushManager.\n *\n * Converts a base64url string (RFC 4648 URL-safe alphabet, no padding) into a\n * Uint8Array of raw bytes suitable for use as `applicationServerKey` when\n * subscribing to push notifications.\n *\n * @param {string} base64String - The base64url-encoded VAPID public key.\n * @returns {Uint8Array} The decoded public key as a byte array.\n */\nfunction urlBase64ToUint8Array(base64String) {\n const padding = \"=\".repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, \"+\").replace(/_/g, \"/\");\n const rawData = atob(base64);\n const output = new Uint8Array(rawData.length);\n for (let i = 0; i < rawData.length; i++) {\n output[i] = rawData.charCodeAt(i);\n }\n return output;\n}\n\n/**\n * Create an Error with a machine-readable `code` property.\n * @param {string} code - Short error code identifying the error.\n * @param {string} [message] - Human-readable error message.\n * @returns {Error} The Error instance with its `code` property set.\n */\nfunction createError(code, message) {\n const err = new Error(message);\n err.code = code;\n return err;\n}\n\n// ---------------------------------------------------------------------------\n// PushModule\n// ---------------------------------------------------------------------------\n\nexport class PushModule {\n /**\n * @param {{\n * vapidPublicKey?: string,\n * manualServiceWorkerRegistration?: boolean,\n * serviceWorkerUrl?: string,\n * serviceWorkerScope?: string,\n * serviceWorkerRegistration?: ServiceWorkerRegistration | null,\n * isPushEnabled?: boolean,\n * onRemoteMessageReceived?: ((payload: any) => void) | null,\n * apiKey?: string,\n * apiBase?: string,\n * deviceId?: string,\n * getSessionToken?: (() => string | null) | null,\n * onPushReceived?: ((payload: any) => void) | null,\n * onNotificationClick?: ((payload: any) => void) | null,\n * onSubscriptionChanged?: ((subscription: Object|null) => Promise<void>|void) | null,\n * }} [config]\n */\n constructor(config) {\n const cfg = config ?? {};\n this.vapidPublicKey = cfg.vapidPublicKey ?? null;\n this.manualServiceWorkerRegistration = cfg.manualServiceWorkerRegistration === true;\n this.serviceWorkerUrl = cfg.serviceWorkerUrl ?? LogDropConstants.PUSH_SW_PATH;\n this.serviceWorkerScope = cfg.serviceWorkerScope ?? LogDropConstants.PUSH_SW_SCOPE;\n this.serviceWorkerRegistration = cfg.serviceWorkerRegistration ?? null;\n // Default to enabled so callers that omit the flag still get push; explicit\n // false disables subscribe().\n this.isPushEnabled = cfg.isPushEnabled !== false;\n this.onRemoteMessageReceived =\n typeof cfg.onRemoteMessageReceived === \"function\"\n ? cfg.onRemoteMessageReceived\n : null;\n this.apiKey = cfg.apiKey ?? null;\n this.apiBase = cfg.apiBase ?? \"\";\n this.deviceId = cfg.deviceId ?? null;\n this.getSessionToken = typeof cfg.getSessionToken === \"function\" ? cfg.getSessionToken : null;\n this.onPushReceived = typeof cfg.onPushReceived === \"function\" ? cfg.onPushReceived : null;\n this.onNotificationClick =\n typeof cfg.onNotificationClick === \"function\" ? cfg.onNotificationClick : null;\n this.onSubscriptionChanged =\n typeof cfg.onSubscriptionChanged === \"function\" ? cfg.onSubscriptionChanged : null;\n\n this._messageHandler = null;\n this._installed = false;\n this._tornDown = false;\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n install() {\n if (this._installed || this._tornDown) return;\n if (!hasWindow()) return;\n const sw = this._getServiceWorkerContainer();\n if (!sw || typeof sw.addEventListener !== \"function\") return;\n\n this._messageHandler = (event) => {\n try {\n const data = event && event.data;\n if (!data || typeof data !== \"object\") return;\n if (data.type === \"logdrop:push-received\" && this.onPushReceived) {\n try { this.onPushReceived(data.payload); } catch {}\n } else if (data.type === \"logdrop:notification-click\") {\n if (this.onNotificationClick) {\n try { this.onNotificationClick(data.payload); } catch {}\n } else if (typeof this.onRemoteMessageReceived === \"function\") {\n try { this.onRemoteMessageReceived(data.payload); } catch {}\n }\n }\n } catch {\n // swallow listener errors \u2014 we must not propagate into the SW bridge\n }\n };\n\n sw.addEventListener(\"message\", this._messageHandler);\n this._installed = true;\n }\n\n uninstall() {\n if (!this._installed) {\n this._messageHandler = null;\n return;\n }\n if (hasWindow()) {\n const sw = this._getServiceWorkerContainer();\n if (sw && typeof sw.removeEventListener === \"function\" && this._messageHandler) {\n try {\n sw.removeEventListener(\"message\", this._messageHandler);\n } catch {\n // ignore\n }\n }\n }\n this._messageHandler = null;\n this._installed = false;\n }\n\n teardown() {\n this.uninstall();\n this._tornDown = true;\n }\n\n // -------------------------------------------------------------------------\n // Permission\n // -------------------------------------------------------------------------\n\n getPermissionState() {\n if (typeof Notification === \"undefined\") return \"unsupported\";\n try {\n return Notification.permission ?? \"unsupported\";\n } catch {\n return \"unsupported\";\n }\n }\n\n updateServerConfig({ isPushEnabled, vapidPublicKey } = {}) {\n if (typeof isPushEnabled === \"boolean\") this.isPushEnabled = isPushEnabled;\n if (typeof vapidPublicKey === \"string\" || vapidPublicKey === null) {\n this.vapidPublicKey = vapidPublicKey;\n }\n void this._syncServiceWorkerConfig();\n void this._syncGrantedSubscription();\n }\n\n requestPendingMessages() {\n const sw = this._getServiceWorkerContainer();\n try {\n if (sw?.controller && typeof sw.controller.postMessage === \"function\") {\n sw.controller.postMessage({ type: \"logdrop:drain-pending\" });\n }\n } catch {\n // best effort\n }\n }\n\n // -------------------------------------------------------------------------\n // subscribe()\n // -------------------------------------------------------------------------\n\n async subscribe() {\n if (this._tornDown) {\n throw createError(\n \"TEARDOWN\",\n \"PushModule has been torn down; subscribe() is no longer available\"\n );\n }\n\n // 1. Secure context check (REQ-026)\n if (hasWindow() && window.isSecureContext === false) {\n throw createError(\n \"INSECURE_CONTEXT\",\n \"Push requires a secure context (HTTPS). window.isSecureContext is false.\"\n );\n }\n\n // 2. Feature detection (REQ-015). We intentionally look at the feature\n // that actually matters (navigator.serviceWorker + Notification). The\n // concrete PushManager capability is probed a second time against the\n // registration below, which catches environments that expose\n // navigator.serviceWorker but cannot register push (e.g. iOS Safari\n // without Home-Screen install, tests that explicitly strip pushManager).\n const notificationAvailable = typeof Notification !== \"undefined\";\n const serviceWorkerAvailable =\n typeof navigator !== \"undefined\" && !!navigator.serviceWorker;\n if (!serviceWorkerAvailable || !notificationAvailable) {\n throw createError(\n \"PUSH_UNSUPPORTED\",\n \"Push notifications are not supported in this browser (serviceWorker or Notification API unavailable).\"\n );\n }\n\n // 3. isPushEnabled === false \u2192 no-op (REQ-005)\n if (this.isPushEnabled === false) {\n return null;\n }\n\n // 4. Require vapidPublicKey\n if (!this.vapidPublicKey) {\n throw createError(\n \"MISSING_VAPID_KEY\",\n \"vapidPublicKey is required to subscribe to push notifications\"\n );\n }\n\n // 5. Permission state handling\n const current = this.getPermissionState();\n if (current === \"denied\") {\n throw createError(\n \"PERMISSION_DENIED\",\n \"Notification permission has been denied by the user\"\n );\n }\n if (current === \"default\") {\n const result = await Notification.requestPermission();\n if (result !== \"granted\") {\n throw createError(\n \"PERMISSION_DENIED\",\n \"Notification permission was not granted\"\n );\n }\n } else if (current !== \"granted\") {\n // 'unsupported' or anything unexpected\n throw createError(\n \"PUSH_UNSUPPORTED\",\n `Unsupported Notification.permission state: ${current}`\n );\n }\n\n const sw = this._getServiceWorkerContainer();\n if (!sw) {\n throw createError(\n \"PUSH_UNSUPPORTED\",\n \"navigator.serviceWorker is not available\"\n );\n }\n\n // 6. Acquire registration (REQ-004, REQ-006)\n // register() returns immediately with an installing/waiting registration.\n // pushManager.subscribe() requires an *active* SW, so we always wait for\n // navigator.serviceWorker.ready after registering to get the active one.\n let registration;\n if (this.serviceWorkerRegistration) {\n registration = this.serviceWorkerRegistration;\n } else if (this.manualServiceWorkerRegistration) {\n registration = await sw.ready;\n } else {\n await sw.register(this.serviceWorkerUrl, {\n scope: this.serviceWorkerScope,\n });\n registration = this.serviceWorkerRegistration || await sw.ready;\n }\n\n if (!registration) {\n throw createError(\n \"PUSH_UNSUPPORTED\",\n \"Failed to obtain a service worker registration\"\n );\n }\n\n if (!registration.pushManager) {\n throw createError(\n \"PUSH_UNSUPPORTED\",\n \"ServiceWorkerRegistration.pushManager is not available\"\n );\n }\n\n // 7. Best-effort ping/pong handshake (REQ-007). We fire-and-await with a\n // short timeout so a missing or non-LogDrop SW does not block subscribe.\n await this._handshake(sw, registration);\n\n // 8. Subscribe via PushManager.\n // If a subscription exists with a different VAPID key, unsubscribe it first\n // then retry \u2014 this happens when the dev server restarts (new ephemeral keys).\n const applicationServerKey = urlBase64ToUint8Array(this.vapidPublicKey);\n const existingSubscription = await registration.pushManager.getSubscription();\n const existingApplicationServerKey = existingSubscription?.options?.applicationServerKey;\n if (\n existingSubscription &&\n existingApplicationServerKey &&\n !this._keysEqual(existingApplicationServerKey, applicationServerKey)\n ) {\n await existingSubscription.unsubscribe();\n }\n let subscription;\n try {\n subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey,\n });\n } catch (err) {\n const msg = err && err.message ? err.message : String(err);\n if (msg.includes(\"applicationServerKey\") || msg.includes(\"gcm_sender_id\")) {\n // Stale subscription with different key \u2014 clear it and retry once\n const stale = await registration.pushManager.getSubscription();\n if (stale) await stale.unsubscribe();\n subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey,\n });\n } else {\n throw err;\n }\n }\n\n // 9. POST subscription to backend (REQ-011). Failures here must NOT lose\n // the live subscription; we surface them as errors so callers can retry.\n const subscriptionPayload = typeof subscription.toJSON === \"function\"\n ? subscription.toJSON()\n : subscription;\n if (this.onSubscriptionChanged) {\n await this.onSubscriptionChanged(subscriptionPayload);\n }\n await this._syncServiceWorkerConfig(registration);\n\n return subscription;\n }\n\n // -------------------------------------------------------------------------\n // unsubscribe()\n // -------------------------------------------------------------------------\n\n async unsubscribe() {\n if (this._tornDown) {\n throw createError(\n \"TEARDOWN\",\n \"PushModule has been torn down; unsubscribe() is no longer available\"\n );\n }\n\n const sw = this._getServiceWorkerContainer();\n if (!sw) return null;\n\n let registration;\n try {\n registration = await sw.ready;\n } catch {\n return null;\n }\n\n if (!registration || !registration.pushManager) return null;\n\n let subscription = null;\n try {\n subscription = await registration.pushManager.getSubscription();\n } catch {\n subscription = null;\n }\n\n if (!subscription) return null;\n\n try {\n await subscription.unsubscribe();\n } catch {\n // The push service will eventually invalidate the endpoint. Backend\n // cleanup follows the same provider-rejection flow as mobile tokens.\n }\n\n return null;\n }\n\n // -------------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------------\n\n _getServiceWorkerContainer() {\n if (typeof navigator === \"undefined\") return null;\n return navigator.serviceWorker ?? null;\n }\n\n /**\n * Sends a `logdrop:ping` to the SW and resolves when either a\n * `logdrop:pong` arrives or a 500ms timeout elapses \u2014 whichever comes first.\n */\n _handshake(sw, registration) {\n return new Promise((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n try {\n if (typeof sw.removeEventListener === \"function\") {\n sw.removeEventListener(\"message\", onMessage);\n }\n } catch {\n // ignore\n }\n clearTimeout(timer);\n resolve();\n };\n\n const onMessage = (event) => {\n try {\n const data = event && event.data;\n if (data && data.type === \"logdrop:pong\") {\n finish();\n }\n } catch {\n // ignore\n }\n };\n\n try {\n if (typeof sw.addEventListener === \"function\") {\n sw.addEventListener(\"message\", onMessage);\n }\n } catch {\n // ignore\n }\n\n const timer = setTimeout(finish, 500);\n // Do not keep the event loop alive for the handshake timeout.\n if (timer && typeof timer.unref === \"function\") {\n try { timer.unref(); } catch { /* ignore */ }\n }\n\n try {\n if (registration && registration.active && typeof registration.active.postMessage === \"function\") {\n registration.active.postMessage({ type: \"logdrop:ping\" });\n } else {\n // No active worker to ping \u2014 skip handshake entirely.\n finish();\n }\n } catch {\n finish();\n }\n });\n }\n\n async _syncServiceWorkerConfig(registration = null) {\n const sw = this._getServiceWorkerContainer();\n if (!sw) return;\n let resolvedRegistration = registration || this.serviceWorkerRegistration;\n if (!resolvedRegistration) {\n try { resolvedRegistration = await sw.ready; } catch { return; }\n }\n const target = resolvedRegistration?.active || sw.controller;\n if (!target || typeof target.postMessage !== \"function\") return;\n target.postMessage({\n type: \"logdrop:push-config\",\n config: {\n vapidPublicKey: this.vapidPublicKey,\n apiBase: this.apiBase,\n apiKey: this.apiKey,\n sessionToken: this.getSessionToken ? this.getSessionToken() : null,\n deviceUuid: this.deviceId,\n },\n });\n }\n\n async _syncGrantedSubscription() {\n if (\n this.isPushEnabled !== true ||\n !this.vapidPublicKey ||\n this.getPermissionState() !== \"granted\" ||\n !this.deviceId ||\n !this.getSessionToken?.()\n ) {\n return;\n }\n try {\n await this.subscribe();\n } catch {\n // Existing permission/subscription reconciliation is best effort. A\n // later init or explicit subscribe() call retries without prompting.\n }\n }\n\n reconcileGrantedSubscription() {\n return this._syncGrantedSubscription();\n }\n\n _keysEqual(left, right) {\n const leftBytes = new Uint8Array(left);\n const rightBytes = new Uint8Array(right);\n if (leftBytes.length !== rightBytes.length) return false;\n for (let i = 0; i < leftBytes.length; i++) {\n if (leftBytes[i] !== rightBytes[i]) return false;\n }\n return true;\n }\n\n}\n", "function pushData(payload) {\n if (!payload || typeof payload !== \"object\") return {};\n return payload.data && typeof payload.data === \"object\" ? payload.data : payload;\n}\n\nexport function executeWebPushAction(action) {\n if (!action || String(action.kind || \"\").toUpperCase() !== \"OPEN_DEEPLINK\") return false;\n const target = String(action.target || action.fallbackTarget || \"\").trim();\n if (!target || typeof window === \"undefined\") return false;\n try {\n if (String(action.deeplinkMode || \"\").toUpperCase() === \"EXTERNAL_BROWSER\") {\n window.open(target, \"_blank\", \"noopener,noreferrer\");\n } else {\n window.location.assign(target);\n }\n return true;\n } catch {\n const fallback = String(action.fallbackTarget || \"\").trim();\n if (!fallback || fallback === target) return false;\n try {\n window.location.assign(fallback);\n return true;\n } catch {\n return false;\n }\n }\n}\n\nexport class InAppMessagePresenter {\n constructor({ onAction } = {}) {\n this.onAction = typeof onAction === \"function\" ? onAction : null;\n this.queue = [];\n this.active = null;\n this._visibilityHandler = () => this._showNext();\n if (typeof document !== \"undefined\") {\n document.addEventListener?.(\"visibilitychange\", this._visibilityHandler);\n }\n }\n\n enqueue(payload) {\n const data = pushData(payload);\n if (String(data.messageKind || \"\").toUpperCase() !== \"IN_APP\" ||\n !data.inApp || typeof data.inApp !== \"object\") return false;\n const notificationId = String(data.notificationId || \"\").trim();\n if (notificationId && (this.active?.notificationId === notificationId ||\n this.queue.some((item) => item.notificationId === notificationId))) return false;\n const ttlSeconds = Number(data.inApp.ttlSeconds);\n this.queue.push({\n payload,\n notificationId,\n expiresAt: Number.isFinite(ttlSeconds) && ttlSeconds > 0\n ? Date.now() + ttlSeconds * 1000\n : null,\n });\n this._showNext();\n return true;\n }\n\n teardown() {\n if (typeof document !== \"undefined\") {\n document.removeEventListener?.(\"visibilitychange\", this._visibilityHandler);\n }\n this.queue = [];\n this._finish(false);\n }\n\n _showNext() {\n if (this.active || typeof document === \"undefined\" || !document.body ||\n document.visibilityState === \"hidden\") return;\n while (this.queue.length && this.queue[0].expiresAt && this.queue[0].expiresAt <= Date.now()) {\n this.queue.shift();\n }\n const item = this.queue.shift();\n if (!item) return;\n this.active = { ...item, element: this._render(item) };\n }\n\n _render(item) {\n const data = pushData(item.payload);\n const message = data.inApp;\n const isBanner = String(message.template || \"\").toUpperCase() === \"BANNER\";\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-logdrop-in-app\", \"true\");\n root.setAttribute(\"role\", \"dialog\");\n root.setAttribute(\"aria-modal\", isBanner ? \"false\" : \"true\");\n root.style.cssText = isBanner\n ? `position:fixed;${String(message.position).toUpperCase() === \"BOTTOM\" ? \"bottom\" : \"top\"}:16px;left:50%;transform:translateX(-50%);z-index:2147483646;width:min(560px,calc(100% - 32px));font-family:system-ui,sans-serif`\n : \"position:fixed;inset:0;z-index:2147483646;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(15,23,42,.62);font-family:system-ui,sans-serif\";\n\n const panel = document.createElement(\"div\");\n panel.style.cssText = `position:relative;box-sizing:border-box;width:100%;max-width:${isBanner ? \"560px\" : \"520px\"};${message.isFullHeight === true && !isBanner ? \"height:calc(100vh - 48px);\" : \"max-height:calc(100vh - 48px);\"}overflow:auto;background:#fff;color:#111827;border-radius:14px;padding:20px;box-shadow:0 20px 55px rgba(0,0,0,.3)`;\n\n if (message.dismissible !== false) {\n const close = document.createElement(\"button\");\n close.type = \"button\";\n close.setAttribute(\"aria-label\", \"Close\");\n close.textContent = \"\u00D7\";\n close.style.cssText = \"position:absolute;top:8px;right:10px;border:0;background:transparent;font-size:24px;line-height:1;color:#6b7280;cursor:pointer\";\n close.addEventListener(\"click\", () => this._finish(true), { once: true });\n panel.appendChild(close);\n }\n\n if (message.imageUrl) {\n const image = document.createElement(\"img\");\n image.src = String(message.imageUrl);\n image.alt = \"\";\n image.style.cssText = \"display:block;width:100%;max-height:280px;object-fit:cover;border-radius:10px;margin-bottom:16px\";\n panel.appendChild(image);\n }\n if (message.headline) {\n const title = document.createElement(\"h2\");\n title.textContent = String(message.headline);\n title.style.cssText = \"margin:0 28px 8px 0;font-size:20px;line-height:1.3\";\n panel.appendChild(title);\n }\n if (message.body) {\n const body = document.createElement(\"p\");\n body.textContent = String(message.body);\n body.style.cssText = \"margin:0;color:#4b5563;line-height:1.5;white-space:pre-wrap\";\n panel.appendChild(body);\n }\n\n const buttons = [message.secondaryButton, message.primaryButton].filter((button) => button?.label);\n if (buttons.length) {\n const row = document.createElement(\"div\");\n row.style.cssText = \"display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-top:18px\";\n buttons.forEach((button, index) => {\n const element = document.createElement(\"button\");\n element.type = \"button\";\n element.textContent = String(button.label);\n const primary = index === buttons.length - 1 && message.primaryButton === button;\n element.style.cssText = primary\n ? \"padding:9px 15px;border:0;border-radius:8px;background:#111827;color:#fff;cursor:pointer\"\n : \"padding:9px 15px;border:1px solid #d1d5db;border-radius:8px;background:#fff;color:#111827;cursor:pointer\";\n element.addEventListener(\"click\", () => {\n try { this.onAction?.(item.payload, button.action || null); } catch {}\n executeWebPushAction(button.action);\n this._finish(true);\n }, { once: true });\n row.appendChild(element);\n });\n panel.appendChild(row);\n }\n\n root.appendChild(panel);\n if (!isBanner && message.dismissible !== false) {\n root.addEventListener(\"click\", (event) => {\n if (event.target === root) this._finish(true);\n });\n }\n document.body.appendChild(root);\n return root;\n }\n\n _finish(showNext) {\n if (this.active?.element?.parentNode) this.active.element.parentNode.removeChild(this.active.element);\n this.active = null;\n if (showNext) this._showNext();\n }\n}\n", "// Minimal Protobuf encoder/decoder for LogDrop SDK V2\n// Supports: string, bytes, int64, bool, enum, repeated string, embedded message\n// Wire types: 0 = varint, 2 = length-delimited\n\n// \u2500\u2500\u2500 Writer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ProtoWriter {\n constructor() {\n /** @type {number[]} */\n this._buf = [];\n }\n\n /** Encode a varint (unsigned 64-bit safe up to Number.MAX_SAFE_INTEGER). */\n _writeVarint(value) {\n let v = value >>> 0; // ensure unsigned 32-bit for small values\n if (value <= 0x7f) { this._buf.push(v); return; }\n // Handle values > 32 bits by using BigInt-free manual encoding\n // For SDK purposes values will stay within safe integer range\n while (v > 0x7f) {\n this._buf.push((v & 0x7f) | 0x80);\n v >>>= 7;\n }\n this._buf.push(v);\n }\n\n /** Write a tag (field number + wire type). */\n _writeTag(fieldNumber, wireType) {\n this._writeVarint((fieldNumber << 3) | wireType);\n }\n\n /** Write a string field (wire type 2). Skips if empty (proto3 default). */\n writeString(fieldNumber, value) {\n if (!value) return;\n const bytes = new TextEncoder().encode(value);\n this._writeTag(fieldNumber, 2);\n this._writeVarint(bytes.length);\n for (let i = 0; i < bytes.length; i++) this._buf.push(bytes[i]);\n }\n\n /** Write a bytes field (wire type 2). Skips if empty. */\n writeBytes(fieldNumber, value) {\n if (!value || value.length === 0) return;\n this._writeTag(fieldNumber, 2);\n this._writeVarint(value.length);\n for (let i = 0; i < value.length; i++) this._buf.push(value[i]);\n }\n\n /** Write an int64 / int32 field as varint (wire type 0). Skips if 0 (proto3 default). */\n writeInt64(fieldNumber, value) {\n if (!value) return;\n this._writeTag(fieldNumber, 0);\n this._writeVarint(value);\n }\n\n /**\n * Encode a varint for values that may exceed 32 bits (up to\n * Number.MAX_SAFE_INTEGER). The base `_writeVarint` truncates via `>>> 0`,\n * so it must not be used for large numbers such as millisecond timestamps.\n */\n _writeVarintLong(value) {\n let v = Math.floor(value);\n while (v > 0x7f) {\n this._buf.push((v % 128) | 0x80);\n v = Math.floor(v / 128);\n }\n this._buf.push(v % 128);\n }\n\n /** Write an int64 field that may exceed 32 bits (wire type 0). Skips if 0. */\n writeInt64Long(fieldNumber, value) {\n if (!value) return;\n this._writeTag(fieldNumber, 0);\n this._writeVarintLong(value);\n }\n\n /** Write a double field (wire type 1, fixed 64-bit little-endian IEEE-754). */\n writeDouble(fieldNumber, value) {\n this._writeTag(fieldNumber, 1);\n const buf = new ArrayBuffer(8);\n new DataView(buf).setFloat64(0, value, true);\n const bytes = new Uint8Array(buf);\n for (let i = 0; i < 8; i++) this._buf.push(bytes[i]);\n }\n\n /** Write a raw length-delimited string, even when empty (bypasses proto3 default skip). */\n writeStringForce(fieldNumber, value) {\n const bytes = new TextEncoder().encode(value ?? \"\");\n this._writeTag(fieldNumber, 2);\n this._writeVarint(bytes.length);\n for (let i = 0; i < bytes.length; i++) this._buf.push(bytes[i]);\n }\n\n /** Write a bool, even when false (bypasses proto3 default skip). */\n writeBoolForce(fieldNumber, value) {\n this._writeTag(fieldNumber, 0);\n this._buf.push(value ? 1 : 0);\n }\n\n /** Write a bool field (wire type 0). Skips if false (proto3 default). */\n writeBool(fieldNumber, value) {\n if (!value) return;\n this._writeTag(fieldNumber, 0);\n this._buf.push(1);\n }\n\n /** Write an enum field (wire type 0). Skips if 0 (proto3 default). */\n writeEnum(fieldNumber, value) {\n this.writeInt64(fieldNumber, value);\n }\n\n /** Write a repeated string field. */\n writeRepeatedString(fieldNumber, values) {\n if (!values || !values.length) return;\n for (const v of values) {\n this.writeString(fieldNumber, v);\n }\n }\n\n /** Write an embedded message field (wire type 2). */\n writeMessage(fieldNumber, writerFn) {\n const sub = new ProtoWriter();\n writerFn(sub);\n const bytes = sub.finish();\n if (bytes.length === 0) return; // skip empty sub-messages\n this._writeTag(fieldNumber, 2);\n this._writeVarint(bytes.length);\n for (let i = 0; i < bytes.length; i++) this._buf.push(bytes[i]);\n }\n\n /** Return the finished Uint8Array. */\n finish() {\n return new Uint8Array(this._buf);\n }\n}\n\n// \u2500\u2500\u2500 Reader \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ProtoReader {\n /**\n * @param {Uint8Array} buf\n */\n constructor(buf) {\n this._buf = buf;\n this._pos = 0;\n }\n\n /** Are there more bytes to read? */\n hasMore() {\n return this._pos < this._buf.length;\n }\n\n /** Read a varint and return as a JS number (safe for values < 2^53). */\n _readVarint() {\n let result = 0;\n let shift = 0;\n while (this._pos < this._buf.length) {\n const byte = this._buf[this._pos++];\n result |= (byte & 0x7f) << shift;\n if ((byte & 0x80) === 0) return result >>> 0;\n shift += 7;\n if (shift > 35) {\n // For >32-bit values, just skip to end of varint\n while (this._pos < this._buf.length && (this._buf[this._pos++] & 0x80) !== 0) { }\n return result >>> 0;\n }\n }\n return result >>> 0;\n }\n\n /** Read a tag and return { fieldNumber, wireType }. */\n readTag() {\n if (!this.hasMore()) return null;\n const v = this._readVarint();\n return { fieldNumber: v >>> 3, wireType: v & 0x07 };\n }\n\n /** Read a length-delimited field and return as Uint8Array. */\n readBytes() {\n const startPos = this._pos;\n const len = this._readVarint();\n\n if (!Number.isInteger(len) || len < 0 || this._pos + len > this._buf.length) {\n this._pos = startPos;\n throw new Error(\"Unexpected end of buffer in readBytes\");\n }\n\n const slice = this._buf.slice(this._pos, this._pos + len);\n this._pos += len;\n return slice;\n }\n\n /** Read a length-delimited field and return as string. */\n readString() {\n const bytes = this.readBytes();\n return new TextDecoder().decode(bytes);\n }\n\n /** Read a varint field and return as number. */\n readVarint() {\n return this._readVarint();\n }\n\n /**\n * Read a varint that may exceed 32 bits (up to Number.MAX_SAFE_INTEGER),\n * using multiplication instead of bit-shifting to avoid 32-bit truncation.\n */\n readVarintLong() {\n let result = 0;\n let multiplier = 1;\n while (this._pos < this._buf.length) {\n const byte = this._buf[this._pos++];\n result += (byte & 0x7f) * multiplier;\n if ((byte & 0x80) === 0) break;\n multiplier *= 128;\n }\n return result;\n }\n\n /** Read a fixed 64-bit little-endian IEEE-754 double (wire type 1). */\n readDouble() {\n if (this._pos + 8 > this._buf.length) {\n throw new Error(\"Unexpected end of buffer in readDouble\");\n }\n const dv = new DataView(this._buf.buffer, this._buf.byteOffset + this._pos, 8);\n const val = dv.getFloat64(0, true);\n this._pos += 8;\n return val;\n }\n\n /** Read a bool field. */\n readBool() {\n return this._readVarint() !== 0;\n }\n\n /** Skip a field based on wireType. */\n skip(wireType) {\n switch (wireType) {\n case 0: // varint\n this._readVarint();\n break;\n case 1: // 64-bit\n if (this._pos + 8 > this._buf.length) {\n throw new Error(\"Unexpected end of buffer while skipping 64-bit field\");\n }\n this._pos += 8;\n break;\n case 2: // length-delimited\n {\n const len = this._readVarint();\n if (!Number.isInteger(len) || len < 0 || this._pos + len > this._buf.length) {\n throw new Error(\"Unexpected end of buffer while skipping length-delimited field\");\n }\n this._pos += len;\n }\n break;\n case 5: // 32-bit\n if (this._pos + 4 > this._buf.length) {\n throw new Error(\"Unexpected end of buffer while skipping 32-bit field\");\n }\n this._pos += 4;\n break;\n default:\n throw new Error(`Unknown wire type: ${wireType}`);\n }\n }\n}\n\n// \u2500\u2500\u2500 Message Encoders \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Encode a Device message into the provided ProtoWriter.\n *\n * Writes the following string fields when present:\n * 1: deviceUuid\n * 3: iosApnsDeviceToken\n * 4: androidFirebaseToken\n * 5: huaweiToken\n * 6: osName\n * 7: osVersion\n * 8: deviceBrand\n * 9: deviceModel\n * 10: appVersion\n * 11: sdkVersion\n * 12: sdkType\n * 13: bridgeSdkType\n * 14: customAttributes\n * 15: removedCustomAttributeKeys\n * 16: webPushSubscription\n *\n * @param {ProtoWriter} w - The ProtoWriter to write bytes into.\n * @param {Object} device - Object containing device fields (see list above).\n */\nfunction encodeDevice(w, device) {\n w.writeString(1, device.deviceUuid);\n w.writeString(3, device.iosApnsDeviceToken);\n w.writeString(4, device.androidFirebaseToken);\n w.writeString(5, device.huaweiToken);\n w.writeString(6, device.osName);\n w.writeString(7, device.osVersion);\n w.writeString(8, device.deviceBrand);\n w.writeString(9, device.deviceModel);\n w.writeString(10, device.appVersion);\n w.writeString(11, device.sdkVersion);\n w.writeString(12, device.sdkType);\n w.writeString(13, device.bridgeSdkType);\n for (const [key, value] of Object.entries(device.customAttributes || {})) {\n w.writeMessage(14, (entry) => {\n entry.writeString(1, key);\n entry.writeString(2, value);\n });\n }\n for (const key of device.removedCustomAttributeKeys || []) {\n w.writeString(15, key);\n }\n if (device.webPushSubscription) {\n w.writeMessage(16, (sub) => {\n sub.writeString(1, device.webPushSubscription.endpoint);\n sub.writeString(2, device.webPushSubscription.p256dh);\n sub.writeString(3, device.webPushSubscription.auth);\n sub.writeInt64Long(4, device.webPushSubscription.expirationTime);\n });\n }\n}\n\n/**\n * Serialize a UserUpdateRequest into protobuf binary.\n * @param {{ userUuid: string, device?: Object }} req - Request object containing `userUuid` and an optional `device` (encoded as a nested Device message when present).\n * @returns {Uint8Array} The protobuf-encoded bytes for the UserUpdateRequest.\n */\nexport function encodeUserUpdateRequest(req) {\n const w = new ProtoWriter();\n w.writeString(1, req.userUuid);\n if (req.device) {\n w.writeMessage(2, (sub) => encodeDevice(sub, req.device));\n }\n return w.finish();\n}\n\n/**\n * Decode an SdkTokenResponse protobuf message from the provided bytes.\n * @param {Uint8Array} buf - The encoded SdkTokenResponse message.\n * @returns {{ accessToken: string, refreshToken: string }} Object with `accessToken` and `refreshToken` decoded from the message.\n */\nexport function decodeSdkTokenResponse(buf) {\n const r = new ProtoReader(buf);\n const result = { accessToken: \"\", refreshToken: \"\" };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: result.accessToken = r.readString(); break;\n case 2: result.refreshToken = r.readString(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Encode an InitRequest protobuf message.\n * @param {{ refreshToken?: string, deviceUuid: string }} req - Request fields where `refreshToken` is optional and `deviceUuid` is the device identifier.\n * @returns {Uint8Array} The serialized InitRequest message.\n */\nexport function encodeInitRequest(req) {\n const w = new ProtoWriter();\n w.writeString(2, req.refreshToken);\n w.writeString(3, req.deviceUuid);\n return w.finish();\n}\n\nfunction readOptionalString(value) {\n return value ? value : null;\n}\n\nfunction decodeHttpWhitelistEntry(buf) {\n const r = new ProtoReader(buf);\n const result = { domain: \"\", path: null };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.domain = r.readString(); break;\n case 2: result.path = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeSdkRiskActionConfig(buf) {\n const r = new ProtoReader(buf);\n const result = {\n showPopupEnabled: false,\n appBlockEnabled: false,\n networkBlockEnabled: false,\n blockedRequestPaths: [],\n blockedDomains: [],\n title: null,\n message: null,\n buttonText: null,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.showPopupEnabled = r.readBool(); break;\n case 2: result.appBlockEnabled = r.readBool(); break;\n case 3: result.networkBlockEnabled = r.readBool(); break;\n case 4: result.blockedRequestPaths.push(r.readString()); break;\n case 5: result.blockedDomains.push(r.readString()); break;\n case 6: result.title = readOptionalString(r.readString()); break;\n case 7: result.message = readOptionalString(r.readString()); break;\n case 8: result.buttonText = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeHttpWhitelistRiskConfig(buf) {\n const r = new ProtoReader(buf);\n const result = {\n enabled: false,\n whitelist: [],\n actions: decodeSdkRiskActionConfig(new Uint8Array()),\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.enabled = r.readBool(); break;\n case 2: result.whitelist.push(decodeHttpWhitelistEntry(r.readBytes())); break;\n case 3: result.actions = decodeSdkRiskActionConfig(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeRiskPolicyRule(buf) {\n const r = new ProtoReader(buf);\n const result = {\n enabled: false,\n priority: 0,\n matchType: \"ANY\",\n eventIds: [],\n actionIds: [],\n message: null,\n title: null,\n buttonText: null,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.enabled = r.readBool(); break;\n case 2: result.priority = r.readVarint(); break;\n case 3: result.matchType = r.readVarint() === 1 ? \"ALL\" : \"ANY\"; break;\n case 4:\n if (tag.wireType === 2) result.eventIds.push(...decodePackedVarints(r.readBytes()));\n else result.eventIds.push(r.readVarint());\n break;\n case 5:\n if (tag.wireType === 2) result.actionIds.push(...decodePackedVarints(r.readBytes()));\n else result.actionIds.push(r.readVarint());\n break;\n case 6: result.message = readOptionalString(r.readString()); break;\n case 7: result.title = readOptionalString(r.readString()); break;\n case 8: result.buttonText = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodePackedVarints(buf) {\n const r = new ProtoReader(buf);\n const values = [];\n while (r.hasMore()) values.push(r.readVarint());\n return values;\n}\n\nfunction decodeRiskPolicy(buf) {\n const r = new ProtoReader(buf);\n const result = { version: 0, rules: [] };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.version = r.readVarint(); break;\n case 2: result.rules.push(decodeRiskPolicyRule(r.readBytes())); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeRiskDetectedConfig(buf) {\n const r = new ProtoReader(buf);\n const result = {\n riskPolicy: { version: 0, rules: [] },\n enabled: false,\n botDetectionEnabled: false,\n otherRiskTypesEnabled: false,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.riskPolicy = decodeRiskPolicy(r.readBytes()); break;\n case 2: result.enabled = r.readBool(); break;\n case 3: result.botDetectionEnabled = r.readBool(); break;\n case 4: result.otherRiskTypesEnabled = r.readBool(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction ipReputationThreatLevelName(value) {\n switch (value) {\n case 1: return \"MEDIUM\";\n case 2: return \"HIGH\";\n case 3: return \"CRITICAL\";\n default: return \"UNSPECIFIED\";\n }\n}\n\nfunction decodeIpReputationPolicyRule(buf) {\n const r = new ProtoReader(buf);\n const result = {\n enabled: false,\n priority: 0,\n threatLevels: [],\n actionIds: [],\n message: null,\n title: null,\n buttonText: null,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.enabled = r.readBool(); break;\n case 2: result.priority = r.readVarint(); break;\n case 3: {\n const values = tag.wireType === 2 ? decodePackedVarints(r.readBytes()) : [r.readVarint()];\n result.threatLevels.push(...values.map(ipReputationThreatLevelName));\n break;\n }\n case 4:\n if (tag.wireType === 2) result.actionIds.push(...decodePackedVarints(r.readBytes()));\n else result.actionIds.push(r.readVarint());\n break;\n case 5: result.message = readOptionalString(r.readString()); break;\n case 6: result.title = readOptionalString(r.readString()); break;\n case 7: result.buttonText = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeIpReputationPolicy(buf) {\n const r = new ProtoReader(buf);\n const result = { version: 0, rules: [] };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.version = r.readVarint(); break;\n case 2: result.rules.push(decodeIpReputationPolicyRule(r.readBytes())); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeIpReputationDetectedConfig(buf) {\n const r = new ProtoReader(buf);\n const result = { riskPolicy: { version: 0, rules: [] } };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.riskPolicy = decodeIpReputationPolicy(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeIpReputationActiveAction(buf) {\n const r = new ProtoReader(buf);\n const result = {\n signature: \"\",\n eventId: \"\",\n threatLevel: \"UNSPECIFIED\",\n riskScore: 0,\n actionIds: [],\n expireAtEpochMillis: 0,\n message: null,\n title: null,\n buttonText: null,\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.signature = r.readString(); break;\n case 2: result.eventId = r.readString(); break;\n case 3: result.threatLevel = ipReputationThreatLevelName(r.readVarint()); break;\n case 4: result.riskScore = r.readVarint(); break;\n case 5:\n if (tag.wireType === 2) result.actionIds.push(...decodePackedVarints(r.readBytes()));\n else result.actionIds.push(r.readVarint());\n break;\n case 6: result.expireAtEpochMillis = r.readVarintLong(); break;\n case 7: result.message = readOptionalString(r.readString()); break;\n case 8: result.title = readOptionalString(r.readString()); break;\n case 9: result.buttonText = readOptionalString(r.readString()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeWebPushConfig(buf) {\n const r = new ProtoReader(buf);\n const result = { enabled: false, vapidPublicKey: \"\" };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.enabled = r.readBool(); break;\n case 2: result.vapidPublicKey = r.readString(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\nfunction decodeSdkRiskConfig(buf) {\n const r = new ProtoReader(buf);\n const result = {\n httpWhitelist: decodeHttpWhitelistRiskConfig(new Uint8Array()),\n riskDetected: decodeRiskDetectedConfig(new Uint8Array()),\n ipReputationDetected: decodeIpReputationDetectedConfig(new Uint8Array()),\n };\n while (r.hasMore()) {\n const tag = r.readTag();\n switch (tag.fieldNumber) {\n case 1: result.httpWhitelist = decodeHttpWhitelistRiskConfig(r.readBytes()); break;\n case 2: result.riskDetected = decodeRiskDetectedConfig(r.readBytes()); break;\n case 3: result.ipReputationDetected = decodeIpReputationDetectedConfig(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Parse a ConfigResponse protobuf message into a plain JavaScript object.\n * @param {Uint8Array} buf - Protobuf-encoded ConfigResponse bytes.\n * @returns {Object} An object with the following properties:\n * - perUserMaxFileSizeLimitInBytes {number}\n * - perUserMinFileSizeLimitInBytes {number}\n * - databaseMaxStorageLimitInBytes {number}\n * - isSDKDisabled {boolean}\n * - isHttpLoggingEnabled {boolean}\n * - isCrashTrackingEnabled {boolean}\n * - httpDomainBlackList {string[]}\n * - sensitiveInfoFilter {string[]}\n * - sslPinning {null}\n * - accessToken {string}\n * - limitType {number} \u2014 0 = DAILY, 1 = MONTHLY\n * - riskConfig {Object|null}\n * - activeIpReputationAction {Object|null}\n * - serverNowEpochMillis {number}\n */\nexport function decodeConfigResponse(buf) {\n const r = new ProtoReader(buf);\n const result = {\n perUserMaxFileSizeLimitInBytes: 0,\n perUserMinFileSizeLimitInBytes: 0,\n databaseMaxStorageLimitInBytes: 0,\n isSDKDisabled: false,\n isHttpLoggingEnabled: false,\n isCrashTrackingEnabled: false,\n isEventTrackingEnabled: false,\n httpDomainBlackList: [],\n sensitiveInfoFilter: [],\n sslPinning: null,\n accessToken: \"\",\n limitType: 0, // DAILY=0, MONTHLY=1\n riskConfig: null,\n activeIpReputationAction: null,\n serverNowEpochMillis: 0,\n webPushConfig: { enabled: false, vapidPublicKey: \"\" }\n };\n\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: result.perUserMaxFileSizeLimitInBytes = r.readVarintLong(); break;\n case 2: result.perUserMinFileSizeLimitInBytes = r.readVarintLong(); break;\n case 3: result.databaseMaxStorageLimitInBytes = r.readVarintLong(); break;\n case 4: result.isSDKDisabled = r.readBool(); break;\n case 5: result.isHttpLoggingEnabled = r.readBool(); break;\n case 6: result.isCrashTrackingEnabled = r.readBool(); break;\n case 7: result.httpDomainBlackList.push(r.readString()); break;\n case 8: result.sensitiveInfoFilter.push(r.readString()); break;\n case 9: r.skip(tag.wireType); break; // SslPinningConfig - skip for web\n case 10: result.accessToken = r.readString(); break;\n case 11: result.limitType = r.readVarint(); break;\n case 12: result.riskConfig = decodeSdkRiskConfig(r.readBytes()); break;\n case 13: result.activeIpReputationAction = decodeIpReputationActiveAction(r.readBytes()); break;\n case 14: result.serverNowEpochMillis = r.readVarintLong(); break;\n case 15: result.isEventTrackingEnabled = r.readBool(); break;\n case 18: result.webPushConfig = decodeWebPushConfig(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Encode a LogRequest message to Protocol Buffers binary.\n *\n * Writes the following fields when present:\n * - field 1: content (bytes)\n * - field 2: deviceUuid (string)\n * - field 4: appVersion (string)\n * - field 5: sdkVersion (string)\n * - field 6: osVersion (string)\n * - field 7: errorCount (string)\n * - field 8: firstRealUserUuid (string)\n * - field 9: uploadId (string)\n * (field 3 is intentionally omitted)\n * @param {{ content: Uint8Array, deviceUuid: string, appVersion?: string, sdkVersion?: string, osVersion?: string, errorCount?: string, firstRealUserUuid?: string, uploadId?: string }} req - Log request payload\n * @returns {Uint8Array} The encoded protobuf message\n */\nexport function encodeLogRequest(req) {\n const w = new ProtoWriter();\n w.writeBytes(1, req.content);\n w.writeString(2, req.deviceUuid);\n // field 3 is skipped in proto (no field 3)\n w.writeString(4, req.appVersion);\n w.writeString(5, req.sdkVersion);\n w.writeString(6, req.osVersion);\n w.writeString(7, req.errorCount);\n w.writeString(8, req.firstRealUserUuid);\n w.writeString(9, req.uploadId);\n return w.finish();\n}\n\n/**\n * Parse a LogResponse protobuf and extract the remaining limit.\n * @param {Uint8Array} buf - The encoded LogResponse message.\n * @returns {{ remainingLimit: number }} An object with `remainingLimit` parsed from the message.\n */\nexport function decodeLogResponse(buf) {\n const r = new ProtoReader(buf);\n const result = { remainingLimit: 0 };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: result.remainingLimit = r.readVarint(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Encode a CrashReportRequest message to protobuf binary format.\n *\n * @param {{ content: Uint8Array, deviceUuid: string, sdkVersion?: string }} req - Request object containing crash report data.\n * - content: Raw crash report payload as bytes.\n * - deviceUuid: Device identifier string.\n * - sdkVersion: Optional SDK version string.\n * @returns {Uint8Array} The serialized CrashReportRequest as a Uint8Array.\n */\nexport function encodeCrashReportRequest(req) {\n const w = new ProtoWriter();\n w.writeBytes(1, req.content);\n w.writeString(2, req.deviceUuid);\n // field 3 is skipped in proto (no field 3)\n w.writeString(4, req.sdkVersion);\n return w.finish();\n}\n\n// \u2500\u2500\u2500 google.protobuf.Struct \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Encodes an arbitrary JSON-serializable object as a google.protobuf.Struct so it\n// can be used for the EventItem.properties field.\n//\n// Struct { map<string, Value> fields = 1; }\n// Value { oneof kind { NullValue null_value=1; double number_value=2;\n// string string_value=3; bool bool_value=4;\n// Struct struct_value=5; ListValue list_value=6; } }\n// ListValue { repeated Value values = 1; }\n\n/**\n * Encode a single google.protobuf.Value into the provided writer.\n * @param {ProtoWriter} w - Writer positioned inside a Value message.\n * @param {*} value - Any JSON-serializable value.\n */\nfunction encodeStructValue(w, value) {\n if (value === null || value === undefined) {\n // null_value = 0 (field 1). Force-write so the value is unambiguous.\n w._writeTag(1, 0);\n w._writeVarint(0);\n return;\n }\n const t = typeof value;\n if (t === \"number\") {\n if (Number.isFinite(value)) {\n w.writeDouble(2, value);\n } else {\n w._writeTag(1, 0);\n w._writeVarint(0);\n }\n return;\n }\n if (t === \"boolean\") {\n w.writeBoolForce(4, value);\n return;\n }\n if (t === \"string\") {\n w.writeStringForce(3, value);\n return;\n }\n if (Array.isArray(value)) {\n // list_value (field 6) = ListValue { repeated Value values = 1; }\n w.writeMessage(6, (lw) => {\n for (const item of value) {\n lw.writeMessage(1, (vw) => encodeStructValue(vw, item));\n }\n });\n return;\n }\n if (t === \"object\") {\n // struct_value (field 5) = Struct\n w.writeMessage(5, (sw) => encodeStruct(sw, value));\n return;\n }\n // Fallback: coerce to string\n w.writeStringForce(3, String(value));\n}\n\n/**\n * Encode a plain object as a google.protobuf.Struct into the provided writer.\n * @param {ProtoWriter} w - Writer positioned inside a Struct message.\n * @param {Object} obj - Object whose enumerable keys become Struct fields.\n */\nfunction encodeStruct(w, obj) {\n for (const key of Object.keys(obj)) {\n // Each map<string,Value> entry is a message: key (1, string), value (2, Value).\n w.writeMessage(1, (entry) => {\n entry.writeStringForce(1, key);\n entry.writeMessage(2, (vw) => encodeStructValue(vw, obj[key]));\n });\n }\n}\n\n// \u2500\u2500\u2500 EventBatchRequest \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Encode an EventItem message.\n * @param {ProtoWriter} w\n * @param {{ eventId: string, eventCode: string, timestamp: number, properties?: Object }} evt\n */\nfunction encodeEventItem(w, evt) {\n w.writeString(1, evt.eventId);\n w.writeString(2, evt.eventCode);\n w.writeInt64Long(3, evt.timestamp);\n if (evt.properties && typeof evt.properties === \"object\" && Object.keys(evt.properties).length > 0) {\n w.writeMessage(4, (pw) => encodeStruct(pw, evt.properties));\n }\n}\n\n/**\n * Encode an EventSession message.\n * @param {ProtoWriter} w\n * @param {{ sessionId: string, userUuid?: string, events?: Array }} session\n */\nfunction encodeEventSession(w, session) {\n w.writeString(1, session.sessionId);\n w.writeString(2, session.userUuid);\n if (Array.isArray(session.events)) {\n for (const evt of session.events) {\n w.writeMessage(3, (ew) => encodeEventItem(ew, evt));\n }\n }\n}\n\n/**\n * Serialize an EventBatchRequest into protobuf binary.\n * @param {{ deviceUuid: string, sessions?: Array, firstRealUserUuid?: string, uploadId?: string }} req\n * @returns {Uint8Array} The encoded protobuf message.\n */\nexport function encodeEventBatchRequest(req) {\n const w = new ProtoWriter();\n w.writeString(1, req.deviceUuid);\n if (Array.isArray(req.sessions)) {\n for (const session of req.sessions) {\n w.writeMessage(2, (sw) => encodeEventSession(sw, session));\n }\n }\n w.writeString(3, req.firstRealUserUuid);\n w.writeString(4, req.uploadId);\n return w.finish();\n}\n\n/**\n * Decode an EventBatchResponse protobuf message.\n * @param {Uint8Array} buf - The encoded EventBatchResponse message.\n * @returns {{ count: number }} Object with `count` parsed from the message.\n */\nexport function decodeEventBatchResponse(buf) {\n const r = new ProtoReader(buf);\n const result = { count: 0 };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: result.count = r.readVarint(); break;\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n// \u2500\u2500\u2500 EventBatchRequest / Struct decoders (round-trip / testing) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Decode a google.protobuf.Value message into a JS value.\n * @param {Uint8Array} buf\n * @returns {*}\n */\nfunction decodeStructValue(buf) {\n const r = new ProtoReader(buf);\n let result = null;\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: r.readVarint(); result = null; break; // null_value\n case 2: result = r.readDouble(); break; // number_value\n case 3: result = r.readString(); break; // string_value\n case 4: result = r.readBool(); break; // bool_value\n case 5: result = decodeStruct(r.readBytes()); break; // struct_value\n case 6: result = decodeStructList(r.readBytes()); break; // list_value\n default: r.skip(tag.wireType);\n }\n }\n return result;\n}\n\n/**\n * Decode a google.protobuf.ListValue into a JS array.\n * @param {Uint8Array} buf\n * @returns {Array}\n */\nfunction decodeStructList(buf) {\n const r = new ProtoReader(buf);\n const arr = [];\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n if (tag.fieldNumber === 1) arr.push(decodeStructValue(r.readBytes()));\n else r.skip(tag.wireType);\n }\n return arr;\n}\n\n/**\n * Decode a google.protobuf.Struct into a plain JS object.\n * @param {Uint8Array} buf\n * @returns {Object}\n */\nfunction decodeStruct(buf) {\n const r = new ProtoReader(buf);\n const obj = {};\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n if (tag.fieldNumber === 1) {\n const entry = new ProtoReader(r.readBytes());\n let key = \"\";\n let value = null;\n while (entry.hasMore()) {\n const et = entry.readTag();\n if (!et) break;\n if (et.fieldNumber === 1) key = entry.readString();\n else if (et.fieldNumber === 2) value = decodeStructValue(entry.readBytes());\n else entry.skip(et.wireType);\n }\n obj[key] = value;\n } else {\n r.skip(tag.wireType);\n }\n }\n return obj;\n}\n\nfunction decodeEventItem(buf) {\n const r = new ProtoReader(buf);\n const item = { eventId: \"\", eventCode: \"\", timestamp: 0, properties: {} };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: item.eventId = r.readString(); break;\n case 2: item.eventCode = r.readString(); break;\n case 3: item.timestamp = r.readVarintLong(); break;\n case 4: item.properties = decodeStruct(r.readBytes()); break;\n default: r.skip(tag.wireType);\n }\n }\n return item;\n}\n\nfunction decodeEventSession(buf) {\n const r = new ProtoReader(buf);\n const session = { sessionId: \"\", userUuid: \"\", events: [] };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: session.sessionId = r.readString(); break;\n case 2: session.userUuid = r.readString(); break;\n case 3: session.events.push(decodeEventItem(r.readBytes())); break;\n default: r.skip(tag.wireType);\n }\n }\n return session;\n}\n\n/**\n * Decode an EventBatchRequest protobuf message into a plain JS object.\n * @param {Uint8Array} buf\n * @returns {{ deviceUuid: string, sessions: Array, firstRealUserUuid: string, uploadId: string }}\n */\nexport function decodeEventBatchRequest(buf) {\n const r = new ProtoReader(buf);\n const req = { deviceUuid: \"\", sessions: [], firstRealUserUuid: \"\", uploadId: \"\" };\n while (r.hasMore()) {\n const tag = r.readTag();\n if (!tag) break;\n switch (tag.fieldNumber) {\n case 1: req.deviceUuid = r.readString(); break;\n case 2: req.sessions.push(decodeEventSession(r.readBytes())); break;\n case 3: req.firstRealUserUuid = r.readString(); break;\n case 4: req.uploadId = r.readString(); break;\n default: r.skip(tag.wireType);\n }\n }\n return req;\n}\n", "// LogDrop EventModule \u2014 internal event tracking\n// Mirrors the lifecycle pattern used by PushModule\n// (constructor config slice, install() / uninstall() / teardown()).\n//\n// Listener coexistence note (REQ-032):\n// This module registers its own visibilitychange and pagehide handlers\n// on document and window respectively. The DOM event model supports\n// multiple listeners per event, so these coexist safely with any other\n// handlers registered on the same DOM events.\n\nimport { LogDropConstants } from \"../constants.js\";\nimport { encodeEventBatchRequest, decodeEventBatchResponse } from \"../protobuf.js\";\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n/**\n * Detects whether a global `window` object is available in the current environment.\n * @returns {boolean} `true` if `window` is defined in the current environment, `false` otherwise.\n */\n\nfunction hasWindow() {\n return typeof window !== \"undefined\";\n}\n\n/**\n * Selects the most appropriate global fetch implementation available in the current environment.\n *\n * Prefers `window.fetch` (bound to `window`) when present so code that stubs `window.fetch` is respected, and otherwise falls back to the global `fetch`.\n * @returns {Function|null} The chosen `fetch` function (with `window.fetch` bound to `window` when used), or `null` if no fetch implementation is available.\n */\nfunction getFetch() {\n if (hasWindow() && typeof window.fetch === \"function\") {\n return window.fetch.bind(window);\n }\n if (typeof fetch === \"function\") {\n return fetch;\n }\n return null;\n}\n\n/**\n * Create a UUID v4 string in dashed format.\n * @returns {string} A UUID v4 formatted string (e.g. `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`). When the Web Crypto API is available the value is produced via `crypto.randomUUID()`, otherwise a Math.random()-based fallback is used.\n */\nfunction generateEventId() {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback\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\n/**\n * Determine whether the browser Navigation API is present and supports event listeners.\n * @returns {boolean} `true` if the global `navigation` object exists and has an `addEventListener` function, `false` otherwise.\n */\nfunction hasNavigationApi() {\n return (\n typeof navigation !== \"undefined\" &&\n typeof navigation.addEventListener === \"function\"\n );\n}\n\n// ---------------------------------------------------------------------------\n// EventModule\n// ---------------------------------------------------------------------------\n\nexport class EventModule {\n /**\n * @param {{\n * deviceId: string,\n * getSessionId: () => string,\n * getUserUuid: () => string|null,\n * release: string|undefined,\n * apiKey: string,\n * apiBase: string,\n * isEventTrackingEnabled: boolean,\n * isFirstVisit: boolean,\n * isSdkUpdated: boolean,\n * previousRelease: string|null,\n * }} config\n */\n constructor(config) {\n const cfg = config ?? {};\n this._deviceId = cfg.deviceId ?? \"\";\n this._getSessionId = typeof cfg.getSessionId === \"function\" ? cfg.getSessionId : () => \"\";\n this._getUserUuid = typeof cfg.getUserUuid === \"function\" ? cfg.getUserUuid : () => null;\n // Resolves the first *real* (identified) user uuid. Returns null while the\n // user is anonymous so first_real_user_uuid stays empty (spec: optional).\n this._getRealUserUuid = typeof cfg.getRealUserUuid === \"function\" ? cfg.getRealUserUuid : () => null;\n // Called for each event after a successful send so the host client can mirror\n // it into the log stream at EVENT level. No-op when not provided.\n this._logEvent = typeof cfg.logEvent === \"function\" ? cfg.logEvent : null;\n // Resolves the per-session access token required by the events/collect\n // endpoint (server rejects requests without x-session-token \u2192 400).\n this._getSessionToken = typeof cfg.getSessionToken === \"function\" ? cfg.getSessionToken : null;\n this._release = cfg.release ?? undefined;\n this._apiKey = cfg.apiKey ?? \"\";\n this._apiBase = cfg.apiBase ?? \"\";\n this._isEventTrackingEnabled = cfg.isEventTrackingEnabled === true;\n this._isFirstVisit = cfg.isFirstVisit === true;\n this._isSdkUpdated = cfg.isSdkUpdated === true;\n this._previousRelease = cfg.previousRelease ?? null;\n this._dbPromise = cfg.dbPromise ?? null;\n\n this._eventQueue = [];\n this._eventPersistPromises = new Set();\n this._activeMemoryBatch = null;\n this._eventFlushInProgress = false;\n this._installed = false;\n this._tornDown = false;\n\n // Listener references (REQ-033)\n this._visibilityHandler = null;\n this._pageHideHandler = null;\n this._navigateHandler = null;\n this._popstateHandler = null;\n\n // For pushState/replaceState fallback restoration\n this._originalPushState = null;\n this._originalReplaceState = null;\n this._usesNavigationApi = false;\n\n // Track last known URL for previousUrl in page-view events\n this._lastUrl = null;\n\n // Permission tracking (REQ-034)\n this._permissionStatuses = [];\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n install() {\n if (this._installed || this._tornDown) return;\n\n this._installed = true;\n\n // Record initial URL\n this._lastUrl = this._getCurrentUrl();\n\n // Enqueue initial lifecycle events unconditionally \u2014 these are captured once\n // at session start and must not be gated by isEventTrackingEnabled, which may\n // not be set until the /logdrop/init response arrives. They will be held in\n // the queue and sent once setEnabled(true) is called and a flush fires.\n this._enqueueEventUnconditional(\"ao\", {});\n\n if (this._isFirstVisit) {\n this._enqueueEventUnconditional(\"ai\", {});\n }\n\n if (this._isSdkUpdated) {\n this._enqueueEventUnconditional(\"au\", {\n pv: this._previousRelease,\n nv: this._release,\n });\n }\n\n // Record session start time for time_in_app tracking\n this._sessionStartTime = Date.now();\n\n // Attach visibility handler (REQ-006, REQ-007)\n this._visibilityHandler = () => {\n try {\n if (typeof document === \"undefined\") return;\n if (document.visibilityState === \"hidden\") {\n this._enqueueEvent(\"ab\", {});\n // time_in_app: elapsed duration since session start or last foreground\n if (this._sessionStartTime != null) {\n this._enqueueEvent(\"ta\", { ed: Date.now() - this._sessionStartTime });\n }\n this._sessionStartTime = null;\n } else if (document.visibilityState === \"visible\") {\n this._enqueueEvent(\"af\", {});\n this._sessionStartTime = Date.now();\n }\n } catch {\n // never break host app\n }\n };\n\n if (typeof document !== \"undefined\" && typeof document.addEventListener === \"function\") {\n document.addEventListener(\"visibilitychange\", this._visibilityHandler);\n }\n\n // Attach pagehide handler for keepalive flush (REQ-021)\n this._pageHideHandler = () => {\n try {\n this._flush(true); // keepalive = true\n } catch {\n // silently swallow (SEC-002)\n }\n };\n\n if (hasWindow() && typeof window.addEventListener === \"function\") {\n window.addEventListener(\"pagehide\", this._pageHideHandler);\n }\n\n // SPA detection (REQ-009, REQ-010)\n this._installSpaDetection();\n\n // Permission tracking (REQ-034)\n void this._installPermissionTracking();\n }\n\n uninstall() {\n if (!this._installed) return;\n\n // Remove visibility handler\n if (\n this._visibilityHandler &&\n typeof document !== \"undefined\" &&\n typeof document.removeEventListener === \"function\"\n ) {\n try {\n document.removeEventListener(\"visibilitychange\", this._visibilityHandler);\n } catch {\n // ignore\n }\n }\n this._visibilityHandler = null;\n\n // Remove pagehide handler\n if (\n this._pageHideHandler &&\n hasWindow() &&\n typeof window.removeEventListener === \"function\"\n ) {\n try {\n window.removeEventListener(\"pagehide\", this._pageHideHandler);\n } catch {\n // ignore\n }\n }\n this._pageHideHandler = null;\n\n // Remove SPA detection\n this._uninstallSpaDetection();\n\n // Remove permission tracking\n this._uninstallPermissionTracking();\n\n this._installed = false;\n }\n\n teardown() {\n this.uninstall();\n this._tornDown = true;\n }\n\n // -------------------------------------------------------------------------\n // Kill switch (REQ-027)\n // -------------------------------------------------------------------------\n\n setEnabled(bool) {\n this._isEventTrackingEnabled = bool === true;\n }\n\n // -------------------------------------------------------------------------\n // Event queue\n // -------------------------------------------------------------------------\n\n _enqueueEvent(eventCode, properties) {\n if (!this._isEventTrackingEnabled || this._tornDown) return;\n this._enqueueEventUnconditional(eventCode, properties);\n }\n\n // Public entry point for callers outside the module (e.g. risk events from\n // LogDropClient). Enqueues an event honoring the isEventTrackingEnabled gate.\n trackEvent(eventCode, properties) {\n this._enqueueEvent(eventCode, properties);\n }\n\n // Validate an event against the server registry: the code must be recognized\n // and every required property must be present and non-empty.\n _isValidEvent(eventCode, properties) {\n if (!LogDropConstants.VALID_EVENT_CODES.includes(eventCode)) {\n return false;\n }\n const required = LogDropConstants.EVENT_REQUIRED_PROPS[eventCode] ?? [];\n const props = properties ?? {};\n for (const key of required) {\n const val = props[key];\n if (val === undefined || val === null || val === \"\") {\n return false;\n }\n }\n return true;\n }\n\n // Enqueue without the isEventTrackingEnabled gate \u2014 used for initial lifecycle\n // events that must be captured before the server config response arrives.\n _enqueueEventUnconditional(eventCode, properties) {\n if (this._tornDown) return;\n\n // Guard: the server rejects the entire batch (HTTP 400) if any event uses an\n // unknown code or omits a required property. Drop such events here so one bad\n // event can never poison a whole batch.\n if (!this._isValidEvent(eventCode, properties)) return;\n\n const event = {\n eventId: generateEventId(),\n eventCode,\n timestamp: Date.now(),\n properties: properties ?? {},\n _sessionId: this._getSessionId(),\n userUuid: this._getUserUuid(),\n };\n this._eventQueue.push(event);\n\n const persistPromise = this._persistEvent(event);\n this._eventPersistPromises.add(persistPromise);\n void persistPromise.finally(() => this._eventPersistPromises.delete(persistPromise));\n\n // Immediate flush at 30 items (REQ-020)\n if (this._eventQueue.length >= 30) {\n this._flush();\n }\n }\n\n // -------------------------------------------------------------------------\n // Flush\n // -------------------------------------------------------------------------\n\n async _persistEvent(event) {\n if (!this._dbPromise) return null;\n try {\n const db = await this._dbPromise;\n const tx = db.transaction(\"events\", \"readwrite\");\n const request = tx.objectStore(\"events\").add({ ...event });\n await new Promise((resolve, reject) => {\n tx.oncomplete = resolve;\n tx.onerror = () => reject(tx.error);\n });\n event._dbId = request.result;\n return request.result;\n } catch {\n return null;\n }\n }\n\n async _readStore(storeName) {\n if (!this._dbPromise) return [];\n const db = await this._dbPromise;\n const tx = db.transaction(storeName, \"readonly\");\n const request = tx.objectStore(storeName).getAll();\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => reject(request.error);\n });\n }\n\n async _replaceEventBatch(batch) {\n const db = await this._dbPromise;\n const tx = db.transaction(\"event_upload_batch\", \"readwrite\");\n const store = tx.objectStore(\"event_upload_batch\");\n store.clear();\n if (batch) store.add(batch);\n await new Promise((resolve, reject) => {\n tx.oncomplete = resolve;\n tx.onerror = () => reject(tx.error);\n });\n }\n\n async _getOrCreateEventBatch() {\n await Promise.all([...this._eventPersistPromises]);\n\n if (this._dbPromise) {\n try {\n const allEvents = await this._readStore(\"events\");\n const storedBatches = await this._readStore(\"event_upload_batch\");\n const storedBatch = storedBatches[0] ?? null;\n\n if (storedBatch) {\n const rows = allEvents.filter((event) => event.id <= storedBatch.lastEventId);\n if (rows.length > 0) {\n return { uploadId: storedBatch.uploadId, events: rows, persisted: true };\n }\n await this._replaceEventBatch(null);\n }\n\n if (allEvents.length > 0) {\n const batch = {\n uploadId: generateEventId(),\n lastEventId: allEvents[allEvents.length - 1].id,\n };\n await this._replaceEventBatch(batch);\n return { uploadId: batch.uploadId, events: allEvents, persisted: true };\n }\n } catch {\n // IndexedDB is best-effort; keep the original in-memory upload path available.\n }\n }\n\n if (!this._activeMemoryBatch && this._eventQueue.length > 0) {\n this._activeMemoryBatch = {\n uploadId: generateEventId(),\n events: [...this._eventQueue],\n persisted: false,\n };\n }\n return this._activeMemoryBatch;\n }\n\n async _acknowledgeEventBatch(batch) {\n const eventIds = new Set(batch.events.map((event) => event.eventId));\n\n if (batch.persisted && this._dbPromise) {\n const db = await this._dbPromise;\n const tx = db.transaction(\"events\", \"readwrite\");\n const store = tx.objectStore(\"events\");\n batch.events.forEach((event) => store.delete(event.id));\n await new Promise((resolve, reject) => {\n tx.oncomplete = resolve;\n tx.onerror = () => reject(tx.error);\n });\n await this._replaceEventBatch(null);\n } else {\n this._activeMemoryBatch = null;\n }\n\n this._eventQueue = this._eventQueue.filter((event) => !eventIds.has(event.eventId));\n }\n\n async _flush(keepalive = false) {\n if (this._tornDown) return;\n if (!this._isEventTrackingEnabled) return;\n if (this._eventFlushInProgress) return;\n if (this._eventQueue.length === 0 && !this._dbPromise) return;\n\n this._eventFlushInProgress = true;\n\n // Resolve fetch before mutating the queue \u2014 if unavailable, bail cleanly\n const fetchFn = getFetch();\n if (!fetchFn) {\n this._eventFlushInProgress = false;\n return;\n }\n\n // Resolve the session token required by the server. Without a valid\n // x-session-token the events/collect endpoint responds with 400.\n let sessionToken = null;\n if (this._getSessionToken) {\n try {\n sessionToken = await this._getSessionToken();\n } catch {\n sessionToken = null;\n }\n }\n if (!sessionToken) {\n // Keep events queued for a later flush once a token is available.\n this._eventFlushInProgress = false;\n return;\n }\n\n try {\n const batch = await this._getOrCreateEventBatch();\n if (!batch || batch.events.length === 0) return;\n const events = batch.events;\n\n // Group events by sessionId (REQ-016)\n const sessionMap = new Map();\n for (const evt of events) {\n const sid = evt._sessionId;\n if (!sessionMap.has(sid)) {\n sessionMap.set(sid, { userUuid: evt.userUuid, events: [] });\n }\n sessionMap.get(sid).events.push({\n eventId: evt.eventId,\n eventCode: evt.eventCode,\n timestamp: evt.timestamp,\n properties: evt.properties,\n });\n }\n\n const sessions = [];\n for (const [sessionId, sessionData] of sessionMap) {\n sessions.push({\n sessionId,\n userUuid: sessionData.userUuid,\n events: sessionData.events,\n });\n }\n\n // Only a real, identified user populates first_real_user_uuid; it stays\n // empty while anonymous (session user_uuid falls back to the deviceUuid).\n const firstRealUserUuid = this._getRealUserUuid() ?? \"\";\n\n const payload = {\n deviceUuid: this._deviceId,\n sessions,\n firstRealUserUuid,\n uploadId: batch.uploadId,\n };\n\n const protoBytes = encodeEventBatchRequest(payload);\n\n const url = `${this._apiBase}${LogDropConstants.EVENTS_PATH}`;\n const fetchOptions = {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-protobuf\",\n \"Accept\": \"application/x-protobuf\",\n \"x-api-key\": this._apiKey,\n \"x-session-token\": sessionToken,\n },\n body: new Blob([protoBytes], { type: \"application/x-protobuf\" }),\n };\n\n if (keepalive) {\n fetchOptions.keepalive = true;\n }\n\n const res = await fetchFn(url, fetchOptions);\n if (res.ok) {\n // Mirror every successfully sent event into the log stream (EVENT level).\n if (this._logEvent) {\n for (const s of payload.sessions) {\n for (const e of s.events) {\n try {\n this._logEvent({\n eventId: e.eventId,\n eventCode: e.eventCode,\n eventName: LogDropConstants.EVENT_NAMES[e.eventCode] ?? e.eventCode,\n timestamp: e.timestamp,\n sessionId: s.sessionId,\n properties: e.properties ?? {},\n });\n } catch {\n // never let logging break the flush\n }\n }\n }\n }\n\n // Best-effort: parse EventBatchResponse (non-critical)\n try {\n const responseBytes = new Uint8Array(await res.arrayBuffer());\n if (responseBytes.length > 0) decodeEventBatchResponse(responseBytes);\n } catch {\n // ignore response decode errors\n }\n await this._acknowledgeEventBatch(batch);\n }\n } catch (err) {\n // Surface the error instead of swallowing it\n throw err;\n } finally {\n this._eventFlushInProgress = false;\n }\n }\n\n // -------------------------------------------------------------------------\n // SPA detection\n // -------------------------------------------------------------------------\n\n _installSpaDetection() {\n if (hasNavigationApi()) {\n // Primary: Navigation API (REQ-009)\n this._usesNavigationApi = true;\n this._navigateHandler = (event) => {\n try {\n // Track the current route internally. No server event is emitted:\n // the LogDrop event registry has no page-view/screen-view code, so\n // SPA navigations are not reported to /events/collect.\n const destUrl = (event && event.destination && event.destination.url)\n ? event.destination.url\n : this._getCurrentUrl();\n queueMicrotask(() => {\n this._lastUrl = destUrl;\n });\n } catch {\n // never break host app\n }\n };\n navigation.addEventListener(\"navigate\", this._navigateHandler);\n } else {\n // Fallback: monkey-patch pushState/replaceState + popstate (REQ-010)\n this._usesNavigationApi = false;\n this._installHistoryPatches();\n }\n }\n\n _uninstallSpaDetection() {\n if (this._usesNavigationApi) {\n // Remove Navigation API listener\n if (\n this._navigateHandler &&\n typeof navigation !== \"undefined\" &&\n typeof navigation.removeEventListener === \"function\"\n ) {\n try {\n navigation.removeEventListener(\"navigate\", this._navigateHandler);\n } catch {\n // ignore\n }\n }\n this._navigateHandler = null;\n } else {\n // Restore monkey-patched history methods (REQ-011)\n this._restoreHistoryPatches();\n }\n\n // Remove popstate listener\n if (\n this._popstateHandler &&\n hasWindow() &&\n typeof window.removeEventListener === \"function\"\n ) {\n try {\n window.removeEventListener(\"popstate\", this._popstateHandler);\n } catch {\n // ignore\n }\n }\n this._popstateHandler = null;\n }\n\n _installHistoryPatches() {\n if (typeof history === \"undefined\") return;\n\n // Store originals for restoration (REQ-011)\n this._originalPushState = history.pushState;\n this._originalReplaceState = history.replaceState;\n\n const self = this;\n\n // Monkey-patch pushState. We still call through to the original so the host\n // app's routing is unaffected, and we keep _lastUrl current, but no server\n // event is emitted (registry has no page-view/screen-view code).\n history.pushState = function (...args) {\n // Call through to original (COR-004)\n self._originalPushState.apply(this, args);\n self._lastUrl = self._getCurrentUrl();\n };\n\n // Monkey-patch replaceState\n history.replaceState = function (...args) {\n // Call through to original (COR-004)\n self._originalReplaceState.apply(this, args);\n self._lastUrl = self._getCurrentUrl();\n };\n\n // popstate listener for back/forward \u2014 track route only, no event emitted.\n this._popstateHandler = () => {\n try {\n this._lastUrl = this._getCurrentUrl();\n } catch {\n // never break host app\n }\n };\n\n if (hasWindow() && typeof window.addEventListener === \"function\") {\n window.addEventListener(\"popstate\", this._popstateHandler);\n }\n }\n\n _restoreHistoryPatches() {\n if (typeof history === \"undefined\") return;\n\n if (this._originalPushState) {\n history.pushState = this._originalPushState;\n this._originalPushState = null;\n }\n if (this._originalReplaceState) {\n history.replaceState = this._originalReplaceState;\n this._originalReplaceState = null;\n }\n }\n\n // -------------------------------------------------------------------------\n // Permission tracking (REQ-034)\n // -------------------------------------------------------------------------\n\n async _installPermissionTracking() {\n const PERMISSIONS = [\n { pt: \"notification\", apiName: \"notifications\" },\n { pt: \"geolocation\", apiName: \"geolocation\" },\n { pt: \"camera\", apiName: \"camera\" },\n { pt: \"microphone\", apiName: \"microphone\" },\n ];\n\n const hasPermissionsApi =\n typeof navigator !== \"undefined\" &&\n navigator.permissions &&\n typeof navigator.permissions.query === \"function\";\n\n if (hasPermissionsApi) {\n for (const { pt, apiName } of PERMISSIONS) {\n try {\n const status = await navigator.permissions.query({ name: apiName });\n this._enqueueEvent(\"ap\", { pt, ps: status.state });\n status.onchange = () => {\n try {\n if (!this._installed) return;\n this._enqueueEvent(\"ap\", { pt, ps: status.state });\n } catch { /* ignore */ }\n };\n this._permissionStatuses.push(status);\n } catch {\n // Query rejected (e.g., Firefox rejecting camera/microphone)\n const ps = pt === \"notification\" ? this._getNotificationPermission() : \"unsupported\";\n this._enqueueEvent(\"ap\", { pt, ps });\n }\n }\n } else {\n // No Permissions API \u2014 use fallbacks\n this._enqueueEvent(\"ap\", { pt: \"notification\", ps: this._getNotificationPermission() });\n for (const pt of [\"geolocation\", \"camera\", \"microphone\"]) {\n this._enqueueEvent(\"ap\", { pt, ps: \"unsupported\" });\n }\n }\n }\n\n _getNotificationPermission() {\n try {\n if (typeof Notification !== \"undefined\" && Notification.permission) {\n const raw = Notification.permission; // \"granted\" | \"denied\" | \"default\"\n return raw === \"default\" ? \"prompt\" : raw;\n }\n } catch { /* ignore */ }\n return \"unsupported\";\n }\n\n _uninstallPermissionTracking() {\n for (const status of this._permissionStatuses) {\n try { status.onchange = null; } catch { /* ignore */ }\n }\n this._permissionStatuses = [];\n }\n\n // -------------------------------------------------------------------------\n // DOM accessors (safe for environments without full browser globals)\n // -------------------------------------------------------------------------\n\n _getCurrentUrl() {\n try {\n if (typeof location !== \"undefined\" && location.href) return location.href;\n } catch {\n // ignore\n }\n return \"\";\n }\n\n _getReferrer() {\n try {\n if (typeof document !== \"undefined\" && document.referrer != null) return document.referrer;\n } catch {\n // ignore\n }\n return \"\";\n }\n\n _getTitle() {\n try {\n if (typeof document !== \"undefined\" && document.title != null) return document.title;\n } catch {\n // ignore\n }\n return \"\";\n }\n}\n", "function hasWindow() {\n return typeof window !== \"undefined\";\n}\n\nexport class HeadlessBrowserSignalProvider {\n detect() {\n if (typeof navigator === \"undefined\") return null;\n\n const indicators = [];\n\n // navigator.webdriver is true in headless/automated browsers\n if (navigator.webdriver === true) {\n indicators.push(\"webdriver\");\n }\n\n // Chrome API object is absent in headless Chromium\n if (\n typeof navigator.userAgent === \"string\" &&\n navigator.userAgent.toLowerCase().includes(\"chrome\") &&\n hasWindow() &&\n !window.chrome\n ) {\n indicators.push(\"missing_chrome_api\");\n }\n\n if (hasWindow()) {\n // Playwright fingerprint\n if (window.__playwright__binding__ !== undefined || window.__pwInitScripts__ !== undefined) {\n indicators.push(\"playwright_binding\");\n }\n\n // CDP / ChromeDriver markers (keys starting with cdc_)\n for (const key of Object.keys(window)) {\n if (key.startsWith(\"cdc_\")) {\n indicators.push(\"cdp_marker\");\n break;\n }\n }\n }\n\n if (indicators.length === 0) return null;\n\n return {\n id: \"headless_browser_detected\",\n weight: 0.90,\n severity: 1.0,\n confidence: 0.90,\n evidence: { indicators: indicators.join(\",\") },\n };\n }\n}\n", "export class AutomationEnvironmentSignalProvider {\n detect() {\n if (typeof window === \"undefined\") return null;\n\n const indicators = [];\n\n // Playwright markers\n if (window.__playwright__binding__ !== undefined || window.__pwInitScripts__ !== undefined) {\n indicators.push(\"playwright\");\n }\n\n // Puppeteer markers\n if (window.__puppeteer_evaluation_script__ !== undefined) {\n indicators.push(\"puppeteer\");\n }\n\n // Selenium / WebDriver markers on document\n if (typeof document !== \"undefined\") {\n if (document.$wdc_ !== undefined || document.__webdriver_evaluate !== undefined) {\n indicators.push(\"selenium\");\n }\n }\n\n if (indicators.length === 0) return null;\n\n return {\n id: \"automation_environment_detected\",\n // Keep the shared automation signal aligned with Android/iOS.\n weight: 0.60,\n severity: 1.0,\n confidence: 1.0,\n evidence: { indicators: indicators.join(\",\") },\n };\n }\n}\n", "const BUFFER_SIZE = 60;\nconst ANALYSIS_WINDOW_MS = 4000;\nconst MIN_SAMPLES = 8;\nconst ROBOTIC_TIMING_STDDEV_MS = 18;\nconst ROBOTIC_TIMING_MEAN_MS = 120;\nconst ROBOTIC_PATH_STRAIGHTNESS = 0.985;\nconst DENSE_BURST_COUNT = 10;\nconst DENSE_BURST_WINDOW_MS = 2500;\n\nfunction stddev(values) {\n if (values.length < 2) return 0;\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\n const variance = values.reduce((s, v) => s + (v - mean) ** 2, 0) / (values.length - 1);\n return Math.sqrt(variance);\n}\n\nfunction mean(values) {\n return values.length === 0 ? 0 : values.reduce((a, b) => a + b, 0) / values.length;\n}\n\nexport class PointerBehaviorSignalProvider {\n constructor() {\n this._samples = [];\n }\n\n recordSample(x, y, time) {\n this._samples.push({ x, y, time });\n if (this._samples.length > BUFFER_SIZE) {\n this._samples.shift();\n }\n }\n\n // Test-only injection hook\n _injectSamples(samples) {\n this._samples = samples.slice(-BUFFER_SIZE);\n }\n\n detect() {\n const now = this._samples.length > 0 ? this._samples[this._samples.length - 1].time : 0;\n const windowStart = now - ANALYSIS_WINDOW_MS;\n const recent = this._samples.filter((s) => s.time >= windowStart);\n\n if (recent.length < MIN_SAMPLES) return null;\n\n // Inter-event timing intervals\n const intervals = [];\n for (let i = 1; i < recent.length; i++) {\n intervals.push(recent[i].time - recent[i - 1].time);\n }\n\n const timingMean = mean(intervals);\n const timingStddev = stddev(intervals);\n const roboticTiming = timingStddev < ROBOTIC_TIMING_STDDEV_MS && timingMean < ROBOTIC_TIMING_MEAN_MS;\n\n // Path analysis\n let pathLength = 0;\n for (let i = 1; i < recent.length; i++) {\n const dx = recent[i].x - recent[i - 1].x;\n const dy = recent[i].y - recent[i - 1].y;\n pathLength += Math.sqrt(dx * dx + dy * dy);\n }\n const first = recent[0];\n const last = recent[recent.length - 1];\n const dx = last.x - first.x;\n const dy = last.y - first.y;\n const straightLine = Math.sqrt(dx * dx + dy * dy);\n const straightness = pathLength > 0 ? straightLine / pathLength : 0;\n const roboticPath = straightness > ROBOTIC_PATH_STRAIGHTNESS;\n\n // Dense burst\n const span = last.time - first.time;\n const denseBurst = recent.length >= DENSE_BURST_COUNT && span < DENSE_BURST_WINDOW_MS;\n const evenlyTimedBurst = timingStddev < 30 && timingMean < 180;\n const linearBurst = denseBurst && roboticPath && evenlyTimedBurst;\n\n const triggered = roboticTiming || linearBurst || (roboticPath && denseBurst);\n if (!triggered) return null;\n\n return {\n id: \"automation_pointer_pattern\",\n weight: 0.60,\n severity: 1.0,\n confidence: 1.0,\n evidence: {\n stddev: timingStddev.toFixed(2),\n mean_interval: timingMean.toFixed(2),\n straight: straightness.toFixed(4),\n span: span.toFixed(0),\n samples: recent.length.toString(),\n },\n };\n }\n}\n", "const BUFFER_SIZE = 20;\nconst MIN_KEYSTROKES = 6;\nconst ROBOTIC_STDDEV_MS = 20;\n\nfunction stddev(values) {\n if (values.length < 2) return 0;\n const m = values.reduce((a, b) => a + b, 0) / values.length;\n const variance = values.reduce((s, v) => s + (v - m) ** 2, 0) / (values.length - 1);\n return Math.sqrt(variance);\n}\n\nexport class KeyboardCadenceSignalProvider {\n constructor() {\n this._timestamps = [];\n }\n\n recordTimestamp(ts) {\n this._timestamps.push(ts);\n if (this._timestamps.length > BUFFER_SIZE) {\n this._timestamps.shift();\n }\n }\n\n // Test-only injection hook\n _injectTimestamps(timestamps) {\n this._timestamps = timestamps.slice(-BUFFER_SIZE);\n }\n\n detect() {\n if (this._timestamps.length < MIN_KEYSTROKES) return null;\n\n const intervals = [];\n for (let i = 1; i < this._timestamps.length; i++) {\n intervals.push(this._timestamps[i] - this._timestamps[i - 1]);\n }\n\n const s = stddev(intervals);\n if (s >= ROBOTIC_STDDEV_MS) return null;\n\n return {\n id: \"keyboard_too_uniform\",\n weight: 0.55,\n severity: 1.0,\n confidence: 0.80,\n evidence: {\n stddev: s.toFixed(2),\n samples: this._timestamps.length.toString(),\n },\n };\n }\n}\n", "function isChromium(ua) {\n return typeof ua === \"string\" && ua.toLowerCase().includes(\"chrome\") && !ua.toLowerCase().includes(\"firefox\");\n}\n\nexport class HardwareConsistencySignalProvider {\n detect() {\n if (typeof navigator === \"undefined\") return null;\n\n const ua = navigator.userAgent;\n const chromium = isChromium(ua);\n const indicators = [];\n\n // Empty plugins on claimed Chromium desktop\n const plugins = navigator.plugins;\n if (chromium && plugins !== undefined && plugins.length === 0) {\n indicators.push(\"empty_plugins\");\n }\n\n // Missing or empty languages\n const languages = navigator.languages;\n if (!languages || languages.length === 0) {\n indicators.push(\"missing_languages\");\n }\n\n // Missing deviceMemory on Chromium (only Chromium supports this API)\n if (chromium && navigator.deviceMemory === undefined) {\n indicators.push(\"missing_device_memory\");\n }\n\n if (indicators.length === 0) return null;\n\n return {\n id: \"hardware_inconsistency\",\n weight: 0.40,\n severity: 0.7,\n confidence: 0.60,\n evidence: { indicators: indicators.join(\",\") },\n };\n }\n}\n", "// Threshold in pixels \u2014 docked DevTools typically adds 300px; 200px avoids\n// false positives from zoom levels and browser chrome on small windows.\nconst SIZE_THRESHOLD = 200;\n\nexport class DevToolsSignalProvider {\n detect() {\n if (typeof window === \"undefined\") return null;\n\n const widthDiff = (window.outerWidth ?? 0) - (window.innerWidth ?? 0);\n const heightDiff = (window.outerHeight ?? 0) - (window.innerHeight ?? 0);\n\n if (widthDiff <= SIZE_THRESHOLD && heightDiff <= SIZE_THRESHOLD) return null;\n\n return {\n id: \"devtools_open\",\n weight: 0.40,\n severity: 0.7,\n confidence: 0.75,\n evidence: {\n width_diff: widthDiff.toString(),\n height_diff: heightDiff.toString(),\n },\n };\n }\n}\n", "// Best-effort detection of *undocked* (separate-window) DevTools.\n//\n// The size-diff heuristic in devToolsSignal.js only works when DevTools is\n// docked to the page (it shrinks the viewport). When the user pops DevTools out\n// into its own OS window, the viewport is unchanged and that heuristic fails.\n//\n// This provider uses the well-known \"console getter\" trick: we log a bait\n// object that has a property getter. When the DevTools Console panel renders a\n// logged value, it eagerly evaluates the object's getters to build a preview \u2014\n// firing our getter. If the getter fires, the Console is being rendered, i.e.\n// DevTools is open (docked OR undocked).\n//\n// Trade-off: `probe()` emits a periodic console.log, so it leaves a small\n// footprint in the console. This is gated by a constant so it can be disabled.\n//\n// The RiskModule drives this provider: it calls `probe()` on a short interval,\n// then reads the result via `detect()`. In Chromium the getter fires\n// synchronously during `console.log`, so the flag set by the most recent\n// `probe()` reflects the current state.\n\nexport class DevToolsConsoleSignalProvider {\n constructor() {\n this._triggered = false;\n this._bait = this._makeBait();\n }\n\n _makeBait() {\n const self = this;\n const bait = {};\n // The Console preview reads own-enumerable property getters. When DevTools\n // renders the bait, this getter runs and flips the flag.\n Object.defineProperty(bait, \"id\", {\n enumerable: true,\n configurable: true,\n get() {\n self._triggered = true;\n return \"\";\n },\n });\n return bait;\n }\n\n // Logs the bait so an open Console panel triggers the getter. Meant to be\n // called on a short interval. Resets the flag first so `detect()` reflects\n // only the current probe.\n probe() {\n if (typeof console === \"undefined\" || typeof console.log !== \"function\") return;\n this._triggered = false;\n try {\n // A zero-size CSS format keeps the visible footprint minimal while still\n // forcing the console to render (and thus preview) the bait object.\n console.log(\"%c%o\", \"font-size:0;color:transparent\", this._bait);\n } catch {\n // never break the host app\n }\n }\n\n detect() {\n if (!this._triggered) return null;\n\n return {\n id: \"devtools_open\",\n weight: 0.40,\n severity: 0.7,\n // Lower than the size-based signal: the console trick is more heuristic\n // and can be defeated by users who disable console preview.\n confidence: 0.6,\n evidence: {\n method: \"console_getter\",\n },\n };\n }\n}\n", "// Chrome 115+ (Aug 2023) changed incognito storage quota from a fixed ~120 MB\n// cap to RAM/10 (~800 MB\u20131.6 GB on typical hardware), making quota-based\n// detection unreliable for modern Chrome. webkitRequestFileSystem \u2014 the\n// previous reliable signal \u2014 was also removed in Chrome 115.\n//\n// Detection coverage:\n// Firefox private \u2192 storage.estimate() returns ~0 quota \u2713\n// Safari private \u2192 localStorage.setItem() throws \u2713\n// Chrome < 115 \u2192 webkitRequestFileSystem error \u2713\n// Chrome 115+ \u2192 not detectable via browser APIs \u2717\n\n// Firefox private mode returns near-zero quota; 10 MB gives a safe margin.\nconst FIREFOX_PRIVATE_QUOTA_THRESHOLD = 10 * 1024 * 1024;\n\nexport class IncognitoSignalProvider {\n constructor() {\n this._detected = null;\n this._method = null;\n this._checkPromise = this._check();\n }\n\n async _check() {\n const win = typeof window !== \"undefined\" ? window : null;\n\n // Method 1: webkitRequestFileSystem \u2014 Chrome < 115 incognito blocks it\n const fs = win && (win.RequestFileSystem || win.webkitRequestFileSystem);\n if (fs) {\n const blocked = await new Promise((resolve) => {\n try {\n fs(0 /* TEMPORARY */, 100, () => resolve(false), () => resolve(true));\n } catch {\n resolve(false);\n }\n });\n if (blocked) {\n this._detected = true;\n this._method = \"filesystem_api\";\n return;\n }\n }\n\n // Method 2: storage.estimate() quota \u2014 Firefox private returns ~0\n if (\n typeof navigator !== \"undefined\" &&\n navigator.storage &&\n typeof navigator.storage.estimate === \"function\"\n ) {\n try {\n const { quota } = await navigator.storage.estimate();\n if (typeof quota === \"number\" && quota < FIREFOX_PRIVATE_QUOTA_THRESHOLD) {\n this._detected = true;\n this._method = \"storage_quota\";\n return;\n }\n // Quota is normal-sized \u2014 not private (or Chrome 115+ incognito which\n // is indistinguishable from normal browsing via this API)\n this._detected = false;\n return;\n } catch {\n // fall through to localStorage check\n }\n }\n\n // Method 3: localStorage throw \u2014 Safari private browsing\n if (typeof localStorage !== \"undefined\") {\n try {\n localStorage.setItem(\"_ld_priv_test\", \"1\");\n localStorage.removeItem(\"_ld_priv_test\");\n this._detected = false;\n } catch {\n this._detected = true;\n this._method = \"localstorage_throw\";\n }\n return;\n }\n\n this._detected = false;\n }\n\n detect() {\n if (!this._detected) return null;\n\n return {\n id: \"private_browsing_detected\",\n weight: 0.30,\n severity: 0.5,\n confidence: 0.70,\n evidence: { method: this._method ?? \"unknown\" },\n };\n }\n}\n", "// Soft signal for Chrome 115+ incognito detection via cross-session localStorage\n// persistence. Normal mode: localStorage survives tab close; incognito: wiped\n// when all private windows close.\n//\n// Flow per page load:\n// - Same session (sessionStorage marker set): skip, return null\n// - New session, localStorage token exists: normal mode \u2014 no signal, increment count\n// - New session, localStorage token absent: possible incognito first visit \u2014 fire signal\n//\n// Caveat: fires on genuine first visits and cleared-cookie users (false positive).\n// Confidence is deliberately low (0.50) to reflect this.\n\nconst LS_KEY = \"_ld_cv\";\nconst SS_KEY = \"_ld_sm\";\n\nfunction hasStorage(key) {\n try {\n return typeof global !== \"undefined\"\n ? global[key] != null\n : typeof window !== \"undefined\" && window[key] != null;\n } catch {\n return false;\n }\n}\n\nfunction getLS() {\n try {\n return typeof localStorage !== \"undefined\" ? localStorage : null;\n } catch {\n return null;\n }\n}\n\nfunction getSS() {\n try {\n return typeof sessionStorage !== \"undefined\" ? sessionStorage : null;\n } catch {\n return null;\n }\n}\n\nexport class SessionPersistenceSignalProvider {\n detect() {\n const ls = getLS();\n const ss = getSS();\n\n if (!ls || !ss) return null;\n\n // Within-session reload: skip entirely\n if (ss.getItem(SS_KEY) === \"1\") return null;\n\n // Mark this session so reloads skip\n ss.setItem(SS_KEY, \"1\");\n\n // Try to read existing cross-session token\n let token = null;\n try {\n const raw = ls.getItem(LS_KEY);\n if (raw) token = JSON.parse(raw);\n } catch {\n // Corrupted token \u2014 treat as absent\n token = null;\n }\n\n const sessionCount = (token?.n ?? 0) + 1;\n ls.setItem(LS_KEY, JSON.stringify({ t: Date.now(), n: sessionCount }));\n\n if (token !== null) {\n // Token existed \u2014 localStorage persisted across sessions \u2192 normal mode\n return null;\n }\n\n // No token found on a new session \u2014 possible incognito\n return {\n id: \"session_not_persistent\",\n weight: 0.25,\n severity: 0.6,\n confidence: 0.50,\n evidence: {\n method: \"localstorage_persistence\",\n sessions: sessionCount,\n },\n };\n }\n}\n", "export const RiskEventIds = Object.freeze({\n JAILBREAK_DETECTED: 1,\n DEBUGGER_ATTACHED: 2,\n HOOKING_SUSPECTED: 3,\n PROXY_CONFIGURED: 4,\n VPN_SUSPECTED: 5,\n SIMULATOR_IN_USE: 6,\n AUTOMATION_ENVIRONMENT_DETECTED: 7,\n AUTOMATION_TOUCH_PATTERN: 8,\n DEVICE_CLOCK_MISMATCH: 9,\n DEVTOOLS_OPEN: 10,\n HEADLESS_BROWSER_DETECTED: 11,\n AUTOMATION_POINTER_PATTERN: 12,\n KEYBOARD_TOO_UNIFORM: 13,\n PRIVATE_BROWSING_DETECTED: 14,\n SESSION_NOT_PERSISTENT: 15,\n HARDWARE_INCONSISTENCY: 16,\n});\n\nexport const RiskActionIds = Object.freeze({\n BLOCK_ALL_NETWORK: 1,\n SHOW_WARNING: 2,\n BLOCK_APP: 3,\n});\n\nconst KNOWN_EVENT_IDS = new Set(Object.values(RiskEventIds));\nconst KNOWN_ACTION_IDS = new Set(Object.values(RiskActionIds));\n\nconst SIGNAL_EVENT_IDS = Object.freeze({\n devtools_open: RiskEventIds.DEVTOOLS_OPEN,\n headless_browser_detected: RiskEventIds.HEADLESS_BROWSER_DETECTED,\n automation_environment_detected: RiskEventIds.AUTOMATION_ENVIRONMENT_DETECTED,\n automation_pointer_pattern: RiskEventIds.AUTOMATION_POINTER_PATTERN,\n keyboard_too_uniform: RiskEventIds.KEYBOARD_TOO_UNIFORM,\n private_browsing_detected: RiskEventIds.PRIVATE_BROWSING_DETECTED,\n session_not_persistent: RiskEventIds.SESSION_NOT_PERSISTENT,\n hardware_inconsistency: RiskEventIds.HARDWARE_INCONSISTENCY,\n});\n\nexport function eventIdForSignal(signalId) {\n return SIGNAL_EVENT_IDS[signalId] ?? null;\n}\n\nexport function actionName(actionId) {\n switch (actionId) {\n case RiskActionIds.BLOCK_ALL_NETWORK: return \"block_all_network\";\n case RiskActionIds.SHOW_WARNING: return \"show_warning\";\n case RiskActionIds.BLOCK_APP: return \"block_app\";\n default: return null;\n }\n}\n\nexport function evaluateRiskPolicy(policy, detectedEventIds) {\n const detected = new Set(detectedEventIds ?? []);\n const rules = Array.isArray(policy?.rules) ? policy.rules : [];\n if (rules.length === 0 || detected.size === 0) return emptyEvaluation();\n\n const matchedRules = rules\n .filter((rule) => rule?.enabled === true)\n .map((rule) => {\n const eventIds = (rule.eventIds ?? []).filter((id) => KNOWN_EVENT_IDS.has(id));\n const actionIds = (rule.actionIds ?? []).filter((id) => KNOWN_ACTION_IDS.has(id));\n return { ...rule, eventIds, actionIds };\n })\n .filter((rule) => {\n if (rule.eventIds.length === 0 || rule.actionIds.length === 0) return false;\n const matchType = String(rule.matchType || \"ANY\").toUpperCase();\n if (matchType === \"ANY\") return rule.eventIds.some((id) => detected.has(id));\n if (matchType === \"ALL\") return rule.eventIds.every((id) => detected.has(id));\n return false;\n })\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n\n if (matchedRules.length === 0) return emptyEvaluation();\n\n const actionIds = [...new Set(matchedRules.flatMap((rule) => rule.actionIds))];\n const firstText = (key) => matchedRules\n .map((rule) => typeof rule[key] === \"string\" ? rule[key].trim() : \"\")\n .find(Boolean) || null;\n\n return {\n matchedRules,\n actionIds,\n title: firstText(\"title\"),\n message: firstText(\"message\"),\n buttonText: firstText(\"buttonText\"),\n };\n}\n\nexport function policyEvaluationSignature(evaluation) {\n if (!evaluation || evaluation.actionIds.length === 0) return null;\n return JSON.stringify({\n actions: [...evaluation.actionIds].sort((a, b) => a - b),\n rules: evaluation.matchedRules.map((rule) => rule.priority ?? 0),\n });\n}\n\nfunction emptyEvaluation() {\n return {\n matchedRules: [],\n actionIds: [],\n title: null,\n message: null,\n buttonText: null,\n };\n}\n", "import { HeadlessBrowserSignalProvider } from \"./signals/headlessBrowserSignal.js\";\nimport { AutomationEnvironmentSignalProvider } from \"./signals/automationEnvironmentSignal.js\";\nimport { PointerBehaviorSignalProvider } from \"./signals/pointerBehaviorSignal.js\";\nimport { KeyboardCadenceSignalProvider } from \"./signals/keyboardCadenceSignal.js\";\nimport { HardwareConsistencySignalProvider } from \"./signals/hardwareConsistencySignal.js\";\nimport { DevToolsSignalProvider } from \"./signals/devToolsSignal.js\";\nimport { DevToolsConsoleSignalProvider } from \"./signals/devToolsConsoleSignal.js\";\nimport { IncognitoSignalProvider } from \"./signals/incognitoSignal.js\";\nimport { SessionPersistenceSignalProvider } from \"./signals/sessionPersistenceSignal.js\";\nimport { LogDropConstants } from \"../constants.js\";\nimport {\n evaluateRiskPolicy,\n eventIdForSignal,\n policyEvaluationSignature,\n} from \"./riskPolicy.js\";\n\n// ---------------------------------------------------------------------------\n// Scoring \u2014 same multiplicative formula as iOS RiskEngine / BotEngine\n// ---------------------------------------------------------------------------\n\nfunction computeScore(signals) {\n let complement = 1;\n for (const s of signals) {\n complement *= 1 - s.weight * s.severity * s.confidence;\n }\n return Math.round(Math.min(100, Math.max(0, 100 * (1 - complement))));\n}\n\nfunction scoreToLabel(score, collecting) {\n if (collecting) return \"collecting\";\n if (score >= 60) return \"automation_suspected\";\n if (score >= 30) return \"uncertain\";\n return \"likely_human\";\n}\n\nfunction scoreToRiskLevel(score) {\n if (score >= 75) return \"critical\";\n if (score >= 50) return \"high\";\n if (score >= 25) return \"medium\";\n return \"low\";\n}\n\n// Same combined session posture contract as Android/iOS SessionThreatManager.\nfunction scoresToPosture(riskScore, botScore) {\n if (riskScore >= 75) return \"critical\";\n if (riskScore >= 50 || botScore >= 60) return \"at_risk\";\n if (riskScore >= 25 || botScore >= 30) return \"elevated\";\n return \"safe\";\n}\n\n// ---------------------------------------------------------------------------\n// Signal categorisation \u2014 bot detection and risk detection are separate.\n// Bot signals \u2192 drive the bot score / label (is this an automated client?)\n// Risk signals \u2192 drive the risk score / posture (environment/integrity risk)\n// A signal in one category must NOT influence the other category's score.\n// ---------------------------------------------------------------------------\n\nconst BOT_SIGNAL_IDS = new Set([\n \"headless_browser_detected\",\n \"automation_environment_detected\",\n \"automation_pointer_pattern\",\n \"keyboard_too_uniform\",\n]);\n\nconst RISK_SIGNAL_IDS = new Set([\n \"devtools_open\",\n \"private_browsing_detected\",\n \"session_not_persistent\",\n \"hardware_inconsistency\",\n]);\n\n// ---------------------------------------------------------------------------\n// RiskModule\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_INTERVAL_MS = 30_000;\n// Require 3s of activity before the first meaningful evaluation\nconst MIN_COLLECT_MS = 3_000;\n// Minimum pointer samples before behavioural signals are considered\nconst MIN_POINTER_SAMPLES = 8;\n// Sticky label: require this many consecutive non-suspected evals to downgrade\nconst STICKY_DOWNGRADE_COUNT = 3;\n\nexport class RiskModule {\n // Static helpers exposed for testing\n static _computeScore = computeScore;\n static _scoreToLabel = scoreToLabel;\n static _scoreToRiskLevel = scoreToRiskLevel;\n static _scoresToPosture = scoresToPosture;\n static _scoreToPosture = scoreToRiskLevel;\n\n constructor(config = {}) {\n const cfg = config ?? {};\n this._onThreatChanged = typeof cfg.onThreatChanged === \"function\" ? cfg.onThreatChanged : null;\n // Fired immediately when a discrete risk event occurs (e.g. DevTools opened),\n // independent of the periodic posture-change callback.\n this._onRiskEvent = typeof cfg.onRiskEvent === \"function\" ? cfg.onRiskEvent : null;\n this._onPolicyChanged = typeof cfg.onPolicyChanged === \"function\" ? cfg.onPolicyChanged : null;\n this._intervalMs = cfg.checkIntervalMs ?? DEFAULT_INTERVAL_MS;\n this._botDetectionEnabled = cfg.botDetectionEnabled !== false;\n this._otherRiskTypesEnabled = cfg.otherRiskTypesEnabled !== false;\n this._riskPolicy = cfg.riskPolicy ?? { version: 0, rules: [] };\n\n this._installed = false;\n this._tornDown = false;\n\n this._snapshot = null;\n this._lastPosture = null;\n this._lastReportedSignals = new Map();\n this._lastPolicySignature = null;\n this._installTime = null;\n\n // DevTools open/close state tracking (for instant risk events)\n this._devtoolsOpen = false;\n\n // Sticky label tracking\n this._stickyLabel = null;\n this._consecutiveNonSuspected = 0;\n\n // Signal providers\n this._headless = new HeadlessBrowserSignalProvider();\n this._automation = new AutomationEnvironmentSignalProvider();\n this._pointer = new PointerBehaviorSignalProvider();\n this._keyboard = new KeyboardCadenceSignalProvider();\n this._hardware = new HardwareConsistencySignalProvider();\n this._devtools = new DevToolsSignalProvider();\n this._devtoolsConsole = new DevToolsConsoleSignalProvider();\n this._incognito = new IncognitoSignalProvider();\n this._sessionPersistence = new SessionPersistenceSignalProvider();\n\n // DOM listener references\n this._mousemoveHandler = null;\n this._keydownHandler = null;\n this._resizeHandler = null;\n this._timer = null;\n // Short-interval timer that drives the console-getter DevTools probe.\n this._devtoolsProbeTimer = null;\n }\n\n install() {\n if (this._installed || this._tornDown) return;\n this._installed = true;\n this._installTime = Date.now();\n\n // Attach behavioural listeners\n if (this._botDetectionEnabled && typeof window !== \"undefined\" && typeof window.addEventListener === \"function\") {\n this._mousemoveHandler = (e) => {\n try {\n const t = typeof performance !== \"undefined\" ? performance.now() : Date.now();\n this._pointer.recordSample(e.clientX, e.clientY, t);\n } catch {\n // never break host app\n }\n };\n window.addEventListener(\"mousemove\", this._mousemoveHandler, { passive: true });\n }\n\n if (this._botDetectionEnabled && typeof document !== \"undefined\" && typeof document.addEventListener === \"function\") {\n this._keydownHandler = (e) => {\n try {\n // Skip modifier-only keys\n if ([\"Shift\", \"Control\", \"Alt\", \"Meta\"].includes(e.key)) return;\n this._keyboard.recordTimestamp(typeof performance !== \"undefined\" ? performance.now() : Date.now());\n } catch {\n // never break host app\n }\n };\n document.addEventListener(\"keydown\", this._keydownHandler, { passive: true });\n }\n\n // Detect DevTools open/close instantly. Docked DevTools changes the\n // inner/outer window size, which fires a \"resize\" event \u2014 this lets us\n // report the risk the moment it happens instead of waiting for the\n // periodic 30s evaluation tick.\n if (this._otherRiskTypesEnabled && typeof window !== \"undefined\" && typeof window.addEventListener === \"function\") {\n this._resizeHandler = () => {\n try { this._checkDevtools(); } catch {}\n };\n window.addEventListener(\"resize\", this._resizeHandler, { passive: true });\n }\n\n // Run initial evaluation and start periodic timer\n this.evaluate();\n\n // Initial DevTools check \u2014 reports if DevTools is already open at load.\n if (this._otherRiskTypesEnabled) this._checkDevtools();\n\n this._timer = setInterval(() => {\n try { this.evaluate(); } catch {}\n }, this._intervalMs);\n\n // Don't keep the Node.js event loop alive (matches other timers in the SDK).\n if (this._timer && typeof this._timer.unref === \"function\") {\n this._timer.unref();\n }\n\n // Console-getter probe \u2014 catches undocked (separate-window) DevTools that\n // the size-diff heuristic and the \"resize\" listener cannot see. Each tick\n // logs the bait then re-checks the DevTools state so the risk event fires\n // promptly when the Console panel starts rendering.\n if (\n LogDropConstants.DEVTOOLS_CONSOLE_PROBE_ENABLED &&\n this._otherRiskTypesEnabled &&\n typeof window !== \"undefined\" &&\n typeof console !== \"undefined\" &&\n typeof console.log === \"function\"\n ) {\n // Prime once immediately, then poll.\n try { this._devtoolsConsole.probe(); this._checkDevtools(); } catch {}\n\n this._devtoolsProbeTimer = setInterval(() => {\n try {\n this._devtoolsConsole.probe();\n this._checkDevtools();\n } catch {}\n }, LogDropConstants.DEVTOOLS_PROBE_INTERVAL_MS);\n\n if (this._devtoolsProbeTimer && typeof this._devtoolsProbeTimer.unref === \"function\") {\n this._devtoolsProbeTimer.unref();\n }\n }\n }\n\n // Returns a single DevTools signal (never both), preferring the reliable\n // size-based signal and falling back to the console-getter signal that also\n // covers undocked DevTools. Returning one signal avoids double-counting the\n // same \"devtools_open\" event in the risk score.\n _detectDevtoolsSignal() {\n return this._devtools.detect() || this._devtoolsConsole.detect();\n }\n\n // Checks the current DevTools open state and refreshes the full evaluation on\n // transitions. Generic evaluation reports the canonical `devtools_open` id.\n _checkDevtools() {\n if (!this._installed || this._tornDown) return;\n\n const signal = this._detectDevtoolsSignal();\n const open = signal !== null;\n\n if (open && !this._devtoolsOpen) {\n this._devtoolsOpen = true;\n this.evaluate();\n } else if (!open && this._devtoolsOpen) {\n this._devtoolsOpen = false;\n this.evaluate();\n }\n }\n\n teardown() {\n if (!this._installed) return;\n this._tornDown = true;\n\n if (this._timer !== null) {\n clearInterval(this._timer);\n this._timer = null;\n }\n\n if (this._devtoolsProbeTimer !== null) {\n clearInterval(this._devtoolsProbeTimer);\n this._devtoolsProbeTimer = null;\n }\n\n if (this._mousemoveHandler && typeof window !== \"undefined\") {\n try { window.removeEventListener(\"mousemove\", this._mousemoveHandler); } catch {}\n this._mousemoveHandler = null;\n }\n\n if (this._keydownHandler && typeof document !== \"undefined\") {\n try { document.removeEventListener(\"keydown\", this._keydownHandler); } catch {}\n this._keydownHandler = null;\n }\n\n if (this._resizeHandler && typeof window !== \"undefined\") {\n try { window.removeEventListener(\"resize\", this._resizeHandler); } catch {}\n this._resizeHandler = null;\n }\n }\n\n evaluate() {\n if (!this._installed) return;\n\n // Run all signal providers\n const rawSignals = [\n ...(this._botDetectionEnabled ? [\n this._headless.detect(),\n this._automation.detect(),\n this._pointer._samples.length >= MIN_POINTER_SAMPLES ? this._pointer.detect() : null,\n this._keyboard._timestamps.length >= 6 ? this._keyboard.detect() : null,\n ] : []),\n ...(this._otherRiskTypesEnabled ? [\n this._hardware.detect(),\n this._detectDevtoolsSignal(),\n this._incognito.detect(),\n this._sessionPersistence.detect(),\n ] : []),\n ].filter(Boolean);\n\n // Split signals into the two independent categories and score each on its own.\n const botSignals = this._botDetectionEnabled\n ? rawSignals.filter((s) => BOT_SIGNAL_IDS.has(s.id))\n : [];\n const riskSignals = this._otherRiskTypesEnabled\n ? rawSignals.filter((s) => RISK_SIGNAL_IDS.has(s.id))\n : [];\n\n const botScore = computeScore(botSignals);\n const riskScore = computeScore(riskSignals);\n\n // Collecting phase: not enough time has passed and no interaction data\n const elapsed = this._installTime != null ? Date.now() - this._installTime : Infinity;\n const hasPointerData = this._pointer._samples.length >= MIN_POINTER_SAMPLES;\n const collecting = elapsed < MIN_COLLECT_MS && !hasPointerData && rawSignals.length === 0;\n\n // Keep the separate mobile contracts: riskLevel comes from risk only,\n // while session posture combines risk and bot scores.\n let label = this._botDetectionEnabled ? scoreToLabel(botScore, collecting) : \"disabled\";\n const riskLevel = scoreToRiskLevel(riskScore);\n const posture = scoresToPosture(riskScore, botScore);\n\n // Label stabilisation \u2014 automation_suspected is sticky\n if (this._botDetectionEnabled && label === \"automation_suspected\") {\n this._stickyLabel = \"automation_suspected\";\n this._consecutiveNonSuspected = 0;\n } else if (this._botDetectionEnabled && this._stickyLabel === \"automation_suspected\") {\n this._consecutiveNonSuspected++;\n if (this._consecutiveNonSuspected < STICKY_DOWNGRADE_COUNT) {\n label = \"automation_suspected\";\n } else {\n this._stickyLabel = null;\n this._consecutiveNonSuspected = 0;\n }\n }\n\n // Build evidence map from all fired signals\n const evidence = {};\n for (const s of rawSignals) {\n for (const [k, v] of Object.entries(s.evidence ?? {})) {\n evidence[`${s.id}.${k}`] = v;\n }\n }\n\n const reasons = riskSignals.map((signal) => signal.id);\n if (label === \"automation_suspected\" || label === \"uncertain\") reasons.push(label);\n if (reasons.length === 0) {\n reasons.push(posture === \"safe\" ? \"no_local_threats_detected\" : \"local_heuristics_triggered\");\n }\n\n this._snapshot = {\n botScore,\n riskScore,\n label,\n riskLevel,\n posture,\n reasons,\n riskSignals: riskSignals.map((signal) => signal.id),\n botSignals: botSignals.map((signal) => signal.id),\n evidence,\n timestamp: Date.now(),\n };\n\n this._evaluatePolicy([...riskSignals, ...botSignals]);\n this._reportDetectedSignals(riskSignals, botSignals);\n\n // Fire callback only when posture changes\n if (posture !== this._lastPosture) {\n this._lastPosture = posture;\n if (this._onThreatChanged) {\n try { this._onThreatChanged(this.getSessionThreat()); } catch {}\n }\n }\n }\n\n _reportDetectedSignals(riskSignals, botSignals) {\n if (!this._onRiskEvent) return;\n\n const report = (signal, score, category) => {\n if (category === \"bot\" && score < 30) return;\n if (category === \"risk\" && score <= 0) return;\n\n const key = `${category}:${signal.id}`;\n if (this._lastReportedSignals.get(key) === score) return;\n this._lastReportedSignals.set(key, score);\n\n try {\n this._onRiskEvent({\n type: signal.id,\n score,\n category,\n evidence: signal.evidence ?? {},\n snapshot: this.getBotSnapshot(),\n });\n } catch {\n // never break the host app\n }\n };\n\n for (const signal of riskSignals) report(signal, this._snapshot.riskScore, \"risk\");\n for (const signal of botSignals) report(signal, this._snapshot.botScore, \"bot\");\n }\n\n _evaluatePolicy(activeSignals) {\n const detectedEventIds = activeSignals\n .map((signal) => eventIdForSignal(signal.id))\n .filter((eventId) => eventId !== null);\n const evaluation = evaluateRiskPolicy(this._riskPolicy, detectedEventIds);\n const signature = policyEvaluationSignature(evaluation);\n if (signature === this._lastPolicySignature) return;\n this._lastPolicySignature = signature;\n if (this._onPolicyChanged) {\n try { this._onPolicyChanged(evaluation); } catch {}\n }\n }\n\n getBotSnapshot() {\n if (!this._installed) return null;\n return this._snapshot\n ? { ...this._snapshot }\n : {\n botScore: 0,\n riskScore: 0,\n label: \"collecting\",\n riskLevel: \"low\",\n posture: \"safe\",\n reasons: [\"no_local_threats_detected\"],\n riskSignals: [],\n botSignals: [],\n evidence: {},\n timestamp: Date.now(),\n };\n }\n\n getSessionThreat() {\n if (!this._installed) return null;\n const snap = this.getBotSnapshot();\n return {\n botScore: snap.botScore,\n botLabel: snap.label,\n riskScore: snap.riskScore,\n riskLevel: snap.riskLevel,\n posture: snap.posture,\n reasons: [...snap.reasons],\n timestamp: snap.timestamp,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["index_exports", "__export", "LogDrop", "LogDropClient", "LogFlow", "LogLevel", "capturePageState", "fingerprintStack", "generateUUID", "LogDropConstants", "genId", "hasWindow", "perfNow", "safeUrlToString", "input", "safeJsonParse", "str", "parseXhrResponseHeaders", "raw", "out", "lines", "line", "idx", "k", "v", "normalizeBody", "body", "buildFinalNetworkPayload", "requestId", "method", "url", "status", "tookMs", "requestHeaders", "requestBody", "responseHeaders", "responseBody", "errorType", "errorMessage", "didComplete", "isSuccess", "payload", "normalizeUrl", "rawUrl", "baseHref", "stripQuery", "stripHash", "u", "toAbsoluteUrl", "matchExclude", "exclude", "s", "rule", "shouldSample", "sampleRate", "extractFetchMethod", "init", "extractResponseHeaders", "res", "extractFetchHeaders", "source", "NetworkInstrumentation", "opts", "absUrl", "eventName", "meta", "start", "headers", "req", "h", "reqBody", "isError", "isSlow", "ct", "text", "respHeaders", "err", "proto", "async", "user", "password", "name", "value", "client", "ld", "finalize", "txt", "parsed", "hasWindow", "urlBase64ToUint8Array", "base64String", "padding", "base64", "rawData", "output", "i", "createError", "code", "message", "err", "PushModule", "config", "cfg", "LogDropConstants", "sw", "event", "data", "isPushEnabled", "vapidPublicKey", "notificationAvailable", "current", "registration", "applicationServerKey", "existingSubscription", "existingApplicationServerKey", "subscription", "msg", "stale", "subscriptionPayload", "resolve", "settled", "finish", "onMessage", "timer", "resolvedRegistration", "target", "left", "right", "leftBytes", "rightBytes", "pushData", "payload", "executeWebPushAction", "action", "target", "fallback", "InAppMessagePresenter", "onAction", "data", "notificationId", "item", "ttlSeconds", "message", "isBanner", "root", "panel", "close", "image", "title", "body", "buttons", "button", "row", "index", "element", "primary", "event", "showNext", "ProtoWriter", "_ProtoWriter", "value", "v", "fieldNumber", "wireType", "bytes", "i", "buf", "values", "writerFn", "sub", "ProtoReader", "result", "shift", "byte", "startPos", "len", "slice", "multiplier", "val", "encodeDevice", "w", "device", "key", "entry", "encodeUserUpdateRequest", "req", "decodeSdkTokenResponse", "r", "tag", "encodeInitRequest", "readOptionalString", "decodeHttpWhitelistEntry", "decodeSdkRiskActionConfig", "decodeHttpWhitelistRiskConfig", "decodeRiskPolicyRule", "decodePackedVarints", "decodeRiskPolicy", "decodeRiskDetectedConfig", "ipReputationThreatLevelName", "decodeIpReputationPolicyRule", "decodeIpReputationPolicy", "decodeIpReputationDetectedConfig", "decodeIpReputationActiveAction", "decodeWebPushConfig", "decodeSdkRiskConfig", "decodeConfigResponse", "encodeLogRequest", "decodeLogResponse", "encodeCrashReportRequest", "encodeStructValue", "lw", "item", "vw", "sw", "encodeStruct", "obj", "encodeEventItem", "evt", "pw", "encodeEventSession", "session", "ew", "encodeEventBatchRequest", "decodeEventBatchResponse", "hasWindow", "getFetch", "generateEventId", "c", "r", "hasNavigationApi", "EventModule", "config", "cfg", "bool", "eventCode", "properties", "LogDropConstants", "required", "props", "key", "val", "event", "persistPromise", "tx", "request", "resolve", "reject", "storeName", "batch", "store", "allEvents", "storedBatch", "rows", "eventIds", "keepalive", "fetchFn", "sessionToken", "events", "sessionMap", "evt", "sid", "sessions", "sessionId", "sessionData", "firstRealUserUuid", "payload", "protoBytes", "encodeEventBatchRequest", "url", "fetchOptions", "res", "s", "e", "responseBytes", "decodeEventBatchResponse", "err", "destUrl", "self", "args", "PERMISSIONS", "pt", "apiName", "status", "ps", "raw", "hasWindow", "HeadlessBrowserSignalProvider", "indicators", "key", "AutomationEnvironmentSignalProvider", "indicators", "stddev", "values", "mean", "a", "b", "variance", "s", "v", "PointerBehaviorSignalProvider", "x", "y", "time", "samples", "windowStart", "recent", "intervals", "i", "timingMean", "timingStddev", "roboticTiming", "pathLength", "dx", "dy", "first", "last", "straightLine", "straightness", "roboticPath", "span", "denseBurst", "evenlyTimedBurst", "stddev", "values", "m", "a", "b", "variance", "s", "v", "KeyboardCadenceSignalProvider", "ts", "timestamps", "intervals", "isChromium", "ua", "HardwareConsistencySignalProvider", "chromium", "indicators", "plugins", "languages", "DevToolsSignalProvider", "widthDiff", "heightDiff", "DevToolsConsoleSignalProvider", "self", "bait", "IncognitoSignalProvider", "win", "fs", "resolve", "quota", "LS_KEY", "SS_KEY", "getLS", "getSS", "SessionPersistenceSignalProvider", "ls", "ss", "SS_KEY", "token", "raw", "LS_KEY", "sessionCount", "RiskEventIds", "RiskActionIds", "KNOWN_EVENT_IDS", "KNOWN_ACTION_IDS", "SIGNAL_EVENT_IDS", "eventIdForSignal", "signalId", "actionName", "actionId", "evaluateRiskPolicy", "policy", "detectedEventIds", "detected", "rules", "emptyEvaluation", "matchedRules", "rule", "eventIds", "id", "actionIds", "matchType", "a", "b", "firstText", "key", "policyEvaluationSignature", "evaluation", "computeScore", "signals", "complement", "s", "scoreToLabel", "score", "collecting", "scoreToRiskLevel", "scoresToPosture", "riskScore", "botScore", "BOT_SIGNAL_IDS", "RISK_SIGNAL_IDS", "DEFAULT_INTERVAL_MS", "MIN_COLLECT_MS", "MIN_POINTER_SAMPLES", "STICKY_DOWNGRADE_COUNT", "RiskModule", "config", "cfg", "HeadlessBrowserSignalProvider", "AutomationEnvironmentSignalProvider", "PointerBehaviorSignalProvider", "KeyboardCadenceSignalProvider", "HardwareConsistencySignalProvider", "DevToolsSignalProvider", "DevToolsConsoleSignalProvider", "IncognitoSignalProvider", "SessionPersistenceSignalProvider", "LogDropConstants", "open", "rawSignals", "botSignals", "riskSignals", "elapsed", "hasPointerData", "label", "riskLevel", "posture", "evidence", "k", "v", "reasons", "signal", "report", "category", "key", "activeSignals", "detectedEventIds", "eventIdForSignal", "eventId", "evaluation", "evaluateRiskPolicy", "signature", "policyEvaluationSignature", "snap", "__publicField", "LogLevel", "_logLevelValues", "LogFlow", "name", "id", "customAttributes", "LOGDROP_DOMAIN_EXCLUDE", "LOGDROP_INIT_CACHE_KEY", "LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY", "LOGDROP_IP_REPUTATION_ACTION_KEY", "LOGDROP_IP_REPUTATION_SIGNATURES_KEY", "LOGDROP_LAST_USER_UPDATE_KEY", "REDACTED_PROTO_PLACEHOLDER", "SENSITIVE_PROTO_FIELD_NAMES", "nowIso", "d", "pad2", "n", "pad3", "yyyy", "mm", "dd", "HH", "MM", "SS", "ms", "safeStringify", "obj", "hasWindow", "getBaseHref", "normalizeBaseUrl", "baseUrl", "normalized", "fallback", "LogDropConstants", "base", "crc32", "bytes", "crc", "i", "c", "k", "generateUUID", "hex", "b", "r", "fingerprintStack", "stack", "lines", "errorType", "frameNames", "l", "line", "m", "key", "capturePageState", "LogDropClient", "nowIso", "c", "r", "args", "bytes", "limit", "preview", "byte", "fieldName", "normalizedFieldName", "SENSITIVE_PROTO_FIELD_NAMES", "value", "REDACTED_PROTO_PLACEHOLDER", "containsSensitiveData", "summary", "entry", "summarizedEntry", "key", "label", "payload", "protoBytes", "payloadSummary", "responseBytes", "decoder", "decodedSummary", "err", "hasWindow", "deviceId", "normalizedDeviceId", "LOGDROP_TOKEN_RECOVERY_IDENTITY_KEY", "LOGDROP_LAST_USER_UPDATE_KEY", "uuid", "userUuid", "raw", "parsed", "snapshot", "subscription", "keys", "endpoint", "p256dh", "auth", "expirationTime", "normalizedSubscription", "normalized", "recoveryIdentity", "rawValue", "persistedIdentity", "persistedRecoveryIdentity", "reason", "recoveryTarget", "recovered", "storageKey", "tokenName", "normalizedValue", "sessionToken", "accessToken", "refreshToken", "normalizedAccessToken", "normalizedRefreshToken", "normalizedRecoveryIdentity", "webSecretKey", "deviceUuid", "data", "hashBuffer", "b", "ua", "osName", "osVersion", "match", "isExternalUser", "options", "descriptor", "task", "resolve", "result", "config", "fetchFn", "osInfo", "last", "runtime", "LogDropConstants", "device", "deltaFields", "field", "subscriptionChanged", "identityChanged", "hasDeviceDelta", "headers", "usedSignatureAuth", "requestPayload", "encodeUserUpdateRequest", "url", "res", "decodeSdkTokenResponse", "tokenResponse", "info", "snap", "model", "battery", "estimate", "freeBytes", "uaData", "userAgent", "mobileMatch", "parts", "s", "androidDevice", "p", "os", "browser", "osPart", "brPart", "preferred", "edge", "chrome", "firefox", "safari", "k", "sizes", "i", "deviceInfo", "LogLevel", "cached", "LOGDROP_INIT_CACHE_KEY", "response", "applyNetworkChange", "prevHttpLogging", "RiskActionIds", "forceRiskGuard", "NetworkInstrumentation", "eventName", "LogFlow", "getBaseHref", "rawUrl", "riskPolicyBlocks", "ipReputationBlocks", "requestUrl", "sdkUrl", "sdkPath", "requestPath", "LOGDROP_IP_REPUTATION_ACTION_KEY", "action", "serverNow", "receivedAt", "receivedMonotonic", "receivedTimeOrigin", "currentMonotonic", "currentTimeOrigin", "expiresAt", "matchingRule", "rule", "a", "signature", "values", "LOGDROP_IP_REPUTATION_SIGNATURES_KEY", "next", "remaining", "serverNowEpochMillis", "receivedAtClientEpochMillis", "id", "actionName", "showWarning", "clearReason", "previous", "actionIds", "riskDetected", "enabled", "RiskModule", "evt", "evaluation", "apiKey", "defaultWebSecretKey", "baseUrl", "normalizeBaseUrl", "networkCfg", "LOGDROP_DOMAIN_EXCLUDE", "InAppMessagePresenter", "PushModule", "storedRelease", "isSdkUpdated", "previousRelease", "EventModule", "eventLog", "externalId", "completion", "success", "arg0", "arg1", "logFlow", "tagged", "_logLevelValues", "tag", "message", "level", "userInfo", "threadName", "stackTrace", "crashType", "riskScore", "actionsApplied", "blocked", "notificationId", "previousNames", "matchedEventIds", "riskPolicyBlock", "ipReputationBlock", "blockAll", "normalCapture", "showIpReputationWarning", "ipAction", "ipBlocksApp", "policyBlocksApp", "blockApp", "overlay", "panel", "title", "button", "logsSuccess", "crashesSuccess", "safeStringify", "persistPromise", "reject", "request", "db", "tx", "logRecord", "batch", "store", "crash", "ids", "isCustomCrash", "sourceUrl", "line", "column", "pageState", "capturePageState", "sessionStartedAt", "generateUUID", "crashInput", "errorIdentity", "logPromise", "crashPromise", "event", "cursor", "logs", "jsonStr", "currentSize", "maxLimit", "bytesToFree", "idsToDelete", "freedBytes", "log", "logSize", "groups", "sessionId", "deviceInfoLogs", "msg", "sessionGroups", "maxFileSize", "remainingLimit", "effectiveMaxSize", "chunk", "appendSessionLogs", "sessionLogs", "logEntry", "entrySize", "jsonString", "uint8Array", "compressedStream", "compressedBlob", "gzipBytes", "uploadId", "encodeLogRequest", "decodeLogResponse", "logResponse", "encodeCrashReportRequest", "crashes", "crashIds", "formatted", "di", "allLogs", "pendingLogs", "anySuccess", "activeBatch", "activeIds", "activeLogs", "droppedLogIds", "session", "rawDeviceInfo", "formattedLogs", "payloadJson", "payloadSize", "gzipBlob", "uploadResult", "sentLogIds", "attempt", "recoveryReasons", "encodeInitRequest", "decodeConfigResponse", "stack", "LogDrop"]
|
|
7
7
|
}
|