@deriv-com/analytics
Version:
Comprehensive analytics package for Deriv applications. Provides unified event tracking, A/B testing, and user analytics through RudderStack, PostHog and GrowthBook integrations with built-in caching and offline support.
1 lines • 51.1 kB
Source Map (JSON)
{"version":3,"sources":["../../src/providers/rudderstack.ts","../../src/utils/storage.ts","../../src/analytics.ts"],"sourcesContent":["import { RudderAnalytics } from '@rudderstack/analytics-js'\nimport { rudderstackDataplane } from '../utils/urls'\nimport { createLogger } from '../utils/helpers'\n\n// Constants\nconst COOKIE_MAX_AGE_SECONDS = 180 * 24 * 60 * 60 // 180 days (~6 months)\n\n/**\n * RudderStack analytics wrapper with singleton pattern.\n * Handles user tracking, page views, and event analytics.\n */\nexport class RudderStack {\n analytics = new RudderAnalytics()\n has_identified = false\n has_initialized = false\n current_page = ''\n rudderstack_anonymous_cookie_key = 'rudder_anonymous_id'\n private static _instance: RudderStack\n private onLoadedCallback?: () => void\n private debug = false\n private log = createLogger('[RudderStack]', () => this.debug)\n\n constructor(RUDDERSTACK_KEY: string, onLoaded?: () => void, debug = false) {\n this.onLoadedCallback = onLoaded\n this.debug = debug\n this.init(RUDDERSTACK_KEY)\n }\n\n /**\n * Get or create the singleton instance of RudderStack\n * @param RUDDERSTACK_KEY - RudderStack write key\n * @param onLoaded - Optional callback when RudderStack is loaded\n * @param debug - Enable debug logging\n * @returns The RudderStack singleton instance\n */\n public static getRudderStackInstance = (\n RUDDERSTACK_KEY: string,\n onLoaded?: () => void,\n debug = false\n ): RudderStack => {\n if (!RudderStack._instance) {\n RudderStack._instance = new RudderStack(RUDDERSTACK_KEY, onLoaded, debug)\n }\n return RudderStack._instance\n }\n\n /**\n * Get the anonymous ID from cookies\n * @returns The anonymous ID or undefined if not found\n */\n getAnonymousId = (): string | undefined => {\n return document.cookie.match('(^|;)\\\\s*' + this.rudderstack_anonymous_cookie_key + '\\\\s*=\\\\s*([^;]+)')?.pop()\n }\n\n /**\n * Set anonymous ID cookie if it doesn't exist\n * Creates a secure cookie with proper domain and security attributes\n */\n setCookieIfNotExists = (): void => {\n const anonymous_id = this.getAnonymousId()\n\n if (!anonymous_id) {\n try {\n const hostname = window.location.hostname\n const external_domains = ['webflow.io']\n const is_external_domain = external_domains.some(domain => hostname.endsWith(domain))\n const domain_name = is_external_domain ? hostname : hostname.split('.').slice(-2).join('.')\n\n // Generate cryptographically secure UUID\n let uuid: string\n if (crypto?.randomUUID) {\n uuid = crypto.randomUUID()\n } else if (crypto?.getRandomValues) {\n // Fallback: Generate UUID v4 using crypto.getRandomValues\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 // Convert to UUID string format\n const hex = Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('')\n uuid = `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n } else {\n // Crypto API not available - this should not happen in modern browsers\n throw new Error('Crypto API not available for secure random UUID generation')\n }\n\n const isSecure = window.location.protocol === 'https:'\n const secureFlag = isSecure ? '; Secure' : ''\n\n document.cookie = `${this.rudderstack_anonymous_cookie_key}=${uuid}; path=/; Domain=${domain_name}; max-age=${COOKIE_MAX_AGE_SECONDS}; SameSite=Lax${secureFlag}`\n } catch (error) {\n console.warn('RudderStack: Failed to set anonymous ID cookie', error)\n }\n }\n }\n\n /**\n * Get the current user ID\n * @returns The user ID, null, or undefined if not identified\n */\n getUserId = () => this.analytics.getUserId()\n\n /**\n * Initialize RudderStack with the provided key\n * @param RUDDERSTACK_KEY - RudderStack write key\n */\n init = (RUDDERSTACK_KEY: string): void => {\n if (!RUDDERSTACK_KEY) {\n console.warn('RudderStack: Initialization skipped - no key provided')\n return\n }\n\n this.log('init | loading SDK', { dataplane: rudderstackDataplane })\n\n try {\n this.setCookieIfNotExists()\n\n this.analytics.load(RUDDERSTACK_KEY, rudderstackDataplane, {\n externalAnonymousIdCookieName: this.rudderstack_anonymous_cookie_key,\n storage: { type: 'localStorage' },\n // Performance optimizations\n lockIntegrationsVersion: true,\n onLoaded: () => {\n this.has_initialized = true\n this.has_identified = !!this.getUserId()\n this.log('init | SDK loaded successfully', {\n userId: this.getUserId(),\n anonymousId: this.getAnonymousId(),\n })\n this.onLoadedCallback?.()\n },\n })\n } catch (error) {\n console.error('RudderStack: Failed to initialize', error)\n }\n }\n\n /**\n * Identify a user with RudderStack\n * Only identifies if user hasn't been identified yet\n * @param user_id - The user ID to identify\n * @param payload - Optional user traits (e.g., language, custom properties)\n */\n identifyEvent = (user_id: string, payload?: Record<string, any>): void => {\n if (!this.has_initialized) {\n console.warn('RudderStack: Cannot identify - not initialized')\n return\n }\n\n const currentUserId = this.getUserId()\n if (!currentUserId || currentUserId !== user_id) {\n try {\n this.log('identifyEvent | identifying user', { user_id, traits: payload })\n this.analytics.identify(user_id, payload || {})\n this.has_identified = true\n } catch (error) {\n console.error('RudderStack: Failed to identify user', error)\n }\n } else {\n this.log('identifyEvent | user already identified', { user_id })\n this.has_identified = true\n }\n }\n\n /**\n * Track a page view event\n * @param current_page - The page name/path\n * @param platform - The platform name (default: 'Deriv App')\n * @param user_id - The user ID\n * @param properties - Additional page properties\n */\n pageView = (\n current_page: string,\n platform = 'Deriv App',\n user_id: string,\n properties?: Record<string, unknown>\n ): void => {\n if (!this.has_initialized || current_page === this.current_page) return\n\n try {\n const pageProperties = {\n ...(user_id && { user_id }),\n ...properties,\n }\n\n this.log('pageView | tracking page view', { platform, current_page, properties: pageProperties })\n // Type assertion needed due to RudderStack's type definitions\n this.analytics.page(platform, current_page, pageProperties as any)\n this.current_page = current_page\n } catch (error) {\n console.error('RudderStack: Failed to track page view', error)\n }\n }\n\n /**\n * Reset the RudderStack instance\n * Clears user identification and resets tracking state\n */\n reset = (): void => {\n if (!this.has_initialized) return\n\n try {\n this.log('reset | resetting RudderStack session')\n this.analytics.reset()\n this.has_identified = false\n } catch (error) {\n console.error('RudderStack: Failed to reset', error)\n }\n }\n\n /**\n * Track a custom event with payload\n * Payload is pre-cleaned by analytics.ts using cleanObject before being passed here\n * @param event - The event name\n * @param payload - The event payload with core attributes\n */\n track = (event: string, payload: Record<string, any>): void => {\n if (!this.has_initialized) return\n\n try {\n this.log('track | sending event to RudderStack', { event, payload })\n // Type assertion needed to match RudderStack's ApiObject type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.analytics.track(event as string, payload as any)\n } catch (err) {\n console.warn('RudderStack: Failed to track event', err)\n }\n }\n}\n","export const CACHE_STORAGE_EVENTS = 'cached_analytics_events'\nexport const CACHE_STORAGE_PAGES = 'cached_analytics_page_views'\n\nexport type CachedEvent = {\n name: string\n properties: Record<string, unknown>\n timestamp: number\n}\n\nexport type CachedPageView = {\n name: string\n properties?: Record<string, unknown>\n timestamp: number\n}\n\nexport const cacheEventToStorage = (eventName: string, properties: Record<string, unknown>): void => {\n try {\n const existingCache = localStorage.getItem(CACHE_STORAGE_EVENTS)\n const events: CachedEvent[] = existingCache ? JSON.parse(existingCache) : []\n events.push({ name: eventName, properties, timestamp: Date.now() })\n localStorage.setItem(CACHE_STORAGE_EVENTS, JSON.stringify(events))\n } catch (err) {\n console.warn('Analytics: Failed to cache event', err)\n }\n}\n\nexport const cachePageViewToStorage = (pageName: string, properties?: Record<string, unknown>): void => {\n try {\n const existingCache = localStorage.getItem(CACHE_STORAGE_PAGES)\n const pages: CachedPageView[] = existingCache ? JSON.parse(existingCache) : []\n pages.push({ name: pageName, properties, timestamp: Date.now() })\n localStorage.setItem(CACHE_STORAGE_PAGES, JSON.stringify(pages))\n } catch (err) {\n console.warn('Analytics: Failed to cache page view', err)\n }\n}\n\nexport const getCachedEvents = (): CachedEvent[] => {\n try {\n const storedEventsString = localStorage.getItem(CACHE_STORAGE_EVENTS)\n if (storedEventsString) {\n const events = JSON.parse(storedEventsString)\n return Array.isArray(events) ? events : []\n }\n } catch (err) {\n console.warn('Analytics: Failed to get cached events', err)\n }\n return []\n}\n\nexport const getCachedPageViews = (): CachedPageView[] => {\n try {\n const storedPagesString = localStorage.getItem(CACHE_STORAGE_PAGES)\n if (storedPagesString) {\n const pages = JSON.parse(storedPagesString)\n return Array.isArray(pages) ? pages : []\n }\n } catch (err) {\n console.warn('Analytics: Failed to get cached pages', err)\n }\n return []\n}\n\nexport const clearCachedEvents = (): void => {\n try {\n localStorage.removeItem(CACHE_STORAGE_EVENTS)\n } catch (err) {\n console.warn('Analytics: Failed to clear cached events', err)\n }\n}\n\nexport const clearCachedPageViews = (): void => {\n try {\n localStorage.removeItem(CACHE_STORAGE_PAGES)\n } catch (err) {\n console.warn('Analytics: Failed to clear cached page views', err)\n }\n}\n","import { RudderStack } from './providers/rudderstack'\nimport {\n cacheEventToStorage,\n cachePageViewToStorage,\n getCachedEvents,\n getCachedPageViews,\n clearCachedEvents,\n clearCachedPageViews,\n} from './utils/storage'\nimport { isUUID, getCountry, cleanObject, flattenObject, createLogger, isInternalEmail } from './utils/helpers'\n// Optional Growthbook types - only import if using Growthbook\nimport type { Growthbook, GrowthbookConfigs } from './providers/growthbook'\nimport type { TGrowthbookAttributes, TGrowthbookOptions } from './providers/growthbookTypes'\n\n// Optional Posthog types - only import if using Posthog\nimport type { Posthog } from './providers/posthog'\nimport type { TPosthogIdentifyTraits, TPosthogOptions } from './providers/posthogTypes'\n\ndeclare global {\n interface Window {\n AnalyticsInstance: ReturnType<typeof createAnalyticsInstance>\n }\n}\n\n/**\n * Configuration options for initializing the analytics instance\n */\ntype Options = {\n /** GrowthBook client API key for A/B testing and feature flags */\n growthbookKey?: string\n /** GrowthBook decryption key for encrypted feature payloads */\n growthbookDecryptionKey?: string\n /** RudderStack write key for event tracking */\n rudderstackKey?: string\n /** Additional configuration options for GrowthBook */\n growthbookOptions?: TGrowthbookOptions\n /** PostHog configuration options including API keys and settings */\n posthogOptions?: TPosthogOptions\n /** Enable debug logging — logs all analytics calls prefixed with [ANALYTIC] */\n debug?: boolean\n}\n\n/**\n * Creates a unified analytics instance that integrates RudderStack and GrowthBook.\n *\n * This function provides a centralized interface for:\n * - Event tracking across multiple analytics platforms\n * - A/B testing and feature flag management via GrowthBook\n * - Offline event caching with automatic replay\n *\n * @param {Options} _options - Optional initialization configuration\n * @returns {Object} Analytics instance with methods for tracking, identification, and feature management\n *\n * @example\n * ```typescript\n * const analytics = createAnalyticsInstance();\n *\n * // Initialize with providers\n * await analytics.initialise({\n * rudderstackKey: 'YOUR_RS_KEY',\n * growthbookKey: 'YOUR_GB_KEY',\n * growthbookDecryptionKey: 'YOUR_GB_DECRYPT_KEY'\n * });\n *\n * // Set user attributes\n * analytics.setAttributes({\n * user_id: 'user123',\n * country: 'US',\n * user_language: 'en'\n * });\n *\n * // Track events\n * analytics.trackEvent('button_clicked', { button_name: 'signup' });\n *\n * // Track page views\n * analytics.pageView('/dashboard', 'Deriv App');\n * ```\n */\nexport function createAnalyticsInstance(_options?: Options) {\n let _debug = _options?.debug ?? false\n\n const log = createLogger('', () => _debug)\n\n let _growthbook: Growthbook | undefined,\n _rudderstack: RudderStack,\n _posthog: Posthog | undefined,\n core_data: Record<string, any> = {},\n tracking_config: { [key: string]: boolean } = {},\n offline_event_cache: Array<{ event: string; payload: Record<string, any> }> = [],\n _pending_identify_calls: Array<{ userId: string; traits?: Record<string, any> }> = [],\n _storage_cache_processed = false\n\n const processStorageCache = () => {\n if (_storage_cache_processed) return\n if (!_rudderstack?.has_initialized) return\n\n _storage_cache_processed = true\n\n try {\n const storedEvents = getCachedEvents()\n if (storedEvents.length > 0) {\n log(`processStorageCache | replaying ${storedEvents.length} cached event(s)`, storedEvents)\n storedEvents.forEach(event => {\n const cleaned_properties = cleanObject(event.properties)\n _rudderstack?.track(event.name, cleaned_properties)\n })\n clearCachedEvents()\n }\n\n const storedPages = getCachedPageViews()\n if (storedPages.length > 0) {\n log(`processStorageCache | replaying ${storedPages.length} cached page view(s)`, storedPages)\n storedPages.forEach(page => {\n _rudderstack?.pageView(page.name, 'Deriv App', getId(), page.properties)\n })\n clearCachedPageViews()\n }\n } catch (err) {\n console.warn('Analytics: Failed to process storage cache', err)\n }\n }\n\n const onSdkLoaded = () => {\n log('onSdkLoaded | RudderStack SDK loaded')\n processStorageCache()\n\n if (_pending_identify_calls.length > 0) {\n log(`onSdkLoaded | flushing ${_pending_identify_calls.length} pending identify call(s)`)\n }\n _pending_identify_calls.forEach(({ userId, traits }) => {\n if (userId) {\n _rudderstack?.identifyEvent(userId, traits)\n }\n })\n _pending_identify_calls = []\n }\n\n /**\n * Initializes the analytics instance with specified provider configurations.\n * This method should be called before tracking any events.\n *\n * Features:\n * - Lazy-loads providers (GrowthBook, PostHog) only when configured\n * - Automatically fetches user's country for GrowthBook targeting\n * - Processes any cached events from previous sessions\n * - Sets up event tracking callback for GrowthBook experiments\n *\n * @param {Options} options - Configuration options for analytics providers\n * @returns {Promise<void>} Resolves when initialization is complete\n *\n * @example\n * ```typescript\n * await analytics.initialise({\n * rudderstackKey: 'YOUR_RS_KEY',\n * growthbookKey: 'YOUR_GB_KEY',\n * growthbookDecryptionKey: 'YOUR_GB_DECRYPT_KEY',\n * posthogOptions: {\n * apiKey: 'YOUR_POSTHOG_API_KEY',\n * config: {\n * session_recording: {\n * recordCrossOriginIframes: true,\n * minimumDurationMilliseconds: 30000\n * }\n * }\n * }\n * });\n * ```\n */\n const initialise = async ({\n growthbookKey,\n growthbookDecryptionKey,\n rudderstackKey,\n growthbookOptions,\n posthogOptions,\n debug,\n }: Options) => {\n if (debug !== undefined) _debug = debug\n\n log('initialise | starting analytics initialization', {\n rudderstack: !!rudderstackKey,\n growthbook: !!growthbookKey,\n posthog: !!posthogOptions,\n })\n\n try {\n // Only fetch country if GrowthBook is enabled and country not provided\n const country = growthbookOptions?.attributes?.country || (growthbookKey ? await getCountry() : undefined)\n\n if (rudderstackKey) {\n log('initialise | initializing RudderStack')\n _rudderstack = RudderStack.getRudderStackInstance(rudderstackKey, onSdkLoaded, _debug)\n }\n\n if (growthbookOptions?.attributes && Object.keys(growthbookOptions.attributes).length > 0) {\n const attrs = growthbookOptions.attributes\n const anonymousId = _rudderstack?.getAnonymousId()\n\n core_data = {\n ...core_data,\n country,\n ...(attrs.user_language && { user_language: attrs.user_language }),\n ...(attrs.account_type && { account_type: attrs.account_type }),\n ...(attrs.app_id && { app_id: attrs.app_id }),\n ...(attrs.residence_country && { residence_country: attrs.residence_country }),\n ...(attrs.device_type && { device_type: attrs.device_type }),\n ...(attrs.url && { url: attrs.url }),\n ...(attrs.email_hash && { email_hash: attrs.email_hash }),\n ...(attrs.network_type && { network_type: attrs.network_type }),\n ...(attrs.network_rtt && { network_rtt: attrs.network_rtt }),\n ...(attrs.network_downlink && { network_downlink: attrs.network_downlink }),\n ...(attrs.account_currency && { account_currency: attrs.account_currency }),\n ...(attrs.account_mode && { account_mode: attrs.account_mode }),\n loggedIn: !!attrs.loggedIn,\n ...(attrs.user_id && !isUUID(attrs.user_id) && { user_id: attrs.user_id }),\n ...(anonymousId && { anonymous_id: anonymousId }),\n }\n }\n\n growthbookOptions ??= {}\n growthbookOptions.attributes ??= {}\n const anonId = _rudderstack?.getAnonymousId()\n growthbookOptions.attributes.id ??= anonId\n growthbookOptions.attributes.country ??= country\n\n if (growthbookKey) {\n log('initialise | initializing GrowthBook')\n // Dynamically import Growthbook only when needed\n const { Growthbook } = await import('./providers/growthbook')\n _growthbook = Growthbook.getGrowthBookInstance(\n growthbookKey,\n growthbookDecryptionKey,\n growthbookOptions,\n _debug\n )\n log('initialise | GrowthBook initialized')\n\n const interval = setInterval(() => {\n if (Object.keys(tracking_config).length > 0) clearInterval(interval)\n else tracking_config = getFeatureValue('tracking-buttons-config', {}) as { [key: string]: boolean }\n }, 1000)\n }\n\n if (posthogOptions) {\n log('initialise | initializing PostHog')\n // Dynamically import Posthog only when needed\n const { Posthog } = await import('./providers/posthog')\n _posthog = Posthog.getPosthogInstance(posthogOptions, _debug)\n log('initialise | PostHog initialized')\n }\n\n log('initialise | analytics initialization complete')\n } catch (err) {\n console.warn('Analytics: Failed to initialize', err)\n }\n }\n\n /**\n * Sets user and context attributes for analytics tracking and targeting.\n * These attributes are automatically included in all subsequent events.\n *\n * Attributes are used for:\n * - Event enrichment (added to all tracked events)\n * - GrowthBook targeting (feature flags and A/B tests)\n * - User segmentation across analytics platforms\n *\n * @param {TCoreAttributes} attributes - User and context attributes\n *\n * @example\n * ```typescript\n * analytics.setAttributes({\n * user_id: 'CR123456',\n * country: 'US',\n * user_language: 'en',\n * device_type: 'desktop',\n * account_type: 'real',\n * loggedIn: true\n * });\n * ```\n */\n const setAttributes = (attributes: Record<string, any>) => {\n log('setAttributes | received attributes', attributes)\n\n const { user_id, ...rest } = attributes\n const user_identity = user_id ?? getId()\n\n if (_growthbook) {\n const config: TGrowthbookAttributes = { ...rest }\n if (user_id && !isUUID(user_id)) config.user_id = user_id\n if (user_identity) {\n config.id = user_identity\n config.user_id = user_identity\n }\n log('setAttributes | called GrowthBook setAttributes', config)\n _growthbook.setAttributes(config)\n }\n\n core_data = {\n ...core_data,\n ...Object.fromEntries(Object.entries(rest).filter(([, v]) => v !== undefined)),\n ...(user_id !== undefined && !isUUID(user_id) && { user_id }),\n }\n\n log('setAttributes | updated core_data', core_data)\n }\n\n const getFeatureState = (id: string) => _growthbook?.getFeatureState(id)?.experimentResult?.name\n\n const getFeatureValue = <K extends keyof GrowthbookConfigs, V extends GrowthbookConfigs[K]>(\n id: K,\n defaultValue: V\n ) => _growthbook?.getFeatureValue(id as string, defaultValue)\n\n const getGrowthbookStatus = async () => await _growthbook?.getStatus()\n const isFeatureOn = (key: string) => _growthbook?.isOn(key)\n const setUrl = (href: string) => _growthbook?.setUrl(href)\n\n const getId = () => {\n const userId = _rudderstack?.getUserId() || ''\n return userId && !isUUID(userId) ? userId : ''\n }\n\n const getAnonymousId = () => _rudderstack?.getAnonymousId() || ''\n\n /**\n * Tracks a page view event.\n *\n * Features:\n * - Automatically includes user ID if available\n * - Caches page views when offline or provider not initialized\n *\n * @param {string} current_page - The current page URL or path\n * @param {string} [platform='Deriv App'] - The platform name\n * @param {Record<string, unknown>} [properties] - Additional page properties\n *\n * @example\n * ```typescript\n * analytics.pageView('/dashboard');\n * analytics.pageView('/trade', 'Deriv Trader', { section: 'multipliers' });\n * ```\n */\n const pageView = (current_page: string, platform = 'Deriv App', properties?: Record<string, unknown>) => {\n const userId = getId()\n\n log('pageView | called', { current_page, platform, properties, userId })\n\n // Handle RudderStack pageView independently\n if (_rudderstack?.has_initialized) {\n log('pageView | sending page view to RudderStack', { current_page, platform })\n _rudderstack.pageView(current_page, platform, userId, properties)\n } else {\n log('pageView | RudderStack not initialized — caching page view to localStorage', { current_page })\n cachePageViewToStorage(current_page, { platform, ...properties })\n }\n\n // PostHog handles page views automatically via autocapture\n // No need to manually send page views to PostHog\n }\n\n /**\n * Identifies a user across analytics platforms.\n * This method should be called after user login or when user identity is known.\n *\n * Features:\n * - Queues identify calls if provider not yet initialized\n * - Allows custom traits for each provider or shared traits for both\n * - Identifies user in PostHog if configured\n *\n * @param {string} [user_id] - The user ID to identify. If not provided, uses stored user ID\n * @param {Record<string, any>} [traits] - Optional traits to send to both providers, or provider-specific traits\n *\n * @example\n * ```typescript\n * // Simple identify\n * analytics.identifyEvent('CR123456');\n *\n * // Identify with same traits for both providers\n * analytics.identifyEvent('CR123456', {\n * language: 'en',\n * country_of_residence: 'US'\n * });\n *\n * // Identify with provider-specific traits\n * analytics.identifyEvent('CR123456', {\n * rudderstack: { language: 'en', custom_field: 'value' },\n * posthog: { language: 'en', country_of_residence: 'US' }\n * });\n * ```\n */\n const identifyEvent = (user_id?: string, traits?: Record<string, any>) => {\n const stored_user_id = user_id || getId()\n if (!stored_user_id) {\n log('identifyEvent | skipped — no user_id available')\n return\n }\n\n log('identifyEvent | called', { user_id: stored_user_id, traits })\n\n // Strip PII: replace raw email with is_internal flag\n const sanitizePII = (t?: Record<string, any>) => {\n if (!t) return t\n const { email, ...safe } = t\n return { ...safe, ...(email && { is_internal: isInternalEmail(email) }) }\n }\n\n // Check if traits has provider-specific structure\n const hasProviderStructure = traits?.rudderstack !== undefined || traits?.posthog !== undefined\n let rudderstackTraits, posthogTraits\n if (hasProviderStructure) {\n // Merge shared top-level props with provider-specific ones (provider-specific wins on conflict)\n const { rudderstack, posthog, ...sharedTraits } = traits as any\n rudderstackTraits = sanitizePII({ ...sharedTraits, ...rudderstack })\n posthogTraits = sanitizePII({ ...sharedTraits, ...posthog })\n } else {\n rudderstackTraits = sanitizePII(traits)\n posthogTraits = sanitizePII(traits)\n }\n\n // Handle RudderStack identification independently\n if (_rudderstack) {\n if (_rudderstack.has_initialized) {\n log('identifyEvent | calling RudderStack identify', {\n user_id: stored_user_id,\n traits: rudderstackTraits,\n })\n _rudderstack.identifyEvent(stored_user_id, rudderstackTraits)\n } else {\n if (!_pending_identify_calls.some(call => call.userId === stored_user_id)) {\n log('identifyEvent | RudderStack not initialized — queuing identify call', {\n user_id: stored_user_id,\n })\n _pending_identify_calls.push({ userId: stored_user_id, traits: rudderstackTraits })\n }\n }\n }\n\n // Handle PostHog identification independently\n if (_posthog?.has_initialized) {\n log('identifyEvent | calling PostHog identify', { user_id: stored_user_id, traits: posthogTraits })\n _posthog.identifyEvent(stored_user_id, posthogTraits as TPosthogIdentifyTraits)\n }\n }\n\n const reset = () => {\n log('reset | resetting all providers')\n // Reset each provider independently\n if (_rudderstack?.has_initialized) {\n log('reset | resetting RudderStack')\n _rudderstack.reset()\n }\n if (_posthog?.has_initialized) {\n log('reset | resetting PostHog')\n _posthog.reset()\n }\n }\n\n /**\n * Tracks a custom event with associated data.\n *\n * Features:\n * - Automatically enriches events with core attributes\n * - RudderStack: Caches events when offline or not initialized\n * - PostHog: Sends immediately if initialized (has built-in caching)\n * - Respects feature flag configurations\n * - Each provider works independently - one failing won't affect the other\n *\n * @param {string} event - The event name to track\n * @param {Record<string, any>} analytics_data - The event data payload\n */\n const trackEvent = (event: string, analytics_data: Record<string, any>) => {\n const userId = getId()\n\n log('trackEvent | called', { event, analytics_data, userId, core_data })\n\n const final_payload = {\n ...core_data,\n ...analytics_data,\n ...(userId && !core_data.user_id && { user_id: userId }),\n }\n\n log('trackEvent | built payload', { event, final_payload })\n\n const shouldTrack = !(event in tracking_config) || tracking_config[event as string]\n if (!shouldTrack) {\n log('trackEvent | skipped — event disabled by tracking_config', { event })\n return\n }\n\n // Handle RudderStack independently\n const hasRudderstackInitialized = _rudderstack?.has_initialized\n if (!navigator.onLine || !hasRudderstackInitialized) {\n if (!hasRudderstackInitialized) {\n log('trackEvent | RudderStack not initialized — caching event to localStorage', { event })\n cacheEventToStorage(event as string, final_payload)\n } else {\n log('trackEvent | offline — caching event to memory', { event })\n offline_event_cache.push({ event, payload: final_payload })\n }\n } else {\n // Send cached events to RudderStack\n if (offline_event_cache.length > 0) {\n log(`trackEvent | flushing ${offline_event_cache.length} offline cached event(s) to RudderStack`)\n offline_event_cache.forEach(cache => {\n const cleaned_cache_payload = cleanObject(cache.payload)\n _rudderstack?.track(cache.event, cleaned_cache_payload)\n })\n offline_event_cache = []\n }\n\n // Send current event to RudderStack\n const cleaned_payload = cleanObject(final_payload)\n log('trackEvent | sending event to RudderStack', { event, payload: cleaned_payload })\n _rudderstack?.track(event, cleaned_payload)\n }\n\n // Handle PostHog independently - send immediately if initialized\n if (_posthog?.has_initialized) {\n const posthog_payload = cleanObject(flattenObject(final_payload))\n log('trackEvent | sending event to PostHog', { event, payload: posthog_payload })\n _posthog.capture(event as string, posthog_payload)\n }\n }\n\n /**\n * Ensures client_id is set in PostHog stored person properties.\n * Call this when the user ID is available and PostHog is loaded.\n * Useful for backfilling client_id for users identified in previous sessions.\n * No-op if client_id is already present or PostHog is not initialized.\n *\n * @param params.user_id - The user ID to use as client_id\n * @param params.email - The user's email, used to determine is_internal\n * @param params.language - The user's language (BCP 47 tag, e.g. \"en-GB\")\n * @param params.country_of_residence - The user's country of residence\n *\n * @example\n * ```typescript\n * if (window.posthog?.__loaded && userId) {\n * analytics.backfillPersonProperties({ user_id: userId, email, language, country_of_residence })\n * }\n * ```\n */\n const backfillPersonProperties = ({\n user_id,\n email,\n language,\n country_of_residence,\n }: {\n user_id: string\n email?: string\n language?: string\n country_of_residence?: string\n }): void => {\n log('backfillPersonProperties | called', { user_id })\n if (_posthog?.has_initialized) {\n log('backfillPersonProperties | backfilling person properties in PostHog', { user_id })\n _posthog.backfillPersonProperties({ user_id, email, language, country_of_residence })\n } else {\n log('backfillPersonProperties | skipped — PostHog not initialized')\n }\n }\n\n const getInstances = () => ({ ab: _growthbook, tracking: _rudderstack, posthog: _posthog })\n\n /**\n * Check whether a PostHog feature flag is enabled for the current user.\n * Returns undefined if PostHog is not initialized.\n */\n const isPosthogFeatureEnabled = (key: string): boolean | undefined => _posthog?.isFeatureEnabled(key)\n\n /**\n * Get the value of a PostHog feature flag.\n * Returns a string variant for multivariate flags, true/false for boolean flags,\n * or undefined if the flag does not exist or PostHog is not initialized.\n */\n const getPosthogFeatureFlag = (key: string): string | boolean | undefined => _posthog?.getFeatureFlag(key)\n\n /**\n * Get the JSON payload attached to a PostHog feature flag.\n * Returns undefined if the flag has no payload or PostHog is not initialized.\n */\n const getPosthogFeatureFlagPayload = (\n key: string\n ): string | number | boolean | null | Record<string, unknown> | unknown[] | undefined =>\n _posthog?.getFeatureFlagPayload(key)\n\n /**\n * Get all currently active PostHog feature flags and their values.\n * Returns an empty object if PostHog is not initialized.\n */\n const getPosthogAllFlags = (): Record<string, string | boolean> => _posthog?.getAllFlags() ?? {}\n\n /**\n * Subscribe to PostHog feature flag changes.\n * The callback fires immediately with current flags and again whenever flags are reloaded.\n * Returns an unsubscribe function — call it to stop listening.\n */\n const onPosthogFeatureFlags = (\n callback: (flags: string[], variants: Record<string, string | boolean>) => void\n ): (() => void) => _posthog?.onFeatureFlags(callback) ?? (() => {})\n\n /**\n * Force PostHog to reload feature flags from the server.\n * Useful after attribute/identity changes that may affect flag targeting.\n */\n const reloadPosthogFeatureFlags = (): void => _posthog?.reloadFeatureFlags()\n\n const AnalyticsInstance = {\n initialise,\n setAttributes,\n identifyEvent,\n backfillPersonProperties,\n getFeatureState,\n getFeatureValue,\n getGrowthbookStatus,\n isFeatureOn,\n setUrl,\n getId,\n getAnonymousId,\n trackEvent,\n getInstances,\n pageView,\n reset,\n isPosthogFeatureEnabled,\n getPosthogFeatureFlag,\n getPosthogFeatureFlagPayload,\n getPosthogAllFlags,\n onPosthogFeatureFlags,\n reloadPosthogFeatureFlags,\n }\n\n if (typeof window !== 'undefined') {\n window.AnalyticsInstance = AnalyticsInstance\n }\n\n return AnalyticsInstance\n}\n\nexport const Analytics = createAnalyticsInstance()\n"],"mappings":"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","names":["COOKIE_MAX_AGE_SECONDS","_RudderStack","RUDDERSTACK_KEY","onLoaded","debug","RudderAnalytics","createLogger","hostname","domain_name","domain","uuid","bytes","hex","byte","secureFlag","error","rudderstackDataplane","user_id","payload","currentUserId","current_page","platform","properties","pageProperties","event","err","RudderStack","CACHE_STORAGE_EVENTS","CACHE_STORAGE_PAGES","cacheEventToStorage","eventName","properties","existingCache","events","err","cachePageViewToStorage","pageName","pages","getCachedEvents","storedEventsString","getCachedPageViews","storedPagesString","clearCachedEvents","clearCachedPageViews","createAnalyticsInstance","_options","_debug","log","createLogger","_growthbook","_rudderstack","_posthog","core_data","tracking_config","offline_event_cache","_pending_identify_calls","_storage_cache_processed","processStorageCache","storedEvents","getCachedEvents","event","