@kitbase/analytics 0.1.6 → 0.1.7

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/errors.ts","../src/botDetection.ts","../src/plugins/utils.ts","../src/client-base.ts","../src/queue/index.ts","../src/plugins/page-view.ts","../src/plugins/outbound-links.ts","../src/plugins/click-tracking.ts","../src/plugins/scroll-depth.ts","../src/plugins/visibility.ts","../src/plugins/web-vitals.ts","../src/plugins/frustration.ts","../src/plugins/defaults.ts","../src/client.ts"],"sourcesContent":["// Main client\nexport { KitbaseAnalytics, init, getInstance } from './client.js';\n\n// Types\nexport type {\n KitbaseConfig,\n TrackOptions,\n TrackResponse,\n Tags,\n TagValue,\n OfflineConfig,\n // Analytics types\n AnalyticsConfig,\n PageViewOptions,\n RevenueOptions,\n IdentifyOptions,\n // Bot detection types (@internal)\n BotDetectionConfig,\n} from './types.js';\n\n// Queue types\nexport type { QueuedEvent, QueueStats } from './queue/types.js';\n\n// Bot detection utilities (@internal — may change without notice)\nexport {\n detectBot,\n isBot,\n isUserAgentBot,\n getUserAgent,\n type BotDetectionResult,\n} from './botDetection.js';\n\n// Errors\nexport {\n KitbaseError,\n ApiError,\n AuthenticationError,\n ValidationError,\n TimeoutError,\n} from './errors.js';\n\n// Plugin system\nexport type { KitbasePlugin, PluginContext } from './plugins/types.js';\nexport {\n createDefaultPlugins,\n PageViewPlugin,\n OutboundLinksPlugin,\n ClickTrackingPlugin,\n ScrollDepthPlugin,\n VisibilityPlugin,\n WebVitalsPlugin,\n FrustrationPlugin,\n} from './plugins/index.js';\n","/**\n * Base error class for Kitbase SDK errors\n */\nexport class KitbaseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'KitbaseError';\n Object.setPrototypeOf(this, KitbaseError.prototype);\n }\n}\n\n/**\n * Error thrown when API authentication fails\n */\nexport class AuthenticationError extends KitbaseError {\n constructor(message = 'Invalid API key') {\n super(message);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Error thrown when the API request fails\n */\nexport class ApiError extends KitbaseError {\n public readonly statusCode: number;\n public readonly response?: unknown;\n\n constructor(message: string, statusCode: number, response?: unknown) {\n super(message);\n this.name = 'ApiError';\n this.statusCode = statusCode;\n this.response = response;\n Object.setPrototypeOf(this, ApiError.prototype);\n }\n}\n\n/**\n * Error thrown when request validation fails\n */\nexport class ValidationError extends KitbaseError {\n public readonly field?: string;\n\n constructor(message: string, field?: string) {\n super(message);\n this.name = 'ValidationError';\n this.field = field;\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\n/**\n * Error thrown when a request times out\n */\nexport class TimeoutError extends KitbaseError {\n constructor(message = 'Request timed out') {\n super(message);\n this.name = 'TimeoutError';\n Object.setPrototypeOf(this, TimeoutError.prototype);\n }\n}\n\n\n\n\n\n\n\n\n","/**\n * Bot detection module for filtering automated traffic\n *\n * Detects common automation tools, headless browsers, and bot user agents.\n * Inspired by DataFast's bot detection approach.\n */\n\n/**\n * Known automation tool global variables\n */\nconst AUTOMATION_GLOBALS = [\n '__webdriver_evaluate',\n '__selenium_evaluate',\n '__webdriver_script_function',\n '__webdriver_unwrapped',\n '__fxdriver_evaluate',\n '__driver_evaluate',\n '_Selenium_IDE_Recorder',\n '_selenium',\n 'calledSelenium',\n '$cdc_asdjflasutopfhvcZLmcfl_', // Chrome DevTools Protocol marker\n '__nightmare',\n 'domAutomation',\n 'domAutomationController',\n] as const;\n\n/**\n * Known headless browser user agent patterns\n */\nconst HEADLESS_PATTERNS = [\n 'headlesschrome',\n 'phantomjs',\n 'selenium',\n 'webdriver',\n 'puppeteer',\n 'playwright',\n] as const;\n\n/**\n * Known HTTP client / bot user agent patterns\n */\nconst HTTP_CLIENT_PATTERNS = [\n 'python',\n 'curl',\n 'wget',\n 'java/',\n 'go-http',\n 'node-fetch',\n 'axios',\n 'postman',\n 'insomnia',\n 'httpie',\n 'ruby',\n 'perl',\n 'scrapy',\n 'bot',\n 'spider',\n 'crawler',\n 'slurp',\n 'googlebot',\n 'bingbot',\n 'yandexbot',\n 'baiduspider',\n 'duckduckbot',\n 'facebookexternalhit',\n 'twitterbot',\n 'linkedinbot',\n 'whatsapp',\n 'telegram',\n 'discord',\n 'slack',\n] as const;\n\n/**\n * Bot detection result\n * @internal This is an internal API and may change without notice.\n */\nexport interface BotDetectionResult {\n isBot: boolean;\n reason?: string;\n checks: {\n webdriver: boolean;\n phantomjs: boolean;\n nightmare: boolean;\n automationGlobals: boolean;\n documentAttributes: boolean;\n userAgentHeadless: boolean;\n userAgentHttpClient: boolean;\n missingUserAgent: boolean;\n invalidEnvironment: boolean;\n };\n}\n\n/**\n * Configuration for bot detection\n * @internal This is an internal API and may change without notice.\n */\nexport interface BotDetectionConfig {\n /**\n * Enable bot detection.\n * When enabled and a bot is detected, all tracking events are blocked.\n * Set to false to disable bot detection.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Check for webdriver flag (Chrome, Firefox)\n * @default true\n */\n checkWebdriver?: boolean;\n\n /**\n * Check for PhantomJS\n * @default true\n */\n checkPhantomJS?: boolean;\n\n /**\n * Check for Nightmare.js\n * @default true\n */\n checkNightmare?: boolean;\n\n /**\n * Check for automation tool globals\n * @default true\n */\n checkAutomationGlobals?: boolean;\n\n /**\n * Check document element attributes\n * @default true\n */\n checkDocumentAttributes?: boolean;\n\n /**\n * Check user agent for headless browsers\n * @default true\n */\n checkUserAgentHeadless?: boolean;\n\n /**\n * Check user agent for HTTP clients/bots\n * @default true\n */\n checkUserAgentHttpClient?: boolean;\n\n /**\n * Additional user agent patterns to detect as bots\n */\n additionalBotPatterns?: string[];\n\n /**\n * Callback when a bot is detected\n */\n onBotDetected?: (result: BotDetectionResult) => void;\n}\n\n/**\n * Default bot detection configuration\n * @internal This is an internal API and may change without notice.\n */\nexport const DEFAULT_BOT_DETECTION_CONFIG: Required<Omit<BotDetectionConfig, 'additionalBotPatterns' | 'onBotDetected'>> = {\n enabled: true,\n checkWebdriver: true,\n checkPhantomJS: true,\n checkNightmare: true,\n checkAutomationGlobals: true,\n checkDocumentAttributes: true,\n checkUserAgentHeadless: true,\n checkUserAgentHttpClient: true,\n};\n\n/**\n * Check if running in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Safely get window property\n */\nfunction getWindowProperty(key: string): unknown {\n try {\n return (window as unknown as Record<string, unknown>)[key];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Check for webdriver flag\n */\nfunction checkWebdriver(): boolean {\n if (!isBrowser()) return false;\n\n try {\n return window.navigator?.webdriver === true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check for PhantomJS\n */\nfunction checkPhantomJS(): boolean {\n if (!isBrowser()) return false;\n\n try {\n return !!(\n getWindowProperty('callPhantom') ||\n getWindowProperty('_phantom') ||\n getWindowProperty('phantom')\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Check for Nightmare.js\n */\nfunction checkNightmare(): boolean {\n if (!isBrowser()) return false;\n\n try {\n return !!getWindowProperty('__nightmare');\n } catch {\n return false;\n }\n}\n\n/**\n * Check for automation tool globals\n */\nfunction checkAutomationGlobals(): boolean {\n if (!isBrowser()) return false;\n\n try {\n for (const global of AUTOMATION_GLOBALS) {\n if (getWindowProperty(global) !== undefined) {\n return true;\n }\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Check for webdriver/selenium attributes on document element\n */\nfunction checkDocumentAttributes(): boolean {\n if (!isBrowser()) return false;\n\n try {\n const docEl = document.documentElement;\n if (!docEl) return false;\n\n return !!(\n docEl.getAttribute('webdriver') ||\n docEl.getAttribute('selenium') ||\n docEl.getAttribute('driver')\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Check user agent for headless browser patterns\n */\nfunction checkUserAgentHeadless(): boolean {\n if (!isBrowser()) return false;\n\n try {\n const ua = window.navigator?.userAgent?.toLowerCase() || '';\n if (!ua) return false;\n\n for (const pattern of HEADLESS_PATTERNS) {\n if (ua.includes(pattern)) {\n return true;\n }\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Check user agent for HTTP client patterns\n */\nfunction checkUserAgentHttpClient(additionalPatterns?: string[]): boolean {\n if (!isBrowser()) return false;\n\n try {\n const ua = window.navigator?.userAgent?.toLowerCase() || '';\n if (!ua) return false;\n\n // Check built-in patterns\n for (const pattern of HTTP_CLIENT_PATTERNS) {\n if (ua.includes(pattern)) {\n return true;\n }\n }\n\n // Check additional patterns\n if (additionalPatterns) {\n for (const pattern of additionalPatterns) {\n if (ua.includes(pattern.toLowerCase())) {\n return true;\n }\n }\n }\n\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Check for missing or invalid user agent\n */\nfunction checkMissingUserAgent(): boolean {\n if (!isBrowser()) return false;\n\n try {\n const ua = window.navigator?.userAgent;\n return !ua || ua === '' || ua === 'undefined' || ua.length < 10;\n } catch {\n return false;\n }\n}\n\n/**\n * Check for invalid browser environment (missing required objects)\n */\nfunction checkInvalidEnvironment(): boolean {\n if (!isBrowser()) return false;\n\n try {\n // Check for missing or fake navigator/location/document\n if (\n !window.navigator ||\n !window.location ||\n !window.document ||\n typeof window.navigator !== 'object' ||\n typeof window.location !== 'object' ||\n typeof window.document !== 'object'\n ) {\n return true;\n }\n return false;\n } catch {\n return true;\n }\n}\n\n/**\n * Detect if the current visitor is a bot\n *\n * @internal This is an internal API and may change without notice.\n * @param config - Bot detection configuration\n * @returns Bot detection result\n *\n * @example\n * ```typescript\n * const result = detectBot();\n * if (result.isBot) {\n * console.log('Bot detected:', result.reason);\n * }\n * ```\n */\nexport function detectBot(config: BotDetectionConfig = {}): BotDetectionResult {\n const mergedConfig = { ...DEFAULT_BOT_DETECTION_CONFIG, ...config };\n\n const checks = {\n webdriver: mergedConfig.checkWebdriver ? checkWebdriver() : false,\n phantomjs: mergedConfig.checkPhantomJS ? checkPhantomJS() : false,\n nightmare: mergedConfig.checkNightmare ? checkNightmare() : false,\n automationGlobals: mergedConfig.checkAutomationGlobals ? checkAutomationGlobals() : false,\n documentAttributes: mergedConfig.checkDocumentAttributes ? checkDocumentAttributes() : false,\n userAgentHeadless: mergedConfig.checkUserAgentHeadless ? checkUserAgentHeadless() : false,\n userAgentHttpClient: mergedConfig.checkUserAgentHttpClient\n ? checkUserAgentHttpClient(config.additionalBotPatterns)\n : false,\n missingUserAgent: checkMissingUserAgent(),\n invalidEnvironment: checkInvalidEnvironment(),\n };\n\n // Determine the reason for bot detection\n let reason: string | undefined;\n if (checks.webdriver) {\n reason = 'WebDriver detected';\n } else if (checks.phantomjs) {\n reason = 'PhantomJS detected';\n } else if (checks.nightmare) {\n reason = 'Nightmare.js detected';\n } else if (checks.automationGlobals) {\n reason = 'Automation tool globals detected';\n } else if (checks.documentAttributes) {\n reason = 'Automation attributes on document element';\n } else if (checks.userAgentHeadless) {\n reason = 'Headless browser user agent detected';\n } else if (checks.userAgentHttpClient) {\n reason = 'HTTP client/bot user agent detected';\n } else if (checks.missingUserAgent) {\n reason = 'Missing or invalid user agent';\n } else if (checks.invalidEnvironment) {\n reason = 'Invalid browser environment';\n }\n\n const isBot = Object.values(checks).some(Boolean);\n\n const result: BotDetectionResult = {\n isBot,\n reason,\n checks,\n };\n\n // Call callback if provided and bot was detected\n if (isBot && config.onBotDetected) {\n try {\n config.onBotDetected(result);\n } catch {\n // Ignore callback errors\n }\n }\n\n return result;\n}\n\n/**\n * Quick check if current visitor is a bot\n *\n * @internal This is an internal API and may change without notice.\n * @param config - Bot detection configuration\n * @returns true if bot detected, false otherwise\n *\n * @example\n * ```typescript\n * if (isBot()) {\n * console.log('Bot detected, skipping tracking');\n * return;\n * }\n * ```\n */\nexport function isBot(config: BotDetectionConfig = {}): boolean {\n return detectBot(config).isBot;\n}\n\n/**\n * Check a custom user agent string for bot patterns\n * Useful for server-side bot detection\n *\n * @internal This is an internal API and may change without notice.\n * @param userAgent - The user agent string to check\n * @param additionalPatterns - Additional patterns to check\n * @returns true if bot user agent detected\n *\n * @example\n * ```typescript\n * // Server-side usage\n * const ua = request.headers['user-agent'];\n * if (isUserAgentBot(ua)) {\n * console.log('Bot request detected');\n * }\n * ```\n */\nexport function isUserAgentBot(userAgent: string, additionalPatterns?: string[]): boolean {\n if (!userAgent || userAgent.length < 10) {\n return true;\n }\n\n const ua = userAgent.toLowerCase();\n\n // Check headless patterns\n for (const pattern of HEADLESS_PATTERNS) {\n if (ua.includes(pattern)) {\n return true;\n }\n }\n\n // Check HTTP client patterns\n for (const pattern of HTTP_CLIENT_PATTERNS) {\n if (ua.includes(pattern)) {\n return true;\n }\n }\n\n // Check additional patterns\n if (additionalPatterns) {\n for (const pattern of additionalPatterns) {\n if (ua.includes(pattern.toLowerCase())) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Get the current user agent (browser only)\n *\n * @internal This is an internal API and may change without notice.\n * @returns User agent string or null if not in browser\n */\nexport function getUserAgent(): string | null {\n if (!isBrowser()) return null;\n\n try {\n return window.navigator?.userAgent || null;\n } catch {\n return null;\n }\n}\n","import type { Tags } from '../types-lite.js';\n\n/**\n * CSS selector matching interactive elements for click tracking.\n * Includes standard HTML elements and common ARIA roles.\n */\nexport const CLICKABLE_SELECTOR = [\n 'a', 'button', 'input', 'select', 'textarea',\n '[role=\"button\"]', '[role=\"link\"]', '[role=\"menuitem\"]', '[role=\"tab\"]',\n].join(', ');\n\n/**\n * Find the nearest clickable element from a click event.\n * Uses `composedPath()` to traverse through Shadow DOM boundaries.\n * When a match is found inside a Shadow DOM, the custom-element host\n * is returned so that tracked attributes reflect the public component.\n */\nexport function findClickableElement(event: MouseEvent): Element | null {\n const path = event.composedPath?.() as Element[] | undefined;\n\n if (path) {\n for (const node of path) {\n if (!(node instanceof Element)) continue;\n if (node === document.documentElement) break;\n\n if (node.matches(CLICKABLE_SELECTOR)) {\n const root = node.getRootNode();\n if (root instanceof ShadowRoot && root.host instanceof Element) {\n return root.host;\n }\n return node;\n }\n\n // Custom elements (tag name contains a hyphen per spec)\n if (node.tagName.includes('-')) {\n return node;\n }\n }\n }\n\n // Fallback for browsers without composedPath\n const target = event.target as Element | null;\n if (!target?.closest) return null;\n return target.closest(CLICKABLE_SELECTOR);\n}\n\n/**\n * Build a lightweight CSS selector for an element.\n * Used to identify frustration signal targets.\n */\nexport function buildCssSelector(el: Element): string {\n if (el.id) return `#${el.id}`;\n const tag = el.tagName.toLowerCase();\n const classes = el.className && typeof el.className === 'string'\n ? '.' + el.className.trim().split(/\\s+/).slice(0, 2).join('.')\n : '';\n if (classes) return `${tag}${classes}`;\n return tag;\n}\n\n/**\n * Get root domain from hostname (e.g., blog.example.com -> example.com)\n */\nexport function getRootDomain(hostname: string): string {\n const parts = hostname.replace(/^www\\./, '').split('.');\n if (parts.length >= 2) {\n return parts.slice(-2).join('.');\n }\n return hostname;\n}\n\n/**\n * Check if two hostnames share the same root domain\n */\nexport function isSameRootDomain(host1: string, host2: string): boolean {\n return getRootDomain(host1) === getRootDomain(host2);\n}\n\n/**\n * Get UTM parameters from current URL\n */\nexport function getUtmParams(): Tags {\n if (typeof window === 'undefined') return {};\n\n const params = new URLSearchParams(window.location.search);\n const utmParams: Tags = {};\n\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];\n for (const key of utmKeys) {\n const value = params.get(key);\n if (value) {\n utmParams[`__${key}`] = value;\n }\n }\n\n return utmParams;\n}\n","import type {\n TrackOptions,\n TrackResponse,\n LogPayload,\n Tags,\n PageViewOptions,\n RevenueOptions,\n IdentifyOptions,\n} from './types.js';\nimport type { KitbaseLiteConfig } from './types-lite.js';\nimport {\n ApiError,\n AuthenticationError,\n TimeoutError,\n ValidationError,\n} from './errors.js';\nimport {\n detectBot,\n DEFAULT_BOT_DETECTION_CONFIG,\n type BotDetectionConfig,\n type BotDetectionResult,\n} from './botDetection.js';\nimport type { KitbasePlugin, PluginContext } from './plugins/types.js';\nimport {\n findClickableElement,\n CLICKABLE_SELECTOR,\n getRootDomain,\n isSameRootDomain,\n getUtmParams,\n} from './plugins/utils.js';\n\nconst DEFAULT_BASE_URL = 'https://api.kitbase.dev';\nconst TIMEOUT = 30000;\nconst ANALYTICS_CHANNEL = '__analytics';\n\n/**\n * Kitbase base client for tracking events (lite version without offline queue)\n *\n * This is a lightweight version of the Kitbase client that sends events\n * directly to the API without offline queueing support.\n *\n * @example\n * ```typescript\n * import { Kitbase } from '@kitbase/analytics/lite';\n *\n * const kitbase = new Kitbase({\n * sdkKey: '<YOUR_API_KEY>',\n * debug: true,\n * });\n *\n * // Register super properties (included in all events)\n * kitbase.register({ app_version: '2.1.0', platform: 'web' });\n *\n * // Track events\n * await kitbase.track({\n * channel: 'payments',\n * event: 'Page Viewed',\n * icon: '👀',\n * });\n * ```\n */\nexport class KitbaseAnalytics {\n protected readonly sdkKey: string;\n protected readonly baseUrl: string;\n\n // Super properties (memory-only, merged into all events)\n protected superProperties: Tags = {};\n\n // Time event tracking\n protected timedEvents: Map<string, number> = new Map();\n\n // Debug mode\n protected debugMode: boolean;\n\n // Analytics config (stored for PluginContext)\n protected analyticsConfig: KitbaseLiteConfig['analytics'];\n\n protected userId: string | null = null;\n\n // Bot detection\n protected botDetectionConfig: BotDetectionConfig;\n protected botDetectionResult: BotDetectionResult | null = null;\n\n // Client-side session tracking\n private clientSessionId: string | null = null;\n private lastActivityAt: number = 0;\n private static readonly SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n\n // Plugin system\n private _plugins: Map<string, KitbasePlugin> = new Map();\n private _pluginContext: PluginContext | null = null;\n\n constructor(config: KitbaseLiteConfig, defaultPlugins?: KitbasePlugin[]) {\n if (!config.sdkKey) {\n throw new ValidationError('SDK key is required', 'sdkKey');\n }\n\n this.sdkKey = config.sdkKey;\n // Remove trailing slashes to prevent double-slash in URLs\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.debugMode = config.debug ?? false;\n\n // Store analytics config for plugin context\n this.analyticsConfig = config.analytics;\n\n // Initialize bot detection\n this.botDetectionConfig = {\n ...DEFAULT_BOT_DETECTION_CONFIG,\n ...config.botDetection,\n };\n\n if (this.botDetectionConfig.enabled) {\n this.botDetectionResult = detectBot(this.botDetectionConfig);\n if (this.botDetectionResult.isBot) {\n this.log('Bot detected', {\n reason: this.botDetectionResult.reason,\n checks: this.botDetectionResult.checks,\n });\n } else {\n this.log('Bot detection enabled, no bot detected');\n }\n }\n\n // Register default plugins\n if (defaultPlugins) {\n for (const plugin of defaultPlugins) {\n this.use(plugin);\n }\n }\n }\n\n // ============================================================\n // Plugin System\n // ============================================================\n\n /**\n * Register a plugin\n *\n * @param plugin - The plugin instance to register\n *\n * @example\n * ```typescript\n * kitbase.use(new WebVitalsPlugin());\n * ```\n */\n use(plugin: KitbasePlugin): void {\n if (this._plugins.has(plugin.name)) {\n this.log(`Plugin \"${plugin.name}\" already registered`);\n return;\n }\n\n const ctx = this.getPluginContext();\n const result = plugin.setup(ctx);\n if (result === false) {\n this.log(`Plugin \"${plugin.name}\" declined to activate`);\n return;\n }\n\n this._plugins.set(plugin.name, plugin);\n\n // Install public methods from plugin\n const methods = plugin.methods;\n if (methods) {\n for (const [name, fn] of Object.entries(methods)) {\n (this as any)[name] = fn;\n }\n }\n\n this.log(`Plugin \"${plugin.name}\" registered`);\n }\n\n /**\n * Get the names of all registered plugins\n */\n getPlugins(): string[] {\n return Array.from(this._plugins.keys());\n }\n\n private getPluginContext(): PluginContext {\n if (this._pluginContext) return this._pluginContext;\n\n this._pluginContext = {\n track: (options: TrackOptions) => this.track(options),\n config: Object.freeze({\n autoTrackPageViews: this.analyticsConfig?.autoTrackPageViews,\n autoTrackOutboundLinks: this.analyticsConfig?.autoTrackOutboundLinks,\n autoTrackClicks: this.analyticsConfig?.autoTrackClicks,\n autoTrackScrollDepth: this.analyticsConfig?.autoTrackScrollDepth,\n autoTrackVisibility: this.analyticsConfig?.autoTrackVisibility,\n autoTrackWebVitals: this.analyticsConfig?.autoTrackWebVitals,\n autoDetectFrustration: this.analyticsConfig?.autoDetectFrustration,\n }),\n debug: this.debugMode,\n log: (message: string, data?: unknown) => this.log(message, data),\n isBotBlockingActive: () => this.isBotBlockingActive(),\n findClickableElement,\n CLICKABLE_SELECTOR,\n getRootDomain,\n isSameRootDomain,\n getUtmParams,\n };\n\n return this._pluginContext;\n }\n\n // ============================================================\n // Debug Mode\n // ============================================================\n\n /**\n * Enable or disable debug mode\n * When enabled, all SDK operations are logged to the console\n *\n * @param enabled - Whether to enable debug mode\n *\n * @example\n * ```typescript\n * kitbase.setDebugMode(true);\n * // All events and operations will now be logged\n * ```\n */\n setDebugMode(enabled: boolean): void {\n this.debugMode = enabled;\n this.log(`Debug mode ${enabled ? 'enabled' : 'disabled'}`);\n }\n\n /**\n * Check if debug mode is enabled\n */\n isDebugMode(): boolean {\n return this.debugMode;\n }\n\n /**\n * Internal logging function\n */\n protected log(message: string, data?: unknown): void {\n if (!this.debugMode) return;\n\n const prefix = '[Kitbase]';\n if (data !== undefined) {\n console.log(prefix, message, data);\n } else {\n console.log(prefix, message);\n }\n }\n\n // ============================================================\n // Super Properties\n // ============================================================\n\n /**\n * Register super properties that will be included with every event\n * These properties are stored in memory only and reset on page reload\n *\n * @param properties - Properties to register\n *\n * @example\n * ```typescript\n * kitbase.register({\n * app_version: '2.1.0',\n * platform: 'web',\n * environment: 'production',\n * });\n * ```\n */\n register(properties: Tags): void {\n this.superProperties = { ...this.superProperties, ...properties };\n this.log('Super properties registered', properties);\n }\n\n /**\n * Register super properties only if they haven't been set yet\n * Useful for setting default values that shouldn't override existing ones\n *\n * @param properties - Properties to register if not already set\n *\n * @example\n * ```typescript\n * kitbase.registerOnce({ first_visit: new Date().toISOString() });\n * ```\n */\n registerOnce(properties: Tags): void {\n const newProps: Tags = {};\n for (const [key, value] of Object.entries(properties)) {\n if (!(key in this.superProperties)) {\n newProps[key] = value;\n }\n }\n if (Object.keys(newProps).length > 0) {\n this.superProperties = { ...this.superProperties, ...newProps };\n this.log('Super properties registered (once)', newProps);\n }\n }\n\n /**\n * Remove a super property\n *\n * @param key - The property key to remove\n *\n * @example\n * ```typescript\n * kitbase.unregister('platform');\n * ```\n */\n unregister(key: string): void {\n if (key in this.superProperties) {\n delete this.superProperties[key];\n this.log('Super property removed', { key });\n }\n }\n\n /**\n * Get all registered super properties\n *\n * @returns A copy of the current super properties\n *\n * @example\n * ```typescript\n * const props = kitbase.getSuperProperties();\n * console.log(props); // { app_version: '2.1.0', platform: 'web' }\n * ```\n */\n getSuperProperties(): Tags {\n return { ...this.superProperties };\n }\n\n /**\n * Clear all super properties\n *\n * @example\n * ```typescript\n * kitbase.clearSuperProperties();\n * ```\n */\n clearSuperProperties(): void {\n this.superProperties = {};\n this.log('Super properties cleared');\n }\n\n // ============================================================\n // Time Events (Duration Tracking)\n // ============================================================\n\n /**\n * Start timing an event\n * When the same event is tracked later, a $duration property (in seconds)\n * will automatically be included\n *\n * @param eventName - The name of the event to time\n *\n * @example\n * ```typescript\n * kitbase.timeEvent('Video Watched');\n * // ... user watches video ...\n * await kitbase.track({\n * channel: 'engagement',\n * event: 'Video Watched',\n * tags: { video_id: '123' }\n * });\n * // Event will include $duration: 45.2 (seconds)\n * ```\n */\n timeEvent(eventName: string): void {\n this.timedEvents.set(eventName, Date.now());\n this.log('Timer started', { event: eventName });\n }\n\n /**\n * Cancel a timed event without tracking it\n *\n * @param eventName - The name of the event to cancel timing for\n *\n * @example\n * ```typescript\n * kitbase.timeEvent('Checkout Flow');\n * // User abandons checkout\n * kitbase.cancelTimeEvent('Checkout Flow');\n * ```\n */\n cancelTimeEvent(eventName: string): void {\n if (this.timedEvents.has(eventName)) {\n this.timedEvents.delete(eventName);\n this.log('Timer cancelled', { event: eventName });\n }\n }\n\n /**\n * Get all currently timed events\n *\n * @returns Array of event names that are currently being timed\n *\n * @example\n * ```typescript\n * const timedEvents = kitbase.getTimedEvents();\n * console.log(timedEvents); // ['Video Watched', 'Checkout Flow']\n * ```\n */\n getTimedEvents(): string[] {\n return Array.from(this.timedEvents.keys());\n }\n\n /**\n * Get the duration of a timed event (without stopping it)\n * @internal\n *\n * @param eventName - The name of the event\n * @returns Duration in seconds, or null if not being timed\n */\n getEventDuration(eventName: string): number | null {\n const startTime = this.timedEvents.get(eventName);\n if (startTime === undefined) return null;\n return (Date.now() - startTime) / 1000;\n }\n\n // ============================================================\n // Bot Detection\n // ============================================================\n\n /**\n * Check if the current visitor is detected as a bot\n *\n * @internal This is an internal API and may change without notice.\n * @returns true if bot detected, false otherwise\n *\n * @example\n * ```typescript\n * if (kitbase.isBot()) {\n * console.log('Bot detected, tracking disabled');\n * }\n * ```\n */\n isBot(): boolean {\n if (!this.botDetectionConfig?.enabled) {\n return false;\n }\n\n // Re-run detection if not yet done\n if (!this.botDetectionResult) {\n this.botDetectionResult = detectBot(this.botDetectionConfig);\n }\n\n return this.botDetectionResult.isBot;\n }\n\n /**\n * Get detailed bot detection result\n *\n * @internal This is an internal API and may change without notice.\n * @returns Bot detection result with detailed checks, or null if detection not enabled\n *\n * @example\n * ```typescript\n * const result = kitbase.getBotDetectionResult();\n * if (result?.isBot) {\n * console.log('Bot detected:', result.reason);\n * console.log('Checks:', result.checks);\n * }\n * ```\n */\n getBotDetectionResult(): BotDetectionResult | null {\n if (!this.botDetectionConfig.enabled) {\n return null;\n }\n\n // Re-run detection if not yet done\n if (!this.botDetectionResult) {\n this.botDetectionResult = detectBot(this.botDetectionConfig);\n }\n\n return this.botDetectionResult;\n }\n\n /**\n * Force re-run bot detection\n * Useful if you want to check again after page state changes\n *\n * @internal This is an internal API and may change without notice.\n * @returns Updated bot detection result\n *\n * @example\n * ```typescript\n * const result = kitbase.redetectBot();\n * console.log('Is bot:', result.isBot);\n * ```\n */\n redetectBot(): BotDetectionResult {\n this.botDetectionResult = detectBot(this.botDetectionConfig);\n this.log('Bot detection re-run', {\n isBot: this.botDetectionResult.isBot,\n reason: this.botDetectionResult.reason,\n });\n return this.botDetectionResult;\n }\n\n /**\n * Check if bot blocking is currently active\n * When bot detection is enabled and a bot is detected, all events are blocked.\n *\n * @internal This is an internal API and may change without notice.\n * @returns true if bots are being blocked from tracking\n */\n isBotBlockingActive(): boolean {\n return this.botDetectionConfig?.enabled === true && this.isBot();\n }\n\n // ============================================================\n // Client Session Tracking\n // ============================================================\n\n /**\n * Get or create a client-side session ID.\n * Rotates the session after 30 minutes of inactivity.\n * @internal\n */\n protected getClientSessionId(): string {\n const now = Date.now();\n if (\n !this.clientSessionId ||\n (this.lastActivityAt > 0 && now - this.lastActivityAt > KitbaseAnalytics.SESSION_TIMEOUT_MS)\n ) {\n this.clientSessionId = KitbaseAnalytics.generateUUID();\n this.log('New client session started', { sessionId: this.clientSessionId });\n }\n this.lastActivityAt = now;\n return this.clientSessionId;\n }\n\n /**\n * Generate a UUID v4, with fallback for environments where\n * crypto.randomUUID() is not available (older WebViews, Ionic).\n */\n private static generateUUID(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n // Fallback using crypto.getRandomValues (wider browser/WebView support)\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n // Set version 4 and variant bits\n bytes[6] = (bytes[6]! & 0x0f) | 0x40;\n bytes[8] = (bytes[8]! & 0x3f) | 0x80;\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n // Last resort fallback (Math.random - not cryptographically secure but functional)\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 // Track Event\n // ============================================================\n\n /**\n * Track an event\n *\n * Events are sent directly to the API. For offline queueing support,\n * use the full Kitbase client instead.\n *\n * @param options - Event tracking options\n * @returns Promise resolving to the track response, or void if tracking is blocked\n * @throws {ValidationError} When required fields are missing\n * @throws {AuthenticationError} When the API key is invalid\n * @throws {ApiError} When the API returns an error\n * @throws {TimeoutError} When the request times out\n */\n async track(options: TrackOptions): Promise<TrackResponse | void> {\n this.validateTrackOptions(options);\n\n // Check if bot blocking is active\n if (this.isBotBlockingActive()) {\n this.log('Event skipped - bot detected', { event: options.event });\n return;\n }\n\n // Calculate duration if this event was being timed\n let duration: number | undefined;\n const startTime = this.timedEvents.get(options.event);\n if (startTime !== undefined) {\n duration = (Date.now() - startTime) / 1000;\n this.timedEvents.delete(options.event);\n this.log('Timer stopped', { event: options.event, duration });\n }\n\n // Merge super properties with event tags (event tags take precedence)\n const mergedTags: Tags = {\n ...this.superProperties,\n ...(options.tags ?? {}),\n ...(duration !== undefined ? { $duration: duration } : {}),\n };\n\n const payload: LogPayload = {\n channel: options.channel,\n event: options.event,\n client_timestamp: Date.now(),\n client_session_id: this.getClientSessionId(),\n ...(options.user_id && { user_id: options.user_id }),\n ...(options.icon && { icon: options.icon }),\n ...(options.notify !== undefined && { notify: options.notify }),\n ...(options.description && { description: options.description }),\n ...(Object.keys(mergedTags).length > 0 && { tags: mergedTags }),\n };\n\n this.log('Track', { event: options.event, payload });\n\n // Send directly to API\n const response = await this.sendRequest<TrackResponse>('/sdk/v1/logs', payload);\n this.log('Event sent successfully', { id: response.id });\n return response;\n }\n\n protected validateTrackOptions(options: TrackOptions): void {\n if (!options.event) {\n throw new ValidationError('Event is required', 'event');\n }\n }\n\n /**\n * Send a request to the API\n */\n protected async sendRequest<T>(endpoint: string, body: unknown): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), TIMEOUT);\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': `${this.sdkKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorBody = await this.parseResponseBody(response);\n\n if (response.status === 401) {\n throw new AuthenticationError();\n }\n\n throw new ApiError(\n this.getErrorMessage(errorBody, response.statusText),\n response.status,\n errorBody,\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new TimeoutError();\n }\n\n throw error;\n }\n }\n\n protected async parseResponseBody(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n return null;\n }\n }\n\n protected getErrorMessage(body: unknown, fallback: string): string {\n if (body && typeof body === 'object' && 'message' in body) {\n return String((body as { message: unknown }).message);\n }\n if (body && typeof body === 'object' && 'error' in body) {\n return String((body as { error: unknown }).error);\n }\n return fallback;\n }\n\n // ============================================================\n // Analytics — Stub methods (overridden by plugins via methods)\n // ============================================================\n\n /**\n * Track a page view\n *\n * @param options - Page view options\n * @returns Promise resolving to the track response\n *\n * @example\n * ```typescript\n * // Track current page\n * await kitbase.trackPageView();\n *\n * // Track with custom path\n * await kitbase.trackPageView({ path: '/products/123', title: 'Product Details' });\n * ```\n */\n async trackPageView(options?: PageViewOptions): Promise<TrackResponse | void> {\n this.log('trackPageView() called but page-view plugin is not registered');\n }\n\n /**\n * Track a click on an interactive element\n */\n async trackClick(tags: Tags): Promise<TrackResponse | void> {\n this.log('trackClick() called but click-tracking plugin is not registered');\n }\n\n /**\n * Track an outbound link click\n *\n * @param options - Outbound link options\n * @returns Promise resolving to the track response\n *\n * @example\n * ```typescript\n * await kitbase.trackOutboundLink({\n * url: 'https://example.com',\n * text: 'Visit Example',\n * });\n * ```\n */\n async trackOutboundLink(options: { url: string; text?: string }): Promise<TrackResponse | void> {\n this.log('trackOutboundLink() called but outbound-links plugin is not registered');\n }\n\n // ============================================================\n // Analytics — Revenue & Identity (non-plugin)\n // ============================================================\n\n /**\n * Track a revenue event\n *\n * @param options - Revenue options\n * @returns Promise resolving to the track response\n *\n * @example\n * ```typescript\n * // Track a $19.99 purchase\n * await kitbase.trackRevenue({\n * amount: 1999,\n * currency: 'USD',\n * tags: { product_id: 'prod_123', plan: 'premium' },\n * });\n * ```\n */\n async trackRevenue(options: RevenueOptions): Promise<TrackResponse | void> {\n return this.track({\n channel: ANALYTICS_CHANNEL,\n event: 'revenue',\n user_id: options.user_id ?? this.userId ?? undefined,\n tags: {\n __revenue: options.amount,\n __currency: options.currency ?? 'USD',\n ...(options.tags ?? {}),\n },\n });\n }\n\n /**\n * Identify a user\n * Sets the user identity on the server.\n * Call this when a user signs up or logs in.\n *\n * @param options - Identify options\n * @returns Promise that resolves when the identity is set\n *\n * @example\n * ```typescript\n * await kitbase.identify({\n * userId: 'user_123',\n * traits: { email: 'user@example.com', plan: 'premium' },\n * });\n * ```\n */\n async identify(options: IdentifyOptions): Promise<void> {\n this.userId = options.userId;\n\n // Register user traits as super properties\n if (options.traits) {\n this.register({\n __user_id: options.userId,\n ...options.traits,\n });\n } else {\n this.register({ __user_id: options.userId });\n }\n\n // Call the identify endpoint\n try {\n const response = await fetch(`${this.baseUrl}/sdk/v1/identify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': this.sdkKey,\n },\n body: JSON.stringify({\n user_id: options.userId,\n traits: options.traits,\n }),\n });\n\n if (!response.ok) {\n this.log('Identify API call failed', { status: response.status });\n } else {\n this.log('Identity set on server', {\n userId: options.userId,\n });\n }\n } catch (err) {\n this.log('Failed to call identify endpoint', err);\n }\n\n this.log('User identified', { userId: options.userId });\n }\n\n /**\n * Get the current user ID (set via identify)\n */\n getUserId(): string | null {\n return this.userId;\n }\n\n /**\n * Reset the user identity\n * Call this when a user logs out\n *\n * @example\n * ```typescript\n * kitbase.reset();\n * ```\n */\n reset(): void {\n // Clear user ID\n this.userId = null;\n\n // Clear client session\n this.clientSessionId = null;\n this.lastActivityAt = 0;\n\n // Clear super properties\n this.clearSuperProperties();\n\n this.log('User reset complete');\n }\n\n // ============================================================\n // Cleanup\n // ============================================================\n\n /**\n * Shutdown the client and cleanup resources\n * Call this when you're done using the client to stop timers and close connections\n *\n * @example\n * ```typescript\n * kitbase.shutdown();\n * ```\n */\n shutdown(): void {\n this.log('Shutting down');\n\n // Clear timed events\n this.timedEvents.clear();\n\n // Teardown plugins in reverse order\n const pluginNames = Array.from(this._plugins.keys()).reverse();\n for (const name of pluginNames) {\n const plugin = this._plugins.get(name)!;\n try {\n plugin.teardown();\n this.log(`Plugin \"${name}\" torn down`);\n } catch (err) {\n this.log(`Plugin \"${name}\" teardown failed`, err);\n }\n }\n this._plugins.clear();\n this._pluginContext = null;\n\n this.log('Shutdown complete');\n }\n}\n","import Dexie, { type Table } from 'dexie';\nimport type { LogPayload } from '../types.js';\nimport type {\n OfflineConfig,\n QueuedEvent,\n QueueStats,\n EventQueueInterface,\n SendEventsCallback,\n} from './types.js';\n\nconst DEFAULT_CONFIG: Required<OfflineConfig> = {\n enabled: false,\n maxQueueSize: 1000,\n flushInterval: 30000,\n flushBatchSize: 50,\n maxRetries: 3,\n retryBaseDelay: 1000,\n};\n\n/**\n * Check if IndexedDB is available\n */\nfunction isIndexedDBAvailable(): boolean {\n try {\n return (\n typeof window !== 'undefined' &&\n typeof window.indexedDB !== 'undefined' &&\n window.indexedDB !== null\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Check if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Dexie database for event queue\n */\nclass KitbaseQueueDB extends Dexie {\n events!: Table<QueuedEvent, number>;\n\n constructor(dbName: string) {\n super(dbName);\n this.version(1).stores({\n events: '++id, timestamp, retries, lastAttempt',\n });\n }\n}\n\n/**\n * In-memory queue implementation for Node.js or when IndexedDB is unavailable\n */\nclass MemoryQueue {\n private queue: QueuedEvent[] = [];\n private idCounter = 1;\n\n async enqueue(payload: LogPayload): Promise<number> {\n const event: QueuedEvent = {\n id: this.idCounter++,\n payload,\n timestamp: Date.now(),\n retries: 0,\n };\n this.queue.push(event);\n return event.id!;\n }\n\n async dequeue(count: number): Promise<QueuedEvent[]> {\n // Sort by timestamp (oldest first) and get the first `count` events\n this.queue.sort((a, b) => a.timestamp - b.timestamp);\n return this.queue.slice(0, count);\n }\n\n async delete(ids: number[]): Promise<void> {\n this.queue = this.queue.filter((e) => !ids.includes(e.id!));\n }\n\n async updateRetries(ids: number[]): Promise<void> {\n const now = Date.now();\n for (const event of this.queue) {\n if (ids.includes(event.id!)) {\n event.retries++;\n event.lastAttempt = now;\n }\n }\n }\n\n async getStats(): Promise<{ size: number; oldestEvent?: number }> {\n const size = this.queue.length;\n const oldestEvent =\n size > 0\n ? Math.min(...this.queue.map((e) => e.timestamp))\n : undefined;\n return { size, oldestEvent };\n }\n\n async clear(): Promise<void> {\n this.queue = [];\n }\n\n async enforceMaxSize(maxSize: number): Promise<void> {\n if (this.queue.length > maxSize) {\n // Sort by timestamp and keep only the newest events\n this.queue.sort((a, b) => a.timestamp - b.timestamp);\n this.queue = this.queue.slice(-maxSize);\n }\n }\n\n async getEventsExceedingRetries(maxRetries: number): Promise<number[]> {\n return this.queue\n .filter((e) => e.retries >= maxRetries)\n .map((e) => e.id!);\n }\n}\n\n/**\n * Event queue for offline support\n * Uses IndexedDB (via Dexie) in browser, in-memory queue in Node.js\n */\nexport class EventQueue implements EventQueueInterface {\n private readonly config: Required<OfflineConfig>;\n private readonly dbName: string;\n private db: KitbaseQueueDB | null = null;\n private memoryQueue: MemoryQueue | null = null;\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private isFlushing = false;\n private sendEvents: SendEventsCallback | null = null;\n private readonly useIndexedDB: boolean;\n private debugMode = false;\n private debugLogger: ((message: string, data?: unknown) => void) | null = null;\n\n constructor(config: OfflineConfig = {}, dbName = '_ka_events') {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.dbName = dbName;\n this.useIndexedDB = isIndexedDBAvailable();\n\n if (this.useIndexedDB) {\n this.db = new KitbaseQueueDB(this.dbName);\n } else {\n this.memoryQueue = new MemoryQueue();\n }\n }\n\n /**\n * Set debug mode and logger\n */\n setDebugMode(enabled: boolean, logger?: (message: string, data?: unknown) => void): void {\n this.debugMode = enabled;\n this.debugLogger = logger ?? null;\n }\n\n private log(message: string, data?: unknown): void {\n if (this.debugMode && this.debugLogger) {\n this.debugLogger(message, data);\n }\n }\n\n /**\n * Set the callback for sending events\n */\n setSendCallback(callback: SendEventsCallback): void {\n this.sendEvents = callback;\n }\n\n /**\n * Check if the queue storage is available\n */\n isAvailable(): boolean {\n return this.useIndexedDB || this.memoryQueue !== null;\n }\n\n /**\n * Get the storage type being used\n */\n getStorageType(): 'indexeddb' | 'memory' {\n return this.useIndexedDB ? 'indexeddb' : 'memory';\n }\n\n /**\n * Add an event to the queue\n */\n async enqueue(payload: LogPayload): Promise<void> {\n const event: Omit<QueuedEvent, 'id'> = {\n payload,\n timestamp: Date.now(),\n retries: 0,\n };\n\n if (this.useIndexedDB && this.db) {\n await this.db.events.add(event as QueuedEvent);\n this.log('Event queued to IndexedDB', payload);\n } else if (this.memoryQueue) {\n await this.memoryQueue.enqueue(payload);\n this.log('Event queued to memory', payload);\n }\n\n // Enforce max queue size\n await this.enforceMaxQueueSize();\n }\n\n /**\n * Get and remove the next batch of events to send\n */\n async dequeue(count: number): Promise<QueuedEvent[]> {\n if (this.useIndexedDB && this.db) {\n // Get events sorted by timestamp (oldest first), excluding those with too many retries\n return this.db.events\n .where('retries')\n .below(this.config.maxRetries)\n .sortBy('timestamp')\n .then((events) => events.slice(0, count));\n } else if (this.memoryQueue) {\n const events = await this.memoryQueue.dequeue(count);\n return events.filter((e) => e.retries < this.config.maxRetries);\n }\n return [];\n }\n\n /**\n * Mark events as successfully sent (remove from queue)\n */\n async markSent(ids: number[]): Promise<void> {\n if (ids.length === 0) return;\n\n if (this.useIndexedDB && this.db) {\n await this.db.events.bulkDelete(ids);\n this.log(`Removed ${ids.length} sent events from queue`);\n } else if (this.memoryQueue) {\n await this.memoryQueue.delete(ids);\n this.log(`Removed ${ids.length} sent events from memory queue`);\n }\n }\n\n /**\n * Mark events as failed and increment retry count\n */\n async markFailed(ids: number[]): Promise<void> {\n if (ids.length === 0) return;\n\n const now = Date.now();\n\n if (this.useIndexedDB && this.db) {\n await this.db.transaction('rw', this.db.events, async () => {\n for (const id of ids) {\n const event = await this.db!.events.get(id);\n if (event) {\n await this.db!.events.update(id, {\n retries: event.retries + 1,\n lastAttempt: now,\n });\n }\n }\n });\n this.log(`Marked ${ids.length} events as failed`);\n } else if (this.memoryQueue) {\n await this.memoryQueue.updateRetries(ids);\n this.log(`Marked ${ids.length} events as failed in memory queue`);\n }\n\n // Remove events that have exceeded max retries\n await this.removeExpiredRetries();\n }\n\n /**\n * Remove events that have exceeded max retry attempts\n */\n private async removeExpiredRetries(): Promise<void> {\n if (this.useIndexedDB && this.db) {\n const expiredIds = await this.db.events\n .where('retries')\n .aboveOrEqual(this.config.maxRetries)\n .primaryKeys();\n if (expiredIds.length > 0) {\n await this.db.events.bulkDelete(expiredIds);\n this.log(`Removed ${expiredIds.length} events that exceeded max retries`);\n }\n } else if (this.memoryQueue) {\n const expiredIds = await this.memoryQueue.getEventsExceedingRetries(\n this.config.maxRetries\n );\n if (expiredIds.length > 0) {\n await this.memoryQueue.delete(expiredIds);\n this.log(`Removed ${expiredIds.length} events that exceeded max retries`);\n }\n }\n }\n\n /**\n * Enforce the maximum queue size by removing oldest events\n */\n private async enforceMaxQueueSize(): Promise<void> {\n if (this.useIndexedDB && this.db) {\n const count = await this.db.events.count();\n if (count > this.config.maxQueueSize) {\n const excess = count - this.config.maxQueueSize;\n const oldestEvents = await this.db.events\n .orderBy('timestamp')\n .limit(excess)\n .primaryKeys();\n await this.db.events.bulkDelete(oldestEvents);\n this.log(`Removed ${excess} oldest events to enforce queue size limit`);\n }\n } else if (this.memoryQueue) {\n await this.memoryQueue.enforceMaxSize(this.config.maxQueueSize);\n }\n }\n\n /**\n * Get queue statistics\n */\n async getStats(): Promise<QueueStats> {\n if (this.useIndexedDB && this.db) {\n const size = await this.db.events.count();\n const oldestEvent = await this.db.events\n .orderBy('timestamp')\n .first()\n .then((e) => e?.timestamp);\n return { size, oldestEvent, isFlushing: this.isFlushing };\n } else if (this.memoryQueue) {\n const stats = await this.memoryQueue.getStats();\n return { ...stats, isFlushing: this.isFlushing };\n }\n return { size: 0, isFlushing: this.isFlushing };\n }\n\n /**\n * Clear all events from the queue\n */\n async clear(): Promise<void> {\n if (this.useIndexedDB && this.db) {\n await this.db.events.clear();\n this.log('Queue cleared (IndexedDB)');\n } else if (this.memoryQueue) {\n await this.memoryQueue.clear();\n this.log('Queue cleared (memory)');\n }\n }\n\n /**\n * Start the automatic flush timer\n */\n startFlushTimer(): void {\n if (this.flushTimer) return;\n\n this.flushTimer = setInterval(() => {\n this.flush().catch((err) => {\n this.log('Flush timer error', err);\n });\n }, this.config.flushInterval);\n\n // Also listen for online events in browser\n if (isBrowser()) {\n window.addEventListener('online', this.handleOnline);\n }\n\n this.log(`Flush timer started (interval: ${this.config.flushInterval}ms)`);\n }\n\n /**\n * Stop the automatic flush timer\n */\n stopFlushTimer(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n\n if (isBrowser()) {\n window.removeEventListener('online', this.handleOnline);\n }\n\n this.log('Flush timer stopped');\n }\n\n /**\n * Handle coming back online\n */\n private handleOnline = (): void => {\n this.log('Browser came online, triggering flush');\n this.flush().catch((err) => {\n this.log('Online flush error', err);\n });\n };\n\n /**\n * Check if we're currently online\n */\n private isOnline(): boolean {\n if (isBrowser()) {\n return navigator.onLine;\n }\n // Assume online in Node.js\n return true;\n }\n\n /**\n * Manually trigger a flush of queued events\n */\n async flush(): Promise<void> {\n if (this.isFlushing) {\n this.log('Flush already in progress, skipping');\n return;\n }\n\n if (!this.isOnline()) {\n this.log('Offline, skipping flush');\n return;\n }\n\n if (!this.sendEvents) {\n this.log('No send callback configured, skipping flush');\n return;\n }\n\n this.isFlushing = true;\n\n try {\n const stats = await this.getStats();\n if (stats.size === 0) {\n this.log('Queue is empty, nothing to flush');\n return;\n }\n\n this.log(`Flushing queue (${stats.size} events)`);\n\n // Process in batches\n let processed = 0;\n while (true) {\n const events = await this.dequeue(this.config.flushBatchSize);\n if (events.length === 0) break;\n\n this.log(`Sending batch of ${events.length} events`);\n\n try {\n const sentIds = await this.sendEvents(events);\n await this.markSent(sentIds);\n\n // Mark remaining as failed\n const failedIds = events\n .filter((e) => !sentIds.includes(e.id!))\n .map((e) => e.id!);\n if (failedIds.length > 0) {\n await this.markFailed(failedIds);\n }\n\n processed += sentIds.length;\n } catch (error) {\n // Mark all as failed on network error\n const allIds = events.map((e) => e.id!);\n await this.markFailed(allIds);\n this.log('Batch send failed', error);\n break; // Stop flushing on error\n }\n }\n\n this.log(`Flush complete, sent ${processed} events`);\n } finally {\n this.isFlushing = false;\n }\n }\n\n /**\n * Close the database connection\n */\n async close(): Promise<void> {\n this.stopFlushTimer();\n if (this.db) {\n this.db.close();\n this.log('Database connection closed');\n }\n }\n}\n\nexport type { OfflineConfig, QueuedEvent, QueueStats, EventQueueInterface, SendEventsCallback };\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport type { PageViewOptions, TrackResponse } from '../types-lite.js';\nimport { getUtmParams } from './utils.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class PageViewPlugin implements KitbasePlugin {\n readonly name = 'page-view';\n private ctx!: PluginContext;\n private active = false;\n private popstateListener: (() => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n this.active = true;\n\n // Defer initial page view so subclass constructors (e.g. offline queue) finish first\n Promise.resolve().then(() => {\n if (this.active) {\n this.trackPageView().catch((err) => ctx.log('Failed to track initial page view', err));\n }\n });\n\n // Intercept pushState\n const originalPushState = history.pushState.bind(history);\n history.pushState = (...args) => {\n originalPushState(...args);\n if (this.active) {\n this.trackPageView().catch((err) => ctx.log('Failed to track page view (pushState)', err));\n }\n };\n\n // Intercept replaceState (preserve behavior, no tracking)\n const originalReplaceState = history.replaceState.bind(history);\n history.replaceState = (...args) => {\n originalReplaceState(...args);\n };\n\n // Listen to popstate (browser back/forward)\n this.popstateListener = () => {\n if (this.active) {\n this.trackPageView().catch((err) => ctx.log('Failed to track page view (popstate)', err));\n }\n };\n window.addEventListener('popstate', this.popstateListener);\n\n ctx.log('Auto page view tracking enabled');\n }\n\n teardown(): void {\n this.active = false;\n if (this.popstateListener) {\n window.removeEventListener('popstate', this.popstateListener);\n this.popstateListener = null;\n }\n }\n\n get methods() {\n return {\n trackPageView: (options?: PageViewOptions): Promise<TrackResponse | void> =>\n this.trackPageView(options),\n };\n }\n\n private async trackPageView(options: PageViewOptions = {}): Promise<TrackResponse | void> {\n const path = options.path ?? (typeof window !== 'undefined' ? window.location.pathname : '');\n const title = options.title ?? (typeof document !== 'undefined' ? document.title : '');\n const referrer = options.referrer ?? (typeof document !== 'undefined' ? document.referrer : '');\n\n return this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'screen_view',\n tags: {\n __path: path,\n __title: title,\n __referrer: referrer,\n ...getUtmParams(),\n ...(options.tags ?? {}),\n },\n });\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport type { TrackResponse } from '../types-lite.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class OutboundLinksPlugin implements KitbasePlugin {\n readonly name = 'outbound-links';\n private ctx!: PluginContext;\n private clickListener: ((event: MouseEvent) => void) | null = null;\n private keydownListener: ((event: KeyboardEvent) => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n\n this.clickListener = (event: MouseEvent) => {\n const link = (event.target as Element)?.closest?.('a');\n if (link) {\n this.handleLinkClick(link as HTMLAnchorElement);\n }\n };\n\n this.keydownListener = (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n const link = (event.target as Element)?.closest?.('a');\n if (link) {\n this.handleLinkClick(link as HTMLAnchorElement);\n }\n }\n };\n\n document.addEventListener('click', this.clickListener);\n document.addEventListener('keydown', this.keydownListener);\n\n ctx.log('Outbound link tracking enabled');\n }\n\n teardown(): void {\n if (this.clickListener) {\n document.removeEventListener('click', this.clickListener);\n this.clickListener = null;\n }\n if (this.keydownListener) {\n document.removeEventListener('keydown', this.keydownListener);\n this.keydownListener = null;\n }\n }\n\n get methods() {\n return {\n trackOutboundLink: (options: { url: string; text?: string }): Promise<TrackResponse | void> =>\n this.trackOutboundLink(options),\n };\n }\n\n private handleLinkClick(link: HTMLAnchorElement): void {\n if (!link.href) return;\n\n try {\n const linkUrl = new URL(link.href);\n\n if (linkUrl.protocol !== 'http:' && linkUrl.protocol !== 'https:') {\n return;\n }\n\n const currentHost = window.location.hostname;\n const linkHost = linkUrl.hostname;\n\n if (linkHost === currentHost) return;\n if (this.ctx.isSameRootDomain(currentHost, linkHost)) return;\n\n this.trackOutboundLink({\n url: link.href,\n text: link.textContent?.trim() || '',\n }).catch((err) => this.ctx.log('Failed to track outbound link', err));\n } catch {\n // Invalid URL, skip\n }\n }\n\n private async trackOutboundLink(options: { url: string; text?: string }): Promise<TrackResponse | void> {\n return this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'outbound_link',\n tags: {\n __url: options.url,\n __text: options.text || '',\n },\n });\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport type { Tags, TrackResponse } from '../types-lite.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class ClickTrackingPlugin implements KitbasePlugin {\n readonly name = 'click-tracking';\n private ctx!: PluginContext;\n private clickListener: ((event: MouseEvent) => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n\n this.clickListener = (event: MouseEvent) => {\n const target = event.target as Element | null;\n\n // data-kb-track-click — user-defined click events via data attributes\n const annotated = target?.closest?.('[data-kb-track-click]');\n if (annotated) {\n const eventName = annotated.getAttribute('data-kb-track-click');\n if (eventName) {\n const channel = annotated.getAttribute('data-kb-click-channel') || 'engagement';\n ctx.track({\n channel,\n event: eventName,\n tags: {\n __path: window.location.pathname,\n },\n }).catch((err) => ctx.log('Failed to track data-attribute click', err));\n return; // skip generic click tracking for annotated elements\n }\n }\n\n const element = ctx.findClickableElement(event);\n if (!element) return;\n\n // Skip outbound links — already handled by outbound link tracking\n if (ctx.config.autoTrackOutboundLinks !== false) {\n const elHref = (element as HTMLAnchorElement).href || element.getAttribute('href') || '';\n if (elHref) {\n try {\n const linkUrl = new URL(elHref, window.location.origin);\n if (\n (linkUrl.protocol === 'http:' || linkUrl.protocol === 'https:') &&\n linkUrl.hostname !== window.location.hostname &&\n !ctx.isSameRootDomain(window.location.hostname, linkUrl.hostname)\n ) {\n return;\n }\n } catch {\n // Invalid URL, continue with click tracking\n }\n }\n }\n\n const tag = element.tagName.toLowerCase();\n const id = element.id || '';\n const className = element.className && typeof element.className === 'string' ? element.className : '';\n const text = (element.textContent || '').trim().slice(0, 100);\n const href = (element as HTMLAnchorElement).href || element.getAttribute('href') || '';\n const path = window.location.pathname;\n\n this.trackClick({ __tag: tag, __id: id, __class: className, __text: text, __href: href, __path: path }).catch(\n (err) => ctx.log('Failed to track click', err),\n );\n };\n\n document.addEventListener('click', this.clickListener);\n ctx.log('Click tracking enabled');\n }\n\n teardown(): void {\n if (this.clickListener) {\n document.removeEventListener('click', this.clickListener);\n this.clickListener = null;\n }\n }\n\n get methods() {\n return {\n trackClick: (tags: Tags): Promise<TrackResponse | void> =>\n this.trackClick(tags),\n };\n }\n\n private async trackClick(tags: Tags): Promise<TrackResponse | void> {\n return this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'click',\n tags,\n });\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class ScrollDepthPlugin implements KitbasePlugin {\n readonly name = 'scroll-depth';\n private ctx!: PluginContext;\n private active = false;\n private maxScrollDepth = 0;\n private scrollListener: (() => void) | null = null;\n private beforeUnloadListener: (() => void) | null = null;\n private popstateListener: (() => void) | null = null;\n private scrollRafScheduled = false;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n this.active = true;\n\n this.scrollListener = () => {\n if (this.scrollRafScheduled) return;\n this.scrollRafScheduled = true;\n requestAnimationFrame(() => {\n this.scrollRafScheduled = false;\n const scrollTop = window.scrollY || document.documentElement.scrollTop;\n const viewportHeight = window.innerHeight;\n const documentHeight = Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n );\n if (documentHeight <= 0) return;\n const depth = Math.min(100, Math.round(((scrollTop + viewportHeight) / documentHeight) * 100));\n if (depth > this.maxScrollDepth) {\n this.maxScrollDepth = depth;\n }\n });\n };\n\n this.beforeUnloadListener = () => {\n this.flushScrollDepth();\n };\n\n window.addEventListener('scroll', this.scrollListener, { passive: true });\n window.addEventListener('beforeunload', this.beforeUnloadListener);\n\n // SPA navigation (pushState / popstate)\n const originalPushState = history.pushState;\n const self = this;\n history.pushState = function (...args) {\n if (self.active) self.flushScrollDepth();\n return originalPushState.apply(this, args);\n };\n\n this.popstateListener = () => {\n if (this.active) this.flushScrollDepth();\n };\n window.addEventListener('popstate', this.popstateListener);\n\n ctx.log('Scroll depth tracking enabled');\n }\n\n teardown(): void {\n this.active = false;\n this.flushScrollDepth();\n if (this.scrollListener) {\n window.removeEventListener('scroll', this.scrollListener);\n this.scrollListener = null;\n }\n if (this.beforeUnloadListener) {\n window.removeEventListener('beforeunload', this.beforeUnloadListener);\n this.beforeUnloadListener = null;\n }\n if (this.popstateListener) {\n window.removeEventListener('popstate', this.popstateListener);\n this.popstateListener = null;\n }\n }\n\n private flushScrollDepth(): void {\n if (this.maxScrollDepth > 0) {\n const path = typeof window !== 'undefined' ? window.location.pathname : '';\n this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'scroll_depth',\n tags: {\n __depth: this.maxScrollDepth,\n __path: path,\n },\n }).catch((err) => this.ctx.log('Failed to track scroll depth', err));\n this.maxScrollDepth = 0;\n }\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\n\nexport class VisibilityPlugin implements KitbasePlugin {\n readonly name = 'visibility';\n private ctx!: PluginContext;\n private active = false;\n private visibilityObservers: Map<number, IntersectionObserver> = new Map();\n private visibilityMutationObserver: MutationObserver | null = null;\n private visibilityData: Map<Element, { visibleSince: number | null; totalMs: number; event: string; channel: string }> = new Map();\n private beforeUnloadListener: (() => void) | null = null;\n private popstateListener: (() => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n if (typeof IntersectionObserver === 'undefined' || typeof MutationObserver === 'undefined') return false;\n this.ctx = ctx;\n this.active = true;\n\n // Scan existing DOM elements\n this.scanForVisibilityElements();\n\n // Watch for dynamically added/removed elements\n this.visibilityMutationObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of Array.from(mutation.addedNodes)) {\n if (node instanceof Element) {\n this.observeVisibilityElement(node);\n for (const el of Array.from(node.querySelectorAll('[data-kb-track-visibility]'))) {\n this.observeVisibilityElement(el);\n }\n }\n }\n for (const node of Array.from(mutation.removedNodes)) {\n if (node instanceof Element) {\n this.flushVisibilityForElement(node);\n for (const el of Array.from(node.querySelectorAll('[data-kb-track-visibility]'))) {\n this.flushVisibilityForElement(el);\n }\n }\n }\n }\n });\n\n this.visibilityMutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n });\n\n // Flush on beforeunload\n this.beforeUnloadListener = () => {\n this.flushAllVisibilityEvents();\n };\n window.addEventListener('beforeunload', this.beforeUnloadListener);\n\n // SPA navigation (pushState / popstate)\n const originalPushState = history.pushState;\n const self = this;\n history.pushState = function (...args) {\n if (self.active) self.flushAllVisibilityEvents();\n return originalPushState.apply(this, args);\n };\n\n this.popstateListener = () => {\n if (this.active) this.flushAllVisibilityEvents();\n };\n window.addEventListener('popstate', this.popstateListener);\n\n ctx.log('Visibility tracking enabled');\n }\n\n teardown(): void {\n this.active = false;\n this.flushAllVisibilityEvents();\n for (const observer of this.visibilityObservers.values()) {\n observer.disconnect();\n }\n this.visibilityObservers.clear();\n if (this.visibilityMutationObserver) {\n this.visibilityMutationObserver.disconnect();\n this.visibilityMutationObserver = null;\n }\n if (this.beforeUnloadListener) {\n window.removeEventListener('beforeunload', this.beforeUnloadListener);\n this.beforeUnloadListener = null;\n }\n if (this.popstateListener) {\n window.removeEventListener('popstate', this.popstateListener);\n this.popstateListener = null;\n }\n this.visibilityData.clear();\n }\n\n private scanForVisibilityElements(): void {\n for (const el of Array.from(document.querySelectorAll('[data-kb-track-visibility]'))) {\n this.observeVisibilityElement(el);\n }\n }\n\n private observeVisibilityElement(el: Element): void {\n const eventName = el.getAttribute('data-kb-track-visibility');\n if (!eventName || this.visibilityData.has(el)) return;\n\n const channel = el.getAttribute('data-kb-visibility-channel') || 'engagement';\n const threshold = parseFloat(el.getAttribute('data-kb-visibility-threshold') || '0.5');\n const clampedThreshold = Math.max(0, Math.min(1, isNaN(threshold) ? 0.5 : threshold));\n\n this.visibilityData.set(el, {\n visibleSince: null,\n totalMs: 0,\n event: eventName,\n channel,\n });\n\n const observer = this.getOrCreateObserver(clampedThreshold);\n observer.observe(el);\n }\n\n private getOrCreateObserver(threshold: number): IntersectionObserver {\n const key = Math.round(threshold * 100);\n\n let observer = this.visibilityObservers.get(key);\n if (observer) return observer;\n\n observer = new IntersectionObserver(\n (entries) => {\n const now = Date.now();\n for (const entry of entries) {\n const data = this.visibilityData.get(entry.target);\n if (!data) continue;\n\n if (entry.isIntersecting) {\n data.visibleSince = now;\n } else if (data.visibleSince !== null) {\n data.totalMs += now - data.visibleSince;\n data.visibleSince = null;\n }\n }\n },\n { threshold },\n );\n\n this.visibilityObservers.set(key, observer);\n return observer;\n }\n\n private flushVisibilityForElement(el: Element): void {\n const data = this.visibilityData.get(el);\n if (!data) return;\n\n if (data.visibleSince !== null) {\n data.totalMs += Date.now() - data.visibleSince;\n data.visibleSince = null;\n }\n\n if (data.totalMs > 0) {\n const durationMs = Math.round(data.totalMs);\n const durationSeconds = Math.round(durationMs / 1000);\n this.ctx.track({\n channel: data.channel,\n event: 'element_visible',\n tags: {\n __element_name: data.event,\n __duration_seconds: durationSeconds,\n __duration_ms: durationMs,\n },\n }).catch((err) => this.ctx.log('Failed to track visibility event', err));\n }\n\n for (const observer of this.visibilityObservers.values()) {\n observer.unobserve(el);\n }\n this.visibilityData.delete(el);\n }\n\n private flushAllVisibilityEvents(): void {\n for (const [, data] of this.visibilityData.entries()) {\n if (data.visibleSince !== null) {\n data.totalMs += Date.now() - data.visibleSince;\n data.visibleSince = null;\n }\n\n if (data.totalMs > 0) {\n const durationMs = Math.round(data.totalMs);\n const durationSeconds = Math.round(durationMs / 1000);\n this.ctx.track({\n channel: data.channel,\n event: 'element_visible',\n tags: {\n element_name: data.event,\n duration_seconds: durationSeconds,\n duration_ms: durationMs,\n },\n }).catch((err) => this.ctx.log('Failed to track visibility event', err));\n }\n\n // Reset for next page / session\n data.totalMs = 0;\n data.visibleSince = null;\n }\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport type { Tags } from '../types-lite.js';\nimport { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class WebVitalsPlugin implements KitbasePlugin {\n readonly name = 'web-vitals';\n private ctx!: PluginContext;\n private sent = false;\n private timeout: ReturnType<typeof setTimeout> | null = null;\n private beforeUnloadListener: (() => void) | null = null;\n private data: { lcp: number | null; cls: number | null; inp: number | null; fcp: number | null; ttfb: number | null } = {\n lcp: null, cls: null, inp: null, fcp: null, ttfb: null,\n };\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n\n const checkAndSend = () => {\n const { lcp, cls, inp, fcp, ttfb } = this.data;\n if (lcp !== null && cls !== null && inp !== null && fcp !== null && ttfb !== null) {\n this.sendWebVitals();\n }\n };\n\n onLCP((metric) => {\n this.data.lcp = metric.value;\n ctx.log('Web Vital collected', { name: 'LCP', value: metric.value });\n checkAndSend();\n });\n\n onCLS((metric) => {\n this.data.cls = metric.value;\n ctx.log('Web Vital collected', { name: 'CLS', value: metric.value });\n checkAndSend();\n });\n\n onINP((metric) => {\n this.data.inp = metric.value;\n ctx.log('Web Vital collected', { name: 'INP', value: metric.value });\n checkAndSend();\n });\n\n onFCP((metric) => {\n this.data.fcp = metric.value;\n ctx.log('Web Vital collected', { name: 'FCP', value: metric.value });\n checkAndSend();\n });\n\n onTTFB((metric) => {\n this.data.ttfb = metric.value;\n ctx.log('Web Vital collected', { name: 'TTFB', value: metric.value });\n checkAndSend();\n });\n\n // Safety timeout — send whatever we have after 30s\n this.timeout = setTimeout(() => {\n this.timeout = null;\n this.sendWebVitals();\n }, 30_000);\n\n // Also send on beforeunload if not already sent\n this.beforeUnloadListener = () => {\n this.sendWebVitals();\n };\n window.addEventListener('beforeunload', this.beforeUnloadListener);\n\n ctx.log('Web Vitals tracking enabled');\n }\n\n teardown(): void {\n if (this.timeout !== null) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n this.sendWebVitals();\n if (this.beforeUnloadListener) {\n window.removeEventListener('beforeunload', this.beforeUnloadListener);\n this.beforeUnloadListener = null;\n }\n }\n\n private sendWebVitals(): void {\n if (this.sent) return;\n\n const { lcp, cls, inp, fcp, ttfb } = this.data;\n\n // Don't send if no metrics were collected at all\n if (lcp === null && cls === null && inp === null && fcp === null && ttfb === null) return;\n\n this.sent = true;\n\n if (this.timeout !== null) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n\n const tags: Tags = {};\n if (lcp !== null) tags.__lcp = lcp;\n if (cls !== null) tags.__cls = cls;\n if (inp !== null) tags.__inp = inp;\n if (fcp !== null) tags.__fcp = fcp;\n if (ttfb !== null) tags.__ttfb = ttfb;\n\n this.ctx.log('Sending Web Vitals', tags);\n\n this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'web_vitals',\n tags,\n }).catch((err) => this.ctx.log('Failed to track web vitals', err));\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport { findClickableElement, buildCssSelector } from './utils.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nconst RAGE_CLICK_THRESHOLD = 3;\nconst RAGE_CLICK_WINDOW_MS = 1000;\nconst RAGE_CLICK_RADIUS_PX = 30;\nconst DEAD_CLICK_TIMEOUT_MS = 1000;\n\nexport class FrustrationPlugin implements KitbasePlugin {\n readonly name = 'frustration';\n private ctx!: PluginContext;\n private rageClickBuffer: Array<{ time: number; x: number; y: number; target: Element }> = [];\n private deadClickObserver: MutationObserver | null = null;\n private deadClickTimeout: ReturnType<typeof setTimeout> | null = null;\n private clickListener: ((e: MouseEvent) => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n\n this.clickListener = (event: MouseEvent) => {\n const target = event.target as Element | null;\n if (!target) return;\n\n const now = Date.now();\n\n // --- Rage Click Detection ---\n this.rageClickBuffer.push({ time: now, x: event.clientX, y: event.clientY, target });\n\n // Prune clicks older than the time window\n this.rageClickBuffer = this.rageClickBuffer.filter(\n (c) => now - c.time < RAGE_CLICK_WINDOW_MS,\n );\n\n if (this.rageClickBuffer.length >= RAGE_CLICK_THRESHOLD) {\n const first = this.rageClickBuffer[0]!;\n const allNearby = this.rageClickBuffer.every(\n (c) => Math.hypot(c.x - first.x, c.y - first.y) < RAGE_CLICK_RADIUS_PX,\n );\n\n if (allNearby) {\n const element = findClickableElement(event) || target;\n const clickCount = this.rageClickBuffer.length;\n this.rageClickBuffer = []; // reset after emitting\n\n ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'rage_click',\n tags: {\n __path: window.location.pathname,\n __tag: element.tagName.toLowerCase(),\n __id: element.id || '',\n __class: element.className && typeof element.className === 'string' ? element.className : '',\n __text: (element.textContent || '').trim().slice(0, 100),\n __selector: buildCssSelector(element),\n __click_count: clickCount,\n },\n }).catch((err) => ctx.log('Failed to track rage click', err));\n return; // skip dead click check after rage click\n }\n }\n\n // --- Dead Click Detection ---\n const clickedElement = findClickableElement(event);\n if (!clickedElement) return;\n\n // Skip dead click detection for links with href — navigating is the expected behavior,\n // not a DOM mutation on the current page (especially target=\"_blank\" links).\n if (target.closest?.('a[href]')) return;\n\n // Skip dead click detection for <select> and <option> — the browser renders\n // native dropdowns outside the DOM, so no MutationObserver-visible change occurs.\n if (clickedElement.tagName === 'SELECT' || target.closest?.('select')) return;\n\n // Clear any pending dead click check\n if (this.deadClickTimeout !== null) {\n clearTimeout(this.deadClickTimeout);\n this.deadClickTimeout = null;\n }\n if (this.deadClickObserver) {\n this.deadClickObserver.disconnect();\n }\n\n let mutationDetected = false;\n\n this.deadClickObserver = new MutationObserver(() => {\n mutationDetected = true;\n });\n\n this.deadClickObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n });\n\n this.deadClickTimeout = setTimeout(() => {\n if (this.deadClickObserver) {\n this.deadClickObserver.disconnect();\n this.deadClickObserver = null;\n }\n\n if (!mutationDetected) {\n ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'dead_click',\n tags: {\n __path: window.location.pathname,\n __tag: clickedElement.tagName.toLowerCase(),\n __id: clickedElement.id || '',\n __class: clickedElement.className && typeof clickedElement.className === 'string' ? clickedElement.className : '',\n __text: (clickedElement.textContent || '').trim().slice(0, 100),\n __selector: buildCssSelector(clickedElement),\n },\n }).catch((err) => ctx.log('Failed to track dead click', err));\n }\n }, DEAD_CLICK_TIMEOUT_MS);\n };\n\n document.addEventListener('click', this.clickListener, true);\n ctx.log('Frustration signal detection enabled');\n }\n\n teardown(): void {\n if (this.clickListener) {\n document.removeEventListener('click', this.clickListener, true);\n this.clickListener = null;\n }\n if (this.deadClickObserver) {\n this.deadClickObserver.disconnect();\n this.deadClickObserver = null;\n }\n if (this.deadClickTimeout !== null) {\n clearTimeout(this.deadClickTimeout);\n this.deadClickTimeout = null;\n }\n this.rageClickBuffer = [];\n }\n}\n","import type { AnalyticsConfig } from '../types-lite.js';\nimport type { KitbasePlugin } from './types.js';\nimport { PageViewPlugin } from './page-view.js';\nimport { OutboundLinksPlugin } from './outbound-links.js';\nimport { ClickTrackingPlugin } from './click-tracking.js';\nimport { ScrollDepthPlugin } from './scroll-depth.js';\nimport { VisibilityPlugin } from './visibility.js';\nimport { WebVitalsPlugin } from './web-vitals.js';\nimport { FrustrationPlugin } from './frustration.js';\n\n/**\n * Create the default set of plugins based on analytics configuration.\n * Reads config flags and instantiates only the enabled plugins.\n */\nexport function createDefaultPlugins(config?: AnalyticsConfig): KitbasePlugin[] {\n const plugins: KitbasePlugin[] = [];\n\n if (config?.autoTrackPageViews !== false) {\n plugins.push(new PageViewPlugin());\n }\n if (config?.autoTrackOutboundLinks !== false) {\n plugins.push(new OutboundLinksPlugin());\n }\n if (config?.autoTrackClicks !== false) {\n plugins.push(new ClickTrackingPlugin());\n }\n if (config?.autoTrackScrollDepth !== false) {\n plugins.push(new ScrollDepthPlugin());\n }\n if (config?.autoTrackVisibility !== false) {\n plugins.push(new VisibilityPlugin());\n }\n if (config?.autoTrackWebVitals === true) {\n plugins.push(new WebVitalsPlugin());\n }\n if (config?.autoDetectFrustration !== false) {\n plugins.push(new FrustrationPlugin());\n }\n\n return plugins;\n}\n","import type {\n KitbaseConfig,\n TrackOptions,\n TrackResponse,\n LogPayload,\n Tags,\n} from './types.js';\nimport { ValidationError } from './errors.js';\nimport { KitbaseAnalytics as KitbaseAnalyticsBase } from './client-base.js';\nimport { EventQueue } from './queue/index.js';\nimport type { QueuedEvent, QueueStats } from './queue/types.js';\nimport { createDefaultPlugins } from './plugins/defaults.js';\n\n/**\n * Kitbase client for tracking events with full offline queue support\n *\n * @example\n * ```typescript\n * import { Kitbase } from '@kitbase/analytics';\n *\n * const kitbase = new Kitbase({\n * sdkKey: '<YOUR_API_KEY>',\n * debug: true,\n * offline: { enabled: true },\n * });\n *\n * // Register super properties (included in all events)\n * kitbase.register({ app_version: '2.1.0', platform: 'web' });\n *\n * // Track events\n * await kitbase.track({\n * channel: 'payments',\n * event: 'Page Viewed',\n * icon: '👀',\n * });\n *\n * // Time events for duration tracking\n * kitbase.timeEvent('Video Watched');\n * // ... later\n * await kitbase.track({\n * channel: 'engagement',\n * event: 'Video Watched', // $duration automatically included\n * });\n *\n * // Track events for a logged-in user (just pass user_id)\n * await kitbase.track({\n * channel: 'payments',\n * event: 'New Subscription',\n * user_id: 'user-123',\n * icon: '💰',\n * notify: true,\n * tags: {\n * plan: 'premium',\n * cycle: 'monthly',\n * },\n * });\n * ```\n */\nlet _instance: KitbaseAnalytics | null = null;\n\n/**\n * Initialize the Kitbase Analytics SDK\n *\n * Creates a singleton instance that is used for all tracking.\n * Call this once at the top of your application entry point.\n *\n * @param config - SDK configuration\n * @returns The KitbaseAnalytics instance\n *\n * @example\n * ```typescript\n * import { init } from '@kitbase/analytics';\n *\n * init({\n * sdkKey: '<YOUR_API_KEY>',\n * debug: true,\n * offline: { enabled: true },\n * });\n * ```\n */\nexport function init(config: KitbaseConfig): KitbaseAnalytics {\n if (_instance) {\n _instance.shutdown();\n }\n _instance = new KitbaseAnalytics(config);\n return _instance;\n}\n\n/**\n * Get the current KitbaseAnalytics singleton instance\n *\n * @returns The instance, or null if `init()` has not been called\n */\nexport function getInstance(): KitbaseAnalytics | null {\n return _instance;\n}\n\nexport class KitbaseAnalytics extends KitbaseAnalyticsBase {\n // Offline queue\n private queue: EventQueue | null = null;\n private offlineEnabled: boolean;\n\n constructor(config: KitbaseConfig) {\n super(config, createDefaultPlugins(config.analytics));\n\n // Initialize offline queue if enabled\n this.offlineEnabled = config.offline?.enabled ?? false;\n\n if (this.offlineEnabled) {\n this.queue = new EventQueue(config.offline);\n this.queue.setDebugMode(this.debugMode, this.log.bind(this));\n this.queue.setSendCallback(this.sendQueuedEvents.bind(this));\n this.queue.startFlushTimer();\n this.log('Offline queueing enabled', {\n storageType: this.queue.getStorageType(),\n });\n }\n }\n\n // ============================================================\n // Debug Mode Override\n // ============================================================\n\n /**\n * Enable or disable debug mode\n * When enabled, all SDK operations are logged to the console\n *\n * @param enabled - Whether to enable debug mode\n *\n * @example\n * ```typescript\n * kitbase.setDebugMode(true);\n * // All events and operations will now be logged\n * ```\n */\n override setDebugMode(enabled: boolean): void {\n super.setDebugMode(enabled);\n if (this.queue) {\n this.queue.setDebugMode(enabled, this.log.bind(this));\n }\n }\n\n // ============================================================\n // Offline Queue\n // ============================================================\n\n /**\n * Get offline queue statistics\n *\n * @returns Queue statistics including size and flush status\n *\n * @example\n * ```typescript\n * const stats = await kitbase.getQueueStats();\n * console.log(stats); // { size: 5, isFlushing: false }\n * ```\n */\n async getQueueStats(): Promise<QueueStats | null> {\n if (!this.queue) return null;\n return this.queue.getStats();\n }\n\n /**\n * Manually flush the offline queue\n * Events are automatically flushed on interval and when coming back online,\n * but this method can be used to trigger an immediate flush\n *\n * @example\n * ```typescript\n * await kitbase.flushQueue();\n * ```\n */\n async flushQueue(): Promise<void> {\n if (!this.queue) return;\n await this.queue.flush();\n }\n\n /**\n * Clear all events from the offline queue\n *\n * @example\n * ```typescript\n * await kitbase.clearQueue();\n * ```\n */\n async clearQueue(): Promise<void> {\n if (!this.queue) return;\n await this.queue.clear();\n }\n\n /**\n * Callback for the queue to send batched events via the batch endpoint.\n * Sends all events in a single HTTP request instead of individual POSTs.\n */\n private async sendQueuedEvents(events: QueuedEvent[]): Promise<number[]> {\n try {\n await this.sendRequest('/sdk/v1/logs/batch', {\n events: events.map((e) => e.payload),\n });\n return events.map((e) => e.id!);\n } catch (error) {\n this.log('Batch send failed', { count: events.length, error });\n return [];\n }\n }\n\n // ============================================================\n // Track Event Override\n // ============================================================\n\n /**\n * Track an event\n *\n * When offline queueing is enabled, events are always written to the local\n * database first (write-ahead), then sent to the server. This ensures no\n * events are lost if the browser crashes or the network fails.\n *\n * @param options - Event tracking options\n * @returns Promise resolving to the track response, or void if tracking is blocked\n * @throws {ValidationError} When required fields are missing\n * @throws {AuthenticationError} When the API key is invalid (only when offline disabled)\n * @throws {ApiError} When the API returns an error (only when offline disabled)\n * @throws {TimeoutError} When the request times out (only when offline disabled)\n */\n override async track(options: TrackOptions): Promise<TrackResponse | void> {\n this.validateTrackOptions(options);\n\n // Check if bot blocking is active\n if (this.isBotBlockingActive()) {\n this.log('Event skipped - bot detected', { event: options.event });\n return;\n }\n\n // Calculate duration if this event was being timed\n let duration: number | undefined;\n const startTime = this.timedEvents.get(options.event);\n if (startTime !== undefined) {\n duration = (Date.now() - startTime) / 1000;\n this.timedEvents.delete(options.event);\n this.log('Timer stopped', { event: options.event, duration });\n }\n\n // Merge super properties with event tags (event tags take precedence)\n const mergedTags: Tags = {\n ...this.superProperties,\n ...(options.tags ?? {}),\n ...(duration !== undefined ? { $duration: duration } : {}),\n };\n\n const payload: LogPayload = {\n channel: options.channel,\n event: options.event,\n client_timestamp: Date.now(),\n client_session_id: this.getClientSessionId(),\n ...(options.user_id && { user_id: options.user_id }),\n ...(options.icon && { icon: options.icon }),\n ...(options.notify !== undefined && { notify: options.notify }),\n ...(options.description && { description: options.description }),\n ...(Object.keys(mergedTags).length > 0 && { tags: mergedTags }),\n };\n\n this.log('Track', { event: options.event, payload });\n\n // If offline queueing is enabled, use write-ahead pattern\n if (this.queue) {\n // Always write to DB first (guaranteed durability)\n await this.queue.enqueue(payload);\n this.log('Event persisted to queue');\n\n // Trigger an immediate flush attempt (non-blocking)\n this.queue.flush().catch((err) => {\n this.log('Background flush failed', err);\n });\n\n // Return immediately after DB write\n return {\n id: `queued-${Date.now()}`,\n event: options.event,\n timestamp: new Date().toISOString(),\n };\n }\n\n // No offline queue - send directly (original behavior)\n const response = await this.sendRequest<TrackResponse>('/sdk/v1/logs', payload);\n this.log('Event sent successfully', { id: response.id });\n return response;\n }\n\n protected override validateTrackOptions(options: TrackOptions): void {\n if (!options.event) {\n throw new ValidationError('Event is required', 'event');\n }\n }\n\n // ============================================================\n // Cleanup\n // ============================================================\n\n /**\n * Shutdown the client and cleanup resources\n * Call this when you're done using the client to stop timers and close connections\n *\n * @example\n * ```typescript\n * await kitbase.shutdown();\n * ```\n */\n override async shutdown(): Promise<void> {\n // Flush queue before plugin teardown so teardown events can still be queued\n if (this.queue) {\n await this.queue.flush();\n }\n\n // Base shutdown: tears down plugins, clears timed events\n super.shutdown();\n\n // Final flush and close queue\n if (this.queue) {\n await this.queue.flush();\n await this.queue.close();\n this.queue = null;\n }\n }\n}\n"],"mappings":"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","names":["KitbaseAnalytics","isBot","isBrowser","Dexie","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","KitbaseAnalytics"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/botDetection.ts","../src/plugins/utils.ts","../src/client-base.ts","../src/queue/index.ts","../src/plugins/page-view.ts","../src/plugins/outbound-links.ts","../src/plugins/click-tracking.ts","../src/plugins/scroll-depth.ts","../src/plugins/visibility.ts","../src/plugins/web-vitals.ts","../src/plugins/frustration.ts","../src/plugins/defaults.ts","../src/client.ts"],"sourcesContent":["// Main client\nexport { KitbaseAnalytics, init, getInstance } from './client.js';\n\n// Types\nexport type {\n KitbaseConfig,\n TrackOptions,\n TrackResponse,\n Tags,\n TagValue,\n OfflineConfig,\n // Analytics types\n AnalyticsConfig,\n PageViewOptions,\n RevenueOptions,\n IdentifyOptions,\n // Bot detection types (@internal)\n BotDetectionConfig,\n} from './types.js';\n\n// Queue types\nexport type { QueuedEvent, QueueStats } from './queue/types.js';\n\n// Bot detection utilities (@internal — may change without notice)\nexport {\n detectBot,\n isBot,\n isUserAgentBot,\n getUserAgent,\n type BotDetectionResult,\n} from './botDetection.js';\n\n// Errors\nexport {\n KitbaseError,\n ApiError,\n AuthenticationError,\n ValidationError,\n TimeoutError,\n} from './errors.js';\n\n// Plugin system\nexport type { KitbasePlugin, PluginContext } from './plugins/types.js';\nexport {\n createDefaultPlugins,\n PageViewPlugin,\n OutboundLinksPlugin,\n ClickTrackingPlugin,\n ScrollDepthPlugin,\n VisibilityPlugin,\n WebVitalsPlugin,\n FrustrationPlugin,\n} from './plugins/index.js';\n","/**\n * Base error class for Kitbase SDK errors\n */\nexport class KitbaseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'KitbaseError';\n Object.setPrototypeOf(this, KitbaseError.prototype);\n }\n}\n\n/**\n * Error thrown when API authentication fails\n */\nexport class AuthenticationError extends KitbaseError {\n constructor(message = 'Invalid API key') {\n super(message);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Error thrown when the API request fails\n */\nexport class ApiError extends KitbaseError {\n public readonly statusCode: number;\n public readonly response?: unknown;\n\n constructor(message: string, statusCode: number, response?: unknown) {\n super(message);\n this.name = 'ApiError';\n this.statusCode = statusCode;\n this.response = response;\n Object.setPrototypeOf(this, ApiError.prototype);\n }\n}\n\n/**\n * Error thrown when request validation fails\n */\nexport class ValidationError extends KitbaseError {\n public readonly field?: string;\n\n constructor(message: string, field?: string) {\n super(message);\n this.name = 'ValidationError';\n this.field = field;\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\n/**\n * Error thrown when a request times out\n */\nexport class TimeoutError extends KitbaseError {\n constructor(message = 'Request timed out') {\n super(message);\n this.name = 'TimeoutError';\n Object.setPrototypeOf(this, TimeoutError.prototype);\n }\n}\n\n\n\n\n\n\n\n\n","/**\n * Bot detection module for filtering automated traffic\n *\n * Detects common automation tools, headless browsers, and bot user agents.\n * Inspired by DataFast's bot detection approach.\n */\n\n/**\n * Known automation tool global variables\n */\nconst AUTOMATION_GLOBALS = [\n '__webdriver_evaluate',\n '__selenium_evaluate',\n '__webdriver_script_function',\n '__webdriver_unwrapped',\n '__fxdriver_evaluate',\n '__driver_evaluate',\n '_Selenium_IDE_Recorder',\n '_selenium',\n 'calledSelenium',\n '$cdc_asdjflasutopfhvcZLmcfl_', // Chrome DevTools Protocol marker\n '__nightmare',\n 'domAutomation',\n 'domAutomationController',\n] as const;\n\n/**\n * Known headless browser user agent patterns\n */\nconst HEADLESS_PATTERNS = [\n 'headlesschrome',\n 'phantomjs',\n 'selenium',\n 'webdriver',\n 'puppeteer',\n 'playwright',\n] as const;\n\n/**\n * Known HTTP client / bot user agent patterns\n */\nconst HTTP_CLIENT_PATTERNS = [\n 'python',\n 'curl',\n 'wget',\n 'java/',\n 'go-http',\n 'node-fetch',\n 'axios',\n 'postman',\n 'insomnia',\n 'httpie',\n 'ruby',\n 'perl',\n 'scrapy',\n 'bot',\n 'spider',\n 'crawler',\n 'slurp',\n 'googlebot',\n 'bingbot',\n 'yandexbot',\n 'baiduspider',\n 'duckduckbot',\n 'facebookexternalhit',\n 'twitterbot',\n 'linkedinbot',\n 'whatsapp',\n 'telegram',\n 'discord',\n 'slack',\n] as const;\n\n/**\n * Bot detection result\n * @internal This is an internal API and may change without notice.\n */\nexport interface BotDetectionResult {\n isBot: boolean;\n reason?: string;\n checks: {\n webdriver: boolean;\n phantomjs: boolean;\n nightmare: boolean;\n automationGlobals: boolean;\n documentAttributes: boolean;\n userAgentHeadless: boolean;\n userAgentHttpClient: boolean;\n missingUserAgent: boolean;\n invalidEnvironment: boolean;\n };\n}\n\n/**\n * Configuration for bot detection\n * @internal This is an internal API and may change without notice.\n */\nexport interface BotDetectionConfig {\n /**\n * Enable bot detection.\n * When enabled and a bot is detected, all tracking events are blocked.\n * Set to false to disable bot detection.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Check for webdriver flag (Chrome, Firefox)\n * @default true\n */\n checkWebdriver?: boolean;\n\n /**\n * Check for PhantomJS\n * @default true\n */\n checkPhantomJS?: boolean;\n\n /**\n * Check for Nightmare.js\n * @default true\n */\n checkNightmare?: boolean;\n\n /**\n * Check for automation tool globals\n * @default true\n */\n checkAutomationGlobals?: boolean;\n\n /**\n * Check document element attributes\n * @default true\n */\n checkDocumentAttributes?: boolean;\n\n /**\n * Check user agent for headless browsers\n * @default true\n */\n checkUserAgentHeadless?: boolean;\n\n /**\n * Check user agent for HTTP clients/bots\n * @default true\n */\n checkUserAgentHttpClient?: boolean;\n\n /**\n * Additional user agent patterns to detect as bots\n */\n additionalBotPatterns?: string[];\n\n /**\n * Callback when a bot is detected\n */\n onBotDetected?: (result: BotDetectionResult) => void;\n}\n\n/**\n * Default bot detection configuration\n * @internal This is an internal API and may change without notice.\n */\nexport const DEFAULT_BOT_DETECTION_CONFIG: Required<Omit<BotDetectionConfig, 'additionalBotPatterns' | 'onBotDetected'>> = {\n enabled: true,\n checkWebdriver: true,\n checkPhantomJS: true,\n checkNightmare: true,\n checkAutomationGlobals: true,\n checkDocumentAttributes: true,\n checkUserAgentHeadless: true,\n checkUserAgentHttpClient: true,\n};\n\n/**\n * Check if running in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Safely get window property\n */\nfunction getWindowProperty(key: string): unknown {\n try {\n return (window as unknown as Record<string, unknown>)[key];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Check for webdriver flag\n */\nfunction checkWebdriver(): boolean {\n if (!isBrowser()) return false;\n\n try {\n return window.navigator?.webdriver === true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check for PhantomJS\n */\nfunction checkPhantomJS(): boolean {\n if (!isBrowser()) return false;\n\n try {\n return !!(\n getWindowProperty('callPhantom') ||\n getWindowProperty('_phantom') ||\n getWindowProperty('phantom')\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Check for Nightmare.js\n */\nfunction checkNightmare(): boolean {\n if (!isBrowser()) return false;\n\n try {\n return !!getWindowProperty('__nightmare');\n } catch {\n return false;\n }\n}\n\n/**\n * Check for automation tool globals\n */\nfunction checkAutomationGlobals(): boolean {\n if (!isBrowser()) return false;\n\n try {\n for (const global of AUTOMATION_GLOBALS) {\n if (getWindowProperty(global) !== undefined) {\n return true;\n }\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Check for webdriver/selenium attributes on document element\n */\nfunction checkDocumentAttributes(): boolean {\n if (!isBrowser()) return false;\n\n try {\n const docEl = document.documentElement;\n if (!docEl) return false;\n\n return !!(\n docEl.getAttribute('webdriver') ||\n docEl.getAttribute('selenium') ||\n docEl.getAttribute('driver')\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Check user agent for headless browser patterns\n */\nfunction checkUserAgentHeadless(): boolean {\n if (!isBrowser()) return false;\n\n try {\n const ua = window.navigator?.userAgent?.toLowerCase() || '';\n if (!ua) return false;\n\n for (const pattern of HEADLESS_PATTERNS) {\n if (ua.includes(pattern)) {\n return true;\n }\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Check user agent for HTTP client patterns\n */\nfunction checkUserAgentHttpClient(additionalPatterns?: string[]): boolean {\n if (!isBrowser()) return false;\n\n try {\n const ua = window.navigator?.userAgent?.toLowerCase() || '';\n if (!ua) return false;\n\n // Check built-in patterns\n for (const pattern of HTTP_CLIENT_PATTERNS) {\n if (ua.includes(pattern)) {\n return true;\n }\n }\n\n // Check additional patterns\n if (additionalPatterns) {\n for (const pattern of additionalPatterns) {\n if (ua.includes(pattern.toLowerCase())) {\n return true;\n }\n }\n }\n\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Check for missing or invalid user agent\n */\nfunction checkMissingUserAgent(): boolean {\n if (!isBrowser()) return false;\n\n try {\n const ua = window.navigator?.userAgent;\n return !ua || ua === '' || ua === 'undefined' || ua.length < 10;\n } catch {\n return false;\n }\n}\n\n/**\n * Check for invalid browser environment (missing required objects)\n */\nfunction checkInvalidEnvironment(): boolean {\n if (!isBrowser()) return false;\n\n try {\n // Check for missing or fake navigator/location/document\n if (\n !window.navigator ||\n !window.location ||\n !window.document ||\n typeof window.navigator !== 'object' ||\n typeof window.location !== 'object' ||\n typeof window.document !== 'object'\n ) {\n return true;\n }\n return false;\n } catch {\n return true;\n }\n}\n\n/**\n * Detect if the current visitor is a bot\n *\n * @internal This is an internal API and may change without notice.\n * @param config - Bot detection configuration\n * @returns Bot detection result\n *\n * @example\n * ```typescript\n * const result = detectBot();\n * if (result.isBot) {\n * console.log('Bot detected:', result.reason);\n * }\n * ```\n */\nexport function detectBot(config: BotDetectionConfig = {}): BotDetectionResult {\n const mergedConfig = { ...DEFAULT_BOT_DETECTION_CONFIG, ...config };\n\n const checks = {\n webdriver: mergedConfig.checkWebdriver ? checkWebdriver() : false,\n phantomjs: mergedConfig.checkPhantomJS ? checkPhantomJS() : false,\n nightmare: mergedConfig.checkNightmare ? checkNightmare() : false,\n automationGlobals: mergedConfig.checkAutomationGlobals ? checkAutomationGlobals() : false,\n documentAttributes: mergedConfig.checkDocumentAttributes ? checkDocumentAttributes() : false,\n userAgentHeadless: mergedConfig.checkUserAgentHeadless ? checkUserAgentHeadless() : false,\n userAgentHttpClient: mergedConfig.checkUserAgentHttpClient\n ? checkUserAgentHttpClient(config.additionalBotPatterns)\n : false,\n missingUserAgent: checkMissingUserAgent(),\n invalidEnvironment: checkInvalidEnvironment(),\n };\n\n // Determine the reason for bot detection\n let reason: string | undefined;\n if (checks.webdriver) {\n reason = 'WebDriver detected';\n } else if (checks.phantomjs) {\n reason = 'PhantomJS detected';\n } else if (checks.nightmare) {\n reason = 'Nightmare.js detected';\n } else if (checks.automationGlobals) {\n reason = 'Automation tool globals detected';\n } else if (checks.documentAttributes) {\n reason = 'Automation attributes on document element';\n } else if (checks.userAgentHeadless) {\n reason = 'Headless browser user agent detected';\n } else if (checks.userAgentHttpClient) {\n reason = 'HTTP client/bot user agent detected';\n } else if (checks.missingUserAgent) {\n reason = 'Missing or invalid user agent';\n } else if (checks.invalidEnvironment) {\n reason = 'Invalid browser environment';\n }\n\n const isBot = Object.values(checks).some(Boolean);\n\n const result: BotDetectionResult = {\n isBot,\n reason,\n checks,\n };\n\n // Call callback if provided and bot was detected\n if (isBot && config.onBotDetected) {\n try {\n config.onBotDetected(result);\n } catch {\n // Ignore callback errors\n }\n }\n\n return result;\n}\n\n/**\n * Quick check if current visitor is a bot\n *\n * @internal This is an internal API and may change without notice.\n * @param config - Bot detection configuration\n * @returns true if bot detected, false otherwise\n *\n * @example\n * ```typescript\n * if (isBot()) {\n * console.log('Bot detected, skipping tracking');\n * return;\n * }\n * ```\n */\nexport function isBot(config: BotDetectionConfig = {}): boolean {\n return detectBot(config).isBot;\n}\n\n/**\n * Check a custom user agent string for bot patterns\n * Useful for server-side bot detection\n *\n * @internal This is an internal API and may change without notice.\n * @param userAgent - The user agent string to check\n * @param additionalPatterns - Additional patterns to check\n * @returns true if bot user agent detected\n *\n * @example\n * ```typescript\n * // Server-side usage\n * const ua = request.headers['user-agent'];\n * if (isUserAgentBot(ua)) {\n * console.log('Bot request detected');\n * }\n * ```\n */\nexport function isUserAgentBot(userAgent: string, additionalPatterns?: string[]): boolean {\n if (!userAgent || userAgent.length < 10) {\n return true;\n }\n\n const ua = userAgent.toLowerCase();\n\n // Check headless patterns\n for (const pattern of HEADLESS_PATTERNS) {\n if (ua.includes(pattern)) {\n return true;\n }\n }\n\n // Check HTTP client patterns\n for (const pattern of HTTP_CLIENT_PATTERNS) {\n if (ua.includes(pattern)) {\n return true;\n }\n }\n\n // Check additional patterns\n if (additionalPatterns) {\n for (const pattern of additionalPatterns) {\n if (ua.includes(pattern.toLowerCase())) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Get the current user agent (browser only)\n *\n * @internal This is an internal API and may change without notice.\n * @returns User agent string or null if not in browser\n */\nexport function getUserAgent(): string | null {\n if (!isBrowser()) return null;\n\n try {\n return window.navigator?.userAgent || null;\n } catch {\n return null;\n }\n}\n","import type { Tags } from '../types-lite.js';\n\n/**\n * CSS selector matching interactive elements for click tracking.\n * Includes standard HTML elements and common ARIA roles.\n */\nexport const CLICKABLE_SELECTOR = [\n 'a', 'button', 'input', 'select', 'textarea',\n '[role=\"button\"]', '[role=\"link\"]', '[role=\"menuitem\"]', '[role=\"tab\"]',\n].join(', ');\n\n/**\n * Find the nearest clickable element from a click event.\n * Uses `composedPath()` to traverse through Shadow DOM boundaries.\n * When a match is found inside a Shadow DOM, the custom-element host\n * is returned so that tracked attributes reflect the public component.\n */\nexport function findClickableElement(event: MouseEvent): Element | null {\n const path = event.composedPath?.() as Element[] | undefined;\n\n if (path) {\n for (const node of path) {\n if (!(node instanceof Element)) continue;\n if (node === document.documentElement) break;\n\n if (node.matches(CLICKABLE_SELECTOR)) {\n const root = node.getRootNode();\n if (root instanceof ShadowRoot && root.host instanceof Element) {\n return root.host;\n }\n return node;\n }\n\n // Custom elements (tag name contains a hyphen per spec)\n if (node.tagName.includes('-')) {\n return node;\n }\n }\n }\n\n // Fallback for browsers without composedPath\n const target = event.target as Element | null;\n if (!target?.closest) return null;\n return target.closest(CLICKABLE_SELECTOR);\n}\n\n/**\n * Build a lightweight CSS selector for an element.\n * Used to identify frustration signal targets.\n */\nexport function buildCssSelector(el: Element): string {\n if (el.id) return `#${el.id}`;\n const tag = el.tagName.toLowerCase();\n const classes = el.className && typeof el.className === 'string'\n ? '.' + el.className.trim().split(/\\s+/).slice(0, 2).join('.')\n : '';\n if (classes) return `${tag}${classes}`;\n return tag;\n}\n\n/**\n * Get root domain from hostname (e.g., blog.example.com -> example.com)\n */\nexport function getRootDomain(hostname: string): string {\n const parts = hostname.replace(/^www\\./, '').split('.');\n if (parts.length >= 2) {\n return parts.slice(-2).join('.');\n }\n return hostname;\n}\n\n/**\n * Check if two hostnames share the same root domain\n */\nexport function isSameRootDomain(host1: string, host2: string): boolean {\n return getRootDomain(host1) === getRootDomain(host2);\n}\n\n/**\n * Get UTM parameters from current URL\n */\nexport function getUtmParams(): Tags {\n if (typeof window === 'undefined') return {};\n\n const params = new URLSearchParams(window.location.search);\n const utmParams: Tags = {};\n\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];\n for (const key of utmKeys) {\n const value = params.get(key);\n if (value) {\n utmParams[`__${key}`] = value;\n }\n }\n\n return utmParams;\n}\n","import type {\n TrackOptions,\n TrackResponse,\n LogPayload,\n Tags,\n PageViewOptions,\n RevenueOptions,\n IdentifyOptions,\n} from './types.js';\nimport type { KitbaseLiteConfig } from './types-lite.js';\nimport {\n ApiError,\n AuthenticationError,\n TimeoutError,\n ValidationError,\n} from './errors.js';\nimport {\n detectBot,\n DEFAULT_BOT_DETECTION_CONFIG,\n type BotDetectionConfig,\n type BotDetectionResult,\n} from './botDetection.js';\nimport type { KitbasePlugin, PluginContext } from './plugins/types.js';\nimport {\n findClickableElement,\n CLICKABLE_SELECTOR,\n getRootDomain,\n isSameRootDomain,\n getUtmParams,\n} from './plugins/utils.js';\n\nconst DEFAULT_BASE_URL = 'https://api.kitbase.dev';\nconst TIMEOUT = 30000;\nconst ANALYTICS_CHANNEL = '__analytics';\n\n/**\n * Kitbase base client for tracking events (lite version without offline queue)\n *\n * This is a lightweight version of the Kitbase client that sends events\n * directly to the API without offline queueing support.\n *\n * @example\n * ```typescript\n * import { Kitbase } from '@kitbase/analytics/lite';\n *\n * const kitbase = new Kitbase({\n * sdkKey: '<YOUR_API_KEY>',\n * debug: true,\n * });\n *\n * // Register super properties (included in all events)\n * kitbase.register({ app_version: '2.1.0', platform: 'web' });\n *\n * // Track events\n * await kitbase.track({\n * channel: 'payments',\n * event: 'Page Viewed',\n * icon: '👀',\n * });\n * ```\n */\nexport class KitbaseAnalytics {\n protected readonly sdkKey: string;\n protected readonly baseUrl: string;\n\n // Super properties (memory-only, merged into all events)\n protected superProperties: Tags = {};\n\n // Time event tracking\n protected timedEvents: Map<string, number> = new Map();\n\n // Debug mode\n protected debugMode: boolean;\n\n // Analytics config (stored for PluginContext)\n protected analyticsConfig: KitbaseLiteConfig['analytics'];\n\n protected userId: string | null = null;\n\n // Bot detection\n protected botDetectionConfig: BotDetectionConfig;\n protected botDetectionResult: BotDetectionResult | null = null;\n\n // Client-side session tracking\n private clientSessionId: string | null = null;\n private lastActivityAt: number = 0;\n private static readonly SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n\n // Plugin system\n private _plugins: Map<string, KitbasePlugin> = new Map();\n private _pluginContext: PluginContext | null = null;\n\n constructor(config: KitbaseLiteConfig, defaultPlugins?: KitbasePlugin[]) {\n if (!config.sdkKey) {\n throw new ValidationError('SDK key is required', 'sdkKey');\n }\n\n this.sdkKey = config.sdkKey;\n // Remove trailing slashes to prevent double-slash in URLs\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.debugMode = config.debug ?? false;\n\n // Store analytics config for plugin context\n this.analyticsConfig = config.analytics;\n\n // Initialize bot detection\n this.botDetectionConfig = {\n ...DEFAULT_BOT_DETECTION_CONFIG,\n ...config.botDetection,\n };\n\n if (this.botDetectionConfig.enabled) {\n this.botDetectionResult = detectBot(this.botDetectionConfig);\n if (this.botDetectionResult.isBot) {\n this.log('Bot detected', {\n reason: this.botDetectionResult.reason,\n checks: this.botDetectionResult.checks,\n });\n } else {\n this.log('Bot detection enabled, no bot detected');\n }\n }\n\n // Register default plugins\n if (defaultPlugins) {\n for (const plugin of defaultPlugins) {\n this.use(plugin);\n }\n }\n }\n\n // ============================================================\n // Plugin System\n // ============================================================\n\n /**\n * Register a plugin\n *\n * @param plugin - The plugin instance to register\n *\n * @example\n * ```typescript\n * kitbase.use(new WebVitalsPlugin());\n * ```\n */\n use(plugin: KitbasePlugin): void {\n if (this._plugins.has(plugin.name)) {\n this.log(`Plugin \"${plugin.name}\" already registered`);\n return;\n }\n\n const ctx = this.getPluginContext();\n const result = plugin.setup(ctx);\n if (result === false) {\n this.log(`Plugin \"${plugin.name}\" declined to activate`);\n return;\n }\n\n this._plugins.set(plugin.name, plugin);\n\n // Install public methods from plugin\n const methods = plugin.methods;\n if (methods) {\n for (const [name, fn] of Object.entries(methods)) {\n (this as any)[name] = fn;\n }\n }\n\n this.log(`Plugin \"${plugin.name}\" registered`);\n }\n\n /**\n * Get the names of all registered plugins\n */\n getPlugins(): string[] {\n return Array.from(this._plugins.keys());\n }\n\n private getPluginContext(): PluginContext {\n if (this._pluginContext) return this._pluginContext;\n\n this._pluginContext = {\n track: (options: TrackOptions) => this.track(options),\n config: Object.freeze({\n autoTrackPageViews: this.analyticsConfig?.autoTrackPageViews,\n autoTrackOutboundLinks: this.analyticsConfig?.autoTrackOutboundLinks,\n autoTrackClicks: this.analyticsConfig?.autoTrackClicks,\n autoTrackScrollDepth: this.analyticsConfig?.autoTrackScrollDepth,\n autoTrackVisibility: this.analyticsConfig?.autoTrackVisibility,\n autoTrackWebVitals: this.analyticsConfig?.autoTrackWebVitals,\n autoDetectFrustration: this.analyticsConfig?.autoDetectFrustration,\n }),\n debug: this.debugMode,\n log: (message: string, data?: unknown) => this.log(message, data),\n isBotBlockingActive: () => this.isBotBlockingActive(),\n findClickableElement,\n CLICKABLE_SELECTOR,\n getRootDomain,\n isSameRootDomain,\n getUtmParams,\n };\n\n return this._pluginContext;\n }\n\n // ============================================================\n // Debug Mode\n // ============================================================\n\n /**\n * Enable or disable debug mode\n * When enabled, all SDK operations are logged to the console\n *\n * @param enabled - Whether to enable debug mode\n *\n * @example\n * ```typescript\n * kitbase.setDebugMode(true);\n * // All events and operations will now be logged\n * ```\n */\n setDebugMode(enabled: boolean): void {\n this.debugMode = enabled;\n this.log(`Debug mode ${enabled ? 'enabled' : 'disabled'}`);\n }\n\n /**\n * Check if debug mode is enabled\n */\n isDebugMode(): boolean {\n return this.debugMode;\n }\n\n /**\n * Internal logging function\n */\n protected log(message: string, data?: unknown): void {\n if (!this.debugMode) return;\n\n const prefix = '[Kitbase]';\n if (data !== undefined) {\n console.log(prefix, message, data);\n } else {\n console.log(prefix, message);\n }\n }\n\n // ============================================================\n // Super Properties\n // ============================================================\n\n /**\n * Register super properties that will be included with every event\n * These properties are stored in memory only and reset on page reload\n *\n * @param properties - Properties to register\n *\n * @example\n * ```typescript\n * kitbase.register({\n * app_version: '2.1.0',\n * platform: 'web',\n * environment: 'production',\n * });\n * ```\n */\n register(properties: Tags): void {\n this.superProperties = { ...this.superProperties, ...properties };\n this.log('Super properties registered', properties);\n }\n\n /**\n * Register super properties only if they haven't been set yet\n * Useful for setting default values that shouldn't override existing ones\n *\n * @param properties - Properties to register if not already set\n *\n * @example\n * ```typescript\n * kitbase.registerOnce({ first_visit: new Date().toISOString() });\n * ```\n */\n registerOnce(properties: Tags): void {\n const newProps: Tags = {};\n for (const [key, value] of Object.entries(properties)) {\n if (!(key in this.superProperties)) {\n newProps[key] = value;\n }\n }\n if (Object.keys(newProps).length > 0) {\n this.superProperties = { ...this.superProperties, ...newProps };\n this.log('Super properties registered (once)', newProps);\n }\n }\n\n /**\n * Remove a super property\n *\n * @param key - The property key to remove\n *\n * @example\n * ```typescript\n * kitbase.unregister('platform');\n * ```\n */\n unregister(key: string): void {\n if (key in this.superProperties) {\n delete this.superProperties[key];\n this.log('Super property removed', { key });\n }\n }\n\n /**\n * Get all registered super properties\n *\n * @returns A copy of the current super properties\n *\n * @example\n * ```typescript\n * const props = kitbase.getSuperProperties();\n * console.log(props); // { app_version: '2.1.0', platform: 'web' }\n * ```\n */\n getSuperProperties(): Tags {\n return { ...this.superProperties };\n }\n\n /**\n * Clear all super properties\n *\n * @example\n * ```typescript\n * kitbase.clearSuperProperties();\n * ```\n */\n clearSuperProperties(): void {\n this.superProperties = {};\n this.log('Super properties cleared');\n }\n\n // ============================================================\n // Time Events (Duration Tracking)\n // ============================================================\n\n /**\n * Start timing an event\n * When the same event is tracked later, a $duration property (in seconds)\n * will automatically be included\n *\n * @param eventName - The name of the event to time\n *\n * @example\n * ```typescript\n * kitbase.timeEvent('Video Watched');\n * // ... user watches video ...\n * await kitbase.track({\n * channel: 'engagement',\n * event: 'Video Watched',\n * tags: { video_id: '123' }\n * });\n * // Event will include $duration: 45.2 (seconds)\n * ```\n */\n timeEvent(eventName: string): void {\n this.timedEvents.set(eventName, Date.now());\n this.log('Timer started', { event: eventName });\n }\n\n /**\n * Cancel a timed event without tracking it\n *\n * @param eventName - The name of the event to cancel timing for\n *\n * @example\n * ```typescript\n * kitbase.timeEvent('Checkout Flow');\n * // User abandons checkout\n * kitbase.cancelTimeEvent('Checkout Flow');\n * ```\n */\n cancelTimeEvent(eventName: string): void {\n if (this.timedEvents.has(eventName)) {\n this.timedEvents.delete(eventName);\n this.log('Timer cancelled', { event: eventName });\n }\n }\n\n /**\n * Get all currently timed events\n *\n * @returns Array of event names that are currently being timed\n *\n * @example\n * ```typescript\n * const timedEvents = kitbase.getTimedEvents();\n * console.log(timedEvents); // ['Video Watched', 'Checkout Flow']\n * ```\n */\n getTimedEvents(): string[] {\n return Array.from(this.timedEvents.keys());\n }\n\n /**\n * Get the duration of a timed event (without stopping it)\n * @internal\n *\n * @param eventName - The name of the event\n * @returns Duration in seconds, or null if not being timed\n */\n getEventDuration(eventName: string): number | null {\n const startTime = this.timedEvents.get(eventName);\n if (startTime === undefined) return null;\n return (Date.now() - startTime) / 1000;\n }\n\n // ============================================================\n // Bot Detection\n // ============================================================\n\n /**\n * Check if the current visitor is detected as a bot\n *\n * @internal This is an internal API and may change without notice.\n * @returns true if bot detected, false otherwise\n *\n * @example\n * ```typescript\n * if (kitbase.isBot()) {\n * console.log('Bot detected, tracking disabled');\n * }\n * ```\n */\n isBot(): boolean {\n if (!this.botDetectionConfig?.enabled) {\n return false;\n }\n\n // Re-run detection if not yet done\n if (!this.botDetectionResult) {\n this.botDetectionResult = detectBot(this.botDetectionConfig);\n }\n\n return this.botDetectionResult.isBot;\n }\n\n /**\n * Get detailed bot detection result\n *\n * @internal This is an internal API and may change without notice.\n * @returns Bot detection result with detailed checks, or null if detection not enabled\n *\n * @example\n * ```typescript\n * const result = kitbase.getBotDetectionResult();\n * if (result?.isBot) {\n * console.log('Bot detected:', result.reason);\n * console.log('Checks:', result.checks);\n * }\n * ```\n */\n getBotDetectionResult(): BotDetectionResult | null {\n if (!this.botDetectionConfig.enabled) {\n return null;\n }\n\n // Re-run detection if not yet done\n if (!this.botDetectionResult) {\n this.botDetectionResult = detectBot(this.botDetectionConfig);\n }\n\n return this.botDetectionResult;\n }\n\n /**\n * Force re-run bot detection\n * Useful if you want to check again after page state changes\n *\n * @internal This is an internal API and may change without notice.\n * @returns Updated bot detection result\n *\n * @example\n * ```typescript\n * const result = kitbase.redetectBot();\n * console.log('Is bot:', result.isBot);\n * ```\n */\n redetectBot(): BotDetectionResult {\n this.botDetectionResult = detectBot(this.botDetectionConfig);\n this.log('Bot detection re-run', {\n isBot: this.botDetectionResult.isBot,\n reason: this.botDetectionResult.reason,\n });\n return this.botDetectionResult;\n }\n\n /**\n * Check if bot blocking is currently active\n * When bot detection is enabled and a bot is detected, all events are blocked.\n *\n * @internal This is an internal API and may change without notice.\n * @returns true if bots are being blocked from tracking\n */\n isBotBlockingActive(): boolean {\n return this.botDetectionConfig?.enabled === true && this.isBot();\n }\n\n // ============================================================\n // Client Session Tracking\n // ============================================================\n\n /**\n * Get or create a client-side session ID.\n * Rotates the session after 30 minutes of inactivity.\n * @internal\n */\n protected getClientSessionId(): string {\n const now = Date.now();\n if (\n !this.clientSessionId ||\n (this.lastActivityAt > 0 && now - this.lastActivityAt > KitbaseAnalytics.SESSION_TIMEOUT_MS)\n ) {\n this.clientSessionId = KitbaseAnalytics.generateUUID();\n this.log('New client session started', { sessionId: this.clientSessionId });\n }\n this.lastActivityAt = now;\n return this.clientSessionId;\n }\n\n /**\n * Generate a UUID v4, with fallback for environments where\n * crypto.randomUUID() is not available (older WebViews, Ionic).\n */\n private static generateUUID(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n // Fallback using crypto.getRandomValues (wider browser/WebView support)\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n // Set version 4 and variant bits\n bytes[6] = (bytes[6]! & 0x0f) | 0x40;\n bytes[8] = (bytes[8]! & 0x3f) | 0x80;\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n // Last resort fallback (Math.random - not cryptographically secure but functional)\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 // Track Event\n // ============================================================\n\n /**\n * Track an event\n *\n * Events are sent directly to the API. For offline queueing support,\n * use the full Kitbase client instead.\n *\n * @param options - Event tracking options\n * @returns Promise resolving to the track response, or void if tracking is blocked\n * @throws {ValidationError} When required fields are missing\n * @throws {AuthenticationError} When the API key is invalid\n * @throws {ApiError} When the API returns an error\n * @throws {TimeoutError} When the request times out\n */\n async track(options: TrackOptions): Promise<TrackResponse | void> {\n this.validateTrackOptions(options);\n\n // Check if bot blocking is active\n if (this.isBotBlockingActive()) {\n this.log('Event skipped - bot detected', { event: options.event });\n return;\n }\n\n // Calculate duration if this event was being timed\n let duration: number | undefined;\n const startTime = this.timedEvents.get(options.event);\n if (startTime !== undefined) {\n duration = (Date.now() - startTime) / 1000;\n this.timedEvents.delete(options.event);\n this.log('Timer stopped', { event: options.event, duration });\n }\n\n // Merge super properties with event tags (event tags take precedence)\n const mergedTags: Tags = {\n ...this.superProperties,\n ...(options.tags ?? {}),\n ...(duration !== undefined ? { $duration: duration } : {}),\n };\n\n const payload: LogPayload = {\n channel: options.channel,\n event: options.event,\n client_timestamp: Date.now(),\n client_session_id: this.getClientSessionId(),\n ...(options.user_id && { user_id: options.user_id }),\n ...(options.icon && { icon: options.icon }),\n ...(options.notify !== undefined && { notify: options.notify }),\n ...(options.description && { description: options.description }),\n ...(Object.keys(mergedTags).length > 0 && { tags: mergedTags }),\n };\n\n this.log('Track', { event: options.event, payload });\n\n // Send directly to API\n const response = await this.sendRequest<TrackResponse>('/sdk/v1/logs', payload);\n this.log('Event sent successfully', { id: response.id });\n return response;\n }\n\n protected validateTrackOptions(options: TrackOptions): void {\n if (!options.event) {\n throw new ValidationError('Event is required', 'event');\n }\n }\n\n /**\n * Send a request to the API\n */\n protected async sendRequest<T>(endpoint: string, body: unknown): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), TIMEOUT);\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': `${this.sdkKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorBody = await this.parseResponseBody(response);\n\n if (response.status === 401) {\n throw new AuthenticationError();\n }\n\n throw new ApiError(\n this.getErrorMessage(errorBody, response.statusText),\n response.status,\n errorBody,\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new TimeoutError();\n }\n\n throw error;\n }\n }\n\n protected async parseResponseBody(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n return null;\n }\n }\n\n protected getErrorMessage(body: unknown, fallback: string): string {\n if (body && typeof body === 'object' && 'message' in body) {\n return String((body as { message: unknown }).message);\n }\n if (body && typeof body === 'object' && 'error' in body) {\n return String((body as { error: unknown }).error);\n }\n return fallback;\n }\n\n // ============================================================\n // Analytics — Stub methods (overridden by plugins via methods)\n // ============================================================\n\n /**\n * Track a page view\n *\n * @param options - Page view options\n * @returns Promise resolving to the track response\n *\n * @example\n * ```typescript\n * // Track current page\n * await kitbase.trackPageView();\n *\n * // Track with custom path\n * await kitbase.trackPageView({ path: '/products/123', title: 'Product Details' });\n * ```\n */\n async trackPageView(options?: PageViewOptions): Promise<TrackResponse | void> {\n this.log('trackPageView() called but page-view plugin is not registered');\n }\n\n /**\n * Track a click on an interactive element\n */\n async trackClick(tags: Tags): Promise<TrackResponse | void> {\n this.log('trackClick() called but click-tracking plugin is not registered');\n }\n\n /**\n * Track an outbound link click\n *\n * @param options - Outbound link options\n * @returns Promise resolving to the track response\n *\n * @example\n * ```typescript\n * await kitbase.trackOutboundLink({\n * url: 'https://example.com',\n * text: 'Visit Example',\n * });\n * ```\n */\n async trackOutboundLink(options: { url: string; text?: string }): Promise<TrackResponse | void> {\n this.log('trackOutboundLink() called but outbound-links plugin is not registered');\n }\n\n // ============================================================\n // Analytics — Revenue & Identity (non-plugin)\n // ============================================================\n\n /**\n * Track a revenue event\n *\n * @param options - Revenue options\n * @returns Promise resolving to the track response\n *\n * @example\n * ```typescript\n * // Track a $19.99 purchase\n * await kitbase.trackRevenue({\n * amount: 1999,\n * currency: 'USD',\n * tags: { product_id: 'prod_123', plan: 'premium' },\n * });\n * ```\n */\n async trackRevenue(options: RevenueOptions): Promise<TrackResponse | void> {\n return this.track({\n channel: ANALYTICS_CHANNEL,\n event: 'revenue',\n user_id: options.user_id ?? this.userId ?? undefined,\n tags: {\n __revenue: options.amount,\n __currency: options.currency ?? 'USD',\n ...(options.tags ?? {}),\n },\n });\n }\n\n /**\n * Identify a user\n * Sets the user identity on the server.\n * Call this when a user signs up or logs in.\n *\n * @param options - Identify options\n * @returns Promise that resolves when the identity is set\n *\n * @example\n * ```typescript\n * await kitbase.identify({\n * userId: 'user_123',\n * traits: { email: 'user@example.com', plan: 'premium' },\n * });\n * ```\n */\n async identify(options: IdentifyOptions): Promise<void> {\n this.userId = options.userId;\n\n // Register user traits as super properties\n if (options.traits) {\n this.register({\n __user_id: options.userId,\n ...options.traits,\n });\n } else {\n this.register({ __user_id: options.userId });\n }\n\n // Call the identify endpoint\n try {\n const response = await fetch(`${this.baseUrl}/sdk/v1/identify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': this.sdkKey,\n },\n body: JSON.stringify({\n user_id: options.userId,\n traits: options.traits,\n }),\n });\n\n if (!response.ok) {\n this.log('Identify API call failed', { status: response.status });\n } else {\n this.log('Identity set on server', {\n userId: options.userId,\n });\n }\n } catch (err) {\n this.log('Failed to call identify endpoint', err);\n }\n\n this.log('User identified', { userId: options.userId });\n }\n\n /**\n * Get the current user ID (set via identify)\n */\n getUserId(): string | null {\n return this.userId;\n }\n\n /**\n * Reset the user identity\n * Call this when a user logs out\n *\n * @example\n * ```typescript\n * kitbase.reset();\n * ```\n */\n reset(): void {\n // Clear user ID\n this.userId = null;\n\n // Clear client session\n this.clientSessionId = null;\n this.lastActivityAt = 0;\n\n // Clear super properties\n this.clearSuperProperties();\n\n this.log('User reset complete');\n }\n\n // ============================================================\n // Cleanup\n // ============================================================\n\n /**\n * Shutdown the client and cleanup resources\n * Call this when you're done using the client to stop timers and close connections\n *\n * @example\n * ```typescript\n * kitbase.shutdown();\n * ```\n */\n shutdown(): void {\n this.log('Shutting down');\n\n // Clear timed events\n this.timedEvents.clear();\n\n // Teardown plugins in reverse order\n const pluginNames = Array.from(this._plugins.keys()).reverse();\n for (const name of pluginNames) {\n const plugin = this._plugins.get(name)!;\n try {\n plugin.teardown();\n this.log(`Plugin \"${name}\" torn down`);\n } catch (err) {\n this.log(`Plugin \"${name}\" teardown failed`, err);\n }\n }\n this._plugins.clear();\n this._pluginContext = null;\n\n this.log('Shutdown complete');\n }\n}\n","import Dexie, { type Table } from 'dexie';\nimport type { LogPayload } from '../types.js';\nimport type {\n OfflineConfig,\n QueuedEvent,\n QueueStats,\n EventQueueInterface,\n SendEventsCallback,\n} from './types.js';\n\nconst DEFAULT_CONFIG: Required<OfflineConfig> = {\n enabled: false,\n maxQueueSize: 1000,\n flushInterval: 30000,\n flushBatchSize: 50,\n maxRetries: 3,\n retryBaseDelay: 1000,\n};\n\n/**\n * Check if IndexedDB is available\n */\nfunction isIndexedDBAvailable(): boolean {\n try {\n return (\n typeof window !== 'undefined' &&\n typeof window.indexedDB !== 'undefined' &&\n window.indexedDB !== null\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Check if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Dexie database for event queue\n */\nclass KitbaseQueueDB extends Dexie {\n events!: Table<QueuedEvent, number>;\n\n constructor(dbName: string) {\n super(dbName);\n this.version(1).stores({\n events: '++id, timestamp, retries, lastAttempt',\n });\n }\n}\n\n/**\n * In-memory queue implementation for Node.js or when IndexedDB is unavailable\n */\nclass MemoryQueue {\n private queue: QueuedEvent[] = [];\n private idCounter = 1;\n\n async enqueue(payload: LogPayload): Promise<number> {\n const event: QueuedEvent = {\n id: this.idCounter++,\n payload,\n timestamp: Date.now(),\n retries: 0,\n };\n this.queue.push(event);\n return event.id!;\n }\n\n async dequeue(count: number): Promise<QueuedEvent[]> {\n // Sort by timestamp (oldest first) and get the first `count` events\n this.queue.sort((a, b) => a.timestamp - b.timestamp);\n return this.queue.slice(0, count);\n }\n\n async delete(ids: number[]): Promise<void> {\n this.queue = this.queue.filter((e) => !ids.includes(e.id!));\n }\n\n async updateRetries(ids: number[]): Promise<void> {\n const now = Date.now();\n for (const event of this.queue) {\n if (ids.includes(event.id!)) {\n event.retries++;\n event.lastAttempt = now;\n }\n }\n }\n\n async getStats(): Promise<{ size: number; oldestEvent?: number }> {\n const size = this.queue.length;\n const oldestEvent =\n size > 0\n ? Math.min(...this.queue.map((e) => e.timestamp))\n : undefined;\n return { size, oldestEvent };\n }\n\n async clear(): Promise<void> {\n this.queue = [];\n }\n\n async enforceMaxSize(maxSize: number): Promise<void> {\n if (this.queue.length > maxSize) {\n // Sort by timestamp and keep only the newest events\n this.queue.sort((a, b) => a.timestamp - b.timestamp);\n this.queue = this.queue.slice(-maxSize);\n }\n }\n\n async getEventsExceedingRetries(maxRetries: number): Promise<number[]> {\n return this.queue\n .filter((e) => e.retries >= maxRetries)\n .map((e) => e.id!);\n }\n}\n\n/**\n * Event queue for offline support\n * Uses IndexedDB (via Dexie) in browser, in-memory queue in Node.js\n */\nexport class EventQueue implements EventQueueInterface {\n private readonly config: Required<OfflineConfig>;\n private readonly dbName: string;\n private db: KitbaseQueueDB | null = null;\n private memoryQueue: MemoryQueue | null = null;\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private isFlushing = false;\n private sendEvents: SendEventsCallback | null = null;\n private readonly useIndexedDB: boolean;\n private debugMode = false;\n private debugLogger: ((message: string, data?: unknown) => void) | null = null;\n\n constructor(config: OfflineConfig = {}, dbName = '_ka_events') {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.dbName = dbName;\n this.useIndexedDB = isIndexedDBAvailable();\n\n if (this.useIndexedDB) {\n this.db = new KitbaseQueueDB(this.dbName);\n } else {\n this.memoryQueue = new MemoryQueue();\n }\n }\n\n /**\n * Set debug mode and logger\n */\n setDebugMode(enabled: boolean, logger?: (message: string, data?: unknown) => void): void {\n this.debugMode = enabled;\n this.debugLogger = logger ?? null;\n }\n\n private log(message: string, data?: unknown): void {\n if (this.debugMode && this.debugLogger) {\n this.debugLogger(message, data);\n }\n }\n\n /**\n * Set the callback for sending events\n */\n setSendCallback(callback: SendEventsCallback): void {\n this.sendEvents = callback;\n }\n\n /**\n * Check if the queue storage is available\n */\n isAvailable(): boolean {\n return this.useIndexedDB || this.memoryQueue !== null;\n }\n\n /**\n * Get the storage type being used\n */\n getStorageType(): 'indexeddb' | 'memory' {\n return this.useIndexedDB ? 'indexeddb' : 'memory';\n }\n\n /**\n * Add an event to the queue\n */\n async enqueue(payload: LogPayload): Promise<void> {\n const event: Omit<QueuedEvent, 'id'> = {\n payload,\n timestamp: Date.now(),\n retries: 0,\n };\n\n if (this.useIndexedDB && this.db) {\n await this.db.events.add(event as QueuedEvent);\n this.log('Event queued to IndexedDB', payload);\n } else if (this.memoryQueue) {\n await this.memoryQueue.enqueue(payload);\n this.log('Event queued to memory', payload);\n }\n\n // Enforce max queue size\n await this.enforceMaxQueueSize();\n }\n\n /**\n * Get and remove the next batch of events to send\n */\n async dequeue(count: number): Promise<QueuedEvent[]> {\n if (this.useIndexedDB && this.db) {\n // Get events sorted by timestamp (oldest first), excluding those with too many retries\n return this.db.events\n .where('retries')\n .below(this.config.maxRetries)\n .sortBy('timestamp')\n .then((events) => events.slice(0, count));\n } else if (this.memoryQueue) {\n const events = await this.memoryQueue.dequeue(count);\n return events.filter((e) => e.retries < this.config.maxRetries);\n }\n return [];\n }\n\n /**\n * Mark events as successfully sent (remove from queue)\n */\n async markSent(ids: number[]): Promise<void> {\n if (ids.length === 0) return;\n\n if (this.useIndexedDB && this.db) {\n await this.db.events.bulkDelete(ids);\n this.log(`Removed ${ids.length} sent events from queue`);\n } else if (this.memoryQueue) {\n await this.memoryQueue.delete(ids);\n this.log(`Removed ${ids.length} sent events from memory queue`);\n }\n }\n\n /**\n * Mark events as failed and increment retry count\n */\n async markFailed(ids: number[]): Promise<void> {\n if (ids.length === 0) return;\n\n const now = Date.now();\n\n if (this.useIndexedDB && this.db) {\n await this.db.transaction('rw', this.db.events, async () => {\n for (const id of ids) {\n const event = await this.db!.events.get(id);\n if (event) {\n await this.db!.events.update(id, {\n retries: event.retries + 1,\n lastAttempt: now,\n });\n }\n }\n });\n this.log(`Marked ${ids.length} events as failed`);\n } else if (this.memoryQueue) {\n await this.memoryQueue.updateRetries(ids);\n this.log(`Marked ${ids.length} events as failed in memory queue`);\n }\n\n // Remove events that have exceeded max retries\n await this.removeExpiredRetries();\n }\n\n /**\n * Remove events that have exceeded max retry attempts\n */\n private async removeExpiredRetries(): Promise<void> {\n if (this.useIndexedDB && this.db) {\n const expiredIds = await this.db.events\n .where('retries')\n .aboveOrEqual(this.config.maxRetries)\n .primaryKeys();\n if (expiredIds.length > 0) {\n await this.db.events.bulkDelete(expiredIds);\n this.log(`Removed ${expiredIds.length} events that exceeded max retries`);\n }\n } else if (this.memoryQueue) {\n const expiredIds = await this.memoryQueue.getEventsExceedingRetries(\n this.config.maxRetries\n );\n if (expiredIds.length > 0) {\n await this.memoryQueue.delete(expiredIds);\n this.log(`Removed ${expiredIds.length} events that exceeded max retries`);\n }\n }\n }\n\n /**\n * Enforce the maximum queue size by removing oldest events\n */\n private async enforceMaxQueueSize(): Promise<void> {\n if (this.useIndexedDB && this.db) {\n const count = await this.db.events.count();\n if (count > this.config.maxQueueSize) {\n const excess = count - this.config.maxQueueSize;\n const oldestEvents = await this.db.events\n .orderBy('timestamp')\n .limit(excess)\n .primaryKeys();\n await this.db.events.bulkDelete(oldestEvents);\n this.log(`Removed ${excess} oldest events to enforce queue size limit`);\n }\n } else if (this.memoryQueue) {\n await this.memoryQueue.enforceMaxSize(this.config.maxQueueSize);\n }\n }\n\n /**\n * Get queue statistics\n */\n async getStats(): Promise<QueueStats> {\n if (this.useIndexedDB && this.db) {\n const size = await this.db.events.count();\n const oldestEvent = await this.db.events\n .orderBy('timestamp')\n .first()\n .then((e) => e?.timestamp);\n return { size, oldestEvent, isFlushing: this.isFlushing };\n } else if (this.memoryQueue) {\n const stats = await this.memoryQueue.getStats();\n return { ...stats, isFlushing: this.isFlushing };\n }\n return { size: 0, isFlushing: this.isFlushing };\n }\n\n /**\n * Clear all events from the queue\n */\n async clear(): Promise<void> {\n if (this.useIndexedDB && this.db) {\n await this.db.events.clear();\n this.log('Queue cleared (IndexedDB)');\n } else if (this.memoryQueue) {\n await this.memoryQueue.clear();\n this.log('Queue cleared (memory)');\n }\n }\n\n /**\n * Start the automatic flush timer\n */\n startFlushTimer(): void {\n if (this.flushTimer) return;\n\n this.flushTimer = setInterval(() => {\n this.flush().catch((err) => {\n this.log('Flush timer error', err);\n });\n }, this.config.flushInterval);\n\n // Also listen for online events in browser\n if (isBrowser()) {\n window.addEventListener('online', this.handleOnline);\n }\n\n this.log(`Flush timer started (interval: ${this.config.flushInterval}ms)`);\n }\n\n /**\n * Stop the automatic flush timer\n */\n stopFlushTimer(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n\n if (isBrowser()) {\n window.removeEventListener('online', this.handleOnline);\n }\n\n this.log('Flush timer stopped');\n }\n\n /**\n * Handle coming back online\n */\n private handleOnline = (): void => {\n this.log('Browser came online, triggering flush');\n this.flush().catch((err) => {\n this.log('Online flush error', err);\n });\n };\n\n /**\n * Check if we're currently online\n */\n private isOnline(): boolean {\n if (isBrowser()) {\n return navigator.onLine;\n }\n // Assume online in Node.js\n return true;\n }\n\n /**\n * Manually trigger a flush of queued events\n */\n async flush(): Promise<void> {\n if (this.isFlushing) {\n this.log('Flush already in progress, skipping');\n return;\n }\n\n if (!this.isOnline()) {\n this.log('Offline, skipping flush');\n return;\n }\n\n if (!this.sendEvents) {\n this.log('No send callback configured, skipping flush');\n return;\n }\n\n this.isFlushing = true;\n\n try {\n const stats = await this.getStats();\n if (stats.size === 0) {\n this.log('Queue is empty, nothing to flush');\n return;\n }\n\n this.log(`Flushing queue (${stats.size} events)`);\n\n // Process in batches\n let processed = 0;\n while (true) {\n const events = await this.dequeue(this.config.flushBatchSize);\n if (events.length === 0) break;\n\n this.log(`Sending batch of ${events.length} events`);\n\n try {\n const sentIds = await this.sendEvents(events);\n await this.markSent(sentIds);\n\n // Mark remaining as failed\n const failedIds = events\n .filter((e) => !sentIds.includes(e.id!))\n .map((e) => e.id!);\n if (failedIds.length > 0) {\n await this.markFailed(failedIds);\n }\n\n processed += sentIds.length;\n } catch (error) {\n // Mark all as failed on network error\n const allIds = events.map((e) => e.id!);\n await this.markFailed(allIds);\n this.log('Batch send failed', error);\n break; // Stop flushing on error\n }\n }\n\n this.log(`Flush complete, sent ${processed} events`);\n } finally {\n this.isFlushing = false;\n }\n }\n\n /**\n * Close the database connection\n */\n async close(): Promise<void> {\n this.stopFlushTimer();\n if (this.db) {\n this.db.close();\n this.log('Database connection closed');\n }\n }\n}\n\nexport type { OfflineConfig, QueuedEvent, QueueStats, EventQueueInterface, SendEventsCallback };\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport type { PageViewOptions, TrackResponse } from '../types-lite.js';\nimport { getUtmParams } from './utils.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class PageViewPlugin implements KitbasePlugin {\n readonly name = 'page-view';\n private ctx!: PluginContext;\n private active = false;\n private popstateListener: (() => void) | null = null;\n private pageshowListener: ((e: PageTransitionEvent) => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n this.active = true;\n\n // Defer initial page view so subclass constructors (e.g. offline queue) finish first\n Promise.resolve().then(() => {\n if (this.active) {\n this.trackPageView().catch((err) => ctx.log('Failed to track initial page view', err));\n }\n });\n\n // Intercept pushState\n const originalPushState = history.pushState.bind(history);\n history.pushState = (...args) => {\n originalPushState(...args);\n if (this.active) {\n this.trackPageView().catch((err) => ctx.log('Failed to track page view (pushState)', err));\n }\n };\n\n // Intercept replaceState (preserve behavior, no tracking)\n const originalReplaceState = history.replaceState.bind(history);\n history.replaceState = (...args) => {\n originalReplaceState(...args);\n };\n\n // Listen to popstate (browser back/forward)\n this.popstateListener = () => {\n if (this.active) {\n this.trackPageView().catch((err) => ctx.log('Failed to track page view (popstate)', err));\n }\n };\n window.addEventListener('popstate', this.popstateListener);\n\n // Listen to pageshow (bfcache restore on back/forward in MPAs)\n if (ctx.config.trackBfcacheRestore !== false) {\n this.pageshowListener = (e: PageTransitionEvent) => {\n if (e.persisted && this.active) {\n this.trackPageView().catch((err) => ctx.log('Failed to track page view (bfcache)', err));\n }\n };\n window.addEventListener('pageshow', this.pageshowListener);\n }\n\n ctx.log('Auto page view tracking enabled');\n }\n\n teardown(): void {\n this.active = false;\n if (this.popstateListener) {\n window.removeEventListener('popstate', this.popstateListener);\n this.popstateListener = null;\n }\n if (this.pageshowListener) {\n window.removeEventListener('pageshow', this.pageshowListener);\n this.pageshowListener = null;\n }\n }\n\n get methods() {\n return {\n trackPageView: (options?: PageViewOptions): Promise<TrackResponse | void> =>\n this.trackPageView(options),\n };\n }\n\n private async trackPageView(options: PageViewOptions = {}): Promise<TrackResponse | void> {\n const path = options.path ?? (typeof window !== 'undefined' ? window.location.pathname : '');\n const title = options.title ?? (typeof document !== 'undefined' ? document.title : '');\n const referrer = options.referrer ?? (typeof document !== 'undefined' ? document.referrer : '');\n\n return this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'screen_view',\n tags: {\n __path: path,\n __title: title,\n __referrer: referrer,\n ...getUtmParams(),\n ...(options.tags ?? {}),\n },\n });\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport type { TrackResponse } from '../types-lite.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class OutboundLinksPlugin implements KitbasePlugin {\n readonly name = 'outbound-links';\n private ctx!: PluginContext;\n private clickListener: ((event: MouseEvent) => void) | null = null;\n private keydownListener: ((event: KeyboardEvent) => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n\n this.clickListener = (event: MouseEvent) => {\n const link = (event.target as Element)?.closest?.('a');\n if (link) {\n this.handleLinkClick(link as HTMLAnchorElement);\n }\n };\n\n this.keydownListener = (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n const link = (event.target as Element)?.closest?.('a');\n if (link) {\n this.handleLinkClick(link as HTMLAnchorElement);\n }\n }\n };\n\n document.addEventListener('click', this.clickListener);\n document.addEventListener('keydown', this.keydownListener);\n\n ctx.log('Outbound link tracking enabled');\n }\n\n teardown(): void {\n if (this.clickListener) {\n document.removeEventListener('click', this.clickListener);\n this.clickListener = null;\n }\n if (this.keydownListener) {\n document.removeEventListener('keydown', this.keydownListener);\n this.keydownListener = null;\n }\n }\n\n get methods() {\n return {\n trackOutboundLink: (options: { url: string; text?: string }): Promise<TrackResponse | void> =>\n this.trackOutboundLink(options),\n };\n }\n\n private handleLinkClick(link: HTMLAnchorElement): void {\n if (!link.href) return;\n\n try {\n const linkUrl = new URL(link.href);\n\n if (linkUrl.protocol !== 'http:' && linkUrl.protocol !== 'https:') {\n return;\n }\n\n const currentHost = window.location.hostname;\n const linkHost = linkUrl.hostname;\n\n if (linkHost === currentHost) return;\n if (this.ctx.isSameRootDomain(currentHost, linkHost)) return;\n\n this.trackOutboundLink({\n url: link.href,\n text: link.textContent?.trim() || '',\n }).catch((err) => this.ctx.log('Failed to track outbound link', err));\n } catch {\n // Invalid URL, skip\n }\n }\n\n private async trackOutboundLink(options: { url: string; text?: string }): Promise<TrackResponse | void> {\n return this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'outbound_link',\n tags: {\n __url: options.url,\n __text: options.text || '',\n },\n });\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport type { Tags, TrackResponse } from '../types-lite.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class ClickTrackingPlugin implements KitbasePlugin {\n readonly name = 'click-tracking';\n private ctx!: PluginContext;\n private clickListener: ((event: MouseEvent) => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n\n this.clickListener = (event: MouseEvent) => {\n const target = event.target as Element | null;\n\n // data-kb-track-click — user-defined click events via data attributes\n const annotated = target?.closest?.('[data-kb-track-click]');\n if (annotated) {\n const eventName = annotated.getAttribute('data-kb-track-click');\n if (eventName) {\n const channel = annotated.getAttribute('data-kb-click-channel') || 'engagement';\n ctx.track({\n channel,\n event: eventName,\n tags: {\n __path: window.location.pathname,\n },\n }).catch((err) => ctx.log('Failed to track data-attribute click', err));\n return; // skip generic click tracking for annotated elements\n }\n }\n\n const element = ctx.findClickableElement(event);\n if (!element) return;\n\n // Skip outbound links — already handled by outbound link tracking\n if (ctx.config.autoTrackOutboundLinks !== false) {\n const elHref = (element as HTMLAnchorElement).href || element.getAttribute('href') || '';\n if (elHref) {\n try {\n const linkUrl = new URL(elHref, window.location.origin);\n if (\n (linkUrl.protocol === 'http:' || linkUrl.protocol === 'https:') &&\n linkUrl.hostname !== window.location.hostname &&\n !ctx.isSameRootDomain(window.location.hostname, linkUrl.hostname)\n ) {\n return;\n }\n } catch {\n // Invalid URL, continue with click tracking\n }\n }\n }\n\n const tag = element.tagName.toLowerCase();\n const id = element.id || '';\n const className = element.className && typeof element.className === 'string' ? element.className : '';\n const text = (element.textContent || '').trim().slice(0, 100);\n const href = (element as HTMLAnchorElement).href || element.getAttribute('href') || '';\n const path = window.location.pathname;\n\n this.trackClick({ __tag: tag, __id: id, __class: className, __text: text, __href: href, __path: path }).catch(\n (err) => ctx.log('Failed to track click', err),\n );\n };\n\n document.addEventListener('click', this.clickListener);\n ctx.log('Click tracking enabled');\n }\n\n teardown(): void {\n if (this.clickListener) {\n document.removeEventListener('click', this.clickListener);\n this.clickListener = null;\n }\n }\n\n get methods() {\n return {\n trackClick: (tags: Tags): Promise<TrackResponse | void> =>\n this.trackClick(tags),\n };\n }\n\n private async trackClick(tags: Tags): Promise<TrackResponse | void> {\n return this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'click',\n tags,\n });\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class ScrollDepthPlugin implements KitbasePlugin {\n readonly name = 'scroll-depth';\n private ctx!: PluginContext;\n private active = false;\n private maxScrollDepth = 0;\n private scrollListener: (() => void) | null = null;\n private beforeUnloadListener: (() => void) | null = null;\n private popstateListener: (() => void) | null = null;\n private scrollRafScheduled = false;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n this.active = true;\n\n this.scrollListener = () => {\n if (this.scrollRafScheduled) return;\n this.scrollRafScheduled = true;\n requestAnimationFrame(() => {\n this.scrollRafScheduled = false;\n const scrollTop = window.scrollY || document.documentElement.scrollTop;\n const viewportHeight = window.innerHeight;\n const documentHeight = Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n );\n if (documentHeight <= 0) return;\n const depth = Math.min(100, Math.round(((scrollTop + viewportHeight) / documentHeight) * 100));\n if (depth > this.maxScrollDepth) {\n this.maxScrollDepth = depth;\n }\n });\n };\n\n this.beforeUnloadListener = () => {\n this.flushScrollDepth();\n };\n\n window.addEventListener('scroll', this.scrollListener, { passive: true });\n window.addEventListener('beforeunload', this.beforeUnloadListener);\n\n // SPA navigation (pushState / popstate)\n const originalPushState = history.pushState;\n const self = this;\n history.pushState = function (...args) {\n if (self.active) self.flushScrollDepth();\n return originalPushState.apply(this, args);\n };\n\n this.popstateListener = () => {\n if (this.active) this.flushScrollDepth();\n };\n window.addEventListener('popstate', this.popstateListener);\n\n ctx.log('Scroll depth tracking enabled');\n }\n\n teardown(): void {\n this.active = false;\n this.flushScrollDepth();\n if (this.scrollListener) {\n window.removeEventListener('scroll', this.scrollListener);\n this.scrollListener = null;\n }\n if (this.beforeUnloadListener) {\n window.removeEventListener('beforeunload', this.beforeUnloadListener);\n this.beforeUnloadListener = null;\n }\n if (this.popstateListener) {\n window.removeEventListener('popstate', this.popstateListener);\n this.popstateListener = null;\n }\n }\n\n private flushScrollDepth(): void {\n if (this.maxScrollDepth > 0) {\n const path = typeof window !== 'undefined' ? window.location.pathname : '';\n this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'scroll_depth',\n tags: {\n __depth: this.maxScrollDepth,\n __path: path,\n },\n }).catch((err) => this.ctx.log('Failed to track scroll depth', err));\n this.maxScrollDepth = 0;\n }\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\n\nexport class VisibilityPlugin implements KitbasePlugin {\n readonly name = 'visibility';\n private ctx!: PluginContext;\n private active = false;\n private visibilityObservers: Map<number, IntersectionObserver> = new Map();\n private visibilityMutationObserver: MutationObserver | null = null;\n private visibilityData: Map<Element, { visibleSince: number | null; totalMs: number; event: string; channel: string }> = new Map();\n private beforeUnloadListener: (() => void) | null = null;\n private popstateListener: (() => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n if (typeof IntersectionObserver === 'undefined' || typeof MutationObserver === 'undefined') return false;\n this.ctx = ctx;\n this.active = true;\n\n // Scan existing DOM elements\n this.scanForVisibilityElements();\n\n // Watch for dynamically added/removed elements\n this.visibilityMutationObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of Array.from(mutation.addedNodes)) {\n if (node instanceof Element) {\n this.observeVisibilityElement(node);\n for (const el of Array.from(node.querySelectorAll('[data-kb-track-visibility]'))) {\n this.observeVisibilityElement(el);\n }\n }\n }\n for (const node of Array.from(mutation.removedNodes)) {\n if (node instanceof Element) {\n this.flushVisibilityForElement(node);\n for (const el of Array.from(node.querySelectorAll('[data-kb-track-visibility]'))) {\n this.flushVisibilityForElement(el);\n }\n }\n }\n }\n });\n\n this.visibilityMutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n });\n\n // Flush on beforeunload\n this.beforeUnloadListener = () => {\n this.flushAllVisibilityEvents();\n };\n window.addEventListener('beforeunload', this.beforeUnloadListener);\n\n // SPA navigation (pushState / popstate)\n const originalPushState = history.pushState;\n const self = this;\n history.pushState = function (...args) {\n if (self.active) self.flushAllVisibilityEvents();\n return originalPushState.apply(this, args);\n };\n\n this.popstateListener = () => {\n if (this.active) this.flushAllVisibilityEvents();\n };\n window.addEventListener('popstate', this.popstateListener);\n\n ctx.log('Visibility tracking enabled');\n }\n\n teardown(): void {\n this.active = false;\n this.flushAllVisibilityEvents();\n for (const observer of this.visibilityObservers.values()) {\n observer.disconnect();\n }\n this.visibilityObservers.clear();\n if (this.visibilityMutationObserver) {\n this.visibilityMutationObserver.disconnect();\n this.visibilityMutationObserver = null;\n }\n if (this.beforeUnloadListener) {\n window.removeEventListener('beforeunload', this.beforeUnloadListener);\n this.beforeUnloadListener = null;\n }\n if (this.popstateListener) {\n window.removeEventListener('popstate', this.popstateListener);\n this.popstateListener = null;\n }\n this.visibilityData.clear();\n }\n\n private scanForVisibilityElements(): void {\n for (const el of Array.from(document.querySelectorAll('[data-kb-track-visibility]'))) {\n this.observeVisibilityElement(el);\n }\n }\n\n private observeVisibilityElement(el: Element): void {\n const eventName = el.getAttribute('data-kb-track-visibility');\n if (!eventName || this.visibilityData.has(el)) return;\n\n const channel = el.getAttribute('data-kb-visibility-channel') || 'engagement';\n const threshold = parseFloat(el.getAttribute('data-kb-visibility-threshold') || '0.5');\n const clampedThreshold = Math.max(0, Math.min(1, isNaN(threshold) ? 0.5 : threshold));\n\n this.visibilityData.set(el, {\n visibleSince: null,\n totalMs: 0,\n event: eventName,\n channel,\n });\n\n const observer = this.getOrCreateObserver(clampedThreshold);\n observer.observe(el);\n }\n\n private getOrCreateObserver(threshold: number): IntersectionObserver {\n const key = Math.round(threshold * 100);\n\n let observer = this.visibilityObservers.get(key);\n if (observer) return observer;\n\n observer = new IntersectionObserver(\n (entries) => {\n const now = Date.now();\n for (const entry of entries) {\n const data = this.visibilityData.get(entry.target);\n if (!data) continue;\n\n if (entry.isIntersecting) {\n data.visibleSince = now;\n } else if (data.visibleSince !== null) {\n data.totalMs += now - data.visibleSince;\n data.visibleSince = null;\n }\n }\n },\n { threshold },\n );\n\n this.visibilityObservers.set(key, observer);\n return observer;\n }\n\n private flushVisibilityForElement(el: Element): void {\n const data = this.visibilityData.get(el);\n if (!data) return;\n\n if (data.visibleSince !== null) {\n data.totalMs += Date.now() - data.visibleSince;\n data.visibleSince = null;\n }\n\n if (data.totalMs > 0) {\n const durationMs = Math.round(data.totalMs);\n const durationSeconds = Math.round(durationMs / 1000);\n this.ctx.track({\n channel: data.channel,\n event: 'element_visible',\n tags: {\n __element_name: data.event,\n __duration_seconds: durationSeconds,\n __duration_ms: durationMs,\n },\n }).catch((err) => this.ctx.log('Failed to track visibility event', err));\n }\n\n for (const observer of this.visibilityObservers.values()) {\n observer.unobserve(el);\n }\n this.visibilityData.delete(el);\n }\n\n private flushAllVisibilityEvents(): void {\n for (const [, data] of this.visibilityData.entries()) {\n if (data.visibleSince !== null) {\n data.totalMs += Date.now() - data.visibleSince;\n data.visibleSince = null;\n }\n\n if (data.totalMs > 0) {\n const durationMs = Math.round(data.totalMs);\n const durationSeconds = Math.round(durationMs / 1000);\n this.ctx.track({\n channel: data.channel,\n event: 'element_visible',\n tags: {\n element_name: data.event,\n duration_seconds: durationSeconds,\n duration_ms: durationMs,\n },\n }).catch((err) => this.ctx.log('Failed to track visibility event', err));\n }\n\n // Reset for next page / session\n data.totalMs = 0;\n data.visibleSince = null;\n }\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport type { Tags } from '../types-lite.js';\nimport { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nexport class WebVitalsPlugin implements KitbasePlugin {\n readonly name = 'web-vitals';\n private ctx!: PluginContext;\n private sent = false;\n private timeout: ReturnType<typeof setTimeout> | null = null;\n private beforeUnloadListener: (() => void) | null = null;\n private data: { lcp: number | null; cls: number | null; inp: number | null; fcp: number | null; ttfb: number | null } = {\n lcp: null, cls: null, inp: null, fcp: null, ttfb: null,\n };\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n\n const checkAndSend = () => {\n const { lcp, cls, inp, fcp, ttfb } = this.data;\n if (lcp !== null && cls !== null && inp !== null && fcp !== null && ttfb !== null) {\n this.sendWebVitals();\n }\n };\n\n onLCP((metric) => {\n this.data.lcp = metric.value;\n ctx.log('Web Vital collected', { name: 'LCP', value: metric.value });\n checkAndSend();\n });\n\n onCLS((metric) => {\n this.data.cls = metric.value;\n ctx.log('Web Vital collected', { name: 'CLS', value: metric.value });\n checkAndSend();\n });\n\n onINP((metric) => {\n this.data.inp = metric.value;\n ctx.log('Web Vital collected', { name: 'INP', value: metric.value });\n checkAndSend();\n });\n\n onFCP((metric) => {\n this.data.fcp = metric.value;\n ctx.log('Web Vital collected', { name: 'FCP', value: metric.value });\n checkAndSend();\n });\n\n onTTFB((metric) => {\n this.data.ttfb = metric.value;\n ctx.log('Web Vital collected', { name: 'TTFB', value: metric.value });\n checkAndSend();\n });\n\n // Safety timeout — send whatever we have after 30s\n this.timeout = setTimeout(() => {\n this.timeout = null;\n this.sendWebVitals();\n }, 30_000);\n\n // Also send on beforeunload if not already sent\n this.beforeUnloadListener = () => {\n this.sendWebVitals();\n };\n window.addEventListener('beforeunload', this.beforeUnloadListener);\n\n ctx.log('Web Vitals tracking enabled');\n }\n\n teardown(): void {\n if (this.timeout !== null) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n this.sendWebVitals();\n if (this.beforeUnloadListener) {\n window.removeEventListener('beforeunload', this.beforeUnloadListener);\n this.beforeUnloadListener = null;\n }\n }\n\n private sendWebVitals(): void {\n if (this.sent) return;\n\n const { lcp, cls, inp, fcp, ttfb } = this.data;\n\n // Don't send if no metrics were collected at all\n if (lcp === null && cls === null && inp === null && fcp === null && ttfb === null) return;\n\n this.sent = true;\n\n if (this.timeout !== null) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n\n const tags: Tags = {};\n if (lcp !== null) tags.__lcp = lcp;\n if (cls !== null) tags.__cls = cls;\n if (inp !== null) tags.__inp = inp;\n if (fcp !== null) tags.__fcp = fcp;\n if (ttfb !== null) tags.__ttfb = ttfb;\n\n this.ctx.log('Sending Web Vitals', tags);\n\n this.ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'web_vitals',\n tags,\n }).catch((err) => this.ctx.log('Failed to track web vitals', err));\n }\n}\n","import type { KitbasePlugin, PluginContext } from './types.js';\nimport { findClickableElement, buildCssSelector } from './utils.js';\n\nconst ANALYTICS_CHANNEL = '__analytics';\n\nconst RAGE_CLICK_THRESHOLD = 3;\nconst RAGE_CLICK_WINDOW_MS = 1000;\nconst RAGE_CLICK_RADIUS_PX = 30;\nconst DEAD_CLICK_TIMEOUT_MS = 1000;\n\nexport class FrustrationPlugin implements KitbasePlugin {\n readonly name = 'frustration';\n private ctx!: PluginContext;\n private rageClickBuffer: Array<{ time: number; x: number; y: number; target: Element }> = [];\n private deadClickObserver: MutationObserver | null = null;\n private deadClickTimeout: ReturnType<typeof setTimeout> | null = null;\n private clickListener: ((e: MouseEvent) => void) | null = null;\n\n setup(ctx: PluginContext): void | false {\n if (typeof window === 'undefined') return false;\n this.ctx = ctx;\n\n this.clickListener = (event: MouseEvent) => {\n const target = event.target as Element | null;\n if (!target) return;\n\n const now = Date.now();\n\n // --- Rage Click Detection ---\n this.rageClickBuffer.push({ time: now, x: event.clientX, y: event.clientY, target });\n\n // Prune clicks older than the time window\n this.rageClickBuffer = this.rageClickBuffer.filter(\n (c) => now - c.time < RAGE_CLICK_WINDOW_MS,\n );\n\n if (this.rageClickBuffer.length >= RAGE_CLICK_THRESHOLD) {\n const first = this.rageClickBuffer[0]!;\n const allNearby = this.rageClickBuffer.every(\n (c) => Math.hypot(c.x - first.x, c.y - first.y) < RAGE_CLICK_RADIUS_PX,\n );\n\n if (allNearby) {\n const element = findClickableElement(event) || target;\n const clickCount = this.rageClickBuffer.length;\n this.rageClickBuffer = []; // reset after emitting\n\n ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'rage_click',\n tags: {\n __path: window.location.pathname,\n __tag: element.tagName.toLowerCase(),\n __id: element.id || '',\n __class: element.className && typeof element.className === 'string' ? element.className : '',\n __text: (element.textContent || '').trim().slice(0, 100),\n __selector: buildCssSelector(element),\n __click_count: clickCount,\n },\n }).catch((err) => ctx.log('Failed to track rage click', err));\n return; // skip dead click check after rage click\n }\n }\n\n // --- Dead Click Detection ---\n const clickedElement = findClickableElement(event);\n if (!clickedElement) return;\n\n // Skip dead click detection for links with href — navigating is the expected behavior,\n // not a DOM mutation on the current page (especially target=\"_blank\" links).\n if (target.closest?.('a[href]')) return;\n\n // Skip dead click detection for <select> and <option> — the browser renders\n // native dropdowns outside the DOM, so no MutationObserver-visible change occurs.\n if (clickedElement.tagName === 'SELECT' || target.closest?.('select')) return;\n\n // Clear any pending dead click check\n if (this.deadClickTimeout !== null) {\n clearTimeout(this.deadClickTimeout);\n this.deadClickTimeout = null;\n }\n if (this.deadClickObserver) {\n this.deadClickObserver.disconnect();\n }\n\n let mutationDetected = false;\n\n this.deadClickObserver = new MutationObserver(() => {\n mutationDetected = true;\n });\n\n this.deadClickObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n });\n\n this.deadClickTimeout = setTimeout(() => {\n if (this.deadClickObserver) {\n this.deadClickObserver.disconnect();\n this.deadClickObserver = null;\n }\n\n if (!mutationDetected) {\n ctx.track({\n channel: ANALYTICS_CHANNEL,\n event: 'dead_click',\n tags: {\n __path: window.location.pathname,\n __tag: clickedElement.tagName.toLowerCase(),\n __id: clickedElement.id || '',\n __class: clickedElement.className && typeof clickedElement.className === 'string' ? clickedElement.className : '',\n __text: (clickedElement.textContent || '').trim().slice(0, 100),\n __selector: buildCssSelector(clickedElement),\n },\n }).catch((err) => ctx.log('Failed to track dead click', err));\n }\n }, DEAD_CLICK_TIMEOUT_MS);\n };\n\n document.addEventListener('click', this.clickListener, true);\n ctx.log('Frustration signal detection enabled');\n }\n\n teardown(): void {\n if (this.clickListener) {\n document.removeEventListener('click', this.clickListener, true);\n this.clickListener = null;\n }\n if (this.deadClickObserver) {\n this.deadClickObserver.disconnect();\n this.deadClickObserver = null;\n }\n if (this.deadClickTimeout !== null) {\n clearTimeout(this.deadClickTimeout);\n this.deadClickTimeout = null;\n }\n this.rageClickBuffer = [];\n }\n}\n","import type { AnalyticsConfig } from '../types-lite.js';\nimport type { KitbasePlugin } from './types.js';\nimport { PageViewPlugin } from './page-view.js';\nimport { OutboundLinksPlugin } from './outbound-links.js';\nimport { ClickTrackingPlugin } from './click-tracking.js';\nimport { ScrollDepthPlugin } from './scroll-depth.js';\nimport { VisibilityPlugin } from './visibility.js';\nimport { WebVitalsPlugin } from './web-vitals.js';\nimport { FrustrationPlugin } from './frustration.js';\n\n/**\n * Create the default set of plugins based on analytics configuration.\n * Reads config flags and instantiates only the enabled plugins.\n */\nexport function createDefaultPlugins(config?: AnalyticsConfig): KitbasePlugin[] {\n const plugins: KitbasePlugin[] = [];\n\n if (config?.autoTrackPageViews !== false) {\n plugins.push(new PageViewPlugin());\n }\n if (config?.autoTrackOutboundLinks !== false) {\n plugins.push(new OutboundLinksPlugin());\n }\n if (config?.autoTrackClicks !== false) {\n plugins.push(new ClickTrackingPlugin());\n }\n if (config?.autoTrackScrollDepth !== false) {\n plugins.push(new ScrollDepthPlugin());\n }\n if (config?.autoTrackVisibility !== false) {\n plugins.push(new VisibilityPlugin());\n }\n if (config?.autoTrackWebVitals === true) {\n plugins.push(new WebVitalsPlugin());\n }\n if (config?.autoDetectFrustration !== false) {\n plugins.push(new FrustrationPlugin());\n }\n\n return plugins;\n}\n","import type {\n KitbaseConfig,\n TrackOptions,\n TrackResponse,\n LogPayload,\n Tags,\n} from './types.js';\nimport { ValidationError } from './errors.js';\nimport { KitbaseAnalytics as KitbaseAnalyticsBase } from './client-base.js';\nimport { EventQueue } from './queue/index.js';\nimport type { QueuedEvent, QueueStats } from './queue/types.js';\nimport { createDefaultPlugins } from './plugins/defaults.js';\n\n/**\n * Kitbase client for tracking events with full offline queue support\n *\n * @example\n * ```typescript\n * import { Kitbase } from '@kitbase/analytics';\n *\n * const kitbase = new Kitbase({\n * sdkKey: '<YOUR_API_KEY>',\n * debug: true,\n * offline: { enabled: true },\n * });\n *\n * // Register super properties (included in all events)\n * kitbase.register({ app_version: '2.1.0', platform: 'web' });\n *\n * // Track events\n * await kitbase.track({\n * channel: 'payments',\n * event: 'Page Viewed',\n * icon: '👀',\n * });\n *\n * // Time events for duration tracking\n * kitbase.timeEvent('Video Watched');\n * // ... later\n * await kitbase.track({\n * channel: 'engagement',\n * event: 'Video Watched', // $duration automatically included\n * });\n *\n * // Track events for a logged-in user (just pass user_id)\n * await kitbase.track({\n * channel: 'payments',\n * event: 'New Subscription',\n * user_id: 'user-123',\n * icon: '💰',\n * notify: true,\n * tags: {\n * plan: 'premium',\n * cycle: 'monthly',\n * },\n * });\n * ```\n */\nlet _instance: KitbaseAnalytics | null = null;\n\n/**\n * Initialize the Kitbase Analytics SDK\n *\n * Creates a singleton instance that is used for all tracking.\n * Call this once at the top of your application entry point.\n *\n * @param config - SDK configuration\n * @returns The KitbaseAnalytics instance\n *\n * @example\n * ```typescript\n * import { init } from '@kitbase/analytics';\n *\n * init({\n * sdkKey: '<YOUR_API_KEY>',\n * debug: true,\n * offline: { enabled: true },\n * });\n * ```\n */\nexport function init(config: KitbaseConfig): KitbaseAnalytics {\n if (_instance) {\n _instance.shutdown();\n }\n _instance = new KitbaseAnalytics(config);\n return _instance;\n}\n\n/**\n * Get the current KitbaseAnalytics singleton instance\n *\n * @returns The instance, or null if `init()` has not been called\n */\nexport function getInstance(): KitbaseAnalytics | null {\n return _instance;\n}\n\nexport class KitbaseAnalytics extends KitbaseAnalyticsBase {\n // Offline queue\n private queue: EventQueue | null = null;\n private offlineEnabled: boolean;\n\n constructor(config: KitbaseConfig) {\n super(config, createDefaultPlugins(config.analytics));\n\n // Initialize offline queue if enabled\n this.offlineEnabled = config.offline?.enabled ?? false;\n\n if (this.offlineEnabled) {\n this.queue = new EventQueue(config.offline);\n this.queue.setDebugMode(this.debugMode, this.log.bind(this));\n this.queue.setSendCallback(this.sendQueuedEvents.bind(this));\n this.queue.startFlushTimer();\n this.log('Offline queueing enabled', {\n storageType: this.queue.getStorageType(),\n });\n }\n }\n\n // ============================================================\n // Debug Mode Override\n // ============================================================\n\n /**\n * Enable or disable debug mode\n * When enabled, all SDK operations are logged to the console\n *\n * @param enabled - Whether to enable debug mode\n *\n * @example\n * ```typescript\n * kitbase.setDebugMode(true);\n * // All events and operations will now be logged\n * ```\n */\n override setDebugMode(enabled: boolean): void {\n super.setDebugMode(enabled);\n if (this.queue) {\n this.queue.setDebugMode(enabled, this.log.bind(this));\n }\n }\n\n // ============================================================\n // Offline Queue\n // ============================================================\n\n /**\n * Get offline queue statistics\n *\n * @returns Queue statistics including size and flush status\n *\n * @example\n * ```typescript\n * const stats = await kitbase.getQueueStats();\n * console.log(stats); // { size: 5, isFlushing: false }\n * ```\n */\n async getQueueStats(): Promise<QueueStats | null> {\n if (!this.queue) return null;\n return this.queue.getStats();\n }\n\n /**\n * Manually flush the offline queue\n * Events are automatically flushed on interval and when coming back online,\n * but this method can be used to trigger an immediate flush\n *\n * @example\n * ```typescript\n * await kitbase.flushQueue();\n * ```\n */\n async flushQueue(): Promise<void> {\n if (!this.queue) return;\n await this.queue.flush();\n }\n\n /**\n * Clear all events from the offline queue\n *\n * @example\n * ```typescript\n * await kitbase.clearQueue();\n * ```\n */\n async clearQueue(): Promise<void> {\n if (!this.queue) return;\n await this.queue.clear();\n }\n\n /**\n * Callback for the queue to send batched events via the batch endpoint.\n * Sends all events in a single HTTP request instead of individual POSTs.\n */\n private async sendQueuedEvents(events: QueuedEvent[]): Promise<number[]> {\n try {\n await this.sendRequest('/sdk/v1/logs/batch', {\n events: events.map((e) => e.payload),\n });\n return events.map((e) => e.id!);\n } catch (error) {\n this.log('Batch send failed', { count: events.length, error });\n return [];\n }\n }\n\n // ============================================================\n // Track Event Override\n // ============================================================\n\n /**\n * Track an event\n *\n * When offline queueing is enabled, events are always written to the local\n * database first (write-ahead), then sent to the server. This ensures no\n * events are lost if the browser crashes or the network fails.\n *\n * @param options - Event tracking options\n * @returns Promise resolving to the track response, or void if tracking is blocked\n * @throws {ValidationError} When required fields are missing\n * @throws {AuthenticationError} When the API key is invalid (only when offline disabled)\n * @throws {ApiError} When the API returns an error (only when offline disabled)\n * @throws {TimeoutError} When the request times out (only when offline disabled)\n */\n override async track(options: TrackOptions): Promise<TrackResponse | void> {\n this.validateTrackOptions(options);\n\n // Check if bot blocking is active\n if (this.isBotBlockingActive()) {\n this.log('Event skipped - bot detected', { event: options.event });\n return;\n }\n\n // Calculate duration if this event was being timed\n let duration: number | undefined;\n const startTime = this.timedEvents.get(options.event);\n if (startTime !== undefined) {\n duration = (Date.now() - startTime) / 1000;\n this.timedEvents.delete(options.event);\n this.log('Timer stopped', { event: options.event, duration });\n }\n\n // Merge super properties with event tags (event tags take precedence)\n const mergedTags: Tags = {\n ...this.superProperties,\n ...(options.tags ?? {}),\n ...(duration !== undefined ? { $duration: duration } : {}),\n };\n\n const payload: LogPayload = {\n channel: options.channel,\n event: options.event,\n client_timestamp: Date.now(),\n client_session_id: this.getClientSessionId(),\n ...(options.user_id && { user_id: options.user_id }),\n ...(options.icon && { icon: options.icon }),\n ...(options.notify !== undefined && { notify: options.notify }),\n ...(options.description && { description: options.description }),\n ...(Object.keys(mergedTags).length > 0 && { tags: mergedTags }),\n };\n\n this.log('Track', { event: options.event, payload });\n\n // If offline queueing is enabled, use write-ahead pattern\n if (this.queue) {\n // Always write to DB first (guaranteed durability)\n await this.queue.enqueue(payload);\n this.log('Event persisted to queue');\n\n // Trigger an immediate flush attempt (non-blocking)\n this.queue.flush().catch((err) => {\n this.log('Background flush failed', err);\n });\n\n // Return immediately after DB write\n return {\n id: `queued-${Date.now()}`,\n event: options.event,\n timestamp: new Date().toISOString(),\n };\n }\n\n // No offline queue - send directly (original behavior)\n const response = await this.sendRequest<TrackResponse>('/sdk/v1/logs', payload);\n this.log('Event sent successfully', { id: response.id });\n return response;\n }\n\n protected override validateTrackOptions(options: TrackOptions): void {\n if (!options.event) {\n throw new ValidationError('Event is required', 'event');\n }\n }\n\n // ============================================================\n // Cleanup\n // ============================================================\n\n /**\n * Shutdown the client and cleanup resources\n * Call this when you're done using the client to stop timers and close connections\n *\n * @example\n * ```typescript\n * await kitbase.shutdown();\n * ```\n */\n override async shutdown(): Promise<void> {\n // Flush queue before plugin teardown so teardown events can still be queued\n if (this.queue) {\n await this.queue.flush();\n }\n\n // Base shutdown: tears down plugins, clears timed events\n super.shutdown();\n\n // Final flush and close queue\n if (this.queue) {\n await this.queue.flush();\n await this.queue.close();\n this.queue = null;\n }\n }\n}\n"],"mappings":"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","names":["KitbaseAnalytics","isBot","isBrowser","Dexie","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","ANALYTICS_CHANNEL","KitbaseAnalytics"]}