@loamly/tracker 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/detection/navigation-timing.ts","../src/detection/referrer.ts","../src/detection/behavioral-classifier.ts","../src/detection/focus-blur.ts","../src/detection/agentic-browser.ts","../src/infrastructure/event-queue.ts","../src/infrastructure/ping.ts","../src/behavioral/scroll-tracker.ts","../src/behavioral/time-tracker.ts","../src/behavioral/form-tracker.ts","../src/spa/router.ts","../src/utils.ts","../src/core.ts"],"sourcesContent":["/**\n * Loamly Tracker\n * \n * Open-source AI traffic detection for websites.\n * See what AI tells your customers — and track when they click.\n * \n * @module @loamly/tracker\n * @version 1.8.0\n * @license MIT\n * @see https://github.com/loamly/loamly\n * @see https://loamly.ai\n */\n\n// Core tracker\nexport { loamly, loamly as default } from './core'\n\n// Types\nexport type {\n LoamlyConfig,\n LoamlyTracker,\n TrackEventOptions,\n NavigationTiming,\n AIDetectionResult,\n} from './types'\n\n// Detection utilities (for advanced usage)\nexport { detectNavigationType } from './detection/navigation-timing'\nexport { detectAIFromReferrer, detectAIFromUTM } from './detection/referrer'\nexport { \n AgenticBrowserAnalyzer,\n createAgenticAnalyzer,\n type AgenticDetectionResult\n} from './detection/agentic-browser'\n\n// Configuration\nexport { VERSION, AI_PLATFORMS, AI_BOT_PATTERNS } from './config'\n\n\n","/**\n * Loamly Tracker Configuration\n * \n * @module @loamly/tracker\n * @license MIT\n * @see https://github.com/loamly/loamly\n */\n\nexport const VERSION = '2.0.0'\n\nexport const DEFAULT_CONFIG = {\n apiHost: 'https://app.loamly.ai',\n endpoints: {\n visit: '/api/ingest/visit',\n behavioral: '/api/ingest/behavioral',\n session: '/api/ingest/session',\n resolve: '/api/tracker/resolve',\n health: '/api/tracker/health',\n ping: '/api/tracker/ping',\n },\n pingInterval: 30000, // 30 seconds\n batchSize: 10,\n batchTimeout: 5000,\n sessionTimeout: 1800000, // 30 minutes\n maxTextLength: 100,\n timeSpentThresholdMs: 5000, // Only send time_spent when delta >= 5 seconds\n} as const\n\n/**\n * Known AI platforms for referrer detection\n */\nexport const AI_PLATFORMS: Record<string, string> = {\n 'chatgpt.com': 'chatgpt',\n 'chat.openai.com': 'chatgpt',\n 'claude.ai': 'claude',\n 'perplexity.ai': 'perplexity',\n 'bard.google.com': 'bard',\n 'gemini.google.com': 'gemini',\n 'copilot.microsoft.com': 'copilot',\n 'github.com/copilot': 'github-copilot',\n 'you.com': 'you',\n 'phind.com': 'phind',\n 'poe.com': 'poe',\n}\n\n/**\n * User agents of known AI crawlers\n */\nexport const AI_BOT_PATTERNS = [\n 'GPTBot',\n 'ChatGPT-User',\n 'ClaudeBot',\n 'Claude-Web',\n 'PerplexityBot',\n 'Amazonbot',\n 'Google-Extended',\n 'CCBot',\n 'anthropic-ai',\n 'cohere-ai',\n]\n\n\n","/**\n * Navigation Timing API Detection\n * \n * Detects whether the user arrived via paste (from AI chat) vs click\n * by analyzing Navigation Timing API patterns.\n * \n * @module @loamly/tracker/detection\n */\n\nimport type { NavigationTiming } from '../types'\n\n/**\n * Analyze Navigation Timing API to detect paste vs click navigation\n * \n * When users paste a URL (common after copying from AI chat), \n * the timing patterns are distinctive:\n * 1. fetchStart is virtually immediate after navigationStart\n * 2. DNS/connect times are often 0 (cached or direct)\n * 3. No redirect chain\n * 4. Uniform timing patterns\n * \n * @returns NavigationTiming result with type and confidence\n */\nexport function detectNavigationType(): NavigationTiming {\n try {\n const entries = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[]\n \n if (!entries || entries.length === 0) {\n return { nav_type: 'unknown', confidence: 0, signals: ['no_timing_data'] }\n }\n\n const nav = entries[0]\n const signals: string[] = []\n let pasteScore = 0\n\n // Signal 1: fetchStart delta from navigationStart\n // Paste navigation typically has very small delta (< 5ms)\n const fetchStartDelta = nav.fetchStart - nav.startTime\n if (fetchStartDelta < 5) {\n pasteScore += 0.25\n signals.push('instant_fetch_start')\n } else if (fetchStartDelta < 20) {\n pasteScore += 0.15\n signals.push('fast_fetch_start')\n }\n\n // Signal 2: DNS lookup time\n // Paste = likely 0 (direct URL entry, no link warmup)\n const dnsTime = nav.domainLookupEnd - nav.domainLookupStart\n if (dnsTime === 0) {\n pasteScore += 0.15\n signals.push('no_dns_lookup')\n }\n\n // Signal 3: TCP connect time\n // Paste = likely 0 (no preconnect from previous page)\n const connectTime = nav.connectEnd - nav.connectStart\n if (connectTime === 0) {\n pasteScore += 0.15\n signals.push('no_tcp_connect')\n }\n\n // Signal 4: No redirects\n // Paste URLs are typically direct, no redirects\n if (nav.redirectCount === 0) {\n pasteScore += 0.1\n signals.push('no_redirects')\n }\n\n // Signal 5: Timing uniformity check\n // Paste navigation tends to have more uniform patterns\n const timingVariance = calculateTimingVariance(nav)\n if (timingVariance < 10) {\n pasteScore += 0.15\n signals.push('uniform_timing')\n }\n\n // Signal 6: No referrer (common for paste)\n if (!document.referrer || document.referrer === '') {\n pasteScore += 0.1\n signals.push('no_referrer')\n }\n\n // Determine navigation type based on score\n const confidence = Math.min(pasteScore, 1)\n const nav_type = pasteScore >= 0.5 ? 'likely_paste' : 'likely_click'\n\n return {\n nav_type,\n confidence: Math.round(confidence * 1000) / 1000,\n signals,\n }\n } catch {\n return { nav_type: 'unknown', confidence: 0, signals: ['detection_error'] }\n }\n}\n\n/**\n * Calculate timing variance to detect paste patterns\n */\nfunction calculateTimingVariance(nav: PerformanceNavigationTiming): number {\n const timings = [\n nav.fetchStart - nav.startTime,\n nav.domainLookupEnd - nav.domainLookupStart,\n nav.connectEnd - nav.connectStart,\n nav.responseStart - nav.requestStart,\n ].filter((t) => t >= 0)\n\n if (timings.length === 0) return 100\n\n const mean = timings.reduce((a, b) => a + b, 0) / timings.length\n const variance = timings.reduce((sum, t) => sum + Math.pow(t - mean, 2), 0) / timings.length\n \n return Math.sqrt(variance)\n}\n\n\n","/**\n * Referrer-based AI Detection\n * \n * Detects when users arrive from known AI platforms\n * based on the document.referrer header.\n * \n * @module @loamly/tracker/detection\n */\n\nimport { AI_PLATFORMS } from '../config'\nimport type { AIDetectionResult } from '../types'\n\n/**\n * Detect AI platform from referrer URL\n * \n * @param referrer - The document.referrer value\n * @returns AI detection result or null if no AI detected\n */\nexport function detectAIFromReferrer(referrer: string): AIDetectionResult | null {\n if (!referrer) {\n return null\n }\n\n try {\n const url = new URL(referrer)\n const hostname = url.hostname.toLowerCase()\n\n // Check against known AI platforms\n for (const [pattern, platform] of Object.entries(AI_PLATFORMS)) {\n if (hostname.includes(pattern) || referrer.includes(pattern)) {\n return {\n isAI: true,\n platform,\n confidence: 0.95, // High confidence when referrer matches\n method: 'referrer',\n }\n }\n }\n\n return null\n } catch {\n // Invalid URL, try pattern matching on raw string\n for (const [pattern, platform] of Object.entries(AI_PLATFORMS)) {\n if (referrer.toLowerCase().includes(pattern.toLowerCase())) {\n return {\n isAI: true,\n platform,\n confidence: 0.85,\n method: 'referrer',\n }\n }\n }\n return null\n }\n}\n\n/**\n * Extract AI platform from UTM parameters\n * \n * @param url - The current page URL\n * @returns AI platform name or null\n */\nexport function detectAIFromUTM(url: string): AIDetectionResult | null {\n try {\n const params = new URL(url).searchParams\n \n // Check utm_source for AI platforms\n const utmSource = params.get('utm_source')?.toLowerCase()\n if (utmSource) {\n for (const [pattern, platform] of Object.entries(AI_PLATFORMS)) {\n if (utmSource.includes(pattern.split('.')[0])) {\n return {\n isAI: true,\n platform,\n confidence: 0.99, // Very high confidence from explicit UTM\n method: 'referrer',\n }\n }\n }\n \n // Generic AI source patterns\n if (utmSource.includes('ai') || utmSource.includes('llm') || utmSource.includes('chatbot')) {\n return {\n isAI: true,\n platform: utmSource,\n confidence: 0.9,\n method: 'referrer',\n }\n }\n }\n\n return null\n } catch {\n return null\n }\n}\n\n\n","/**\n * Lightweight Behavioral ML Classifier\n * \n * LOA-180: Client-side Naive Bayes classifier for AI traffic detection.\n * Research: 75-90% accuracy with 5-8 behavioral signals (Perplexity Dec 2025)\n * \n * @module @loamly/tracker/detection/behavioral-classifier\n */\n\n/**\n * Behavioral signal types for classification\n */\nexport type BehavioralSignal = \n // Time-based signals\n | 'time_to_first_click_immediate' // < 500ms\n | 'time_to_first_click_fast' // 500ms - 2s\n | 'time_to_first_click_normal' // 2s - 10s\n | 'time_to_first_click_delayed' // > 10s\n // Scroll signals\n | 'scroll_speed_none' // No scroll\n | 'scroll_speed_uniform' // Bot-like uniform scrolling\n | 'scroll_speed_variable' // Human-like variable\n | 'scroll_speed_erratic' // Very erratic\n // Navigation signals\n | 'nav_timing_paste'\n | 'nav_timing_click'\n | 'nav_timing_unknown'\n // Context signals\n | 'no_referrer'\n | 'has_referrer'\n | 'deep_landing' // Non-homepage first page\n | 'homepage_landing'\n // Mouse signals\n | 'mouse_movement_none'\n | 'mouse_movement_linear' // Bot-like straight lines\n | 'mouse_movement_curved' // Human-like curves\n // Form signals\n | 'form_fill_instant' // < 100ms per field\n | 'form_fill_fast' // 100-500ms per field\n | 'form_fill_normal' // > 500ms per field\n // Focus signals\n | 'focus_blur_rapid' // Rapid tab switching\n | 'focus_blur_normal'\n\n/**\n * Classification result\n */\nexport interface BehavioralClassificationResult {\n /** Overall classification */\n classification: 'human' | 'ai_influenced' | 'uncertain'\n /** Human probability (0-1) */\n humanProbability: number\n /** AI-influenced probability (0-1) */\n aiProbability: number\n /** Confidence in classification (0-1) */\n confidence: number\n /** Signals detected */\n signals: BehavioralSignal[]\n /** Time when classification was made */\n timestamp: number\n /** Session duration when classified */\n sessionDurationMs: number\n}\n\n/**\n * Behavioral data collector\n */\ninterface BehavioralData {\n firstClickTime: number | null\n scrollEvents: { time: number; position: number }[]\n mouseEvents: { time: number; x: number; y: number }[]\n formEvents: { fieldId: string; startTime: number; endTime: number }[]\n focusBlurEvents: { type: 'focus' | 'blur'; time: number }[]\n startTime: number\n}\n\n/**\n * Pre-trained Naive Bayes weights\n * Research-validated weights from Perplexity Dec 2025 research\n */\nconst NAIVE_BAYES_WEIGHTS = {\n human: {\n time_to_first_click_delayed: 0.85,\n time_to_first_click_normal: 0.75,\n time_to_first_click_fast: 0.50,\n time_to_first_click_immediate: 0.25,\n scroll_speed_variable: 0.80,\n scroll_speed_erratic: 0.70,\n scroll_speed_uniform: 0.35,\n scroll_speed_none: 0.45,\n nav_timing_click: 0.75,\n nav_timing_unknown: 0.55,\n nav_timing_paste: 0.35,\n has_referrer: 0.70,\n no_referrer: 0.45,\n homepage_landing: 0.65,\n deep_landing: 0.50,\n mouse_movement_curved: 0.90,\n mouse_movement_linear: 0.30,\n mouse_movement_none: 0.40,\n form_fill_normal: 0.85,\n form_fill_fast: 0.60,\n form_fill_instant: 0.20,\n focus_blur_normal: 0.75,\n focus_blur_rapid: 0.45,\n },\n ai_influenced: {\n time_to_first_click_immediate: 0.75,\n time_to_first_click_fast: 0.55,\n time_to_first_click_normal: 0.40,\n time_to_first_click_delayed: 0.35,\n scroll_speed_none: 0.55,\n scroll_speed_uniform: 0.70,\n scroll_speed_variable: 0.35,\n scroll_speed_erratic: 0.40,\n nav_timing_paste: 0.75,\n nav_timing_unknown: 0.50,\n nav_timing_click: 0.35,\n no_referrer: 0.65,\n has_referrer: 0.40,\n deep_landing: 0.60,\n homepage_landing: 0.45,\n mouse_movement_none: 0.60,\n mouse_movement_linear: 0.75,\n mouse_movement_curved: 0.25,\n form_fill_instant: 0.80,\n form_fill_fast: 0.55,\n form_fill_normal: 0.30,\n focus_blur_rapid: 0.60,\n focus_blur_normal: 0.40,\n },\n} as const\n\n// Prior probabilities (base rates)\nconst PRIORS = {\n human: 0.85,\n ai_influenced: 0.15,\n}\n\n// Default weight for unknown signals\nconst DEFAULT_WEIGHT = 0.5\n\n/**\n * Behavioral Classifier\n * \n * Lightweight Naive Bayes classifier (~2KB) for client-side AI traffic detection.\n * Collects behavioral signals and classifies after configurable session time.\n */\nexport class BehavioralClassifier {\n private data: BehavioralData\n private classified = false\n private result: BehavioralClassificationResult | null = null\n private minSessionTime: number\n private onClassify: ((result: BehavioralClassificationResult) => void) | null = null\n\n /**\n * Create a new classifier\n * @param minSessionTimeMs Minimum session time before classification (default: 10s)\n */\n constructor(minSessionTimeMs = 10000) {\n this.minSessionTime = minSessionTimeMs\n this.data = {\n firstClickTime: null,\n scrollEvents: [],\n mouseEvents: [],\n formEvents: [],\n focusBlurEvents: [],\n startTime: Date.now(),\n }\n }\n\n /**\n * Set callback for when classification completes\n */\n setOnClassify(callback: (result: BehavioralClassificationResult) => void): void {\n this.onClassify = callback\n }\n\n /**\n * Record a click event\n */\n recordClick(): void {\n if (this.data.firstClickTime === null) {\n this.data.firstClickTime = Date.now()\n }\n this.checkAndClassify()\n }\n\n /**\n * Record a scroll event\n */\n recordScroll(position: number): void {\n this.data.scrollEvents.push({ time: Date.now(), position })\n // Keep only last 50 events to limit memory\n if (this.data.scrollEvents.length > 50) {\n this.data.scrollEvents = this.data.scrollEvents.slice(-50)\n }\n this.checkAndClassify()\n }\n\n /**\n * Record mouse movement\n */\n recordMouse(x: number, y: number): void {\n this.data.mouseEvents.push({ time: Date.now(), x, y })\n // Keep only last 100 events\n if (this.data.mouseEvents.length > 100) {\n this.data.mouseEvents = this.data.mouseEvents.slice(-100)\n }\n this.checkAndClassify()\n }\n\n /**\n * Record form field interaction start\n */\n recordFormStart(fieldId: string): void {\n const existing = this.data.formEvents.find(e => e.fieldId === fieldId && e.endTime === 0)\n if (!existing) {\n this.data.formEvents.push({ fieldId, startTime: Date.now(), endTime: 0 })\n }\n }\n\n /**\n * Record form field interaction end\n */\n recordFormEnd(fieldId: string): void {\n const event = this.data.formEvents.find(e => e.fieldId === fieldId && e.endTime === 0)\n if (event) {\n event.endTime = Date.now()\n }\n this.checkAndClassify()\n }\n\n /**\n * Record focus/blur event\n */\n recordFocusBlur(type: 'focus' | 'blur'): void {\n this.data.focusBlurEvents.push({ type, time: Date.now() })\n // Keep only last 20 events\n if (this.data.focusBlurEvents.length > 20) {\n this.data.focusBlurEvents = this.data.focusBlurEvents.slice(-20)\n }\n }\n\n /**\n * Check if we have enough data and classify\n */\n private checkAndClassify(): void {\n if (this.classified) return\n \n const sessionDuration = Date.now() - this.data.startTime\n if (sessionDuration < this.minSessionTime) return\n \n // Need at least some behavioral data\n const hasData = \n this.data.scrollEvents.length >= 2 ||\n this.data.mouseEvents.length >= 5 ||\n this.data.firstClickTime !== null\n \n if (!hasData) return\n \n this.classify()\n }\n\n /**\n * Force classification (for beforeunload)\n */\n forceClassify(): BehavioralClassificationResult | null {\n if (this.classified) return this.result\n return this.classify()\n }\n\n /**\n * Perform classification\n */\n private classify(): BehavioralClassificationResult {\n const sessionDuration = Date.now() - this.data.startTime\n const signals = this.extractSignals()\n \n // Naive Bayes log-probability calculation\n let humanLogProb = Math.log(PRIORS.human)\n let aiLogProb = Math.log(PRIORS.ai_influenced)\n \n for (const signal of signals) {\n const humanWeight = NAIVE_BAYES_WEIGHTS.human[signal as keyof typeof NAIVE_BAYES_WEIGHTS.human] ?? DEFAULT_WEIGHT\n const aiWeight = NAIVE_BAYES_WEIGHTS.ai_influenced[signal as keyof typeof NAIVE_BAYES_WEIGHTS.ai_influenced] ?? DEFAULT_WEIGHT\n \n humanLogProb += Math.log(humanWeight)\n aiLogProb += Math.log(aiWeight)\n }\n \n // Convert to probabilities using log-sum-exp trick\n const maxLog = Math.max(humanLogProb, aiLogProb)\n const humanExp = Math.exp(humanLogProb - maxLog)\n const aiExp = Math.exp(aiLogProb - maxLog)\n const total = humanExp + aiExp\n \n const humanProbability = humanExp / total\n const aiProbability = aiExp / total\n \n // Determine classification\n let classification: 'human' | 'ai_influenced' | 'uncertain'\n let confidence: number\n \n if (humanProbability > 0.6) {\n classification = 'human'\n confidence = humanProbability\n } else if (aiProbability > 0.6) {\n classification = 'ai_influenced'\n confidence = aiProbability\n } else {\n classification = 'uncertain'\n confidence = Math.max(humanProbability, aiProbability)\n }\n \n this.result = {\n classification,\n humanProbability,\n aiProbability,\n confidence,\n signals,\n timestamp: Date.now(),\n sessionDurationMs: sessionDuration,\n }\n \n this.classified = true\n \n // Call callback if set\n if (this.onClassify) {\n this.onClassify(this.result)\n }\n \n return this.result\n }\n\n /**\n * Extract behavioral signals from collected data\n */\n private extractSignals(): BehavioralSignal[] {\n const signals: BehavioralSignal[] = []\n // Session duration available for future enhancements\n // const sessionDuration = Date.now() - this.data.startTime\n \n // Time to first click\n if (this.data.firstClickTime !== null) {\n const timeToClick = this.data.firstClickTime - this.data.startTime\n if (timeToClick < 500) {\n signals.push('time_to_first_click_immediate')\n } else if (timeToClick < 2000) {\n signals.push('time_to_first_click_fast')\n } else if (timeToClick < 10000) {\n signals.push('time_to_first_click_normal')\n } else {\n signals.push('time_to_first_click_delayed')\n }\n }\n \n // Scroll behavior\n if (this.data.scrollEvents.length === 0) {\n signals.push('scroll_speed_none')\n } else if (this.data.scrollEvents.length >= 3) {\n const scrollDeltas: number[] = []\n for (let i = 1; i < this.data.scrollEvents.length; i++) {\n const delta = this.data.scrollEvents[i].time - this.data.scrollEvents[i - 1].time\n scrollDeltas.push(delta)\n }\n \n // Calculate coefficient of variation for scroll timing\n const mean = scrollDeltas.reduce((a, b) => a + b, 0) / scrollDeltas.length\n const variance = scrollDeltas.reduce((sum, d) => sum + Math.pow(d - mean, 2), 0) / scrollDeltas.length\n const stdDev = Math.sqrt(variance)\n const cv = mean > 0 ? stdDev / mean : 0\n \n if (cv < 0.2) {\n signals.push('scroll_speed_uniform') // Very consistent = bot-like\n } else if (cv < 0.6) {\n signals.push('scroll_speed_variable') // Natural variation\n } else {\n signals.push('scroll_speed_erratic')\n }\n }\n \n // Mouse movement analysis\n if (this.data.mouseEvents.length === 0) {\n signals.push('mouse_movement_none')\n } else if (this.data.mouseEvents.length >= 10) {\n // Calculate linearity using R² of best-fit line\n const n = Math.min(this.data.mouseEvents.length, 20)\n const recentMouse = this.data.mouseEvents.slice(-n)\n \n let sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0\n for (const event of recentMouse) {\n sumX += event.x\n sumY += event.y\n sumXY += event.x * event.y\n sumX2 += event.x * event.x\n }\n \n const denominator = (n * sumX2 - sumX * sumX)\n const slope = denominator !== 0 ? (n * sumXY - sumX * sumY) / denominator : 0\n const intercept = (sumY - slope * sumX) / n\n \n // Calculate R²\n let ssRes = 0, ssTot = 0\n const yMean = sumY / n\n for (const event of recentMouse) {\n const yPred = slope * event.x + intercept\n ssRes += Math.pow(event.y - yPred, 2)\n ssTot += Math.pow(event.y - yMean, 2)\n }\n \n const r2 = ssTot !== 0 ? 1 - (ssRes / ssTot) : 0\n \n if (r2 > 0.95) {\n signals.push('mouse_movement_linear') // Too straight = bot-like\n } else {\n signals.push('mouse_movement_curved') // Natural curves\n }\n }\n \n // Form fill timing\n const completedForms = this.data.formEvents.filter(e => e.endTime > 0)\n if (completedForms.length > 0) {\n const avgFillTime = completedForms.reduce((sum, e) => sum + (e.endTime - e.startTime), 0) / completedForms.length\n \n if (avgFillTime < 100) {\n signals.push('form_fill_instant')\n } else if (avgFillTime < 500) {\n signals.push('form_fill_fast')\n } else {\n signals.push('form_fill_normal')\n }\n }\n \n // Focus/blur patterns\n if (this.data.focusBlurEvents.length >= 4) {\n const recentFB = this.data.focusBlurEvents.slice(-10)\n const intervals: number[] = []\n \n for (let i = 1; i < recentFB.length; i++) {\n intervals.push(recentFB[i].time - recentFB[i - 1].time)\n }\n \n const avgInterval = intervals.reduce((a, b) => a + b, 0) / intervals.length\n \n if (avgInterval < 1000) {\n signals.push('focus_blur_rapid')\n } else {\n signals.push('focus_blur_normal')\n }\n }\n \n // Context signals (will be set from outside)\n // These are typically added by the tracker itself\n \n return signals\n }\n\n /**\n * Add context signals (set by tracker from external data)\n */\n addContextSignal(_signal: BehavioralSignal): void {\n // These will be picked up on next classification\n // For now, we'll handle them in the classify method\n // TODO: Store signals for next classification run\n }\n\n /**\n * Get current result (null if not yet classified)\n */\n getResult(): BehavioralClassificationResult | null {\n return this.result\n }\n\n /**\n * Check if classification has been performed\n */\n hasClassified(): boolean {\n return this.classified\n }\n}\n\n/**\n * Create a classifier instance with standard configuration\n */\nexport function createBehavioralClassifier(minSessionTimeMs = 10000): BehavioralClassifier {\n return new BehavioralClassifier(minSessionTimeMs)\n}\n\n","/**\n * Focus/Blur Event Sequence Analysis\n * \n * LOA-182: Detects paste vs click navigation patterns by analyzing\n * the sequence of focus and blur events when a page loads.\n * \n * Research: 55-65% accuracy (improves when combined with other signals)\n * \n * @module @loamly/tracker/detection/focus-blur\n */\n\n/**\n * Focus/blur event record\n */\nexport interface FocusBlurEvent {\n type: 'focus' | 'blur' | 'window_focus' | 'window_blur'\n target: string\n timestamp: number\n}\n\n/**\n * Focus/blur analysis result\n */\nexport interface FocusBlurResult {\n /** Navigation pattern type */\n nav_type: 'likely_paste' | 'likely_click' | 'unknown'\n /** Confidence score (0-1) */\n confidence: number\n /** Detection signals */\n signals: string[]\n /** Event sequence (last 10 events) */\n sequence: FocusBlurEvent[]\n /** Time from page load to first interaction */\n time_to_first_interaction_ms: number | null\n}\n\n/**\n * Focus/Blur Sequence Analyzer\n * \n * Tracks focus and blur events to detect paste navigation patterns.\n * Paste navigation typically shows:\n * 1. Early window focus event\n * 2. Body focus without prior link navigation\n * 3. No referrer blur pattern\n */\nexport class FocusBlurAnalyzer {\n private sequence: FocusBlurEvent[] = []\n private pageLoadTime: number\n private firstInteractionTime: number | null = null\n private analyzed = false\n private result: FocusBlurResult | null = null\n\n constructor() {\n this.pageLoadTime = performance.now()\n }\n\n /**\n * Initialize event tracking\n * Must be called after DOM is ready\n */\n initTracking(): void {\n // Track focus events (use capturing phase to catch all events)\n document.addEventListener('focus', (e) => {\n this.recordEvent('focus', e.target as HTMLElement)\n }, true)\n\n document.addEventListener('blur', (e) => {\n this.recordEvent('blur', e.target as HTMLElement)\n }, true)\n\n // Track window focus/blur\n window.addEventListener('focus', () => {\n this.recordEvent('window_focus', null)\n })\n\n window.addEventListener('blur', () => {\n this.recordEvent('window_blur', null)\n })\n\n // Track first click/keypress as first interaction\n const recordFirstInteraction = () => {\n if (this.firstInteractionTime === null) {\n this.firstInteractionTime = performance.now()\n }\n }\n document.addEventListener('click', recordFirstInteraction, { once: true, passive: true })\n document.addEventListener('keydown', recordFirstInteraction, { once: true, passive: true })\n }\n\n /**\n * Record a focus/blur event\n */\n private recordEvent(type: FocusBlurEvent['type'], target: HTMLElement | null): void {\n const event: FocusBlurEvent = {\n type,\n target: target?.tagName || 'WINDOW',\n timestamp: performance.now()\n }\n \n this.sequence.push(event)\n \n // Keep only last 20 events to limit memory\n if (this.sequence.length > 20) {\n this.sequence = this.sequence.slice(-20)\n }\n }\n\n /**\n * Analyze the focus/blur sequence for paste patterns\n */\n analyze(): FocusBlurResult {\n if (this.analyzed && this.result) {\n return this.result\n }\n\n const signals: string[] = []\n let confidence = 0\n \n // Get early events (first 500ms after page load)\n const earlyEvents = this.sequence.filter(e => e.timestamp < this.pageLoadTime + 500)\n \n // Pattern 1: Window focus as first event\n const hasEarlyWindowFocus = earlyEvents.some(e => e.type === 'window_focus')\n if (hasEarlyWindowFocus) {\n signals.push('early_window_focus')\n confidence += 0.15\n }\n \n // Pattern 2: Body focus early (paste causes immediate body focus)\n const hasEarlyBodyFocus = earlyEvents.some(\n e => e.type === 'focus' && e.target === 'BODY'\n )\n if (hasEarlyBodyFocus) {\n signals.push('early_body_focus')\n confidence += 0.15\n }\n \n // Pattern 3: No link/anchor focus (would indicate click navigation)\n const hasLinkFocus = this.sequence.some(\n e => e.type === 'focus' && e.target === 'A'\n )\n if (!hasLinkFocus) {\n signals.push('no_link_focus')\n confidence += 0.10\n }\n \n // Pattern 4: First focus is on document/body (not a specific element)\n const firstFocus = this.sequence.find(e => e.type === 'focus')\n if (firstFocus && (firstFocus.target === 'BODY' || firstFocus.target === 'HTML')) {\n signals.push('first_focus_body')\n confidence += 0.10\n }\n \n // Pattern 5: No rapid tab switching (common in human navigation)\n const windowEvents = this.sequence.filter(\n e => e.type === 'window_focus' || e.type === 'window_blur'\n )\n if (windowEvents.length <= 2) {\n signals.push('minimal_window_switches')\n confidence += 0.05\n }\n \n // Pattern 6: Time to first interaction\n // Paste users often have longer time before first interaction\n // (reading content they copied from AI)\n if (this.firstInteractionTime !== null) {\n const timeToInteraction = this.firstInteractionTime - this.pageLoadTime\n if (timeToInteraction > 3000) {\n signals.push('delayed_first_interaction')\n confidence += 0.10\n }\n }\n \n // Cap confidence based on research (55-65% accuracy)\n confidence = Math.min(confidence, 0.65)\n \n // Determine navigation type\n let navType: FocusBlurResult['nav_type']\n if (confidence >= 0.35) {\n navType = 'likely_paste'\n } else if (signals.length === 0) {\n navType = 'unknown'\n } else {\n navType = 'likely_click'\n }\n \n this.result = {\n nav_type: navType,\n confidence,\n signals,\n sequence: this.sequence.slice(-10),\n time_to_first_interaction_ms: this.firstInteractionTime \n ? Math.round(this.firstInteractionTime - this.pageLoadTime)\n : null\n }\n \n this.analyzed = true\n return this.result\n }\n\n /**\n * Get current result (analyze if not done)\n */\n getResult(): FocusBlurResult {\n return this.analyze()\n }\n\n /**\n * Check if analysis has been performed\n */\n hasAnalyzed(): boolean {\n return this.analyzed\n }\n\n /**\n * Get the raw sequence for debugging\n */\n getSequence(): FocusBlurEvent[] {\n return [...this.sequence]\n }\n\n /**\n * Reset the analyzer\n */\n reset(): void {\n this.sequence = []\n this.pageLoadTime = performance.now()\n this.firstInteractionTime = null\n this.analyzed = false\n this.result = null\n }\n}\n\n/**\n * Create a new focus/blur analyzer\n */\nexport function createFocusBlurAnalyzer(): FocusBlurAnalyzer {\n const analyzer = new FocusBlurAnalyzer()\n \n // Initialize tracking when DOM is ready\n if (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => analyzer.initTracking())\n } else {\n analyzer.initTracking()\n }\n }\n \n return analyzer\n}\n\n","/**\n * Agentic Browser Detection\n * \n * LOA-187: Detects AI agentic browsers like Perplexity Comet, ChatGPT Atlas,\n * and other automated browsing agents.\n * \n * Detection methods:\n * - DOM fingerprinting (Perplexity Comet overlay)\n * - Mouse movement patterns (teleporting clicks)\n * - CDP (Chrome DevTools Protocol) automation fingerprint\n * - navigator.webdriver detection\n * \n * @module @loamly/tracker/detection/agentic-browser\n * @license MIT\n */\n\n/**\n * Agentic detection result\n */\nexport interface AgenticDetectionResult {\n /** Whether Perplexity Comet DOM element was detected */\n cometDOMDetected: boolean\n /** Whether CDP automation was detected */\n cdpDetected: boolean\n /** Mouse movement patterns */\n mousePatterns: {\n teleportingClicks: number\n totalMovements: number\n }\n /** Overall agentic probability (0-1) */\n agenticProbability: number\n /** Detection signals */\n signals: string[]\n}\n\n/**\n * Perplexity Comet DOM Detector\n * \n * Detects the Comet browser overlay stop button which is injected\n * into the DOM when Comet is actively browsing.\n */\nexport class CometDetector {\n private detected = false\n private checkComplete = false\n private observer: MutationObserver | null = null\n\n /**\n * Initialize detection\n * @param timeout - Max time to observe for Comet DOM (default: 5s)\n */\n init(timeout = 5000): void {\n if (typeof document === 'undefined') return\n\n // Initial check\n this.check()\n\n if (!this.detected && document.body) {\n // Observe for dynamic injection\n this.observer = new MutationObserver(() => this.check())\n this.observer.observe(document.body, { childList: true, subtree: true })\n\n // Stop observing after timeout\n setTimeout(() => {\n if (this.observer && !this.detected) {\n this.observer.disconnect()\n this.observer = null\n this.checkComplete = true\n }\n }, timeout)\n }\n }\n\n private check(): void {\n // Perplexity Comet injects an overlay with this class\n if (document.querySelector('.pplx-agent-overlay-stop-button')) {\n this.detected = true\n this.checkComplete = true\n if (this.observer) {\n this.observer.disconnect()\n this.observer = null\n }\n }\n }\n\n isDetected(): boolean {\n return this.detected\n }\n\n isCheckComplete(): boolean {\n return this.checkComplete\n }\n\n destroy(): void {\n if (this.observer) {\n this.observer.disconnect()\n this.observer = null\n }\n }\n}\n\n/**\n * Mouse Movement Analyzer\n * \n * Detects unnatural mouse movements characteristic of automated browsers:\n * - Teleporting clicks (instant large movements)\n * - Perfect linear movements\n * - No micro-adjustments\n */\nexport class MouseAnalyzer {\n private lastX = -1\n private lastY = -1\n private teleportingClicks = 0\n private totalMovements = 0\n private readonly teleportThreshold: number\n\n /**\n * @param teleportThreshold - Distance in pixels to consider a teleport (default: 500)\n */\n constructor(teleportThreshold = 500) {\n this.teleportThreshold = teleportThreshold\n }\n\n /**\n * Initialize mouse tracking\n */\n init(): void {\n if (typeof document === 'undefined') return\n\n document.addEventListener('mousemove', this.handleMove, { passive: true })\n document.addEventListener('mousedown', this.handleClick, { passive: true })\n }\n\n private handleMove = (e: MouseEvent): void => {\n this.totalMovements++\n this.lastX = e.clientX\n this.lastY = e.clientY\n }\n\n private handleClick = (e: MouseEvent): void => {\n if (this.lastX !== -1 && this.lastY !== -1) {\n const dx = Math.abs(e.clientX - this.lastX)\n const dy = Math.abs(e.clientY - this.lastY)\n\n // Large instant movement before click = teleporting\n if (dx > this.teleportThreshold || dy > this.teleportThreshold) {\n this.teleportingClicks++\n }\n }\n this.lastX = e.clientX\n this.lastY = e.clientY\n }\n\n getPatterns(): { teleportingClicks: number; totalMovements: number } {\n return {\n teleportingClicks: this.teleportingClicks,\n totalMovements: this.totalMovements,\n }\n }\n\n destroy(): void {\n if (typeof document === 'undefined') return\n document.removeEventListener('mousemove', this.handleMove)\n document.removeEventListener('mousedown', this.handleClick)\n }\n}\n\n/**\n * CDP (Chrome DevTools Protocol) Automation Detector\n * \n * Detects headless browsers and automation tools:\n * - navigator.webdriver (set by Selenium, Puppeteer, Playwright)\n * - Chrome automation flags\n * - Missing browser APIs\n */\nexport class CDPDetector {\n private detected = false\n\n /**\n * Run detection checks\n */\n detect(): boolean {\n if (typeof navigator === 'undefined') return false\n\n // Check 1: navigator.webdriver (Chrome 76+, Firefox 60+)\n // Set to true by automation frameworks\n if ((navigator as Navigator & { webdriver?: boolean }).webdriver) {\n this.detected = true\n return true\n }\n\n // Check 2: Chrome automation extension (legacy check)\n if (typeof window !== 'undefined') {\n const win = window as Window & {\n chrome?: { runtime?: unknown }\n __webdriver_evaluate?: unknown\n __selenium_evaluate?: unknown\n __webdriver_script_function?: unknown\n __webdriver_script_func?: unknown\n __webdriver_script_fn?: unknown\n __fxdriver_evaluate?: unknown\n __driver_unwrapped?: unknown\n __webdriver_unwrapped?: unknown\n __driver_evaluate?: unknown\n __selenium_unwrapped?: unknown\n __fxdriver_unwrapped?: unknown\n }\n\n // Selenium/WebDriver fingerprints\n const automationProps = [\n '__webdriver_evaluate',\n '__selenium_evaluate',\n '__webdriver_script_function',\n '__webdriver_script_func',\n '__webdriver_script_fn',\n '__fxdriver_evaluate',\n '__driver_unwrapped',\n '__webdriver_unwrapped',\n '__driver_evaluate',\n '__selenium_unwrapped',\n '__fxdriver_unwrapped',\n ]\n\n for (const prop of automationProps) {\n if (prop in win) {\n this.detected = true\n return true\n }\n }\n }\n\n return false\n }\n\n isDetected(): boolean {\n return this.detected\n }\n}\n\n/**\n * Agentic Browser Analyzer\n * \n * Combines all detection methods into a unified result.\n */\nexport class AgenticBrowserAnalyzer {\n private cometDetector: CometDetector\n private mouseAnalyzer: MouseAnalyzer\n private cdpDetector: CDPDetector\n private initialized = false\n\n constructor() {\n this.cometDetector = new CometDetector()\n this.mouseAnalyzer = new MouseAnalyzer()\n this.cdpDetector = new CDPDetector()\n }\n\n /**\n * Initialize all detectors\n */\n init(): void {\n if (this.initialized) return\n this.initialized = true\n\n this.cometDetector.init()\n this.mouseAnalyzer.init()\n this.cdpDetector.detect()\n }\n\n /**\n * Get current detection result\n */\n getResult(): AgenticDetectionResult {\n const signals: string[] = []\n let probability = 0\n\n // Comet detection (85% confidence)\n if (this.cometDetector.isDetected()) {\n signals.push('comet_dom_detected')\n probability = Math.max(probability, 0.85)\n }\n\n // CDP detection (92% confidence)\n if (this.cdpDetector.isDetected()) {\n signals.push('cdp_detected')\n probability = Math.max(probability, 0.92)\n }\n\n // Mouse patterns (78% confidence per teleport)\n const mousePatterns = this.mouseAnalyzer.getPatterns()\n if (mousePatterns.teleportingClicks > 0) {\n signals.push(`teleporting_clicks:${mousePatterns.teleportingClicks}`)\n probability = Math.max(probability, 0.78)\n }\n\n return {\n cometDOMDetected: this.cometDetector.isDetected(),\n cdpDetected: this.cdpDetector.isDetected(),\n mousePatterns,\n agenticProbability: probability,\n signals,\n }\n }\n\n /**\n * Cleanup resources\n */\n destroy(): void {\n this.cometDetector.destroy()\n this.mouseAnalyzer.destroy()\n }\n}\n\n/**\n * Create and initialize an agentic browser analyzer\n */\nexport function createAgenticAnalyzer(): AgenticBrowserAnalyzer {\n const analyzer = new AgenticBrowserAnalyzer()\n\n if (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => analyzer.init())\n } else {\n analyzer.init()\n }\n }\n\n return analyzer\n}\n\n","/**\n * Event Queue with Batching, Retry & Persistence\n * \n * Production-grade event delivery with:\n * - Batch processing for network efficiency\n * - Retry with exponential backoff\n * - localStorage persistence for offline support\n * - sendBeacon fallback for unload events\n * \n * @module @loamly/tracker\n */\n\nimport { DEFAULT_CONFIG } from '../config'\n\nexport interface QueuedEvent {\n id: string\n type: string\n payload: Record<string, unknown>\n timestamp: number\n retries: number\n}\n\ninterface EventQueueConfig {\n batchSize: number\n batchTimeout: number\n maxRetries: number\n retryDelayMs: number\n storageKey: string\n}\n\nconst DEFAULT_QUEUE_CONFIG: EventQueueConfig = {\n batchSize: DEFAULT_CONFIG.batchSize,\n batchTimeout: DEFAULT_CONFIG.batchTimeout,\n maxRetries: 3,\n retryDelayMs: 1000,\n storageKey: '_loamly_queue',\n}\n\nexport class EventQueue {\n private queue: QueuedEvent[] = []\n private batchTimer: ReturnType<typeof setTimeout> | null = null\n private config: EventQueueConfig\n private endpoint: string\n private isFlushing = false\n\n constructor(endpoint: string, config: Partial<EventQueueConfig> = {}) {\n this.endpoint = endpoint\n this.config = { ...DEFAULT_QUEUE_CONFIG, ...config }\n this.loadFromStorage()\n }\n\n /**\n * Add event to queue\n */\n push(type: string, payload: Record<string, unknown>): void {\n const event: QueuedEvent = {\n id: this.generateId(),\n type,\n payload,\n timestamp: Date.now(),\n retries: 0,\n }\n\n this.queue.push(event)\n this.saveToStorage()\n this.scheduleBatch()\n }\n\n /**\n * Force flush all events immediately\n */\n async flush(): Promise<void> {\n if (this.isFlushing || this.queue.length === 0) return\n\n this.isFlushing = true\n this.clearBatchTimer()\n\n try {\n const events = [...this.queue]\n this.queue = []\n \n await this.sendBatch(events)\n } finally {\n this.isFlushing = false\n this.saveToStorage()\n }\n }\n\n /**\n * Flush using sendBeacon (for unload events)\n */\n flushBeacon(): boolean {\n if (this.queue.length === 0) return true\n\n const events = this.queue.map(e => ({\n type: e.type,\n ...e.payload,\n _queue_id: e.id,\n _queue_timestamp: e.timestamp,\n }))\n\n const success = navigator.sendBeacon?.(\n this.endpoint,\n JSON.stringify({ events, beacon: true })\n ) ?? false\n\n if (success) {\n this.queue = []\n this.clearStorage()\n }\n\n return success\n }\n\n /**\n * Get current queue length\n */\n get length(): number {\n return this.queue.length\n }\n\n private scheduleBatch(): void {\n if (this.batchTimer) return\n\n // Flush immediately if batch size reached\n if (this.queue.length >= this.config.batchSize) {\n this.flush()\n return\n }\n\n // Schedule batch flush\n this.batchTimer = setTimeout(() => {\n this.batchTimer = null\n this.flush()\n }, this.config.batchTimeout)\n }\n\n private clearBatchTimer(): void {\n if (this.batchTimer) {\n clearTimeout(this.batchTimer)\n this.batchTimer = null\n }\n }\n\n private async sendBatch(events: QueuedEvent[]): Promise<void> {\n if (events.length === 0) return\n\n const payload = {\n events: events.map(e => ({\n type: e.type,\n ...e.payload,\n _queue_id: e.id,\n _queue_timestamp: e.timestamp,\n })),\n batch: true,\n }\n\n try {\n const response = await fetch(this.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`)\n }\n } catch (error) {\n // Retry failed events\n for (const event of events) {\n if (event.retries < this.config.maxRetries) {\n event.retries++\n this.queue.push(event)\n }\n }\n\n // Schedule retry with exponential backoff\n if (this.queue.length > 0) {\n const delay = this.config.retryDelayMs * Math.pow(2, events[0].retries - 1)\n setTimeout(() => this.flush(), delay)\n }\n }\n }\n\n private loadFromStorage(): void {\n try {\n const stored = localStorage.getItem(this.config.storageKey)\n if (stored) {\n const parsed = JSON.parse(stored)\n if (Array.isArray(parsed)) {\n // Only restore events less than 24 hours old\n const cutoff = Date.now() - 24 * 60 * 60 * 1000\n this.queue = parsed.filter((e: QueuedEvent) => e.timestamp > cutoff)\n }\n }\n } catch {\n // localStorage not available or corrupted\n }\n }\n\n private saveToStorage(): void {\n try {\n if (this.queue.length > 0) {\n localStorage.setItem(this.config.storageKey, JSON.stringify(this.queue))\n } else {\n this.clearStorage()\n }\n } catch {\n // localStorage not available\n }\n }\n\n private clearStorage(): void {\n try {\n localStorage.removeItem(this.config.storageKey)\n } catch {\n // Ignore\n }\n }\n\n private generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`\n }\n}\n\n","/**\n * Real-time Ping Service\n * \n * Heartbeat for active session tracking with:\n * - Configurable interval (default 30s)\n * - Visibility-aware (pauses when tab hidden)\n * - Session metrics aggregation\n * \n * @module @loamly/tracker\n */\n\nimport { DEFAULT_CONFIG } from '../config'\n\nexport interface PingData {\n session_id: string\n visitor_id: string\n url: string\n time_on_page_ms: number\n scroll_depth: number\n is_active: boolean\n tracker_version: string\n}\n\nexport interface PingConfig {\n interval: number\n endpoint: string\n onPing?: (data: PingData) => void\n}\n\nexport class PingService {\n private intervalId: ReturnType<typeof setInterval> | null = null\n private config: PingConfig\n private pageLoadTime: number\n private isVisible = true\n private currentScrollDepth = 0\n private sessionId: string\n private visitorId: string\n private version: string\n\n constructor(\n sessionId: string,\n visitorId: string,\n version: string,\n config: Partial<PingConfig> = {}\n ) {\n this.sessionId = sessionId\n this.visitorId = visitorId\n this.version = version\n this.pageLoadTime = Date.now()\n this.config = {\n interval: DEFAULT_CONFIG.pingInterval,\n endpoint: '',\n ...config,\n }\n\n // Track visibility\n document.addEventListener('visibilitychange', this.handleVisibilityChange)\n \n // Track scroll depth\n window.addEventListener('scroll', this.handleScroll, { passive: true })\n }\n\n /**\n * Start the ping service\n */\n start(): void {\n if (this.intervalId) return\n\n this.intervalId = setInterval(() => {\n if (this.isVisible) {\n this.ping()\n }\n }, this.config.interval)\n\n // Send initial ping\n this.ping()\n }\n\n /**\n * Stop the ping service\n */\n stop(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId)\n this.intervalId = null\n }\n\n document.removeEventListener('visibilitychange', this.handleVisibilityChange)\n window.removeEventListener('scroll', this.handleScroll)\n }\n\n /**\n * Update scroll depth (called by external scroll tracker)\n */\n updateScrollDepth(depth: number): void {\n if (depth > this.currentScrollDepth) {\n this.currentScrollDepth = depth\n }\n }\n\n /**\n * Get current ping data\n */\n getData(): PingData {\n return {\n session_id: this.sessionId,\n visitor_id: this.visitorId,\n url: window.location.href,\n time_on_page_ms: Date.now() - this.pageLoadTime,\n scroll_depth: this.currentScrollDepth,\n is_active: this.isVisible,\n tracker_version: this.version,\n }\n }\n\n private ping = async (): Promise<void> => {\n const data = this.getData()\n\n // Call callback if provided\n this.config.onPing?.(data)\n\n // Send to endpoint if configured\n if (this.config.endpoint) {\n try {\n await fetch(this.config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n })\n } catch {\n // Ping failures are silent\n }\n }\n }\n\n private handleVisibilityChange = (): void => {\n this.isVisible = document.visibilityState === 'visible'\n }\n\n private handleScroll = (): void => {\n const scrollPercent = Math.round(\n ((window.scrollY + window.innerHeight) / document.documentElement.scrollHeight) * 100\n )\n if (scrollPercent > this.currentScrollDepth) {\n this.currentScrollDepth = Math.min(scrollPercent, 100)\n }\n }\n}\n\n","/**\n * Advanced Scroll Depth Tracker\n * \n * Production-grade scroll tracking with:\n * - 30% chunk reporting (30%, 60%, 90%, 100%)\n * - requestAnimationFrame throttling for performance\n * - Visibility-aware (only tracks when visible)\n * - Max depth tracking\n * \n * @module @loamly/tracker\n */\n\nexport interface ScrollEvent {\n depth: number\n chunk: number // 30, 60, 90, 100\n time_to_reach_ms: number\n total_height: number\n viewport_height: number\n}\n\nexport interface ScrollTrackerConfig {\n chunks: number[] // Default: [30, 60, 90, 100]\n onChunkReached?: (event: ScrollEvent) => void\n onDepthChange?: (depth: number) => void\n}\n\nconst DEFAULT_CHUNKS = [30, 60, 90, 100]\n\nexport class ScrollTracker {\n private config: ScrollTrackerConfig\n private maxDepth = 0\n private reportedChunks = new Set<number>()\n private startTime: number\n private ticking = false\n private isVisible = true\n\n constructor(config: Partial<ScrollTrackerConfig> = {}) {\n this.config = {\n chunks: DEFAULT_CHUNKS,\n ...config,\n }\n this.startTime = Date.now()\n }\n\n /**\n * Start tracking scroll depth\n */\n start(): void {\n window.addEventListener('scroll', this.handleScroll, { passive: true })\n document.addEventListener('visibilitychange', this.handleVisibility)\n \n // Check initial scroll position (for page refresh)\n this.checkScrollDepth()\n }\n\n /**\n * Stop tracking\n */\n stop(): void {\n window.removeEventListener('scroll', this.handleScroll)\n document.removeEventListener('visibilitychange', this.handleVisibility)\n }\n\n /**\n * Get current max scroll depth\n */\n getMaxDepth(): number {\n return this.maxDepth\n }\n\n /**\n * Get reported chunks\n */\n getReportedChunks(): number[] {\n return Array.from(this.reportedChunks).sort((a, b) => a - b)\n }\n\n /**\n * Get final scroll event (for unload)\n */\n getFinalEvent(): ScrollEvent {\n const docHeight = document.documentElement.scrollHeight\n const viewportHeight = window.innerHeight\n\n return {\n depth: this.maxDepth,\n chunk: this.getChunkForDepth(this.maxDepth),\n time_to_reach_ms: Date.now() - this.startTime,\n total_height: docHeight,\n viewport_height: viewportHeight,\n }\n }\n\n private handleScroll = (): void => {\n if (!this.ticking && this.isVisible) {\n requestAnimationFrame(() => {\n this.checkScrollDepth()\n this.ticking = false\n })\n this.ticking = true\n }\n }\n\n private handleVisibility = (): void => {\n this.isVisible = document.visibilityState === 'visible'\n }\n\n private checkScrollDepth(): void {\n const scrollY = window.scrollY\n const viewportHeight = window.innerHeight\n const docHeight = document.documentElement.scrollHeight\n \n // Avoid division by zero\n if (docHeight <= viewportHeight) {\n this.updateDepth(100)\n return\n }\n\n const scrollableHeight = docHeight - viewportHeight\n const currentDepth = Math.min(100, Math.round((scrollY / scrollableHeight) * 100))\n \n this.updateDepth(currentDepth)\n }\n\n private updateDepth(depth: number): void {\n if (depth <= this.maxDepth) return\n \n this.maxDepth = depth\n this.config.onDepthChange?.(depth)\n\n // Check for chunk milestones\n for (const chunk of this.config.chunks!) {\n if (depth >= chunk && !this.reportedChunks.has(chunk)) {\n this.reportedChunks.add(chunk)\n this.reportChunk(chunk)\n }\n }\n }\n\n private reportChunk(chunk: number): void {\n const docHeight = document.documentElement.scrollHeight\n const viewportHeight = window.innerHeight\n\n const event: ScrollEvent = {\n depth: this.maxDepth,\n chunk,\n time_to_reach_ms: Date.now() - this.startTime,\n total_height: docHeight,\n viewport_height: viewportHeight,\n }\n\n this.config.onChunkReached?.(event)\n }\n\n private getChunkForDepth(depth: number): number {\n const chunks = this.config.chunks!.sort((a, b) => b - a)\n for (const chunk of chunks) {\n if (depth >= chunk) return chunk\n }\n return 0\n }\n}\n\n","/**\n * Time Spent Tracker\n * \n * Accurate time-on-page tracking with:\n * - Visibility-aware (pauses when tab hidden)\n * - Heartbeat updates\n * - Engagement detection (active vs idle)\n * \n * @module @loamly/tracker\n */\n\nexport interface TimeEvent {\n active_time_ms: number\n total_time_ms: number\n idle_time_ms: number\n is_engaged: boolean\n}\n\nexport interface TimeTrackerConfig {\n idleThresholdMs: number // Time without interaction to consider idle\n updateIntervalMs: number // How often to report time\n onUpdate?: (event: TimeEvent) => void\n}\n\nconst DEFAULT_CONFIG: TimeTrackerConfig = {\n idleThresholdMs: 30000, // 30 seconds\n updateIntervalMs: 5000, // 5 seconds\n}\n\nexport class TimeTracker {\n private config: TimeTrackerConfig\n private startTime: number\n private activeTime = 0\n private idleTime = 0\n private lastActivityTime: number\n private lastUpdateTime: number\n private isVisible = true\n private isIdle = false\n private updateInterval: ReturnType<typeof setInterval> | null = null\n private idleCheckInterval: ReturnType<typeof setInterval> | null = null\n\n constructor(config: Partial<TimeTrackerConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config }\n this.startTime = Date.now()\n this.lastActivityTime = this.startTime\n this.lastUpdateTime = this.startTime\n }\n\n /**\n * Start tracking time\n */\n start(): void {\n // Listen for visibility changes\n document.addEventListener('visibilitychange', this.handleVisibility)\n\n // Listen for user activity\n const activityEvents = ['mousemove', 'keydown', 'scroll', 'click', 'touchstart']\n activityEvents.forEach(event => {\n document.addEventListener(event, this.handleActivity, { passive: true })\n })\n\n // Start update interval\n this.updateInterval = setInterval(() => {\n this.update()\n }, this.config.updateIntervalMs)\n\n // Start idle check\n this.idleCheckInterval = setInterval(() => {\n this.checkIdle()\n }, 1000)\n }\n\n /**\n * Stop tracking\n */\n stop(): void {\n document.removeEventListener('visibilitychange', this.handleVisibility)\n \n const activityEvents = ['mousemove', 'keydown', 'scroll', 'click', 'touchstart']\n activityEvents.forEach(event => {\n document.removeEventListener(event, this.handleActivity)\n })\n\n if (this.updateInterval) {\n clearInterval(this.updateInterval)\n this.updateInterval = null\n }\n\n if (this.idleCheckInterval) {\n clearInterval(this.idleCheckInterval)\n this.idleCheckInterval = null\n }\n }\n\n /**\n * Get current time metrics\n */\n getMetrics(): TimeEvent {\n this.updateTimes()\n \n return {\n active_time_ms: this.activeTime,\n total_time_ms: Date.now() - this.startTime,\n idle_time_ms: this.idleTime,\n is_engaged: !this.isIdle && this.isVisible,\n }\n }\n\n /**\n * Get final metrics (for unload)\n */\n getFinalMetrics(): TimeEvent {\n this.updateTimes()\n return this.getMetrics()\n }\n\n private handleVisibility = (): void => {\n const wasVisible = this.isVisible\n this.isVisible = document.visibilityState === 'visible'\n\n if (wasVisible && !this.isVisible) {\n // Tab hidden - update times before stopping\n this.updateTimes()\n } else if (!wasVisible && this.isVisible) {\n // Tab shown - resume tracking\n this.lastUpdateTime = Date.now()\n this.lastActivityTime = Date.now()\n }\n }\n\n private handleActivity = (): void => {\n const now = Date.now()\n \n if (this.isIdle) {\n // Was idle, now active\n this.isIdle = false\n }\n \n this.lastActivityTime = now\n }\n\n private checkIdle(): void {\n const now = Date.now()\n const timeSinceActivity = now - this.lastActivityTime\n\n if (!this.isIdle && timeSinceActivity >= this.config.idleThresholdMs) {\n // User went idle\n this.isIdle = true\n }\n }\n\n private updateTimes(): void {\n const now = Date.now()\n const elapsed = now - this.lastUpdateTime\n\n if (this.isVisible) {\n if (this.isIdle) {\n this.idleTime += elapsed\n } else {\n this.activeTime += elapsed\n }\n }\n\n this.lastUpdateTime = now\n }\n\n private update(): void {\n if (!this.isVisible) return\n\n this.updateTimes()\n this.config.onUpdate?.(this.getMetrics())\n }\n}\n\n","/**\n * Universal Form Tracker\n * \n * Comprehensive form tracking with support for:\n * - Native HTML forms\n * - HubSpot forms\n * - Typeform embeds\n * - JotForm embeds\n * - Gravity Forms\n * - Thank-you page detection\n * - Privacy-preserving field capture\n * \n * @module @loamly/tracker\n */\n\nexport interface FormEvent {\n event_type: 'form_start' | 'form_field' | 'form_submit' | 'form_success'\n form_id: string\n form_type: 'native' | 'hubspot' | 'typeform' | 'jotform' | 'gravity' | 'unknown'\n field_name?: string\n field_type?: string\n time_to_submit_ms?: number\n is_conversion?: boolean\n}\n\nexport interface FormTrackerConfig {\n // Privacy: Never capture these field values\n sensitiveFields: string[]\n // Fields to track interaction (not values)\n trackableFields: string[]\n // Patterns for thank-you page detection\n thankYouPatterns: RegExp[]\n // Callback for form events\n onFormEvent?: (event: FormEvent) => void\n}\n\nconst DEFAULT_CONFIG: FormTrackerConfig = {\n sensitiveFields: [\n 'password', 'pwd', 'pass',\n 'credit', 'card', 'cvv', 'cvc',\n 'ssn', 'social',\n 'secret', 'token', 'key',\n ],\n trackableFields: [\n 'email', 'name', 'phone', 'company',\n 'first', 'last', 'city', 'country',\n ],\n thankYouPatterns: [\n /thank[-_]?you/i,\n /success/i,\n /confirmation/i,\n /submitted/i,\n /complete/i,\n ],\n}\n\nexport class FormTracker {\n private config: FormTrackerConfig\n private formStartTimes = new Map<string, number>()\n private interactedForms = new Set<string>()\n private mutationObserver: MutationObserver | null = null\n\n constructor(config: Partial<FormTrackerConfig> = {}) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config,\n sensitiveFields: [\n ...DEFAULT_CONFIG.sensitiveFields,\n ...(config.sensitiveFields || []),\n ],\n }\n }\n\n /**\n * Start tracking forms\n */\n start(): void {\n // Track native form interactions\n document.addEventListener('focusin', this.handleFocusIn, { passive: true })\n document.addEventListener('submit', this.handleSubmit)\n document.addEventListener('click', this.handleClick, { passive: true })\n\n // Observe DOM for dynamically added forms (HubSpot, Typeform, etc.)\n this.startMutationObserver()\n\n // Check for thank-you page on load\n this.checkThankYouPage()\n\n // Scan for existing embedded forms\n this.scanForEmbeddedForms()\n }\n\n /**\n * Stop tracking\n */\n stop(): void {\n document.removeEventListener('focusin', this.handleFocusIn)\n document.removeEventListener('submit', this.handleSubmit)\n document.removeEventListener('click', this.handleClick)\n this.mutationObserver?.disconnect()\n }\n\n /**\n * Get forms that had interaction\n */\n getInteractedForms(): string[] {\n return Array.from(this.interactedForms)\n }\n\n private handleFocusIn = (e: FocusEvent): void => {\n const target = e.target as HTMLElement\n if (!this.isFormField(target)) return\n\n const form = target.closest('form')\n const formId = this.getFormId(form || target)\n\n // Track form start\n if (!this.formStartTimes.has(formId)) {\n this.formStartTimes.set(formId, Date.now())\n this.interactedForms.add(formId)\n \n this.emitEvent({\n event_type: 'form_start',\n form_id: formId,\n form_type: this.detectFormType(form || target),\n })\n }\n\n // Track field interaction (privacy-safe)\n const fieldName = this.getFieldName(target as HTMLInputElement)\n if (fieldName && !this.isSensitiveField(fieldName)) {\n this.emitEvent({\n event_type: 'form_field',\n form_id: formId,\n form_type: this.detectFormType(form || target),\n field_name: this.sanitizeFieldName(fieldName),\n field_type: (target as HTMLInputElement).type || target.tagName.toLowerCase(),\n })\n }\n }\n\n private handleSubmit = (e: Event): void => {\n const form = e.target as HTMLFormElement\n if (!form || form.tagName !== 'FORM') return\n\n const formId = this.getFormId(form)\n const startTime = this.formStartTimes.get(formId)\n\n this.emitEvent({\n event_type: 'form_submit',\n form_id: formId,\n form_type: this.detectFormType(form),\n time_to_submit_ms: startTime ? Date.now() - startTime : undefined,\n is_conversion: true,\n })\n }\n\n private handleClick = (e: Event): void => {\n const target = e.target as HTMLElement\n \n // Check for HubSpot submit button\n if (target.closest('.hs-button') || target.closest('[type=\"submit\"]')) {\n const form = target.closest('form')\n if (form && form.classList.contains('hs-form')) {\n const formId = this.getFormId(form)\n const startTime = this.formStartTimes.get(formId)\n\n this.emitEvent({\n event_type: 'form_submit',\n form_id: formId,\n form_type: 'hubspot',\n time_to_submit_ms: startTime ? Date.now() - startTime : undefined,\n is_conversion: true,\n })\n }\n }\n\n // Check for Typeform submit\n if (target.closest('[data-qa=\"submit-button\"]')) {\n this.emitEvent({\n event_type: 'form_submit',\n form_id: 'typeform_embed',\n form_type: 'typeform',\n is_conversion: true,\n })\n }\n }\n\n private startMutationObserver(): void {\n this.mutationObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (node instanceof HTMLElement) {\n // Check for HubSpot form\n if (node.classList?.contains('hs-form') || node.querySelector?.('.hs-form')) {\n this.trackEmbeddedForm(node, 'hubspot')\n }\n // Check for Typeform\n if (node.classList?.contains('typeform-widget') || node.querySelector?.('[data-tf-widget]')) {\n this.trackEmbeddedForm(node, 'typeform')\n }\n // Check for JotForm\n if (node.classList?.contains('jotform-form') || node.querySelector?.('.jotform-form')) {\n this.trackEmbeddedForm(node, 'jotform')\n }\n // Check for Gravity Forms\n if (node.classList?.contains('gform_wrapper') || node.querySelector?.('.gform_wrapper')) {\n this.trackEmbeddedForm(node, 'gravity')\n }\n }\n }\n }\n })\n\n this.mutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n })\n }\n\n private scanForEmbeddedForms(): void {\n // HubSpot\n document.querySelectorAll('.hs-form').forEach(form => {\n this.trackEmbeddedForm(form as HTMLElement, 'hubspot')\n })\n \n // Typeform\n document.querySelectorAll('[data-tf-widget], .typeform-widget').forEach(form => {\n this.trackEmbeddedForm(form as HTMLElement, 'typeform')\n })\n \n // JotForm\n document.querySelectorAll('.jotform-form').forEach(form => {\n this.trackEmbeddedForm(form as HTMLElement, 'jotform')\n })\n \n // Gravity Forms\n document.querySelectorAll('.gform_wrapper').forEach(form => {\n this.trackEmbeddedForm(form as HTMLElement, 'gravity')\n })\n }\n\n private trackEmbeddedForm(element: HTMLElement, type: FormEvent['form_type']): void {\n const formId = `${type}_${this.getFormId(element)}`\n \n // Add event listeners for embedded form interactions\n element.addEventListener('focusin', () => {\n if (!this.formStartTimes.has(formId)) {\n this.formStartTimes.set(formId, Date.now())\n this.interactedForms.add(formId)\n \n this.emitEvent({\n event_type: 'form_start',\n form_id: formId,\n form_type: type,\n })\n }\n }, { passive: true })\n }\n\n private checkThankYouPage(): void {\n const url = window.location.href.toLowerCase()\n const title = document.title.toLowerCase()\n \n for (const pattern of this.config.thankYouPatterns) {\n if (pattern.test(url) || pattern.test(title)) {\n this.emitEvent({\n event_type: 'form_success',\n form_id: 'page_conversion',\n form_type: 'unknown',\n is_conversion: true,\n })\n break\n }\n }\n }\n\n private isFormField(element: HTMLElement): boolean {\n const tagName = element.tagName\n return tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT'\n }\n\n private getFormId(element: HTMLElement | null): string {\n if (!element) return 'unknown'\n return element.id || element.getAttribute('name') || element.getAttribute('data-form-id') || 'form_' + Math.random().toString(36).substring(2, 8)\n }\n\n private getFieldName(input: HTMLInputElement): string {\n return input.name || input.id || input.getAttribute('data-name') || ''\n }\n\n private isSensitiveField(fieldName: string): boolean {\n const lowerName = fieldName.toLowerCase()\n return this.config.sensitiveFields.some(sensitive => lowerName.includes(sensitive))\n }\n\n private sanitizeFieldName(fieldName: string): string {\n // Remove any potential PII from field names\n return fieldName.replace(/[0-9]+/g, '*').substring(0, 50)\n }\n\n private detectFormType(element: HTMLElement): FormEvent['form_type'] {\n if (element.classList.contains('hs-form') || element.closest('.hs-form')) {\n return 'hubspot'\n }\n if (element.classList.contains('typeform-widget') || element.closest('[data-tf-widget]')) {\n return 'typeform'\n }\n if (element.classList.contains('jotform-form') || element.closest('.jotform-form')) {\n return 'jotform'\n }\n if (element.classList.contains('gform_wrapper') || element.closest('.gform_wrapper')) {\n return 'gravity'\n }\n if (element.tagName === 'FORM') {\n return 'native'\n }\n return 'unknown'\n }\n\n private emitEvent(event: FormEvent): void {\n this.config.onFormEvent?.(event)\n }\n}\n\n","/**\n * SPA Navigation Router\n * \n * Detects client-side navigation in SPAs with support for:\n * - History API (pushState, replaceState, popstate)\n * - Hash changes (for hash-based routing)\n * - Next.js, React Router, Vue Router, etc.\n * \n * @module @loamly/tracker\n */\n\nexport interface NavigationEvent {\n from_url: string\n to_url: string\n navigation_type: 'push' | 'replace' | 'pop' | 'hash' | 'initial'\n time_on_previous_page_ms: number\n}\n\nexport interface RouterConfig {\n onNavigate?: (event: NavigationEvent) => void\n ignoreHashChange?: boolean\n}\n\nexport class SPARouter {\n private config: RouterConfig\n private currentUrl: string\n private pageEnterTime: number\n private originalPushState: typeof history.pushState | null = null\n private originalReplaceState: typeof history.replaceState | null = null\n\n constructor(config: RouterConfig = {}) {\n this.config = config\n this.currentUrl = window.location.href\n this.pageEnterTime = Date.now()\n }\n\n /**\n * Start listening for navigation events\n */\n start(): void {\n // Patch History API\n this.patchHistoryAPI()\n\n // Listen for popstate (back/forward)\n window.addEventListener('popstate', this.handlePopState)\n\n // Listen for hash changes\n if (!this.config.ignoreHashChange) {\n window.addEventListener('hashchange', this.handleHashChange)\n }\n }\n\n /**\n * Stop listening and restore original methods\n */\n stop(): void {\n // Restore original History API methods\n if (this.originalPushState) {\n history.pushState = this.originalPushState\n }\n if (this.originalReplaceState) {\n history.replaceState = this.originalReplaceState\n }\n\n window.removeEventListener('popstate', this.handlePopState)\n window.removeEventListener('hashchange', this.handleHashChange)\n }\n\n /**\n * Manually trigger a navigation event (for custom routers)\n */\n navigate(url: string, type: NavigationEvent['navigation_type'] = 'push'): void {\n this.emitNavigation(url, type)\n }\n\n /**\n * Get current URL\n */\n getCurrentUrl(): string {\n return this.currentUrl\n }\n\n /**\n * Get time on current page\n */\n getTimeOnPage(): number {\n return Date.now() - this.pageEnterTime\n }\n\n private patchHistoryAPI(): void {\n // Store original methods\n this.originalPushState = history.pushState.bind(history)\n this.originalReplaceState = history.replaceState.bind(history)\n\n // Patch pushState\n history.pushState = (...args) => {\n const result = this.originalPushState!(...args)\n this.handleStateChange('push')\n return result\n }\n\n // Patch replaceState\n history.replaceState = (...args) => {\n const result = this.originalReplaceState!(...args)\n this.handleStateChange('replace')\n return result\n }\n }\n\n private handleStateChange = (type: 'push' | 'replace'): void => {\n const newUrl = window.location.href\n if (newUrl !== this.currentUrl) {\n this.emitNavigation(newUrl, type)\n }\n }\n\n private handlePopState = (): void => {\n const newUrl = window.location.href\n if (newUrl !== this.currentUrl) {\n this.emitNavigation(newUrl, 'pop')\n }\n }\n\n private handleHashChange = (): void => {\n const newUrl = window.location.href\n if (newUrl !== this.currentUrl) {\n this.emitNavigation(newUrl, 'hash')\n }\n }\n\n private emitNavigation(toUrl: string, type: NavigationEvent['navigation_type']): void {\n const event: NavigationEvent = {\n from_url: this.currentUrl,\n to_url: toUrl,\n navigation_type: type,\n time_on_previous_page_ms: Date.now() - this.pageEnterTime,\n }\n\n // Update current state\n this.currentUrl = toUrl\n this.pageEnterTime = Date.now()\n\n // Emit event\n this.config.onNavigate?.(event)\n }\n}\n\n","/**\n * Utility functions for Loamly Tracker\n * @module @loamly/tracker\n */\n\n/**\n * Generate a UUID v4\n */\nexport function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\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/**\n * Get or create a persistent visitor ID\n * (Privacy-respecting, no cookies)\n */\nexport function getVisitorId(): string {\n // Try to get from localStorage first\n try {\n const stored = localStorage.getItem('_loamly_vid')\n if (stored) return stored\n \n const newId = generateUUID()\n localStorage.setItem('_loamly_vid', newId)\n return newId\n } catch {\n // localStorage not available, generate ephemeral ID\n return generateUUID()\n }\n}\n\n/**\n * Get or create a session ID using sessionStorage\n * (Cookie-free session tracking)\n */\nexport function getSessionId(): { sessionId: string; isNew: boolean } {\n try {\n const storedSession = sessionStorage.getItem('loamly_session')\n const storedStart = sessionStorage.getItem('loamly_start')\n \n if (storedSession && storedStart) {\n return { sessionId: storedSession, isNew: false }\n }\n \n const newSession = generateUUID()\n const startTime = Date.now().toString()\n \n sessionStorage.setItem('loamly_session', newSession)\n sessionStorage.setItem('loamly_start', startTime)\n \n return { sessionId: newSession, isNew: true }\n } catch {\n // sessionStorage not available\n return { sessionId: generateUUID(), isNew: true }\n }\n}\n\n/**\n * Extract UTM parameters from URL\n */\nexport function extractUTMParams(url: string): Record<string, string> {\n const params: Record<string, string> = {}\n \n try {\n const searchParams = new URL(url).searchParams\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']\n \n for (const key of utmKeys) {\n const value = searchParams.get(key)\n if (value) params[key] = value\n }\n } catch {\n // Invalid URL\n }\n \n return params\n}\n\n/**\n * Truncate text to max length\n */\nexport function truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text\n return text.substring(0, maxLength - 3) + '...'\n}\n\n/**\n * Safe fetch with timeout\n */\nexport async function safeFetch(\n url: string,\n options: RequestInit,\n timeout = 10000\n): Promise<Response | null> {\n try {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n \n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n })\n \n clearTimeout(timeoutId)\n return response\n } catch {\n return null\n }\n}\n\n/**\n * Send beacon (for unload events)\n */\nexport function sendBeacon(url: string, data: unknown): boolean {\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n return navigator.sendBeacon(url, JSON.stringify(data))\n }\n return false\n}\n\n\n","/**\n * Loamly Tracker Core\n * \n * Cookie-free, privacy-first analytics with comprehensive AI traffic detection.\n * \n * Features:\n * - Navigation Timing API (paste vs click detection)\n * - Behavioral ML Classifier (mouse, scroll, interaction patterns)\n * - Focus/Blur Sequence Analysis (copy-paste detection)\n * - Agentic Browser Detection (Comet, CDP, teleporting clicks)\n * - Advanced Scroll Tracking (30% chunk reporting)\n * - Universal Form Tracking (HubSpot, Typeform, native)\n * - SPA Navigation Support (History API hooks)\n * - Event Queue with Retry (offline support)\n * - Real-time Ping (heartbeat)\n * \n * @module @loamly/tracker\n */\n\nimport { VERSION, DEFAULT_CONFIG } from './config'\nimport { detectNavigationType } from './detection/navigation-timing'\nimport { detectAIFromReferrer, detectAIFromUTM } from './detection/referrer'\nimport { \n BehavioralClassifier, \n type BehavioralClassificationResult \n} from './detection/behavioral-classifier'\nimport {\n FocusBlurAnalyzer,\n type FocusBlurResult\n} from './detection/focus-blur'\nimport {\n AgenticBrowserAnalyzer,\n type AgenticDetectionResult\n} from './detection/agentic-browser'\nimport { EventQueue } from './infrastructure/event-queue'\nimport { PingService } from './infrastructure/ping'\nimport { ScrollTracker, type ScrollEvent } from './behavioral/scroll-tracker'\nimport { TimeTracker, type TimeEvent } from './behavioral/time-tracker'\nimport { FormTracker, type FormEvent } from './behavioral/form-tracker'\nimport { SPARouter, type NavigationEvent } from './spa/router'\nimport { \n getVisitorId, \n getSessionId, \n extractUTMParams, \n truncateText,\n safeFetch,\n sendBeacon \n} from './utils'\nimport type { \n LoamlyConfig, \n LoamlyTracker, \n TrackEventOptions, \n NavigationTiming,\n AIDetectionResult,\n BehavioralMLResult,\n FocusBlurMLResult\n} from './types'\n\n// State\nlet config: LoamlyConfig & { apiHost: string } = { apiHost: DEFAULT_CONFIG.apiHost }\nlet initialized = false\nlet debugMode = false\nlet visitorId: string | null = null\nlet sessionId: string | null = null\nlet navigationTiming: NavigationTiming | null = null\nlet aiDetection: AIDetectionResult | null = null\n\n// Detection modules\nlet behavioralClassifier: BehavioralClassifier | null = null\nlet behavioralMLResult: BehavioralMLResult | null = null\nlet focusBlurAnalyzer: FocusBlurAnalyzer | null = null\nlet focusBlurResult: FocusBlurMLResult | null = null\nlet agenticAnalyzer: AgenticBrowserAnalyzer | null = null\n\n// Infrastructure modules\nlet eventQueue: EventQueue | null = null\nlet pingService: PingService | null = null\n\n// Behavioral tracking modules\nlet scrollTracker: ScrollTracker | null = null\nlet timeTracker: TimeTracker | null = null\nlet formTracker: FormTracker | null = null\n\n// SPA navigation\nlet spaRouter: SPARouter | null = null\n\n/**\n * Debug logger\n */\nfunction log(...args: unknown[]): void {\n if (debugMode) {\n console.log('[Loamly]', ...args)\n }\n}\n\n/**\n * Build API endpoint URL\n */\nfunction endpoint(path: string): string {\n return `${config.apiHost}${path}`\n}\n\n/**\n * Initialize the tracker\n */\nfunction init(userConfig: LoamlyConfig = {}): void {\n if (initialized) {\n log('Already initialized')\n return\n }\n\n config = {\n ...config,\n ...userConfig,\n apiHost: userConfig.apiHost || DEFAULT_CONFIG.apiHost,\n }\n \n debugMode = userConfig.debug ?? false\n \n log('Initializing Loamly Tracker v' + VERSION)\n \n // Get/create visitor ID\n visitorId = getVisitorId()\n log('Visitor ID:', visitorId)\n \n // Get/create session\n const session = getSessionId()\n sessionId = session.sessionId\n log('Session ID:', sessionId, session.isNew ? '(new)' : '(existing)')\n \n // Initialize event queue with batching\n eventQueue = new EventQueue(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {\n batchSize: DEFAULT_CONFIG.batchSize,\n batchTimeout: DEFAULT_CONFIG.batchTimeout,\n })\n \n // Detect navigation timing (paste vs click)\n navigationTiming = detectNavigationType()\n log('Navigation timing:', navigationTiming)\n \n // Detect AI from referrer/UTM\n aiDetection = detectAIFromReferrer(document.referrer) || detectAIFromUTM(window.location.href)\n if (aiDetection) {\n log('AI detected:', aiDetection)\n }\n \n initialized = true\n \n // Auto pageview unless disabled\n if (!userConfig.disableAutoPageview) {\n pageview()\n }\n \n // Set up behavioral tracking unless disabled\n if (!userConfig.disableBehavioral) {\n setupAdvancedBehavioralTracking()\n }\n \n // Initialize behavioral ML classifier (LOA-180)\n behavioralClassifier = new BehavioralClassifier(10000) // 10s min session\n behavioralClassifier.setOnClassify(handleBehavioralClassification)\n setupBehavioralMLTracking()\n \n // Initialize focus/blur analyzer (LOA-182)\n focusBlurAnalyzer = new FocusBlurAnalyzer()\n focusBlurAnalyzer.initTracking()\n \n // Analyze focus/blur after 5 seconds\n setTimeout(() => {\n if (focusBlurAnalyzer) {\n handleFocusBlurAnalysis(focusBlurAnalyzer.analyze())\n }\n }, 5000)\n \n // Initialize agentic browser detection (LOA-187)\n agenticAnalyzer = new AgenticBrowserAnalyzer()\n agenticAnalyzer.init()\n \n // Set up ping service\n if (visitorId && sessionId) {\n pingService = new PingService(sessionId, visitorId, VERSION, {\n interval: DEFAULT_CONFIG.pingInterval,\n endpoint: endpoint(DEFAULT_CONFIG.endpoints.ping),\n })\n pingService.start()\n }\n \n // Set up SPA navigation tracking\n spaRouter = new SPARouter({\n onNavigate: handleSPANavigation,\n })\n spaRouter.start()\n \n // Set up unload handlers\n setupUnloadHandlers()\n \n log('Initialization complete')\n}\n\n/**\n * Set up advanced behavioral tracking with new modules\n */\nfunction setupAdvancedBehavioralTracking(): void {\n // Scroll tracker with 30% chunks\n scrollTracker = new ScrollTracker({\n chunks: [30, 60, 90, 100],\n onChunkReached: (event: ScrollEvent) => {\n log('Scroll chunk:', event.chunk)\n queueEvent('scroll_depth', {\n depth: event.depth,\n chunk: event.chunk,\n time_to_reach_ms: event.time_to_reach_ms,\n })\n },\n })\n scrollTracker.start()\n \n // Time tracker\n timeTracker = new TimeTracker({\n updateIntervalMs: 10000, // Report every 10 seconds\n onUpdate: (event: TimeEvent) => {\n if (event.active_time_ms >= DEFAULT_CONFIG.timeSpentThresholdMs) {\n queueEvent('time_spent', {\n active_time_ms: event.active_time_ms,\n total_time_ms: event.total_time_ms,\n idle_time_ms: event.idle_time_ms,\n is_engaged: event.is_engaged,\n })\n }\n },\n })\n timeTracker.start()\n \n // Form tracker with universal support\n formTracker = new FormTracker({\n onFormEvent: (event: FormEvent) => {\n log('Form event:', event.event_type, event.form_id)\n queueEvent(event.event_type, {\n form_id: event.form_id,\n form_type: event.form_type,\n field_name: event.field_name,\n field_type: event.field_type,\n time_to_submit_ms: event.time_to_submit_ms,\n is_conversion: event.is_conversion,\n })\n },\n })\n formTracker.start()\n \n // Click tracking for links (basic)\n document.addEventListener('click', (e) => {\n const target = e.target as HTMLElement\n const link = target.closest('a')\n \n if (link && link.href) {\n const isExternal = link.hostname !== window.location.hostname\n queueEvent('click', {\n element: 'link',\n href: truncateText(link.href, 200),\n text: truncateText(link.textContent || '', 100),\n is_external: isExternal,\n })\n }\n })\n}\n\n/**\n * Queue an event for batched sending\n */\nfunction queueEvent(eventType: string, data: Record<string, unknown>): void {\n if (!eventQueue) return\n \n eventQueue.push(eventType, {\n visitor_id: visitorId,\n session_id: sessionId,\n event_type: eventType,\n ...data,\n url: window.location.href,\n timestamp: new Date().toISOString(),\n tracker_version: VERSION,\n })\n}\n\n/**\n * Handle SPA navigation\n */\nfunction handleSPANavigation(event: NavigationEvent): void {\n log('SPA navigation:', event.navigation_type, event.to_url)\n \n // Flush pending events before navigation\n eventQueue?.flush()\n \n // Update ping service\n pingService?.updateScrollDepth(0)\n \n // Reset scroll tracker for new page\n scrollTracker?.stop()\n scrollTracker = new ScrollTracker({\n chunks: [30, 60, 90, 100],\n onChunkReached: (scrollEvent: ScrollEvent) => {\n queueEvent('scroll_depth', {\n depth: scrollEvent.depth,\n chunk: scrollEvent.chunk,\n time_to_reach_ms: scrollEvent.time_to_reach_ms,\n })\n },\n })\n scrollTracker.start()\n \n // Track the virtual pageview\n pageview(event.to_url)\n \n // Queue navigation event\n queueEvent('spa_navigation', {\n from_url: event.from_url,\n to_url: event.to_url,\n navigation_type: event.navigation_type,\n time_on_previous_page_ms: event.time_on_previous_page_ms,\n })\n}\n\n/**\n * Set up handlers for page unload\n */\nfunction setupUnloadHandlers(): void {\n const handleUnload = (): void => {\n // Get final scroll depth\n const scrollEvent = scrollTracker?.getFinalEvent()\n if (scrollEvent) {\n sendBeacon(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {\n visitor_id: visitorId,\n session_id: sessionId,\n event_type: 'scroll_depth_final',\n data: scrollEvent,\n url: window.location.href,\n })\n }\n \n // Get final time metrics\n const timeEvent = timeTracker?.getFinalMetrics()\n if (timeEvent) {\n sendBeacon(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {\n visitor_id: visitorId,\n session_id: sessionId,\n event_type: 'time_spent_final',\n data: timeEvent,\n url: window.location.href,\n })\n }\n \n // Get agentic detection result\n const agenticResult = agenticAnalyzer?.getResult()\n if (agenticResult && agenticResult.agenticProbability > 0) {\n sendBeacon(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {\n visitor_id: visitorId,\n session_id: sessionId,\n event_type: 'agentic_detection',\n data: agenticResult,\n url: window.location.href,\n })\n }\n \n // Flush event queue\n eventQueue?.flushBeacon()\n \n // Force classify behavioral ML if not done\n if (behavioralClassifier && !behavioralClassifier.hasClassified()) {\n const result = behavioralClassifier.forceClassify()\n if (result) {\n handleBehavioralClassification(result)\n }\n }\n }\n \n window.addEventListener('beforeunload', handleUnload)\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n handleUnload()\n }\n })\n}\n\n/**\n * Track a page view\n */\nfunction pageview(customUrl?: string): void {\n if (!initialized) {\n log('Not initialized, call init() first')\n return\n }\n\n const url = customUrl || window.location.href\n const payload = {\n visitor_id: visitorId,\n session_id: sessionId,\n url,\n referrer: document.referrer || null,\n title: document.title || null,\n utm_source: extractUTMParams(url).utm_source || null,\n utm_medium: extractUTMParams(url).utm_medium || null,\n utm_campaign: extractUTMParams(url).utm_campaign || null,\n user_agent: navigator.userAgent,\n screen_width: window.screen?.width,\n screen_height: window.screen?.height,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n tracker_version: VERSION,\n navigation_timing: navigationTiming,\n ai_platform: aiDetection?.platform || null,\n is_ai_referrer: aiDetection?.isAI || false,\n }\n\n log('Pageview:', payload)\n\n safeFetch(endpoint(DEFAULT_CONFIG.endpoints.visit), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n}\n\n/**\n * Track a custom event\n */\nfunction track(eventName: string, options: TrackEventOptions = {}): void {\n if (!initialized) {\n log('Not initialized, call init() first')\n return\n }\n\n const payload = {\n visitor_id: visitorId,\n session_id: sessionId,\n event_name: eventName,\n event_type: 'custom',\n properties: options.properties || {},\n revenue: options.revenue,\n currency: options.currency || 'USD',\n url: window.location.href,\n timestamp: new Date().toISOString(),\n tracker_version: VERSION,\n }\n\n log('Event:', eventName, payload)\n\n safeFetch(endpoint('/api/ingest/event'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n}\n\n/**\n * Track a conversion/revenue event\n */\nfunction conversion(eventName: string, revenue: number, currency = 'USD'): void {\n track(eventName, { revenue, currency, properties: { type: 'conversion' } })\n}\n\n/**\n * Identify a user\n */\nfunction identify(userId: string, traits: Record<string, unknown> = {}): void {\n if (!initialized) {\n log('Not initialized, call init() first')\n return\n }\n\n log('Identify:', userId, traits)\n\n const payload = {\n visitor_id: visitorId,\n session_id: sessionId,\n user_id: userId,\n traits,\n timestamp: new Date().toISOString(),\n }\n\n safeFetch(endpoint('/api/ingest/identify'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n}\n\n/**\n * Set up behavioral ML signal collection (LOA-180)\n */\nfunction setupBehavioralMLTracking(): void {\n if (!behavioralClassifier) return\n \n // Mouse movement tracking (sampled for performance)\n let mouseSampleCount = 0\n document.addEventListener('mousemove', (e) => {\n mouseSampleCount++\n // Sample every 10th event for performance\n if (mouseSampleCount % 10 === 0 && behavioralClassifier) {\n behavioralClassifier.recordMouse(e.clientX, e.clientY)\n }\n }, { passive: true })\n \n // Click tracking\n document.addEventListener('click', () => {\n if (behavioralClassifier) {\n behavioralClassifier.recordClick()\n }\n }, { passive: true })\n \n // Scroll tracking for ML (separate from milestone-based)\n let lastScrollY = 0\n document.addEventListener('scroll', () => {\n const currentY = window.scrollY\n if (Math.abs(currentY - lastScrollY) > 50 && behavioralClassifier) {\n lastScrollY = currentY\n behavioralClassifier.recordScroll(currentY)\n }\n }, { passive: true })\n \n // Focus/blur tracking\n document.addEventListener('focusin', (e) => {\n if (behavioralClassifier) {\n behavioralClassifier.recordFocusBlur('focus')\n const target = e.target as HTMLElement\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n behavioralClassifier.recordFormStart(target.id || target.getAttribute('name') || 'unknown')\n }\n }\n }, { passive: true })\n \n document.addEventListener('focusout', (e) => {\n if (behavioralClassifier) {\n behavioralClassifier.recordFocusBlur('blur')\n const target = e.target as HTMLElement\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n behavioralClassifier.recordFormEnd(target.id || target.getAttribute('name') || 'unknown')\n }\n }\n }, { passive: true })\n \n // Also try to classify after 30 seconds as backup\n setTimeout(() => {\n if (behavioralClassifier && !behavioralClassifier.hasClassified()) {\n behavioralClassifier.forceClassify()\n }\n }, 30000)\n}\n\n/**\n * Handle behavioral ML classification result\n */\nfunction handleBehavioralClassification(result: BehavioralClassificationResult): void {\n log('Behavioral ML classification:', result)\n \n // Store result\n behavioralMLResult = {\n classification: result.classification,\n humanProbability: result.humanProbability,\n aiProbability: result.aiProbability,\n confidence: result.confidence,\n signals: result.signals,\n sessionDurationMs: result.sessionDurationMs,\n }\n \n // Send to backend\n queueEvent('ml_classification', {\n classification: result.classification,\n human_probability: result.humanProbability,\n ai_probability: result.aiProbability,\n confidence: result.confidence,\n signals: result.signals,\n session_duration_ms: result.sessionDurationMs,\n navigation_timing: navigationTiming,\n ai_detection: aiDetection,\n focus_blur: focusBlurResult,\n })\n \n // If AI-influenced detected with high confidence, update AI detection\n if (result.classification === 'ai_influenced' && result.confidence >= 0.7) {\n aiDetection = {\n isAI: true,\n confidence: result.confidence,\n method: 'behavioral',\n }\n log('AI detection updated from behavioral ML:', aiDetection)\n }\n}\n\n/**\n * Handle focus/blur analysis result (LOA-182)\n */\nfunction handleFocusBlurAnalysis(result: FocusBlurResult): void {\n log('Focus/blur analysis:', result)\n \n // Store result\n focusBlurResult = {\n navType: result.nav_type,\n confidence: result.confidence,\n signals: result.signals,\n timeToFirstInteractionMs: result.time_to_first_interaction_ms,\n }\n \n // Send to backend\n queueEvent('focus_blur_analysis', {\n nav_type: result.nav_type,\n confidence: result.confidence,\n signals: result.signals,\n time_to_first_interaction_ms: result.time_to_first_interaction_ms,\n sequence_length: result.sequence.length,\n })\n \n // If paste pattern detected with confidence, update AI detection\n if (result.nav_type === 'likely_paste' && result.confidence >= 0.4) {\n // Only update if no stronger detection exists\n if (!aiDetection || aiDetection.confidence < result.confidence) {\n aiDetection = {\n isAI: true,\n confidence: result.confidence,\n method: 'behavioral',\n }\n log('AI detection updated from focus/blur analysis:', aiDetection)\n }\n }\n}\n\n/**\n * Get current session ID\n */\nfunction getCurrentSessionId(): string | null {\n return sessionId\n}\n\n/**\n * Get current visitor ID\n */\nfunction getCurrentVisitorId(): string | null {\n return visitorId\n}\n\n/**\n * Get AI detection result\n */\nfunction getAIDetectionResult(): AIDetectionResult | null {\n return aiDetection\n}\n\n/**\n * Get navigation timing result\n */\nfunction getNavigationTimingResult(): NavigationTiming | null {\n return navigationTiming\n}\n\n/**\n * Get behavioral ML classification result\n */\nfunction getBehavioralMLResult(): BehavioralMLResult | null {\n return behavioralMLResult\n}\n\n/**\n * Get focus/blur analysis result\n */\nfunction getFocusBlurResult(): FocusBlurMLResult | null {\n return focusBlurResult\n}\n\n/**\n * Get agentic browser detection result\n */\nfunction getAgenticResult(): AgenticDetectionResult | null {\n return agenticAnalyzer?.getResult() || null\n}\n\n/**\n * Check if initialized\n */\nfunction isTrackerInitialized(): boolean {\n return initialized\n}\n\n/**\n * Reset the tracker\n */\nfunction reset(): void {\n log('Resetting tracker')\n \n // Stop all services\n pingService?.stop()\n scrollTracker?.stop()\n timeTracker?.stop()\n formTracker?.stop()\n spaRouter?.stop()\n agenticAnalyzer?.destroy()\n \n // Reset state\n initialized = false\n visitorId = null\n sessionId = null\n navigationTiming = null\n aiDetection = null\n behavioralClassifier = null\n behavioralMLResult = null\n focusBlurAnalyzer = null\n focusBlurResult = null\n agenticAnalyzer = null\n eventQueue = null\n pingService = null\n scrollTracker = null\n timeTracker = null\n formTracker = null\n spaRouter = null\n \n try {\n sessionStorage.removeItem('loamly_session')\n sessionStorage.removeItem('loamly_start')\n } catch {\n // Ignore\n }\n}\n\n/**\n * Enable/disable debug mode\n */\nfunction setDebug(enabled: boolean): void {\n debugMode = enabled\n log('Debug mode:', enabled ? 'enabled' : 'disabled')\n}\n\n/**\n * The Loamly Tracker instance\n */\nexport const loamly: LoamlyTracker & { getAgentic: () => AgenticDetectionResult | null } = {\n init,\n pageview,\n track,\n conversion,\n identify,\n getSessionId: getCurrentSessionId,\n getVisitorId: getCurrentVisitorId,\n getAIDetection: getAIDetectionResult,\n getNavigationTiming: getNavigationTimingResult,\n getBehavioralML: getBehavioralMLResult,\n getFocusBlur: getFocusBlurResult,\n getAgentic: getAgenticResult,\n isInitialized: isTrackerInitialized,\n reset,\n debug: setDebug,\n}\n\nexport default loamly\n"],"mappings":"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","names":["endpoint","config","sessionId","visitorId","config","config","DEFAULT_CONFIG","config","DEFAULT_CONFIG","config","config"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/detection/navigation-timing.ts","../src/detection/referrer.ts","../src/detection/behavioral-classifier.ts","../src/detection/focus-blur.ts","../src/detection/agentic-browser.ts","../src/infrastructure/event-queue.ts","../src/infrastructure/ping.ts","../src/behavioral/scroll-tracker.ts","../src/behavioral/time-tracker.ts","../src/behavioral/form-tracker.ts","../src/spa/router.ts","../src/utils.ts","../src/core.ts"],"sourcesContent":["/**\n * Loamly Tracker\n * \n * Open-source AI traffic detection for websites.\n * See what AI tells your customers — and track when they click.\n * \n * @module @loamly/tracker\n * @version 1.8.0\n * @license MIT\n * @see https://github.com/loamly/loamly\n * @see https://loamly.ai\n */\n\n// Core tracker\nexport { loamly, loamly as default } from './core'\n\n// Types\nexport type {\n LoamlyConfig,\n LoamlyTracker,\n TrackEventOptions,\n NavigationTiming,\n AIDetectionResult,\n} from './types'\n\n// Detection utilities (for advanced usage)\nexport { detectNavigationType } from './detection/navigation-timing'\nexport { detectAIFromReferrer, detectAIFromUTM } from './detection/referrer'\nexport { \n AgenticBrowserAnalyzer,\n createAgenticAnalyzer,\n type AgenticDetectionResult\n} from './detection/agentic-browser'\n\n// Configuration\nexport { VERSION, AI_PLATFORMS, AI_BOT_PATTERNS } from './config'\n\n\n","/**\n * Loamly Tracker Configuration\n * \n * @module @loamly/tracker\n * @license MIT\n * @see https://github.com/loamly/loamly\n */\n\nexport const VERSION = '2.0.2'\n\nexport const DEFAULT_CONFIG = {\n apiHost: 'https://app.loamly.ai',\n endpoints: {\n visit: '/api/ingest/visit',\n behavioral: '/api/ingest/behavioral',\n session: '/api/ingest/session',\n resolve: '/api/tracker/resolve',\n health: '/api/tracker/health',\n ping: '/api/tracker/ping',\n },\n pingInterval: 30000, // 30 seconds\n batchSize: 10,\n batchTimeout: 5000,\n sessionTimeout: 1800000, // 30 minutes\n maxTextLength: 100,\n timeSpentThresholdMs: 5000, // Only send time_spent when delta >= 5 seconds\n} as const\n\n/**\n * Known AI platforms for referrer detection\n */\nexport const AI_PLATFORMS: Record<string, string> = {\n 'chatgpt.com': 'chatgpt',\n 'chat.openai.com': 'chatgpt',\n 'claude.ai': 'claude',\n 'perplexity.ai': 'perplexity',\n 'bard.google.com': 'bard',\n 'gemini.google.com': 'gemini',\n 'copilot.microsoft.com': 'copilot',\n 'github.com/copilot': 'github-copilot',\n 'you.com': 'you',\n 'phind.com': 'phind',\n 'poe.com': 'poe',\n}\n\n/**\n * User agents of known AI crawlers\n */\nexport const AI_BOT_PATTERNS = [\n 'GPTBot',\n 'ChatGPT-User',\n 'ClaudeBot',\n 'Claude-Web',\n 'PerplexityBot',\n 'Amazonbot',\n 'Google-Extended',\n 'CCBot',\n 'anthropic-ai',\n 'cohere-ai',\n]\n\n\n","/**\n * Navigation Timing API Detection\n * \n * Detects whether the user arrived via paste (from AI chat) vs click\n * by analyzing Navigation Timing API patterns.\n * \n * @module @loamly/tracker/detection\n */\n\nimport type { NavigationTiming } from '../types'\n\n/**\n * Analyze Navigation Timing API to detect paste vs click navigation\n * \n * When users paste a URL (common after copying from AI chat), \n * the timing patterns are distinctive:\n * 1. fetchStart is virtually immediate after navigationStart\n * 2. DNS/connect times are often 0 (cached or direct)\n * 3. No redirect chain\n * 4. Uniform timing patterns\n * \n * @returns NavigationTiming result with type and confidence\n */\nexport function detectNavigationType(): NavigationTiming {\n try {\n const entries = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[]\n \n if (!entries || entries.length === 0) {\n return { nav_type: 'unknown', confidence: 0, signals: ['no_timing_data'] }\n }\n\n const nav = entries[0]\n const signals: string[] = []\n let pasteScore = 0\n\n // Signal 1: fetchStart delta from navigationStart\n // Paste navigation typically has very small delta (< 5ms)\n const fetchStartDelta = nav.fetchStart - nav.startTime\n if (fetchStartDelta < 5) {\n pasteScore += 0.25\n signals.push('instant_fetch_start')\n } else if (fetchStartDelta < 20) {\n pasteScore += 0.15\n signals.push('fast_fetch_start')\n }\n\n // Signal 2: DNS lookup time\n // Paste = likely 0 (direct URL entry, no link warmup)\n const dnsTime = nav.domainLookupEnd - nav.domainLookupStart\n if (dnsTime === 0) {\n pasteScore += 0.15\n signals.push('no_dns_lookup')\n }\n\n // Signal 3: TCP connect time\n // Paste = likely 0 (no preconnect from previous page)\n const connectTime = nav.connectEnd - nav.connectStart\n if (connectTime === 0) {\n pasteScore += 0.15\n signals.push('no_tcp_connect')\n }\n\n // Signal 4: No redirects\n // Paste URLs are typically direct, no redirects\n if (nav.redirectCount === 0) {\n pasteScore += 0.1\n signals.push('no_redirects')\n }\n\n // Signal 5: Timing uniformity check\n // Paste navigation tends to have more uniform patterns\n const timingVariance = calculateTimingVariance(nav)\n if (timingVariance < 10) {\n pasteScore += 0.15\n signals.push('uniform_timing')\n }\n\n // Signal 6: No referrer (common for paste)\n if (!document.referrer || document.referrer === '') {\n pasteScore += 0.1\n signals.push('no_referrer')\n }\n\n // Determine navigation type based on score\n const confidence = Math.min(pasteScore, 1)\n const nav_type = pasteScore >= 0.5 ? 'likely_paste' : 'likely_click'\n\n return {\n nav_type,\n confidence: Math.round(confidence * 1000) / 1000,\n signals,\n }\n } catch {\n return { nav_type: 'unknown', confidence: 0, signals: ['detection_error'] }\n }\n}\n\n/**\n * Calculate timing variance to detect paste patterns\n */\nfunction calculateTimingVariance(nav: PerformanceNavigationTiming): number {\n const timings = [\n nav.fetchStart - nav.startTime,\n nav.domainLookupEnd - nav.domainLookupStart,\n nav.connectEnd - nav.connectStart,\n nav.responseStart - nav.requestStart,\n ].filter((t) => t >= 0)\n\n if (timings.length === 0) return 100\n\n const mean = timings.reduce((a, b) => a + b, 0) / timings.length\n const variance = timings.reduce((sum, t) => sum + Math.pow(t - mean, 2), 0) / timings.length\n \n return Math.sqrt(variance)\n}\n\n\n","/**\n * Referrer-based AI Detection\n * \n * Detects when users arrive from known AI platforms\n * based on the document.referrer header.\n * \n * @module @loamly/tracker/detection\n */\n\nimport { AI_PLATFORMS } from '../config'\nimport type { AIDetectionResult } from '../types'\n\n/**\n * Detect AI platform from referrer URL\n * \n * @param referrer - The document.referrer value\n * @returns AI detection result or null if no AI detected\n */\nexport function detectAIFromReferrer(referrer: string): AIDetectionResult | null {\n if (!referrer) {\n return null\n }\n\n try {\n const url = new URL(referrer)\n const hostname = url.hostname.toLowerCase()\n\n // Check against known AI platforms\n for (const [pattern, platform] of Object.entries(AI_PLATFORMS)) {\n if (hostname.includes(pattern) || referrer.includes(pattern)) {\n return {\n isAI: true,\n platform,\n confidence: 0.95, // High confidence when referrer matches\n method: 'referrer',\n }\n }\n }\n\n return null\n } catch {\n // Invalid URL, try pattern matching on raw string\n for (const [pattern, platform] of Object.entries(AI_PLATFORMS)) {\n if (referrer.toLowerCase().includes(pattern.toLowerCase())) {\n return {\n isAI: true,\n platform,\n confidence: 0.85,\n method: 'referrer',\n }\n }\n }\n return null\n }\n}\n\n/**\n * Extract AI platform from UTM parameters\n * \n * @param url - The current page URL\n * @returns AI platform name or null\n */\nexport function detectAIFromUTM(url: string): AIDetectionResult | null {\n try {\n const params = new URL(url).searchParams\n \n // Check utm_source for AI platforms\n const utmSource = params.get('utm_source')?.toLowerCase()\n if (utmSource) {\n for (const [pattern, platform] of Object.entries(AI_PLATFORMS)) {\n if (utmSource.includes(pattern.split('.')[0])) {\n return {\n isAI: true,\n platform,\n confidence: 0.99, // Very high confidence from explicit UTM\n method: 'referrer',\n }\n }\n }\n \n // Generic AI source patterns\n if (utmSource.includes('ai') || utmSource.includes('llm') || utmSource.includes('chatbot')) {\n return {\n isAI: true,\n platform: utmSource,\n confidence: 0.9,\n method: 'referrer',\n }\n }\n }\n\n return null\n } catch {\n return null\n }\n}\n\n\n","/**\n * Lightweight Behavioral ML Classifier\n * \n * LOA-180: Client-side Naive Bayes classifier for AI traffic detection.\n * Research: 75-90% accuracy with 5-8 behavioral signals (Perplexity Dec 2025)\n * \n * @module @loamly/tracker/detection/behavioral-classifier\n */\n\n/**\n * Behavioral signal types for classification\n */\nexport type BehavioralSignal = \n // Time-based signals\n | 'time_to_first_click_immediate' // < 500ms\n | 'time_to_first_click_fast' // 500ms - 2s\n | 'time_to_first_click_normal' // 2s - 10s\n | 'time_to_first_click_delayed' // > 10s\n // Scroll signals\n | 'scroll_speed_none' // No scroll\n | 'scroll_speed_uniform' // Bot-like uniform scrolling\n | 'scroll_speed_variable' // Human-like variable\n | 'scroll_speed_erratic' // Very erratic\n // Navigation signals\n | 'nav_timing_paste'\n | 'nav_timing_click'\n | 'nav_timing_unknown'\n // Context signals\n | 'no_referrer'\n | 'has_referrer'\n | 'deep_landing' // Non-homepage first page\n | 'homepage_landing'\n // Mouse signals\n | 'mouse_movement_none'\n | 'mouse_movement_linear' // Bot-like straight lines\n | 'mouse_movement_curved' // Human-like curves\n // Form signals\n | 'form_fill_instant' // < 100ms per field\n | 'form_fill_fast' // 100-500ms per field\n | 'form_fill_normal' // > 500ms per field\n // Focus signals\n | 'focus_blur_rapid' // Rapid tab switching\n | 'focus_blur_normal'\n\n/**\n * Classification result\n */\nexport interface BehavioralClassificationResult {\n /** Overall classification */\n classification: 'human' | 'ai_influenced' | 'uncertain'\n /** Human probability (0-1) */\n humanProbability: number\n /** AI-influenced probability (0-1) */\n aiProbability: number\n /** Confidence in classification (0-1) */\n confidence: number\n /** Signals detected */\n signals: BehavioralSignal[]\n /** Time when classification was made */\n timestamp: number\n /** Session duration when classified */\n sessionDurationMs: number\n}\n\n/**\n * Behavioral data collector\n */\ninterface BehavioralData {\n firstClickTime: number | null\n scrollEvents: { time: number; position: number }[]\n mouseEvents: { time: number; x: number; y: number }[]\n formEvents: { fieldId: string; startTime: number; endTime: number }[]\n focusBlurEvents: { type: 'focus' | 'blur'; time: number }[]\n startTime: number\n}\n\n/**\n * Pre-trained Naive Bayes weights\n * Research-validated weights from Perplexity Dec 2025 research\n */\nconst NAIVE_BAYES_WEIGHTS = {\n human: {\n time_to_first_click_delayed: 0.85,\n time_to_first_click_normal: 0.75,\n time_to_first_click_fast: 0.50,\n time_to_first_click_immediate: 0.25,\n scroll_speed_variable: 0.80,\n scroll_speed_erratic: 0.70,\n scroll_speed_uniform: 0.35,\n scroll_speed_none: 0.45,\n nav_timing_click: 0.75,\n nav_timing_unknown: 0.55,\n nav_timing_paste: 0.35,\n has_referrer: 0.70,\n no_referrer: 0.45,\n homepage_landing: 0.65,\n deep_landing: 0.50,\n mouse_movement_curved: 0.90,\n mouse_movement_linear: 0.30,\n mouse_movement_none: 0.40,\n form_fill_normal: 0.85,\n form_fill_fast: 0.60,\n form_fill_instant: 0.20,\n focus_blur_normal: 0.75,\n focus_blur_rapid: 0.45,\n },\n ai_influenced: {\n time_to_first_click_immediate: 0.75,\n time_to_first_click_fast: 0.55,\n time_to_first_click_normal: 0.40,\n time_to_first_click_delayed: 0.35,\n scroll_speed_none: 0.55,\n scroll_speed_uniform: 0.70,\n scroll_speed_variable: 0.35,\n scroll_speed_erratic: 0.40,\n nav_timing_paste: 0.75,\n nav_timing_unknown: 0.50,\n nav_timing_click: 0.35,\n no_referrer: 0.65,\n has_referrer: 0.40,\n deep_landing: 0.60,\n homepage_landing: 0.45,\n mouse_movement_none: 0.60,\n mouse_movement_linear: 0.75,\n mouse_movement_curved: 0.25,\n form_fill_instant: 0.80,\n form_fill_fast: 0.55,\n form_fill_normal: 0.30,\n focus_blur_rapid: 0.60,\n focus_blur_normal: 0.40,\n },\n} as const\n\n// Prior probabilities (base rates)\nconst PRIORS = {\n human: 0.85,\n ai_influenced: 0.15,\n}\n\n// Default weight for unknown signals\nconst DEFAULT_WEIGHT = 0.5\n\n/**\n * Behavioral Classifier\n * \n * Lightweight Naive Bayes classifier (~2KB) for client-side AI traffic detection.\n * Collects behavioral signals and classifies after configurable session time.\n */\nexport class BehavioralClassifier {\n private data: BehavioralData\n private classified = false\n private result: BehavioralClassificationResult | null = null\n private minSessionTime: number\n private onClassify: ((result: BehavioralClassificationResult) => void) | null = null\n\n /**\n * Create a new classifier\n * @param minSessionTimeMs Minimum session time before classification (default: 10s)\n */\n constructor(minSessionTimeMs = 10000) {\n this.minSessionTime = minSessionTimeMs\n this.data = {\n firstClickTime: null,\n scrollEvents: [],\n mouseEvents: [],\n formEvents: [],\n focusBlurEvents: [],\n startTime: Date.now(),\n }\n }\n\n /**\n * Set callback for when classification completes\n */\n setOnClassify(callback: (result: BehavioralClassificationResult) => void): void {\n this.onClassify = callback\n }\n\n /**\n * Record a click event\n */\n recordClick(): void {\n if (this.data.firstClickTime === null) {\n this.data.firstClickTime = Date.now()\n }\n this.checkAndClassify()\n }\n\n /**\n * Record a scroll event\n */\n recordScroll(position: number): void {\n this.data.scrollEvents.push({ time: Date.now(), position })\n // Keep only last 50 events to limit memory\n if (this.data.scrollEvents.length > 50) {\n this.data.scrollEvents = this.data.scrollEvents.slice(-50)\n }\n this.checkAndClassify()\n }\n\n /**\n * Record mouse movement\n */\n recordMouse(x: number, y: number): void {\n this.data.mouseEvents.push({ time: Date.now(), x, y })\n // Keep only last 100 events\n if (this.data.mouseEvents.length > 100) {\n this.data.mouseEvents = this.data.mouseEvents.slice(-100)\n }\n this.checkAndClassify()\n }\n\n /**\n * Record form field interaction start\n */\n recordFormStart(fieldId: string): void {\n const existing = this.data.formEvents.find(e => e.fieldId === fieldId && e.endTime === 0)\n if (!existing) {\n this.data.formEvents.push({ fieldId, startTime: Date.now(), endTime: 0 })\n }\n }\n\n /**\n * Record form field interaction end\n */\n recordFormEnd(fieldId: string): void {\n const event = this.data.formEvents.find(e => e.fieldId === fieldId && e.endTime === 0)\n if (event) {\n event.endTime = Date.now()\n }\n this.checkAndClassify()\n }\n\n /**\n * Record focus/blur event\n */\n recordFocusBlur(type: 'focus' | 'blur'): void {\n this.data.focusBlurEvents.push({ type, time: Date.now() })\n // Keep only last 20 events\n if (this.data.focusBlurEvents.length > 20) {\n this.data.focusBlurEvents = this.data.focusBlurEvents.slice(-20)\n }\n }\n\n /**\n * Check if we have enough data and classify\n */\n private checkAndClassify(): void {\n if (this.classified) return\n \n const sessionDuration = Date.now() - this.data.startTime\n if (sessionDuration < this.minSessionTime) return\n \n // Need at least some behavioral data\n const hasData = \n this.data.scrollEvents.length >= 2 ||\n this.data.mouseEvents.length >= 5 ||\n this.data.firstClickTime !== null\n \n if (!hasData) return\n \n this.classify()\n }\n\n /**\n * Force classification (for beforeunload)\n */\n forceClassify(): BehavioralClassificationResult | null {\n if (this.classified) return this.result\n return this.classify()\n }\n\n /**\n * Perform classification\n */\n private classify(): BehavioralClassificationResult {\n const sessionDuration = Date.now() - this.data.startTime\n const signals = this.extractSignals()\n \n // Naive Bayes log-probability calculation\n let humanLogProb = Math.log(PRIORS.human)\n let aiLogProb = Math.log(PRIORS.ai_influenced)\n \n for (const signal of signals) {\n const humanWeight = NAIVE_BAYES_WEIGHTS.human[signal as keyof typeof NAIVE_BAYES_WEIGHTS.human] ?? DEFAULT_WEIGHT\n const aiWeight = NAIVE_BAYES_WEIGHTS.ai_influenced[signal as keyof typeof NAIVE_BAYES_WEIGHTS.ai_influenced] ?? DEFAULT_WEIGHT\n \n humanLogProb += Math.log(humanWeight)\n aiLogProb += Math.log(aiWeight)\n }\n \n // Convert to probabilities using log-sum-exp trick\n const maxLog = Math.max(humanLogProb, aiLogProb)\n const humanExp = Math.exp(humanLogProb - maxLog)\n const aiExp = Math.exp(aiLogProb - maxLog)\n const total = humanExp + aiExp\n \n const humanProbability = humanExp / total\n const aiProbability = aiExp / total\n \n // Determine classification\n let classification: 'human' | 'ai_influenced' | 'uncertain'\n let confidence: number\n \n if (humanProbability > 0.6) {\n classification = 'human'\n confidence = humanProbability\n } else if (aiProbability > 0.6) {\n classification = 'ai_influenced'\n confidence = aiProbability\n } else {\n classification = 'uncertain'\n confidence = Math.max(humanProbability, aiProbability)\n }\n \n this.result = {\n classification,\n humanProbability,\n aiProbability,\n confidence,\n signals,\n timestamp: Date.now(),\n sessionDurationMs: sessionDuration,\n }\n \n this.classified = true\n \n // Call callback if set\n if (this.onClassify) {\n this.onClassify(this.result)\n }\n \n return this.result\n }\n\n /**\n * Extract behavioral signals from collected data\n */\n private extractSignals(): BehavioralSignal[] {\n const signals: BehavioralSignal[] = []\n // Session duration available for future enhancements\n // const sessionDuration = Date.now() - this.data.startTime\n \n // Time to first click\n if (this.data.firstClickTime !== null) {\n const timeToClick = this.data.firstClickTime - this.data.startTime\n if (timeToClick < 500) {\n signals.push('time_to_first_click_immediate')\n } else if (timeToClick < 2000) {\n signals.push('time_to_first_click_fast')\n } else if (timeToClick < 10000) {\n signals.push('time_to_first_click_normal')\n } else {\n signals.push('time_to_first_click_delayed')\n }\n }\n \n // Scroll behavior\n if (this.data.scrollEvents.length === 0) {\n signals.push('scroll_speed_none')\n } else if (this.data.scrollEvents.length >= 3) {\n const scrollDeltas: number[] = []\n for (let i = 1; i < this.data.scrollEvents.length; i++) {\n const delta = this.data.scrollEvents[i].time - this.data.scrollEvents[i - 1].time\n scrollDeltas.push(delta)\n }\n \n // Calculate coefficient of variation for scroll timing\n const mean = scrollDeltas.reduce((a, b) => a + b, 0) / scrollDeltas.length\n const variance = scrollDeltas.reduce((sum, d) => sum + Math.pow(d - mean, 2), 0) / scrollDeltas.length\n const stdDev = Math.sqrt(variance)\n const cv = mean > 0 ? stdDev / mean : 0\n \n if (cv < 0.2) {\n signals.push('scroll_speed_uniform') // Very consistent = bot-like\n } else if (cv < 0.6) {\n signals.push('scroll_speed_variable') // Natural variation\n } else {\n signals.push('scroll_speed_erratic')\n }\n }\n \n // Mouse movement analysis\n if (this.data.mouseEvents.length === 0) {\n signals.push('mouse_movement_none')\n } else if (this.data.mouseEvents.length >= 10) {\n // Calculate linearity using R² of best-fit line\n const n = Math.min(this.data.mouseEvents.length, 20)\n const recentMouse = this.data.mouseEvents.slice(-n)\n \n let sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0\n for (const event of recentMouse) {\n sumX += event.x\n sumY += event.y\n sumXY += event.x * event.y\n sumX2 += event.x * event.x\n }\n \n const denominator = (n * sumX2 - sumX * sumX)\n const slope = denominator !== 0 ? (n * sumXY - sumX * sumY) / denominator : 0\n const intercept = (sumY - slope * sumX) / n\n \n // Calculate R²\n let ssRes = 0, ssTot = 0\n const yMean = sumY / n\n for (const event of recentMouse) {\n const yPred = slope * event.x + intercept\n ssRes += Math.pow(event.y - yPred, 2)\n ssTot += Math.pow(event.y - yMean, 2)\n }\n \n const r2 = ssTot !== 0 ? 1 - (ssRes / ssTot) : 0\n \n if (r2 > 0.95) {\n signals.push('mouse_movement_linear') // Too straight = bot-like\n } else {\n signals.push('mouse_movement_curved') // Natural curves\n }\n }\n \n // Form fill timing\n const completedForms = this.data.formEvents.filter(e => e.endTime > 0)\n if (completedForms.length > 0) {\n const avgFillTime = completedForms.reduce((sum, e) => sum + (e.endTime - e.startTime), 0) / completedForms.length\n \n if (avgFillTime < 100) {\n signals.push('form_fill_instant')\n } else if (avgFillTime < 500) {\n signals.push('form_fill_fast')\n } else {\n signals.push('form_fill_normal')\n }\n }\n \n // Focus/blur patterns\n if (this.data.focusBlurEvents.length >= 4) {\n const recentFB = this.data.focusBlurEvents.slice(-10)\n const intervals: number[] = []\n \n for (let i = 1; i < recentFB.length; i++) {\n intervals.push(recentFB[i].time - recentFB[i - 1].time)\n }\n \n const avgInterval = intervals.reduce((a, b) => a + b, 0) / intervals.length\n \n if (avgInterval < 1000) {\n signals.push('focus_blur_rapid')\n } else {\n signals.push('focus_blur_normal')\n }\n }\n \n // Context signals (will be set from outside)\n // These are typically added by the tracker itself\n \n return signals\n }\n\n /**\n * Add context signals (set by tracker from external data)\n */\n addContextSignal(_signal: BehavioralSignal): void {\n // These will be picked up on next classification\n // For now, we'll handle them in the classify method\n // TODO: Store signals for next classification run\n }\n\n /**\n * Get current result (null if not yet classified)\n */\n getResult(): BehavioralClassificationResult | null {\n return this.result\n }\n\n /**\n * Check if classification has been performed\n */\n hasClassified(): boolean {\n return this.classified\n }\n}\n\n/**\n * Create a classifier instance with standard configuration\n */\nexport function createBehavioralClassifier(minSessionTimeMs = 10000): BehavioralClassifier {\n return new BehavioralClassifier(minSessionTimeMs)\n}\n\n","/**\n * Focus/Blur Event Sequence Analysis\n * \n * LOA-182: Detects paste vs click navigation patterns by analyzing\n * the sequence of focus and blur events when a page loads.\n * \n * Research: 55-65% accuracy (improves when combined with other signals)\n * \n * @module @loamly/tracker/detection/focus-blur\n */\n\n/**\n * Focus/blur event record\n */\nexport interface FocusBlurEvent {\n type: 'focus' | 'blur' | 'window_focus' | 'window_blur'\n target: string\n timestamp: number\n}\n\n/**\n * Focus/blur analysis result\n */\nexport interface FocusBlurResult {\n /** Navigation pattern type */\n nav_type: 'likely_paste' | 'likely_click' | 'unknown'\n /** Confidence score (0-1) */\n confidence: number\n /** Detection signals */\n signals: string[]\n /** Event sequence (last 10 events) */\n sequence: FocusBlurEvent[]\n /** Time from page load to first interaction */\n time_to_first_interaction_ms: number | null\n}\n\n/**\n * Focus/Blur Sequence Analyzer\n * \n * Tracks focus and blur events to detect paste navigation patterns.\n * Paste navigation typically shows:\n * 1. Early window focus event\n * 2. Body focus without prior link navigation\n * 3. No referrer blur pattern\n */\nexport class FocusBlurAnalyzer {\n private sequence: FocusBlurEvent[] = []\n private pageLoadTime: number\n private firstInteractionTime: number | null = null\n private analyzed = false\n private result: FocusBlurResult | null = null\n\n constructor() {\n this.pageLoadTime = performance.now()\n }\n\n /**\n * Initialize event tracking\n * Must be called after DOM is ready\n */\n initTracking(): void {\n // Track focus events (use capturing phase to catch all events)\n document.addEventListener('focus', (e) => {\n this.recordEvent('focus', e.target as HTMLElement)\n }, true)\n\n document.addEventListener('blur', (e) => {\n this.recordEvent('blur', e.target as HTMLElement)\n }, true)\n\n // Track window focus/blur\n window.addEventListener('focus', () => {\n this.recordEvent('window_focus', null)\n })\n\n window.addEventListener('blur', () => {\n this.recordEvent('window_blur', null)\n })\n\n // Track first click/keypress as first interaction\n const recordFirstInteraction = () => {\n if (this.firstInteractionTime === null) {\n this.firstInteractionTime = performance.now()\n }\n }\n document.addEventListener('click', recordFirstInteraction, { once: true, passive: true })\n document.addEventListener('keydown', recordFirstInteraction, { once: true, passive: true })\n }\n\n /**\n * Record a focus/blur event\n */\n private recordEvent(type: FocusBlurEvent['type'], target: HTMLElement | null): void {\n const event: FocusBlurEvent = {\n type,\n target: target?.tagName || 'WINDOW',\n timestamp: performance.now()\n }\n \n this.sequence.push(event)\n \n // Keep only last 20 events to limit memory\n if (this.sequence.length > 20) {\n this.sequence = this.sequence.slice(-20)\n }\n }\n\n /**\n * Analyze the focus/blur sequence for paste patterns\n */\n analyze(): FocusBlurResult {\n if (this.analyzed && this.result) {\n return this.result\n }\n\n const signals: string[] = []\n let confidence = 0\n \n // Get early events (first 500ms after page load)\n const earlyEvents = this.sequence.filter(e => e.timestamp < this.pageLoadTime + 500)\n \n // Pattern 1: Window focus as first event\n const hasEarlyWindowFocus = earlyEvents.some(e => e.type === 'window_focus')\n if (hasEarlyWindowFocus) {\n signals.push('early_window_focus')\n confidence += 0.15\n }\n \n // Pattern 2: Body focus early (paste causes immediate body focus)\n const hasEarlyBodyFocus = earlyEvents.some(\n e => e.type === 'focus' && e.target === 'BODY'\n )\n if (hasEarlyBodyFocus) {\n signals.push('early_body_focus')\n confidence += 0.15\n }\n \n // Pattern 3: No link/anchor focus (would indicate click navigation)\n const hasLinkFocus = this.sequence.some(\n e => e.type === 'focus' && e.target === 'A'\n )\n if (!hasLinkFocus) {\n signals.push('no_link_focus')\n confidence += 0.10\n }\n \n // Pattern 4: First focus is on document/body (not a specific element)\n const firstFocus = this.sequence.find(e => e.type === 'focus')\n if (firstFocus && (firstFocus.target === 'BODY' || firstFocus.target === 'HTML')) {\n signals.push('first_focus_body')\n confidence += 0.10\n }\n \n // Pattern 5: No rapid tab switching (common in human navigation)\n const windowEvents = this.sequence.filter(\n e => e.type === 'window_focus' || e.type === 'window_blur'\n )\n if (windowEvents.length <= 2) {\n signals.push('minimal_window_switches')\n confidence += 0.05\n }\n \n // Pattern 6: Time to first interaction\n // Paste users often have longer time before first interaction\n // (reading content they copied from AI)\n if (this.firstInteractionTime !== null) {\n const timeToInteraction = this.firstInteractionTime - this.pageLoadTime\n if (timeToInteraction > 3000) {\n signals.push('delayed_first_interaction')\n confidence += 0.10\n }\n }\n \n // Cap confidence based on research (55-65% accuracy)\n confidence = Math.min(confidence, 0.65)\n \n // Determine navigation type\n let navType: FocusBlurResult['nav_type']\n if (confidence >= 0.35) {\n navType = 'likely_paste'\n } else if (signals.length === 0) {\n navType = 'unknown'\n } else {\n navType = 'likely_click'\n }\n \n this.result = {\n nav_type: navType,\n confidence,\n signals,\n sequence: this.sequence.slice(-10),\n time_to_first_interaction_ms: this.firstInteractionTime \n ? Math.round(this.firstInteractionTime - this.pageLoadTime)\n : null\n }\n \n this.analyzed = true\n return this.result\n }\n\n /**\n * Get current result (analyze if not done)\n */\n getResult(): FocusBlurResult {\n return this.analyze()\n }\n\n /**\n * Check if analysis has been performed\n */\n hasAnalyzed(): boolean {\n return this.analyzed\n }\n\n /**\n * Get the raw sequence for debugging\n */\n getSequence(): FocusBlurEvent[] {\n return [...this.sequence]\n }\n\n /**\n * Reset the analyzer\n */\n reset(): void {\n this.sequence = []\n this.pageLoadTime = performance.now()\n this.firstInteractionTime = null\n this.analyzed = false\n this.result = null\n }\n}\n\n/**\n * Create a new focus/blur analyzer\n */\nexport function createFocusBlurAnalyzer(): FocusBlurAnalyzer {\n const analyzer = new FocusBlurAnalyzer()\n \n // Initialize tracking when DOM is ready\n if (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => analyzer.initTracking())\n } else {\n analyzer.initTracking()\n }\n }\n \n return analyzer\n}\n\n","/**\n * Agentic Browser Detection\n * \n * LOA-187: Detects AI agentic browsers like Perplexity Comet, ChatGPT Atlas,\n * and other automated browsing agents.\n * \n * Detection methods:\n * - DOM fingerprinting (Perplexity Comet overlay)\n * - Mouse movement patterns (teleporting clicks)\n * - CDP (Chrome DevTools Protocol) automation fingerprint\n * - navigator.webdriver detection\n * \n * @module @loamly/tracker/detection/agentic-browser\n * @license MIT\n */\n\n/**\n * Agentic detection result\n */\nexport interface AgenticDetectionResult {\n /** Whether Perplexity Comet DOM element was detected */\n cometDOMDetected: boolean\n /** Whether CDP automation was detected */\n cdpDetected: boolean\n /** Mouse movement patterns */\n mousePatterns: {\n teleportingClicks: number\n totalMovements: number\n }\n /** Overall agentic probability (0-1) */\n agenticProbability: number\n /** Detection signals */\n signals: string[]\n}\n\n/**\n * Perplexity Comet DOM Detector\n * \n * Detects the Comet browser overlay stop button which is injected\n * into the DOM when Comet is actively browsing.\n */\nexport class CometDetector {\n private detected = false\n private checkComplete = false\n private observer: MutationObserver | null = null\n\n /**\n * Initialize detection\n * @param timeout - Max time to observe for Comet DOM (default: 5s)\n */\n init(timeout = 5000): void {\n if (typeof document === 'undefined') return\n\n // Initial check\n this.check()\n\n if (!this.detected && document.body) {\n // Observe for dynamic injection\n this.observer = new MutationObserver(() => this.check())\n this.observer.observe(document.body, { childList: true, subtree: true })\n\n // Stop observing after timeout\n setTimeout(() => {\n if (this.observer && !this.detected) {\n this.observer.disconnect()\n this.observer = null\n this.checkComplete = true\n }\n }, timeout)\n }\n }\n\n private check(): void {\n // Perplexity Comet injects an overlay with this class\n if (document.querySelector('.pplx-agent-overlay-stop-button')) {\n this.detected = true\n this.checkComplete = true\n if (this.observer) {\n this.observer.disconnect()\n this.observer = null\n }\n }\n }\n\n isDetected(): boolean {\n return this.detected\n }\n\n isCheckComplete(): boolean {\n return this.checkComplete\n }\n\n destroy(): void {\n if (this.observer) {\n this.observer.disconnect()\n this.observer = null\n }\n }\n}\n\n/**\n * Mouse Movement Analyzer\n * \n * Detects unnatural mouse movements characteristic of automated browsers:\n * - Teleporting clicks (instant large movements)\n * - Perfect linear movements\n * - No micro-adjustments\n */\nexport class MouseAnalyzer {\n private lastX = -1\n private lastY = -1\n private teleportingClicks = 0\n private totalMovements = 0\n private readonly teleportThreshold: number\n\n /**\n * @param teleportThreshold - Distance in pixels to consider a teleport (default: 500)\n */\n constructor(teleportThreshold = 500) {\n this.teleportThreshold = teleportThreshold\n }\n\n /**\n * Initialize mouse tracking\n */\n init(): void {\n if (typeof document === 'undefined') return\n\n document.addEventListener('mousemove', this.handleMove, { passive: true })\n document.addEventListener('mousedown', this.handleClick, { passive: true })\n }\n\n private handleMove = (e: MouseEvent): void => {\n this.totalMovements++\n this.lastX = e.clientX\n this.lastY = e.clientY\n }\n\n private handleClick = (e: MouseEvent): void => {\n if (this.lastX !== -1 && this.lastY !== -1) {\n const dx = Math.abs(e.clientX - this.lastX)\n const dy = Math.abs(e.clientY - this.lastY)\n\n // Large instant movement before click = teleporting\n if (dx > this.teleportThreshold || dy > this.teleportThreshold) {\n this.teleportingClicks++\n }\n }\n this.lastX = e.clientX\n this.lastY = e.clientY\n }\n\n getPatterns(): { teleportingClicks: number; totalMovements: number } {\n return {\n teleportingClicks: this.teleportingClicks,\n totalMovements: this.totalMovements,\n }\n }\n\n destroy(): void {\n if (typeof document === 'undefined') return\n document.removeEventListener('mousemove', this.handleMove)\n document.removeEventListener('mousedown', this.handleClick)\n }\n}\n\n/**\n * CDP (Chrome DevTools Protocol) Automation Detector\n * \n * Detects headless browsers and automation tools:\n * - navigator.webdriver (set by Selenium, Puppeteer, Playwright)\n * - Chrome automation flags\n * - Missing browser APIs\n */\nexport class CDPDetector {\n private detected = false\n\n /**\n * Run detection checks\n */\n detect(): boolean {\n if (typeof navigator === 'undefined') return false\n\n // Check 1: navigator.webdriver (Chrome 76+, Firefox 60+)\n // Set to true by automation frameworks\n if ((navigator as Navigator & { webdriver?: boolean }).webdriver) {\n this.detected = true\n return true\n }\n\n // Check 2: Chrome automation extension (legacy check)\n if (typeof window !== 'undefined') {\n const win = window as Window & {\n chrome?: { runtime?: unknown }\n __webdriver_evaluate?: unknown\n __selenium_evaluate?: unknown\n __webdriver_script_function?: unknown\n __webdriver_script_func?: unknown\n __webdriver_script_fn?: unknown\n __fxdriver_evaluate?: unknown\n __driver_unwrapped?: unknown\n __webdriver_unwrapped?: unknown\n __driver_evaluate?: unknown\n __selenium_unwrapped?: unknown\n __fxdriver_unwrapped?: unknown\n }\n\n // Selenium/WebDriver fingerprints\n const automationProps = [\n '__webdriver_evaluate',\n '__selenium_evaluate',\n '__webdriver_script_function',\n '__webdriver_script_func',\n '__webdriver_script_fn',\n '__fxdriver_evaluate',\n '__driver_unwrapped',\n '__webdriver_unwrapped',\n '__driver_evaluate',\n '__selenium_unwrapped',\n '__fxdriver_unwrapped',\n ]\n\n for (const prop of automationProps) {\n if (prop in win) {\n this.detected = true\n return true\n }\n }\n }\n\n return false\n }\n\n isDetected(): boolean {\n return this.detected\n }\n}\n\n/**\n * Agentic Browser Analyzer\n * \n * Combines all detection methods into a unified result.\n */\nexport class AgenticBrowserAnalyzer {\n private cometDetector: CometDetector\n private mouseAnalyzer: MouseAnalyzer\n private cdpDetector: CDPDetector\n private initialized = false\n\n constructor() {\n this.cometDetector = new CometDetector()\n this.mouseAnalyzer = new MouseAnalyzer()\n this.cdpDetector = new CDPDetector()\n }\n\n /**\n * Initialize all detectors\n */\n init(): void {\n if (this.initialized) return\n this.initialized = true\n\n this.cometDetector.init()\n this.mouseAnalyzer.init()\n this.cdpDetector.detect()\n }\n\n /**\n * Get current detection result\n */\n getResult(): AgenticDetectionResult {\n const signals: string[] = []\n let probability = 0\n\n // Comet detection (85% confidence)\n if (this.cometDetector.isDetected()) {\n signals.push('comet_dom_detected')\n probability = Math.max(probability, 0.85)\n }\n\n // CDP detection (92% confidence)\n if (this.cdpDetector.isDetected()) {\n signals.push('cdp_detected')\n probability = Math.max(probability, 0.92)\n }\n\n // Mouse patterns (78% confidence per teleport)\n const mousePatterns = this.mouseAnalyzer.getPatterns()\n if (mousePatterns.teleportingClicks > 0) {\n signals.push(`teleporting_clicks:${mousePatterns.teleportingClicks}`)\n probability = Math.max(probability, 0.78)\n }\n\n return {\n cometDOMDetected: this.cometDetector.isDetected(),\n cdpDetected: this.cdpDetector.isDetected(),\n mousePatterns,\n agenticProbability: probability,\n signals,\n }\n }\n\n /**\n * Cleanup resources\n */\n destroy(): void {\n this.cometDetector.destroy()\n this.mouseAnalyzer.destroy()\n }\n}\n\n/**\n * Create and initialize an agentic browser analyzer\n */\nexport function createAgenticAnalyzer(): AgenticBrowserAnalyzer {\n const analyzer = new AgenticBrowserAnalyzer()\n\n if (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => analyzer.init())\n } else {\n analyzer.init()\n }\n }\n\n return analyzer\n}\n\n","/**\n * Event Queue with Batching, Retry & Persistence\n * \n * Production-grade event delivery with:\n * - Batch processing for network efficiency\n * - Retry with exponential backoff\n * - localStorage persistence for offline support\n * - sendBeacon fallback for unload events\n * \n * @module @loamly/tracker\n */\n\nimport { DEFAULT_CONFIG } from '../config'\n\nexport interface QueuedEvent {\n id: string\n type: string\n payload: Record<string, unknown>\n timestamp: number\n retries: number\n}\n\ninterface EventQueueConfig {\n batchSize: number\n batchTimeout: number\n maxRetries: number\n retryDelayMs: number\n storageKey: string\n}\n\nconst DEFAULT_QUEUE_CONFIG: EventQueueConfig = {\n batchSize: DEFAULT_CONFIG.batchSize,\n batchTimeout: DEFAULT_CONFIG.batchTimeout,\n maxRetries: 3,\n retryDelayMs: 1000,\n storageKey: '_loamly_queue',\n}\n\nexport class EventQueue {\n private queue: QueuedEvent[] = []\n private batchTimer: ReturnType<typeof setTimeout> | null = null\n private config: EventQueueConfig\n private endpoint: string\n private isFlushing = false\n\n constructor(endpoint: string, config: Partial<EventQueueConfig> = {}) {\n this.endpoint = endpoint\n this.config = { ...DEFAULT_QUEUE_CONFIG, ...config }\n this.loadFromStorage()\n }\n\n /**\n * Add event to queue\n */\n push(type: string, payload: Record<string, unknown>): void {\n const event: QueuedEvent = {\n id: this.generateId(),\n type,\n payload,\n timestamp: Date.now(),\n retries: 0,\n }\n\n this.queue.push(event)\n this.saveToStorage()\n this.scheduleBatch()\n }\n\n /**\n * Force flush all events immediately\n */\n async flush(): Promise<void> {\n if (this.isFlushing || this.queue.length === 0) return\n\n this.isFlushing = true\n this.clearBatchTimer()\n\n try {\n const events = [...this.queue]\n this.queue = []\n \n await this.sendBatch(events)\n } finally {\n this.isFlushing = false\n this.saveToStorage()\n }\n }\n\n /**\n * Flush using sendBeacon (for unload events)\n */\n flushBeacon(): boolean {\n if (this.queue.length === 0) return true\n\n const events = this.queue.map(e => ({\n type: e.type,\n ...e.payload,\n _queue_id: e.id,\n _queue_timestamp: e.timestamp,\n }))\n\n const success = navigator.sendBeacon?.(\n this.endpoint,\n JSON.stringify({ events, beacon: true })\n ) ?? false\n\n if (success) {\n this.queue = []\n this.clearStorage()\n }\n\n return success\n }\n\n /**\n * Get current queue length\n */\n get length(): number {\n return this.queue.length\n }\n\n private scheduleBatch(): void {\n if (this.batchTimer) return\n\n // Flush immediately if batch size reached\n if (this.queue.length >= this.config.batchSize) {\n this.flush()\n return\n }\n\n // Schedule batch flush\n this.batchTimer = setTimeout(() => {\n this.batchTimer = null\n this.flush()\n }, this.config.batchTimeout)\n }\n\n private clearBatchTimer(): void {\n if (this.batchTimer) {\n clearTimeout(this.batchTimer)\n this.batchTimer = null\n }\n }\n\n private async sendBatch(events: QueuedEvent[]): Promise<void> {\n if (events.length === 0) return\n\n const payload = {\n events: events.map(e => ({\n type: e.type,\n ...e.payload,\n _queue_id: e.id,\n _queue_timestamp: e.timestamp,\n })),\n batch: true,\n }\n\n try {\n const response = await fetch(this.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`)\n }\n } catch (error) {\n // Retry failed events\n for (const event of events) {\n if (event.retries < this.config.maxRetries) {\n event.retries++\n this.queue.push(event)\n }\n }\n\n // Schedule retry with exponential backoff\n if (this.queue.length > 0) {\n const delay = this.config.retryDelayMs * Math.pow(2, events[0].retries - 1)\n setTimeout(() => this.flush(), delay)\n }\n }\n }\n\n private loadFromStorage(): void {\n try {\n const stored = localStorage.getItem(this.config.storageKey)\n if (stored) {\n const parsed = JSON.parse(stored)\n if (Array.isArray(parsed)) {\n // Only restore events less than 24 hours old\n const cutoff = Date.now() - 24 * 60 * 60 * 1000\n this.queue = parsed.filter((e: QueuedEvent) => e.timestamp > cutoff)\n }\n }\n } catch {\n // localStorage not available or corrupted\n }\n }\n\n private saveToStorage(): void {\n try {\n if (this.queue.length > 0) {\n localStorage.setItem(this.config.storageKey, JSON.stringify(this.queue))\n } else {\n this.clearStorage()\n }\n } catch {\n // localStorage not available\n }\n }\n\n private clearStorage(): void {\n try {\n localStorage.removeItem(this.config.storageKey)\n } catch {\n // Ignore\n }\n }\n\n private generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`\n }\n}\n\n","/**\n * Real-time Ping Service\n * \n * Heartbeat for active session tracking with:\n * - Configurable interval (default 30s)\n * - Visibility-aware (pauses when tab hidden)\n * - Session metrics aggregation\n * \n * @module @loamly/tracker\n */\n\nimport { DEFAULT_CONFIG } from '../config'\n\nexport interface PingData {\n session_id: string\n visitor_id: string\n url: string\n time_on_page_ms: number\n scroll_depth: number\n is_active: boolean\n tracker_version: string\n}\n\nexport interface PingConfig {\n interval: number\n endpoint: string\n onPing?: (data: PingData) => void\n}\n\nexport class PingService {\n private intervalId: ReturnType<typeof setInterval> | null = null\n private config: PingConfig\n private pageLoadTime: number\n private isVisible = true\n private currentScrollDepth = 0\n private sessionId: string\n private visitorId: string\n private version: string\n\n constructor(\n sessionId: string,\n visitorId: string,\n version: string,\n config: Partial<PingConfig> = {}\n ) {\n this.sessionId = sessionId\n this.visitorId = visitorId\n this.version = version\n this.pageLoadTime = Date.now()\n this.config = {\n interval: DEFAULT_CONFIG.pingInterval,\n endpoint: '',\n ...config,\n }\n\n // Track visibility\n document.addEventListener('visibilitychange', this.handleVisibilityChange)\n \n // Track scroll depth\n window.addEventListener('scroll', this.handleScroll, { passive: true })\n }\n\n /**\n * Start the ping service\n */\n start(): void {\n if (this.intervalId) return\n\n this.intervalId = setInterval(() => {\n if (this.isVisible) {\n this.ping()\n }\n }, this.config.interval)\n\n // Send initial ping\n this.ping()\n }\n\n /**\n * Stop the ping service\n */\n stop(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId)\n this.intervalId = null\n }\n\n document.removeEventListener('visibilitychange', this.handleVisibilityChange)\n window.removeEventListener('scroll', this.handleScroll)\n }\n\n /**\n * Update scroll depth (called by external scroll tracker)\n */\n updateScrollDepth(depth: number): void {\n if (depth > this.currentScrollDepth) {\n this.currentScrollDepth = depth\n }\n }\n\n /**\n * Get current ping data\n */\n getData(): PingData {\n return {\n session_id: this.sessionId,\n visitor_id: this.visitorId,\n url: window.location.href,\n time_on_page_ms: Date.now() - this.pageLoadTime,\n scroll_depth: this.currentScrollDepth,\n is_active: this.isVisible,\n tracker_version: this.version,\n }\n }\n\n private ping = async (): Promise<void> => {\n const data = this.getData()\n\n // Call callback if provided\n this.config.onPing?.(data)\n\n // Send to endpoint if configured\n if (this.config.endpoint) {\n try {\n await fetch(this.config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n })\n } catch {\n // Ping failures are silent\n }\n }\n }\n\n private handleVisibilityChange = (): void => {\n this.isVisible = document.visibilityState === 'visible'\n }\n\n private handleScroll = (): void => {\n const scrollPercent = Math.round(\n ((window.scrollY + window.innerHeight) / document.documentElement.scrollHeight) * 100\n )\n if (scrollPercent > this.currentScrollDepth) {\n this.currentScrollDepth = Math.min(scrollPercent, 100)\n }\n }\n}\n\n","/**\n * Advanced Scroll Depth Tracker\n * \n * Production-grade scroll tracking with:\n * - 30% chunk reporting (30%, 60%, 90%, 100%)\n * - requestAnimationFrame throttling for performance\n * - Visibility-aware (only tracks when visible)\n * - Max depth tracking\n * \n * @module @loamly/tracker\n */\n\nexport interface ScrollEvent {\n depth: number\n chunk: number // 30, 60, 90, 100\n time_to_reach_ms: number\n total_height: number\n viewport_height: number\n}\n\nexport interface ScrollTrackerConfig {\n chunks: number[] // Default: [30, 60, 90, 100]\n onChunkReached?: (event: ScrollEvent) => void\n onDepthChange?: (depth: number) => void\n}\n\nconst DEFAULT_CHUNKS = [30, 60, 90, 100]\n\nexport class ScrollTracker {\n private config: ScrollTrackerConfig\n private maxDepth = 0\n private reportedChunks = new Set<number>()\n private startTime: number\n private ticking = false\n private isVisible = true\n\n constructor(config: Partial<ScrollTrackerConfig> = {}) {\n this.config = {\n chunks: DEFAULT_CHUNKS,\n ...config,\n }\n this.startTime = Date.now()\n }\n\n /**\n * Start tracking scroll depth\n */\n start(): void {\n window.addEventListener('scroll', this.handleScroll, { passive: true })\n document.addEventListener('visibilitychange', this.handleVisibility)\n \n // Check initial scroll position (for page refresh)\n this.checkScrollDepth()\n }\n\n /**\n * Stop tracking\n */\n stop(): void {\n window.removeEventListener('scroll', this.handleScroll)\n document.removeEventListener('visibilitychange', this.handleVisibility)\n }\n\n /**\n * Get current max scroll depth\n */\n getMaxDepth(): number {\n return this.maxDepth\n }\n\n /**\n * Get reported chunks\n */\n getReportedChunks(): number[] {\n return Array.from(this.reportedChunks).sort((a, b) => a - b)\n }\n\n /**\n * Get final scroll event (for unload)\n */\n getFinalEvent(): ScrollEvent {\n const docHeight = document.documentElement.scrollHeight\n const viewportHeight = window.innerHeight\n\n return {\n depth: this.maxDepth,\n chunk: this.getChunkForDepth(this.maxDepth),\n time_to_reach_ms: Date.now() - this.startTime,\n total_height: docHeight,\n viewport_height: viewportHeight,\n }\n }\n\n private handleScroll = (): void => {\n if (!this.ticking && this.isVisible) {\n requestAnimationFrame(() => {\n this.checkScrollDepth()\n this.ticking = false\n })\n this.ticking = true\n }\n }\n\n private handleVisibility = (): void => {\n this.isVisible = document.visibilityState === 'visible'\n }\n\n private checkScrollDepth(): void {\n const scrollY = window.scrollY\n const viewportHeight = window.innerHeight\n const docHeight = document.documentElement.scrollHeight\n \n // Avoid division by zero\n if (docHeight <= viewportHeight) {\n this.updateDepth(100)\n return\n }\n\n const scrollableHeight = docHeight - viewportHeight\n const currentDepth = Math.min(100, Math.round((scrollY / scrollableHeight) * 100))\n \n this.updateDepth(currentDepth)\n }\n\n private updateDepth(depth: number): void {\n if (depth <= this.maxDepth) return\n \n this.maxDepth = depth\n this.config.onDepthChange?.(depth)\n\n // Check for chunk milestones\n for (const chunk of this.config.chunks!) {\n if (depth >= chunk && !this.reportedChunks.has(chunk)) {\n this.reportedChunks.add(chunk)\n this.reportChunk(chunk)\n }\n }\n }\n\n private reportChunk(chunk: number): void {\n const docHeight = document.documentElement.scrollHeight\n const viewportHeight = window.innerHeight\n\n const event: ScrollEvent = {\n depth: this.maxDepth,\n chunk,\n time_to_reach_ms: Date.now() - this.startTime,\n total_height: docHeight,\n viewport_height: viewportHeight,\n }\n\n this.config.onChunkReached?.(event)\n }\n\n private getChunkForDepth(depth: number): number {\n const chunks = this.config.chunks!.sort((a, b) => b - a)\n for (const chunk of chunks) {\n if (depth >= chunk) return chunk\n }\n return 0\n }\n}\n\n","/**\n * Time Spent Tracker\n * \n * Accurate time-on-page tracking with:\n * - Visibility-aware (pauses when tab hidden)\n * - Heartbeat updates\n * - Engagement detection (active vs idle)\n * \n * @module @loamly/tracker\n */\n\nexport interface TimeEvent {\n active_time_ms: number\n total_time_ms: number\n idle_time_ms: number\n is_engaged: boolean\n}\n\nexport interface TimeTrackerConfig {\n idleThresholdMs: number // Time without interaction to consider idle\n updateIntervalMs: number // How often to report time\n onUpdate?: (event: TimeEvent) => void\n}\n\nconst DEFAULT_CONFIG: TimeTrackerConfig = {\n idleThresholdMs: 30000, // 30 seconds\n updateIntervalMs: 5000, // 5 seconds\n}\n\nexport class TimeTracker {\n private config: TimeTrackerConfig\n private startTime: number\n private activeTime = 0\n private idleTime = 0\n private lastActivityTime: number\n private lastUpdateTime: number\n private isVisible = true\n private isIdle = false\n private updateInterval: ReturnType<typeof setInterval> | null = null\n private idleCheckInterval: ReturnType<typeof setInterval> | null = null\n\n constructor(config: Partial<TimeTrackerConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config }\n this.startTime = Date.now()\n this.lastActivityTime = this.startTime\n this.lastUpdateTime = this.startTime\n }\n\n /**\n * Start tracking time\n */\n start(): void {\n // Listen for visibility changes\n document.addEventListener('visibilitychange', this.handleVisibility)\n\n // Listen for user activity\n const activityEvents = ['mousemove', 'keydown', 'scroll', 'click', 'touchstart']\n activityEvents.forEach(event => {\n document.addEventListener(event, this.handleActivity, { passive: true })\n })\n\n // Start update interval\n this.updateInterval = setInterval(() => {\n this.update()\n }, this.config.updateIntervalMs)\n\n // Start idle check\n this.idleCheckInterval = setInterval(() => {\n this.checkIdle()\n }, 1000)\n }\n\n /**\n * Stop tracking\n */\n stop(): void {\n document.removeEventListener('visibilitychange', this.handleVisibility)\n \n const activityEvents = ['mousemove', 'keydown', 'scroll', 'click', 'touchstart']\n activityEvents.forEach(event => {\n document.removeEventListener(event, this.handleActivity)\n })\n\n if (this.updateInterval) {\n clearInterval(this.updateInterval)\n this.updateInterval = null\n }\n\n if (this.idleCheckInterval) {\n clearInterval(this.idleCheckInterval)\n this.idleCheckInterval = null\n }\n }\n\n /**\n * Get current time metrics\n */\n getMetrics(): TimeEvent {\n this.updateTimes()\n \n return {\n active_time_ms: this.activeTime,\n total_time_ms: Date.now() - this.startTime,\n idle_time_ms: this.idleTime,\n is_engaged: !this.isIdle && this.isVisible,\n }\n }\n\n /**\n * Get final metrics (for unload)\n */\n getFinalMetrics(): TimeEvent {\n this.updateTimes()\n return this.getMetrics()\n }\n\n private handleVisibility = (): void => {\n const wasVisible = this.isVisible\n this.isVisible = document.visibilityState === 'visible'\n\n if (wasVisible && !this.isVisible) {\n // Tab hidden - update times before stopping\n this.updateTimes()\n } else if (!wasVisible && this.isVisible) {\n // Tab shown - resume tracking\n this.lastUpdateTime = Date.now()\n this.lastActivityTime = Date.now()\n }\n }\n\n private handleActivity = (): void => {\n const now = Date.now()\n \n if (this.isIdle) {\n // Was idle, now active\n this.isIdle = false\n }\n \n this.lastActivityTime = now\n }\n\n private checkIdle(): void {\n const now = Date.now()\n const timeSinceActivity = now - this.lastActivityTime\n\n if (!this.isIdle && timeSinceActivity >= this.config.idleThresholdMs) {\n // User went idle\n this.isIdle = true\n }\n }\n\n private updateTimes(): void {\n const now = Date.now()\n const elapsed = now - this.lastUpdateTime\n\n if (this.isVisible) {\n if (this.isIdle) {\n this.idleTime += elapsed\n } else {\n this.activeTime += elapsed\n }\n }\n\n this.lastUpdateTime = now\n }\n\n private update(): void {\n if (!this.isVisible) return\n\n this.updateTimes()\n this.config.onUpdate?.(this.getMetrics())\n }\n}\n\n","/**\n * Universal Form Tracker\n * \n * Comprehensive form tracking with support for:\n * - Native HTML forms\n * - HubSpot forms\n * - Typeform embeds\n * - JotForm embeds\n * - Gravity Forms\n * - Thank-you page detection\n * - Privacy-preserving field capture\n * \n * @module @loamly/tracker\n */\n\nexport interface FormEvent {\n event_type: 'form_start' | 'form_field' | 'form_submit' | 'form_success'\n form_id: string\n form_type: 'native' | 'hubspot' | 'typeform' | 'jotform' | 'gravity' | 'unknown'\n field_name?: string\n field_type?: string\n time_to_submit_ms?: number\n is_conversion?: boolean\n}\n\nexport interface FormTrackerConfig {\n // Privacy: Never capture these field values\n sensitiveFields: string[]\n // Fields to track interaction (not values)\n trackableFields: string[]\n // Patterns for thank-you page detection\n thankYouPatterns: RegExp[]\n // Callback for form events\n onFormEvent?: (event: FormEvent) => void\n}\n\nconst DEFAULT_CONFIG: FormTrackerConfig = {\n sensitiveFields: [\n 'password', 'pwd', 'pass',\n 'credit', 'card', 'cvv', 'cvc',\n 'ssn', 'social',\n 'secret', 'token', 'key',\n ],\n trackableFields: [\n 'email', 'name', 'phone', 'company',\n 'first', 'last', 'city', 'country',\n ],\n thankYouPatterns: [\n /thank[-_]?you/i,\n /success/i,\n /confirmation/i,\n /submitted/i,\n /complete/i,\n ],\n}\n\nexport class FormTracker {\n private config: FormTrackerConfig\n private formStartTimes = new Map<string, number>()\n private interactedForms = new Set<string>()\n private mutationObserver: MutationObserver | null = null\n\n constructor(config: Partial<FormTrackerConfig> = {}) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config,\n sensitiveFields: [\n ...DEFAULT_CONFIG.sensitiveFields,\n ...(config.sensitiveFields || []),\n ],\n }\n }\n\n /**\n * Start tracking forms\n */\n start(): void {\n // Track native form interactions\n document.addEventListener('focusin', this.handleFocusIn, { passive: true })\n document.addEventListener('submit', this.handleSubmit)\n document.addEventListener('click', this.handleClick, { passive: true })\n\n // Observe DOM for dynamically added forms (HubSpot, Typeform, etc.)\n this.startMutationObserver()\n\n // Check for thank-you page on load\n this.checkThankYouPage()\n\n // Scan for existing embedded forms\n this.scanForEmbeddedForms()\n }\n\n /**\n * Stop tracking\n */\n stop(): void {\n document.removeEventListener('focusin', this.handleFocusIn)\n document.removeEventListener('submit', this.handleSubmit)\n document.removeEventListener('click', this.handleClick)\n this.mutationObserver?.disconnect()\n }\n\n /**\n * Get forms that had interaction\n */\n getInteractedForms(): string[] {\n return Array.from(this.interactedForms)\n }\n\n private handleFocusIn = (e: FocusEvent): void => {\n const target = e.target as HTMLElement\n if (!this.isFormField(target)) return\n\n const form = target.closest('form')\n const formId = this.getFormId(form || target)\n\n // Track form start\n if (!this.formStartTimes.has(formId)) {\n this.formStartTimes.set(formId, Date.now())\n this.interactedForms.add(formId)\n \n this.emitEvent({\n event_type: 'form_start',\n form_id: formId,\n form_type: this.detectFormType(form || target),\n })\n }\n\n // Track field interaction (privacy-safe)\n const fieldName = this.getFieldName(target as HTMLInputElement)\n if (fieldName && !this.isSensitiveField(fieldName)) {\n this.emitEvent({\n event_type: 'form_field',\n form_id: formId,\n form_type: this.detectFormType(form || target),\n field_name: this.sanitizeFieldName(fieldName),\n field_type: (target as HTMLInputElement).type || target.tagName.toLowerCase(),\n })\n }\n }\n\n private handleSubmit = (e: Event): void => {\n const form = e.target as HTMLFormElement\n if (!form || form.tagName !== 'FORM') return\n\n const formId = this.getFormId(form)\n const startTime = this.formStartTimes.get(formId)\n\n this.emitEvent({\n event_type: 'form_submit',\n form_id: formId,\n form_type: this.detectFormType(form),\n time_to_submit_ms: startTime ? Date.now() - startTime : undefined,\n is_conversion: true,\n })\n }\n\n private handleClick = (e: Event): void => {\n const target = e.target as HTMLElement\n \n // Check for HubSpot submit button\n if (target.closest('.hs-button') || target.closest('[type=\"submit\"]')) {\n const form = target.closest('form')\n if (form && form.classList.contains('hs-form')) {\n const formId = this.getFormId(form)\n const startTime = this.formStartTimes.get(formId)\n\n this.emitEvent({\n event_type: 'form_submit',\n form_id: formId,\n form_type: 'hubspot',\n time_to_submit_ms: startTime ? Date.now() - startTime : undefined,\n is_conversion: true,\n })\n }\n }\n\n // Check for Typeform submit\n if (target.closest('[data-qa=\"submit-button\"]')) {\n this.emitEvent({\n event_type: 'form_submit',\n form_id: 'typeform_embed',\n form_type: 'typeform',\n is_conversion: true,\n })\n }\n }\n\n private startMutationObserver(): void {\n this.mutationObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (node instanceof HTMLElement) {\n // Check for HubSpot form\n if (node.classList?.contains('hs-form') || node.querySelector?.('.hs-form')) {\n this.trackEmbeddedForm(node, 'hubspot')\n }\n // Check for Typeform\n if (node.classList?.contains('typeform-widget') || node.querySelector?.('[data-tf-widget]')) {\n this.trackEmbeddedForm(node, 'typeform')\n }\n // Check for JotForm\n if (node.classList?.contains('jotform-form') || node.querySelector?.('.jotform-form')) {\n this.trackEmbeddedForm(node, 'jotform')\n }\n // Check for Gravity Forms\n if (node.classList?.contains('gform_wrapper') || node.querySelector?.('.gform_wrapper')) {\n this.trackEmbeddedForm(node, 'gravity')\n }\n }\n }\n }\n })\n\n this.mutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n })\n }\n\n private scanForEmbeddedForms(): void {\n // HubSpot\n document.querySelectorAll('.hs-form').forEach(form => {\n this.trackEmbeddedForm(form as HTMLElement, 'hubspot')\n })\n \n // Typeform\n document.querySelectorAll('[data-tf-widget], .typeform-widget').forEach(form => {\n this.trackEmbeddedForm(form as HTMLElement, 'typeform')\n })\n \n // JotForm\n document.querySelectorAll('.jotform-form').forEach(form => {\n this.trackEmbeddedForm(form as HTMLElement, 'jotform')\n })\n \n // Gravity Forms\n document.querySelectorAll('.gform_wrapper').forEach(form => {\n this.trackEmbeddedForm(form as HTMLElement, 'gravity')\n })\n }\n\n private trackEmbeddedForm(element: HTMLElement, type: FormEvent['form_type']): void {\n const formId = `${type}_${this.getFormId(element)}`\n \n // Add event listeners for embedded form interactions\n element.addEventListener('focusin', () => {\n if (!this.formStartTimes.has(formId)) {\n this.formStartTimes.set(formId, Date.now())\n this.interactedForms.add(formId)\n \n this.emitEvent({\n event_type: 'form_start',\n form_id: formId,\n form_type: type,\n })\n }\n }, { passive: true })\n }\n\n private checkThankYouPage(): void {\n const url = window.location.href.toLowerCase()\n const title = document.title.toLowerCase()\n \n for (const pattern of this.config.thankYouPatterns) {\n if (pattern.test(url) || pattern.test(title)) {\n this.emitEvent({\n event_type: 'form_success',\n form_id: 'page_conversion',\n form_type: 'unknown',\n is_conversion: true,\n })\n break\n }\n }\n }\n\n private isFormField(element: HTMLElement): boolean {\n const tagName = element.tagName\n return tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT'\n }\n\n private getFormId(element: HTMLElement | null): string {\n if (!element) return 'unknown'\n return element.id || element.getAttribute('name') || element.getAttribute('data-form-id') || 'form_' + Math.random().toString(36).substring(2, 8)\n }\n\n private getFieldName(input: HTMLInputElement): string {\n return input.name || input.id || input.getAttribute('data-name') || ''\n }\n\n private isSensitiveField(fieldName: string): boolean {\n const lowerName = fieldName.toLowerCase()\n return this.config.sensitiveFields.some(sensitive => lowerName.includes(sensitive))\n }\n\n private sanitizeFieldName(fieldName: string): string {\n // Remove any potential PII from field names\n return fieldName.replace(/[0-9]+/g, '*').substring(0, 50)\n }\n\n private detectFormType(element: HTMLElement): FormEvent['form_type'] {\n if (element.classList.contains('hs-form') || element.closest('.hs-form')) {\n return 'hubspot'\n }\n if (element.classList.contains('typeform-widget') || element.closest('[data-tf-widget]')) {\n return 'typeform'\n }\n if (element.classList.contains('jotform-form') || element.closest('.jotform-form')) {\n return 'jotform'\n }\n if (element.classList.contains('gform_wrapper') || element.closest('.gform_wrapper')) {\n return 'gravity'\n }\n if (element.tagName === 'FORM') {\n return 'native'\n }\n return 'unknown'\n }\n\n private emitEvent(event: FormEvent): void {\n this.config.onFormEvent?.(event)\n }\n}\n\n","/**\n * SPA Navigation Router\n * \n * Detects client-side navigation in SPAs with support for:\n * - History API (pushState, replaceState, popstate)\n * - Hash changes (for hash-based routing)\n * - Next.js, React Router, Vue Router, etc.\n * \n * @module @loamly/tracker\n */\n\nexport interface NavigationEvent {\n from_url: string\n to_url: string\n navigation_type: 'push' | 'replace' | 'pop' | 'hash' | 'initial'\n time_on_previous_page_ms: number\n}\n\nexport interface RouterConfig {\n onNavigate?: (event: NavigationEvent) => void\n ignoreHashChange?: boolean\n}\n\nexport class SPARouter {\n private config: RouterConfig\n private currentUrl: string\n private pageEnterTime: number\n private originalPushState: typeof history.pushState | null = null\n private originalReplaceState: typeof history.replaceState | null = null\n\n constructor(config: RouterConfig = {}) {\n this.config = config\n this.currentUrl = window.location.href\n this.pageEnterTime = Date.now()\n }\n\n /**\n * Start listening for navigation events\n */\n start(): void {\n // Patch History API\n this.patchHistoryAPI()\n\n // Listen for popstate (back/forward)\n window.addEventListener('popstate', this.handlePopState)\n\n // Listen for hash changes\n if (!this.config.ignoreHashChange) {\n window.addEventListener('hashchange', this.handleHashChange)\n }\n }\n\n /**\n * Stop listening and restore original methods\n */\n stop(): void {\n // Restore original History API methods\n if (this.originalPushState) {\n history.pushState = this.originalPushState\n }\n if (this.originalReplaceState) {\n history.replaceState = this.originalReplaceState\n }\n\n window.removeEventListener('popstate', this.handlePopState)\n window.removeEventListener('hashchange', this.handleHashChange)\n }\n\n /**\n * Manually trigger a navigation event (for custom routers)\n */\n navigate(url: string, type: NavigationEvent['navigation_type'] = 'push'): void {\n this.emitNavigation(url, type)\n }\n\n /**\n * Get current URL\n */\n getCurrentUrl(): string {\n return this.currentUrl\n }\n\n /**\n * Get time on current page\n */\n getTimeOnPage(): number {\n return Date.now() - this.pageEnterTime\n }\n\n private patchHistoryAPI(): void {\n // Store original methods\n this.originalPushState = history.pushState.bind(history)\n this.originalReplaceState = history.replaceState.bind(history)\n\n // Patch pushState\n history.pushState = (...args) => {\n const result = this.originalPushState!(...args)\n this.handleStateChange('push')\n return result\n }\n\n // Patch replaceState\n history.replaceState = (...args) => {\n const result = this.originalReplaceState!(...args)\n this.handleStateChange('replace')\n return result\n }\n }\n\n private handleStateChange = (type: 'push' | 'replace'): void => {\n const newUrl = window.location.href\n if (newUrl !== this.currentUrl) {\n this.emitNavigation(newUrl, type)\n }\n }\n\n private handlePopState = (): void => {\n const newUrl = window.location.href\n if (newUrl !== this.currentUrl) {\n this.emitNavigation(newUrl, 'pop')\n }\n }\n\n private handleHashChange = (): void => {\n const newUrl = window.location.href\n if (newUrl !== this.currentUrl) {\n this.emitNavigation(newUrl, 'hash')\n }\n }\n\n private emitNavigation(toUrl: string, type: NavigationEvent['navigation_type']): void {\n const event: NavigationEvent = {\n from_url: this.currentUrl,\n to_url: toUrl,\n navigation_type: type,\n time_on_previous_page_ms: Date.now() - this.pageEnterTime,\n }\n\n // Update current state\n this.currentUrl = toUrl\n this.pageEnterTime = Date.now()\n\n // Emit event\n this.config.onNavigate?.(event)\n }\n}\n\n","/**\n * Utility functions for Loamly Tracker\n * @module @loamly/tracker\n */\n\n/**\n * Generate a UUID v4\n */\nexport function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\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/**\n * Get or create a persistent visitor ID\n * (Privacy-respecting, no cookies)\n */\nexport function getVisitorId(): string {\n // Try to get from localStorage first\n try {\n const stored = localStorage.getItem('_loamly_vid')\n if (stored) return stored\n \n const newId = generateUUID()\n localStorage.setItem('_loamly_vid', newId)\n return newId\n } catch {\n // localStorage not available, generate ephemeral ID\n return generateUUID()\n }\n}\n\n/**\n * Get or create a session ID using sessionStorage\n * (Cookie-free session tracking)\n */\nexport function getSessionId(): { sessionId: string; isNew: boolean } {\n try {\n const storedSession = sessionStorage.getItem('loamly_session')\n const storedStart = sessionStorage.getItem('loamly_start')\n \n if (storedSession && storedStart) {\n return { sessionId: storedSession, isNew: false }\n }\n \n const newSession = generateUUID()\n const startTime = Date.now().toString()\n \n sessionStorage.setItem('loamly_session', newSession)\n sessionStorage.setItem('loamly_start', startTime)\n \n return { sessionId: newSession, isNew: true }\n } catch {\n // sessionStorage not available\n return { sessionId: generateUUID(), isNew: true }\n }\n}\n\n/**\n * Extract UTM parameters from URL\n */\nexport function extractUTMParams(url: string): Record<string, string> {\n const params: Record<string, string> = {}\n \n try {\n const searchParams = new URL(url).searchParams\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']\n \n for (const key of utmKeys) {\n const value = searchParams.get(key)\n if (value) params[key] = value\n }\n } catch {\n // Invalid URL\n }\n \n return params\n}\n\n/**\n * Truncate text to max length\n */\nexport function truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text\n return text.substring(0, maxLength - 3) + '...'\n}\n\n/**\n * Safe fetch with timeout\n */\nexport async function safeFetch(\n url: string,\n options: RequestInit,\n timeout = 10000\n): Promise<Response | null> {\n try {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n \n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n })\n \n clearTimeout(timeoutId)\n return response\n } catch {\n return null\n }\n}\n\n/**\n * Send beacon (for unload events)\n */\nexport function sendBeacon(url: string, data: unknown): boolean {\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n return navigator.sendBeacon(url, JSON.stringify(data))\n }\n return false\n}\n\n\n","/**\n * Loamly Tracker Core\n * \n * Cookie-free, privacy-first analytics with comprehensive AI traffic detection.\n * \n * Features:\n * - Navigation Timing API (paste vs click detection)\n * - Behavioral ML Classifier (mouse, scroll, interaction patterns)\n * - Focus/Blur Sequence Analysis (copy-paste detection)\n * - Agentic Browser Detection (Comet, CDP, teleporting clicks)\n * - Advanced Scroll Tracking (30% chunk reporting)\n * - Universal Form Tracking (HubSpot, Typeform, native)\n * - SPA Navigation Support (History API hooks)\n * - Event Queue with Retry (offline support)\n * - Real-time Ping (heartbeat)\n * \n * @module @loamly/tracker\n */\n\nimport { VERSION, DEFAULT_CONFIG } from './config'\nimport { detectNavigationType } from './detection/navigation-timing'\nimport { detectAIFromReferrer, detectAIFromUTM } from './detection/referrer'\nimport { \n BehavioralClassifier, \n type BehavioralClassificationResult \n} from './detection/behavioral-classifier'\nimport {\n FocusBlurAnalyzer,\n type FocusBlurResult\n} from './detection/focus-blur'\nimport {\n AgenticBrowserAnalyzer,\n type AgenticDetectionResult\n} from './detection/agentic-browser'\nimport { EventQueue } from './infrastructure/event-queue'\nimport { PingService } from './infrastructure/ping'\nimport { ScrollTracker, type ScrollEvent } from './behavioral/scroll-tracker'\nimport { TimeTracker, type TimeEvent } from './behavioral/time-tracker'\nimport { FormTracker, type FormEvent } from './behavioral/form-tracker'\nimport { SPARouter, type NavigationEvent } from './spa/router'\nimport { \n getVisitorId, \n getSessionId, \n extractUTMParams, \n truncateText,\n safeFetch,\n sendBeacon \n} from './utils'\nimport type { \n LoamlyConfig, \n LoamlyTracker, \n TrackEventOptions, \n NavigationTiming,\n AIDetectionResult,\n BehavioralMLResult,\n FocusBlurMLResult\n} from './types'\n\n// State\nlet config: LoamlyConfig & { apiHost: string } = { apiHost: DEFAULT_CONFIG.apiHost }\nlet initialized = false\nlet debugMode = false\nlet visitorId: string | null = null\nlet sessionId: string | null = null\nlet navigationTiming: NavigationTiming | null = null\nlet aiDetection: AIDetectionResult | null = null\n\n// Detection modules\nlet behavioralClassifier: BehavioralClassifier | null = null\nlet behavioralMLResult: BehavioralMLResult | null = null\nlet focusBlurAnalyzer: FocusBlurAnalyzer | null = null\nlet focusBlurResult: FocusBlurMLResult | null = null\nlet agenticAnalyzer: AgenticBrowserAnalyzer | null = null\n\n// Infrastructure modules\nlet eventQueue: EventQueue | null = null\nlet pingService: PingService | null = null\n\n// Behavioral tracking modules\nlet scrollTracker: ScrollTracker | null = null\nlet timeTracker: TimeTracker | null = null\nlet formTracker: FormTracker | null = null\n\n// SPA navigation\nlet spaRouter: SPARouter | null = null\n\n/**\n * Debug logger\n */\nfunction log(...args: unknown[]): void {\n if (debugMode) {\n console.log('[Loamly]', ...args)\n }\n}\n\n/**\n * Build API endpoint URL\n */\nfunction endpoint(path: string): string {\n return `${config.apiHost}${path}`\n}\n\n/**\n * Initialize the tracker\n */\nfunction init(userConfig: LoamlyConfig = {}): void {\n if (initialized) {\n log('Already initialized')\n return\n }\n\n config = {\n ...config,\n ...userConfig,\n apiHost: userConfig.apiHost || DEFAULT_CONFIG.apiHost,\n }\n \n debugMode = userConfig.debug ?? false\n \n log('Initializing Loamly Tracker v' + VERSION)\n \n // Get/create visitor ID\n visitorId = getVisitorId()\n log('Visitor ID:', visitorId)\n \n // Get/create session\n const session = getSessionId()\n sessionId = session.sessionId\n log('Session ID:', sessionId, session.isNew ? '(new)' : '(existing)')\n \n // Initialize event queue with batching\n eventQueue = new EventQueue(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {\n batchSize: DEFAULT_CONFIG.batchSize,\n batchTimeout: DEFAULT_CONFIG.batchTimeout,\n })\n \n // Detect navigation timing (paste vs click)\n navigationTiming = detectNavigationType()\n log('Navigation timing:', navigationTiming)\n \n // Detect AI from referrer/UTM\n aiDetection = detectAIFromReferrer(document.referrer) || detectAIFromUTM(window.location.href)\n if (aiDetection) {\n log('AI detected:', aiDetection)\n }\n \n initialized = true\n \n // Auto pageview unless disabled\n if (!userConfig.disableAutoPageview) {\n pageview()\n }\n \n // Set up behavioral tracking unless disabled\n if (!userConfig.disableBehavioral) {\n setupAdvancedBehavioralTracking()\n }\n \n // Initialize behavioral ML classifier (LOA-180)\n behavioralClassifier = new BehavioralClassifier(10000) // 10s min session\n behavioralClassifier.setOnClassify(handleBehavioralClassification)\n setupBehavioralMLTracking()\n \n // Initialize focus/blur analyzer (LOA-182)\n focusBlurAnalyzer = new FocusBlurAnalyzer()\n focusBlurAnalyzer.initTracking()\n \n // Analyze focus/blur after 5 seconds\n setTimeout(() => {\n if (focusBlurAnalyzer) {\n handleFocusBlurAnalysis(focusBlurAnalyzer.analyze())\n }\n }, 5000)\n \n // Initialize agentic browser detection (LOA-187)\n agenticAnalyzer = new AgenticBrowserAnalyzer()\n agenticAnalyzer.init()\n \n // Set up ping service\n if (visitorId && sessionId) {\n pingService = new PingService(sessionId, visitorId, VERSION, {\n interval: DEFAULT_CONFIG.pingInterval,\n endpoint: endpoint(DEFAULT_CONFIG.endpoints.ping),\n })\n pingService.start()\n }\n \n // Set up SPA navigation tracking\n spaRouter = new SPARouter({\n onNavigate: handleSPANavigation,\n })\n spaRouter.start()\n \n // Set up unload handlers\n setupUnloadHandlers()\n \n // Report health status\n reportHealth('initialized')\n \n log('Initialization complete')\n}\n\n/**\n * Set up advanced behavioral tracking with new modules\n */\nfunction setupAdvancedBehavioralTracking(): void {\n // Scroll tracker with 30% chunks\n scrollTracker = new ScrollTracker({\n chunks: [30, 60, 90, 100],\n onChunkReached: (event: ScrollEvent) => {\n log('Scroll chunk:', event.chunk)\n queueEvent('scroll_depth', {\n depth: event.depth,\n chunk: event.chunk,\n time_to_reach_ms: event.time_to_reach_ms,\n })\n },\n })\n scrollTracker.start()\n \n // Time tracker\n timeTracker = new TimeTracker({\n updateIntervalMs: 10000, // Report every 10 seconds\n onUpdate: (event: TimeEvent) => {\n if (event.active_time_ms >= DEFAULT_CONFIG.timeSpentThresholdMs) {\n queueEvent('time_spent', {\n active_time_ms: event.active_time_ms,\n total_time_ms: event.total_time_ms,\n idle_time_ms: event.idle_time_ms,\n is_engaged: event.is_engaged,\n })\n }\n },\n })\n timeTracker.start()\n \n // Form tracker with universal support\n formTracker = new FormTracker({\n onFormEvent: (event: FormEvent) => {\n log('Form event:', event.event_type, event.form_id)\n queueEvent(event.event_type, {\n form_id: event.form_id,\n form_type: event.form_type,\n field_name: event.field_name,\n field_type: event.field_type,\n time_to_submit_ms: event.time_to_submit_ms,\n is_conversion: event.is_conversion,\n })\n },\n })\n formTracker.start()\n \n // Click tracking for links (basic)\n document.addEventListener('click', (e) => {\n const target = e.target as HTMLElement\n const link = target.closest('a')\n \n if (link && link.href) {\n const isExternal = link.hostname !== window.location.hostname\n queueEvent('click', {\n element: 'link',\n href: truncateText(link.href, 200),\n text: truncateText(link.textContent || '', 100),\n is_external: isExternal,\n })\n }\n })\n}\n\n/**\n * Queue an event for batched sending\n */\nfunction queueEvent(eventType: string, data: Record<string, unknown>): void {\n if (!eventQueue) return\n \n eventQueue.push(eventType, {\n visitor_id: visitorId,\n session_id: sessionId,\n event_type: eventType,\n ...data,\n url: window.location.href,\n timestamp: new Date().toISOString(),\n tracker_version: VERSION,\n })\n}\n\n/**\n * Handle SPA navigation\n */\nfunction handleSPANavigation(event: NavigationEvent): void {\n log('SPA navigation:', event.navigation_type, event.to_url)\n \n // Flush pending events before navigation\n eventQueue?.flush()\n \n // Update ping service\n pingService?.updateScrollDepth(0)\n \n // Reset scroll tracker for new page\n scrollTracker?.stop()\n scrollTracker = new ScrollTracker({\n chunks: [30, 60, 90, 100],\n onChunkReached: (scrollEvent: ScrollEvent) => {\n queueEvent('scroll_depth', {\n depth: scrollEvent.depth,\n chunk: scrollEvent.chunk,\n time_to_reach_ms: scrollEvent.time_to_reach_ms,\n })\n },\n })\n scrollTracker.start()\n \n // Track the virtual pageview\n pageview(event.to_url)\n \n // Queue navigation event\n queueEvent('spa_navigation', {\n from_url: event.from_url,\n to_url: event.to_url,\n navigation_type: event.navigation_type,\n time_on_previous_page_ms: event.time_on_previous_page_ms,\n })\n}\n\n/**\n * Set up handlers for page unload\n */\nfunction setupUnloadHandlers(): void {\n const handleUnload = (): void => {\n // Get final scroll depth\n const scrollEvent = scrollTracker?.getFinalEvent()\n if (scrollEvent) {\n sendBeacon(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {\n visitor_id: visitorId,\n session_id: sessionId,\n event_type: 'scroll_depth_final',\n data: scrollEvent,\n url: window.location.href,\n })\n }\n \n // Get final time metrics\n const timeEvent = timeTracker?.getFinalMetrics()\n if (timeEvent) {\n sendBeacon(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {\n visitor_id: visitorId,\n session_id: sessionId,\n event_type: 'time_spent_final',\n data: timeEvent,\n url: window.location.href,\n })\n }\n \n // Get agentic detection result\n const agenticResult = agenticAnalyzer?.getResult()\n if (agenticResult && agenticResult.agenticProbability > 0) {\n sendBeacon(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {\n visitor_id: visitorId,\n session_id: sessionId,\n event_type: 'agentic_detection',\n data: agenticResult,\n url: window.location.href,\n })\n }\n \n // Flush event queue\n eventQueue?.flushBeacon()\n \n // Force classify behavioral ML if not done\n if (behavioralClassifier && !behavioralClassifier.hasClassified()) {\n const result = behavioralClassifier.forceClassify()\n if (result) {\n handleBehavioralClassification(result)\n }\n }\n }\n \n window.addEventListener('beforeunload', handleUnload)\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n handleUnload()\n }\n })\n}\n\n/**\n * Track a page view\n */\nfunction pageview(customUrl?: string): void {\n if (!initialized) {\n log('Not initialized, call init() first')\n return\n }\n\n const url = customUrl || window.location.href\n const payload = {\n visitor_id: visitorId,\n session_id: sessionId,\n url,\n referrer: document.referrer || null,\n title: document.title || null,\n utm_source: extractUTMParams(url).utm_source || null,\n utm_medium: extractUTMParams(url).utm_medium || null,\n utm_campaign: extractUTMParams(url).utm_campaign || null,\n user_agent: navigator.userAgent,\n screen_width: window.screen?.width,\n screen_height: window.screen?.height,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n tracker_version: VERSION,\n navigation_timing: navigationTiming,\n ai_platform: aiDetection?.platform || null,\n is_ai_referrer: aiDetection?.isAI || false,\n }\n\n log('Pageview:', payload)\n\n safeFetch(endpoint(DEFAULT_CONFIG.endpoints.visit), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n}\n\n/**\n * Track a custom event\n */\nfunction track(eventName: string, options: TrackEventOptions = {}): void {\n if (!initialized) {\n log('Not initialized, call init() first')\n return\n }\n\n const payload = {\n visitor_id: visitorId,\n session_id: sessionId,\n event_name: eventName,\n event_type: 'custom',\n properties: options.properties || {},\n revenue: options.revenue,\n currency: options.currency || 'USD',\n url: window.location.href,\n timestamp: new Date().toISOString(),\n tracker_version: VERSION,\n }\n\n log('Event:', eventName, payload)\n\n safeFetch(endpoint('/api/ingest/event'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n}\n\n/**\n * Track a conversion/revenue event\n */\nfunction conversion(eventName: string, revenue: number, currency = 'USD'): void {\n track(eventName, { revenue, currency, properties: { type: 'conversion' } })\n}\n\n/**\n * Identify a user\n */\nfunction identify(userId: string, traits: Record<string, unknown> = {}): void {\n if (!initialized) {\n log('Not initialized, call init() first')\n return\n }\n\n log('Identify:', userId, traits)\n\n const payload = {\n visitor_id: visitorId,\n session_id: sessionId,\n user_id: userId,\n traits,\n timestamp: new Date().toISOString(),\n }\n\n safeFetch(endpoint('/api/ingest/identify'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n}\n\n/**\n * Set up behavioral ML signal collection (LOA-180)\n */\nfunction setupBehavioralMLTracking(): void {\n if (!behavioralClassifier) return\n \n // Mouse movement tracking (sampled for performance)\n let mouseSampleCount = 0\n document.addEventListener('mousemove', (e) => {\n mouseSampleCount++\n // Sample every 10th event for performance\n if (mouseSampleCount % 10 === 0 && behavioralClassifier) {\n behavioralClassifier.recordMouse(e.clientX, e.clientY)\n }\n }, { passive: true })\n \n // Click tracking\n document.addEventListener('click', () => {\n if (behavioralClassifier) {\n behavioralClassifier.recordClick()\n }\n }, { passive: true })\n \n // Scroll tracking for ML (separate from milestone-based)\n let lastScrollY = 0\n document.addEventListener('scroll', () => {\n const currentY = window.scrollY\n if (Math.abs(currentY - lastScrollY) > 50 && behavioralClassifier) {\n lastScrollY = currentY\n behavioralClassifier.recordScroll(currentY)\n }\n }, { passive: true })\n \n // Focus/blur tracking\n document.addEventListener('focusin', (e) => {\n if (behavioralClassifier) {\n behavioralClassifier.recordFocusBlur('focus')\n const target = e.target as HTMLElement\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n behavioralClassifier.recordFormStart(target.id || target.getAttribute('name') || 'unknown')\n }\n }\n }, { passive: true })\n \n document.addEventListener('focusout', (e) => {\n if (behavioralClassifier) {\n behavioralClassifier.recordFocusBlur('blur')\n const target = e.target as HTMLElement\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n behavioralClassifier.recordFormEnd(target.id || target.getAttribute('name') || 'unknown')\n }\n }\n }, { passive: true })\n \n // Also try to classify after 30 seconds as backup\n setTimeout(() => {\n if (behavioralClassifier && !behavioralClassifier.hasClassified()) {\n behavioralClassifier.forceClassify()\n }\n }, 30000)\n}\n\n/**\n * Handle behavioral ML classification result\n */\nfunction handleBehavioralClassification(result: BehavioralClassificationResult): void {\n log('Behavioral ML classification:', result)\n \n // Store result\n behavioralMLResult = {\n classification: result.classification,\n humanProbability: result.humanProbability,\n aiProbability: result.aiProbability,\n confidence: result.confidence,\n signals: result.signals,\n sessionDurationMs: result.sessionDurationMs,\n }\n \n // Send to backend\n queueEvent('ml_classification', {\n classification: result.classification,\n human_probability: result.humanProbability,\n ai_probability: result.aiProbability,\n confidence: result.confidence,\n signals: result.signals,\n session_duration_ms: result.sessionDurationMs,\n navigation_timing: navigationTiming,\n ai_detection: aiDetection,\n focus_blur: focusBlurResult,\n })\n \n // If AI-influenced detected with high confidence, update AI detection\n if (result.classification === 'ai_influenced' && result.confidence >= 0.7) {\n aiDetection = {\n isAI: true,\n confidence: result.confidence,\n method: 'behavioral',\n }\n log('AI detection updated from behavioral ML:', aiDetection)\n }\n}\n\n/**\n * Handle focus/blur analysis result (LOA-182)\n */\nfunction handleFocusBlurAnalysis(result: FocusBlurResult): void {\n log('Focus/blur analysis:', result)\n \n // Store result\n focusBlurResult = {\n navType: result.nav_type,\n confidence: result.confidence,\n signals: result.signals,\n timeToFirstInteractionMs: result.time_to_first_interaction_ms,\n }\n \n // Send to backend\n queueEvent('focus_blur_analysis', {\n nav_type: result.nav_type,\n confidence: result.confidence,\n signals: result.signals,\n time_to_first_interaction_ms: result.time_to_first_interaction_ms,\n sequence_length: result.sequence.length,\n })\n \n // If paste pattern detected with confidence, update AI detection\n if (result.nav_type === 'likely_paste' && result.confidence >= 0.4) {\n // Only update if no stronger detection exists\n if (!aiDetection || aiDetection.confidence < result.confidence) {\n aiDetection = {\n isAI: true,\n confidence: result.confidence,\n method: 'behavioral',\n }\n log('AI detection updated from focus/blur analysis:', aiDetection)\n }\n }\n}\n\n/**\n * Get current session ID\n */\nfunction getCurrentSessionId(): string | null {\n return sessionId\n}\n\n/**\n * Get current visitor ID\n */\nfunction getCurrentVisitorId(): string | null {\n return visitorId\n}\n\n/**\n * Get AI detection result\n */\nfunction getAIDetectionResult(): AIDetectionResult | null {\n return aiDetection\n}\n\n/**\n * Get navigation timing result\n */\nfunction getNavigationTimingResult(): NavigationTiming | null {\n return navigationTiming\n}\n\n/**\n * Get behavioral ML classification result\n */\nfunction getBehavioralMLResult(): BehavioralMLResult | null {\n return behavioralMLResult\n}\n\n/**\n * Get focus/blur analysis result\n */\nfunction getFocusBlurResult(): FocusBlurMLResult | null {\n return focusBlurResult\n}\n\n/**\n * Get agentic browser detection result\n */\nfunction getAgenticResult(): AgenticDetectionResult | null {\n return agenticAnalyzer?.getResult() || null\n}\n\n/**\n * Check if initialized\n */\nfunction isTrackerInitialized(): boolean {\n return initialized\n}\n\n/**\n * Report tracker health status\n * Used for monitoring and debugging\n */\nfunction reportHealth(status: 'initialized' | 'error' | 'ready', errorMessage?: string): void {\n if (!config.apiKey) return\n \n try {\n const healthData = {\n workspace_id: config.apiKey,\n status,\n error_message: errorMessage || null,\n version: VERSION,\n url: typeof window !== 'undefined' ? window.location.href : null,\n user_agent: typeof navigator !== 'undefined' ? navigator.userAgent : null,\n timestamp: new Date().toISOString(),\n features: {\n scroll_tracker: !!scrollTracker,\n time_tracker: !!timeTracker,\n form_tracker: !!formTracker,\n spa_router: !!spaRouter,\n behavioral_ml: !!behavioralClassifier,\n focus_blur: !!focusBlurAnalyzer,\n agentic: !!agenticAnalyzer,\n ping_service: !!pingService,\n event_queue: !!eventQueue,\n },\n }\n \n // Fire and forget\n safeFetch(endpoint(DEFAULT_CONFIG.endpoints.health), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(healthData),\n }).catch(() => {\n // Ignore health reporting errors\n })\n \n log('Health reported:', status)\n } catch {\n // Ignore\n }\n}\n\n/**\n * Reset the tracker\n */\nfunction reset(): void {\n log('Resetting tracker')\n \n // Stop all services\n pingService?.stop()\n scrollTracker?.stop()\n timeTracker?.stop()\n formTracker?.stop()\n spaRouter?.stop()\n agenticAnalyzer?.destroy()\n \n // Reset state\n initialized = false\n visitorId = null\n sessionId = null\n navigationTiming = null\n aiDetection = null\n behavioralClassifier = null\n behavioralMLResult = null\n focusBlurAnalyzer = null\n focusBlurResult = null\n agenticAnalyzer = null\n eventQueue = null\n pingService = null\n scrollTracker = null\n timeTracker = null\n formTracker = null\n spaRouter = null\n \n try {\n sessionStorage.removeItem('loamly_session')\n sessionStorage.removeItem('loamly_start')\n } catch {\n // Ignore\n }\n}\n\n/**\n * Enable/disable debug mode\n */\nfunction setDebug(enabled: boolean): void {\n debugMode = enabled\n log('Debug mode:', enabled ? 'enabled' : 'disabled')\n}\n\n/**\n * The Loamly Tracker instance\n */\nexport const loamly: LoamlyTracker & { \n getAgentic: () => AgenticDetectionResult | null \n reportHealth: (status: 'initialized' | 'error' | 'ready', errorMessage?: string) => void\n} = {\n init,\n pageview,\n track,\n conversion,\n identify,\n getSessionId: getCurrentSessionId,\n getVisitorId: getCurrentVisitorId,\n getAIDetection: getAIDetectionResult,\n getNavigationTiming: getNavigationTimingResult,\n getBehavioralML: getBehavioralMLResult,\n getFocusBlur: getFocusBlurResult,\n getAgentic: getAgenticResult,\n isInitialized: isTrackerInitialized,\n reset,\n debug: setDebug,\n reportHealth,\n}\n\nexport default loamly\n"],"mappings":"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","names":["endpoint","config","sessionId","visitorId","config","config","DEFAULT_CONFIG","config","DEFAULT_CONFIG","config","config"]}