@active-reach/web-sdk 1.7.3 → 1.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aegis-sw.js +1 -1
- package/dist/aegis.min.js +1 -1
- package/dist/aegis.min.js.map +1 -1
- package/dist/inapp/AegisInAppManager.d.ts +19 -0
- package/dist/inapp/AegisInAppManager.d.ts.map +1 -1
- package/dist/index.js +38 -5
- package/dist/index.js.map +1 -1
- package/dist/push/AegisWebPush.d.ts +1 -0
- package/dist/push/AegisWebPush.d.ts.map +1 -1
- package/dist/push/AegisWebPush.js +33 -0
- package/dist/push/AegisWebPush.js.map +1 -1
- package/package.json +1 -1
package/dist/aegis.min.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aegis.min.js","sources":["../src/types/config.ts","../src/utils/uuid.ts","../src/utils/logger.ts","../src/utils/identity.ts","../src/core/session.ts","../src/core/queue.ts","../src/core/transport.ts","../src/utils/storage.ts","../src/utils/device.ts","../src/utils/url-parser.ts","../src/plugins/registry.ts","../src/utils/consent.ts","../src/ecommerce/index.ts","../src/core/rate-limiter.ts","../src/governance/murmur3.ts","../src/governance/bloom-filter.ts","../src/governance/name-governor.ts","../src/core/analytics.ts","../src/inapp/renderers/carousel-cards.ts","../src/inapp/renderers/sticky-bar.ts","../src/inapp/renderers/progress-bar.ts","../src/inapp/renderers/coachmark-tour.ts","../src/inapp/AegisInAppManager.ts","../src/inapp/renderers/product-recommendation.ts","../src/widgets/AegisWidgetManager.ts","../src/triggers/TriggerEngine.ts","../src/core/bootstrap.ts","../src/cdn.ts","../src/runtime/AegisMessageRuntime.ts","../src/placements/AegisPlacementManager.ts"],"sourcesContent":["export type CellRegion = 'us-east' | 'us-west' | 'eu-central' | 'ap-south' | 'ap-southeast';\n\nexport interface CellEndpoint {\n region: CellRegion;\n url: string;\n priority: number;\n healthy: boolean;\n}\n\nexport interface AegisConfig {\n write_key: string;\n\n workspace_id?: string;\n \n api_host?: string;\n \n cell_endpoints?: CellEndpoint[];\n \n preferred_region?: CellRegion;\n \n auto_region_detection?: boolean;\n \n batch_size?: number;\n \n batch_interval?: number;\n \n capture_utm?: boolean;\n \n capture_referrer?: boolean;\n \n auto_page_view?: boolean;\n \n session_timeout?: number;\n \n debug?: boolean;\n \n respect_dnt?: boolean;\n \n cross_domain_tracking?: boolean;\n \n cookie_domain?: string;\n \n secure_cookie?: boolean;\n \n enable_offline_mode?: boolean;\n \n max_offline_events?: number;\n \n retry_failed_requests?: boolean;\n \n max_retries?: number;\n \n retry_backoff_multiplier?: number;\n \n request_timeout?: number;\n\n /** Client-side rate limiter — burst (token bucket capacity). Default 100. */\n rate_limit_burst?: number;\n\n /** Client-side rate limiter — sustained tokens per second. Default 20. */\n rate_limit_per_second?: number;\n\n plugins?: string[];\n\n wait_for_consent?: boolean;\n\n default_consent?: {\n analytics?: boolean;\n marketing?: boolean;\n functional?: boolean;\n };\n\n enable_consent_mode?: boolean;\n\n integrate_onetrust?: boolean;\n\n integrate_cookiebot?: boolean;\n\n integrate_google_consent_mode?: boolean;\n\n /** Push notification configuration. When provided, AegisWebPush is initialized. */\n push?: {\n /** VAPID public key for Web Push subscription. */\n vapidPublicKey: string;\n /** Automatically prompt for push permission after SDK init. Default: false. */\n autoPrompt?: boolean;\n /** Delay in ms before showing auto-prompt. Default: 5000. */\n promptDelay?: number;\n /** Path to the service worker file. Default: '/aegis-sw.js'. */\n serviceWorkerPath?: string;\n /** Scope for the service worker registration. Default: '/'. Critical for e-commerce platforms. */\n serviceWorkerScope?: string;\n };\n}\n\nexport interface AegisConfigInternal extends Required<Omit<AegisConfig, 'api_host' | 'cell_endpoints' | 'preferred_region' | 'cookie_domain' | 'plugins' | 'default_consent' | 'workspace_id'>> {\n initialized: boolean;\n workspace_id: string | null;\n api_host: string | null;\n cell_endpoints: CellEndpoint[];\n preferred_region: CellRegion | null;\n cookie_domain: string | null;\n plugins: string[];\n active_cell: CellEndpoint | null;\n default_consent: {\n analytics: boolean;\n marketing: boolean;\n functional: boolean;\n };\n}\n\nexport const DEFAULT_CONFIG: Partial<AegisConfigInternal> = {\n workspace_id: null,\n batch_size: 10,\n batch_interval: 1000,\n capture_utm: true,\n capture_referrer: true,\n auto_page_view: false,\n session_timeout: 30,\n debug: false,\n respect_dnt: true,\n cross_domain_tracking: false,\n secure_cookie: true,\n enable_offline_mode: true,\n max_offline_events: 100,\n retry_failed_requests: true,\n max_retries: 3,\n retry_backoff_multiplier: 2,\n request_timeout: 5000,\n rate_limit_burst: 100,\n rate_limit_per_second: 20,\n auto_region_detection: true,\n wait_for_consent: false,\n enable_consent_mode: false,\n integrate_onetrust: false,\n integrate_cookiebot: false,\n integrate_google_consent_mode: false,\n default_consent: {\n analytics: false,\n marketing: false,\n functional: true,\n },\n initialized: false,\n api_host: null,\n cell_endpoints: [],\n preferred_region: null,\n cookie_domain: null,\n plugins: [],\n active_cell: null,\n};\n","export function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\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\nexport function generateSessionId(): string {\n return `sess_${Date.now()}_${generateUUID().slice(0, 8)}`;\n}\n\nexport function generateMessageId(): string {\n return `msg_${Date.now()}_${generateUUID().slice(0, 8)}`;\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nclass Logger {\n private enabled: boolean = false;\n private prefix: string = '[Aegis SDK]';\n\n enable(): void {\n this.enabled = true;\n }\n\n disable(): void {\n this.enabled = false;\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n debug(message: string, ...args: any[]): void {\n if (!this.enabled) return;\n console.debug(`${this.prefix} ${message}`, ...args);\n }\n\n info(message: string, ...args: any[]): void {\n if (!this.enabled) return;\n console.info(`${this.prefix} ${message}`, ...args);\n }\n\n warn(message: string, ...args: any[]): void {\n console.warn(`${this.prefix} ${message}`, ...args);\n }\n\n error(message: string, ...args: any[]): void {\n console.error(`${this.prefix} ${message}`, ...args);\n }\n}\n\nexport const logger = new Logger();\n","import { generateUUID } from './uuid';\nimport { Storage } from './storage';\nimport { logger } from './logger';\n\nexport interface IdentityState {\n anonymousId: string;\n userId: string | null;\n traits: Record<string, any>;\n}\n\nexport class Identity {\n private storage: Storage;\n private anonymousId: string;\n private userId: string | null = null;\n private traits: Record<string, any> = {};\n\n constructor(storage: Storage) {\n this.storage = storage;\n this.anonymousId = this.getOrCreateAnonymousId();\n this.loadUserIdentity();\n }\n\n private getOrCreateAnonymousId(): string {\n let id = this.storage.get('anon_id');\n\n if (!id) {\n id = generateUUID();\n this.storage.set('anon_id', id, 365);\n logger.debug('Created new anonymous ID:', id);\n } else {\n logger.debug('Loaded existing anonymous ID:', id);\n }\n\n return id;\n }\n\n private loadUserIdentity(): void {\n const storedUserId = this.storage.get('user_id');\n const storedTraits = this.storage.get('user_traits');\n\n if (storedUserId) {\n this.userId = storedUserId;\n logger.debug('Loaded user ID:', storedUserId);\n }\n\n if (storedTraits) {\n try {\n this.traits = JSON.parse(storedTraits);\n logger.debug('Loaded user traits:', this.traits);\n } catch (error) {\n logger.warn('Failed to parse stored traits:', error);\n this.traits = {};\n }\n }\n }\n\n getAnonymousId(): string {\n return this.anonymousId;\n }\n\n setUserId(userId: string, traits?: Record<string, any>): void {\n this.userId = userId;\n this.storage.set('user_id', userId, 365);\n logger.info('User identified:', userId);\n\n if (traits) {\n this.setTraits(traits);\n }\n }\n\n getUserId(): string | null {\n return this.userId;\n }\n\n setTraits(traits: Record<string, any>): void {\n this.traits = { ...this.traits, ...traits };\n this.storage.set('user_traits', JSON.stringify(this.traits), 365);\n logger.debug('User traits updated:', this.traits);\n }\n\n getTraits(): Record<string, any> {\n return { ...this.traits };\n }\n\n reset(): void {\n this.userId = null;\n this.traits = {};\n this.anonymousId = generateUUID();\n\n this.storage.remove('user_id');\n this.storage.remove('user_traits');\n this.storage.set('anon_id', this.anonymousId, 365);\n\n logger.info('Identity reset, new anonymous ID:', this.anonymousId);\n }\n\n alias(newUserId: string): { previousId: string; newUserId: string } {\n const previousId = this.userId || this.anonymousId;\n\n this.setUserId(newUserId);\n\n logger.info('User aliased:', { previousId, newUserId });\n\n return { previousId, newUserId };\n }\n\n getState(): IdentityState {\n return {\n anonymousId: this.anonymousId,\n userId: this.userId,\n traits: this.getTraits(),\n };\n }\n}\n","import { Storage } from '../utils/storage';\nimport { generateSessionId } from '../utils/uuid';\nimport { logger } from '../utils/logger';\nimport { AdClickIDs } from '../utils/url-parser';\n\nexport interface SessionState {\n sessionId: string;\n startTime: number;\n lastActivityTime: number;\n eventCount: number;\n adClickIDs?: AdClickIDs;\n landingPage?: string;\n}\n\nexport class SessionManager {\n private storage: Storage;\n private sessionId: string;\n private sessionTimeout: number;\n private lastActivityTime: number;\n private sessionStartTime: number;\n private eventCount: number = 0;\n private checkInterval: number | null = null;\n private activityThrottle: number = 1000;\n private lastActivityUpdate: number = 0;\n private adClickIDs: AdClickIDs = {};\n private landingPage?: string;\n\n constructor(storage: Storage, sessionTimeoutMinutes: number = 30) {\n this.storage = storage;\n this.sessionTimeout = sessionTimeoutMinutes * 60 * 1000;\n this.lastActivityTime = Date.now();\n this.sessionStartTime = Date.now();\n\n const session = this.loadSession();\n if (session) {\n this.sessionId = session.sessionId;\n this.sessionStartTime = session.startTime;\n this.lastActivityTime = session.lastActivityTime;\n this.eventCount = session.eventCount;\n this.adClickIDs = session.adClickIDs || {};\n this.landingPage = session.landingPage;\n logger.debug('Session loaded:', session);\n } else {\n this.sessionId = this.createNewSession();\n }\n\n this.startActivityTracking();\n this.startExpiryCheck();\n }\n\n private loadSession(): SessionState | null {\n const sessionData = this.storage.get('session');\n\n if (!sessionData) {\n return null;\n }\n\n try {\n const session: SessionState = JSON.parse(sessionData);\n const elapsed = Date.now() - session.lastActivityTime;\n\n if (elapsed < this.sessionTimeout) {\n return session;\n } else {\n logger.debug('Session expired, creating new session');\n this.storage.remove('session');\n return null;\n }\n } catch (error) {\n logger.warn('Failed to parse session data:', error);\n this.storage.remove('session');\n return null;\n }\n }\n\n private createNewSession(): string {\n const newSessionId = generateSessionId();\n this.sessionStartTime = Date.now();\n this.lastActivityTime = Date.now();\n this.eventCount = 0;\n\n this.persistSession();\n logger.info('New session created:', newSessionId);\n\n return newSessionId;\n }\n\n private persistSession(): void {\n const sessionData: SessionState = {\n sessionId: this.sessionId,\n startTime: this.sessionStartTime,\n lastActivityTime: this.lastActivityTime,\n eventCount: this.eventCount,\n adClickIDs: this.adClickIDs,\n landingPage: this.landingPage,\n };\n\n this.storage.set('session', JSON.stringify(sessionData));\n }\n\n private startActivityTracking(): void {\n const events = ['click', 'scroll', 'keypress', 'mousemove', 'touchstart'];\n\n const activityHandler = () => this.onActivity();\n\n events.forEach((event) => {\n window.addEventListener(event, activityHandler, { passive: true });\n });\n\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n this.onActivity();\n }\n });\n }\n\n private startExpiryCheck(): void {\n this.checkInterval = window.setInterval(() => {\n this.checkSessionExpiry();\n }, 60000);\n }\n\n private onActivity(): void {\n const now = Date.now();\n const timeSinceLastUpdate = now - this.lastActivityUpdate;\n\n if (timeSinceLastUpdate < this.activityThrottle) {\n return;\n }\n\n this.lastActivityUpdate = now;\n const timeSinceLastActivity = now - this.lastActivityTime;\n\n if (timeSinceLastActivity > this.sessionTimeout) {\n logger.info('Session expired due to inactivity, creating new session');\n this.sessionId = this.createNewSession();\n } else {\n this.lastActivityTime = now;\n this.persistSession();\n }\n }\n\n private checkSessionExpiry(): void {\n const elapsed = Date.now() - this.lastActivityTime;\n\n if (elapsed > this.sessionTimeout) {\n logger.info('Session expired during check, creating new session');\n this.sessionId = this.createNewSession();\n }\n }\n\n getSessionId(): string {\n return this.sessionId;\n }\n\n incrementEventCount(): void {\n this.eventCount++;\n this.lastActivityTime = Date.now();\n this.persistSession();\n }\n\n getSessionDuration(): number {\n return Date.now() - this.sessionStartTime;\n }\n\n getEventCount(): number {\n return this.eventCount;\n }\n\n getState(): SessionState {\n return {\n sessionId: this.sessionId,\n startTime: this.sessionStartTime,\n lastActivityTime: this.lastActivityTime,\n eventCount: this.eventCount,\n adClickIDs: this.adClickIDs,\n landingPage: this.landingPage,\n };\n }\n\n setAdClickIDs(adClickIDs: AdClickIDs, landingPage?: string): void {\n if (Object.keys(adClickIDs).length > 0) {\n this.adClickIDs = { ...this.adClickIDs, ...adClickIDs };\n if (landingPage) {\n this.landingPage = landingPage;\n }\n this.persistSession();\n logger.info('Ad click IDs stored in session:', this.adClickIDs);\n }\n }\n\n getAdClickIDs(): AdClickIDs {\n return this.adClickIDs;\n }\n\n getLandingPage(): string | undefined {\n return this.landingPage;\n }\n\n destroy(): void {\n if (this.checkInterval) {\n clearInterval(this.checkInterval);\n this.checkInterval = null;\n }\n }\n}\n","import { AegisEvent } from '../types/events';\nimport { Transport } from './transport';\nimport { Storage } from '../utils/storage';\nimport { logger } from '../utils/logger';\n\nexport interface QueueConfig {\n batchSize: number;\n batchInterval: number;\n enableOfflineMode: boolean;\n maxOfflineEvents: number;\n}\n\nexport class EventQueue {\n private buffer: AegisEvent[] = [];\n private config: QueueConfig;\n private transport: Transport;\n private storage: Storage;\n private flushInterval: number | null = null;\n private isFlushing: boolean = false;\n private offlineQueue: AegisEvent[] = [];\n private isOnline: boolean = navigator.onLine;\n\n constructor(config: QueueConfig, transport: Transport, storage: Storage) {\n this.config = config;\n this.transport = transport;\n this.storage = storage;\n\n if (config.enableOfflineMode) {\n this.loadOfflineQueue();\n this.setupOnlineListener();\n }\n\n this.startFlushTimer();\n this.setupUnloadHandlers();\n }\n\n private loadOfflineQueue(): void {\n const offlineData = this.storage.get('offline_queue');\n\n if (!offlineData) {\n return;\n }\n\n try {\n const events = JSON.parse(offlineData) as AegisEvent[];\n\n if (Array.isArray(events) && events.length > 0) {\n this.offlineQueue = events.slice(0, this.config.maxOfflineEvents);\n logger.info(`Loaded ${this.offlineQueue.length} offline events`);\n\n if (this.isOnline) {\n this.flushOfflineQueue();\n }\n }\n } catch (error) {\n logger.warn('Failed to load offline queue:', error);\n this.storage.remove('offline_queue');\n }\n }\n\n private saveOfflineQueue(): void {\n if (this.offlineQueue.length === 0) {\n this.storage.remove('offline_queue');\n return;\n }\n\n try {\n const data = JSON.stringify(this.offlineQueue);\n this.storage.set('offline_queue', data);\n logger.debug(`Saved ${this.offlineQueue.length} events to offline queue`);\n } catch (error) {\n logger.warn('Failed to save offline queue:', error);\n }\n }\n\n private setupOnlineListener(): void {\n window.addEventListener('online', () => {\n logger.info('Connection restored');\n this.isOnline = true;\n this.flushOfflineQueue();\n this.flush();\n });\n\n window.addEventListener('offline', () => {\n logger.warn('Connection lost, entering offline mode');\n this.isOnline = false;\n });\n }\n\n private async flushOfflineQueue(): Promise<void> {\n if (this.offlineQueue.length === 0) {\n return;\n }\n\n logger.info(`Flushing ${this.offlineQueue.length} offline events`);\n\n const events = [...this.offlineQueue];\n this.offlineQueue = [];\n this.storage.remove('offline_queue');\n\n const result = await this.transport.send(events);\n\n if (!result.success) {\n logger.warn('Failed to send offline events, re-queueing');\n this.offlineQueue = [...events, ...this.offlineQueue].slice(\n 0,\n this.config.maxOfflineEvents\n );\n this.saveOfflineQueue();\n } else {\n logger.info('Offline events sent successfully');\n }\n }\n\n push(event: AegisEvent): void {\n if (!this.isOnline && this.config.enableOfflineMode) {\n this.addToOfflineQueue(event);\n return;\n }\n\n this.buffer.push(event);\n logger.debug('Event queued:', event.type, event);\n\n if (this.buffer.length >= this.config.batchSize) {\n this.flush();\n }\n }\n\n private addToOfflineQueue(event: AegisEvent): void {\n if (this.offlineQueue.length >= this.config.maxOfflineEvents) {\n logger.warn('Offline queue full, dropping oldest event');\n this.offlineQueue.shift();\n }\n\n this.offlineQueue.push(event);\n this.saveOfflineQueue();\n logger.debug('Event added to offline queue');\n }\n\n async flush(): Promise<void> {\n if (this.isFlushing) {\n logger.debug('Flush already in progress, skipping');\n return;\n }\n\n if (this.buffer.length === 0) {\n return;\n }\n\n this.isFlushing = true;\n\n const events = [...this.buffer];\n this.buffer = [];\n\n logger.info(`Flushing ${events.length} events`);\n\n try {\n const result = await this.transport.send(events);\n\n if (!result.success) {\n logger.error('Failed to send events:', result.error);\n\n if (this.config.enableOfflineMode) {\n this.offlineQueue = [...this.offlineQueue, ...events].slice(\n 0,\n this.config.maxOfflineEvents\n );\n this.saveOfflineQueue();\n logger.info('Events saved to offline queue');\n } else {\n this.buffer.unshift(...events);\n logger.warn('Events re-queued for retry');\n }\n } else {\n logger.info('Events sent successfully');\n }\n } catch (error) {\n logger.error('Flush error:', error);\n\n if (this.config.enableOfflineMode) {\n this.offlineQueue = [...this.offlineQueue, ...events].slice(\n 0,\n this.config.maxOfflineEvents\n );\n this.saveOfflineQueue();\n }\n } finally {\n this.isFlushing = false;\n }\n }\n\n private startFlushTimer(): void {\n if (this.flushInterval) {\n clearInterval(this.flushInterval);\n }\n\n this.flushInterval = window.setInterval(() => {\n this.flush();\n }, this.config.batchInterval);\n\n logger.debug(\n `Flush timer started with interval: ${this.config.batchInterval}ms`\n );\n }\n\n private setupUnloadHandlers(): void {\n const flushBeforeUnload = () => {\n if (this.buffer.length > 0 || this.offlineQueue.length > 0) {\n this.persistBufferToOfflineQueue();\n this.flush();\n }\n };\n\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n flushBeforeUnload();\n }\n });\n\n window.addEventListener('beforeunload', flushBeforeUnload);\n\n window.addEventListener('pagehide', flushBeforeUnload);\n }\n\n private persistBufferToOfflineQueue(): void {\n if (this.buffer.length === 0) {\n return;\n }\n\n if (this.config.enableOfflineMode) {\n this.offlineQueue = [...this.offlineQueue, ...this.buffer].slice(\n 0,\n this.config.maxOfflineEvents\n );\n this.saveOfflineQueue();\n logger.debug('Buffer persisted to offline queue before unload');\n }\n }\n\n getQueueSize(): number {\n return this.buffer.length;\n }\n\n getOfflineQueueSize(): number {\n return this.offlineQueue.length;\n }\n\n clear(): void {\n this.buffer = [];\n this.offlineQueue = [];\n this.storage.remove('offline_queue');\n logger.info('Queue cleared');\n }\n\n destroy(): void {\n if (this.flushInterval) {\n clearInterval(this.flushInterval);\n this.flushInterval = null;\n }\n\n this.flush();\n }\n}\n","import { AegisEvent, BatchPayload, BatchResponse } from '../types/events';\nimport { CellEndpoint, CellRegion } from '../types/config';\nimport { logger } from '../utils/logger';\nimport { Storage } from '../utils/storage';\n\nexport interface TransportConfig {\n writeKey: string;\n apiHost: string | null;\n cellEndpoints: CellEndpoint[];\n preferredRegion: CellRegion | null;\n autoRegionDetection: boolean;\n requestTimeout: number;\n retryFailedRequests: boolean;\n maxRetries: number;\n retryBackoffMultiplier: number;\n}\n\nexport interface SendResult {\n success: boolean;\n response?: BatchResponse;\n error?: Error;\n endpoint?: string;\n}\n\nexport class Transport {\n private config: TransportConfig;\n private storage: Storage;\n private activeCell: CellEndpoint | null = null;\n private healthCheckInterval: number | null = null;\n private regionLatencyMap: Map<string, number> = new Map();\n\n constructor(config: TransportConfig, storage: Storage) {\n this.config = config;\n this.storage = storage;\n\n if (config.cellEndpoints.length > 0) {\n this.initializeCellularArchitecture();\n }\n }\n\n private async initializeCellularArchitecture(): Promise<void> {\n const cachedCell = this.loadCachedCell();\n\n if (cachedCell && this.isCellHealthy(cachedCell)) {\n this.activeCell = cachedCell;\n logger.info('Using cached cell:', cachedCell);\n } else {\n await this.selectOptimalCell();\n }\n\n this.startHealthChecks();\n }\n\n private loadCachedCell(): CellEndpoint | null {\n const cached = this.storage.get('active_cell');\n\n if (!cached) {\n return null;\n }\n\n try {\n return JSON.parse(cached) as CellEndpoint;\n } catch (error) {\n logger.warn('Failed to parse cached cell:', error);\n return null;\n }\n }\n\n private saveCachedCell(cell: CellEndpoint): void {\n this.storage.set('active_cell', JSON.stringify(cell), 7);\n }\n\n private isCellHealthy(cell: CellEndpoint): boolean {\n return (\n cell.healthy &&\n this.config.cellEndpoints.some(\n (c) => c.region === cell.region && c.url === cell.url\n )\n );\n }\n\n private async selectOptimalCell(): Promise<void> {\n logger.info('Selecting optimal cell...');\n\n if (this.config.preferredRegion) {\n const preferredCell = this.config.cellEndpoints.find(\n (cell) => cell.region === this.config.preferredRegion && cell.healthy\n );\n\n if (preferredCell) {\n this.activeCell = preferredCell;\n this.saveCachedCell(preferredCell);\n logger.info('Using preferred region cell:', preferredCell);\n return;\n }\n }\n\n if (this.config.autoRegionDetection) {\n await this.detectOptimalRegion();\n } else {\n this.selectCellByPriority();\n }\n }\n\n private async detectOptimalRegion(): Promise<void> {\n const healthyCells = this.config.cellEndpoints.filter((cell) => cell.healthy);\n\n if (healthyCells.length === 0) {\n logger.error('No healthy cells available');\n return;\n }\n\n const latencyPromises = healthyCells.map(async (cell) => {\n const latency = await this.measureLatency(cell);\n this.regionLatencyMap.set(cell.region, latency);\n return { cell, latency };\n });\n\n const results = await Promise.all(latencyPromises);\n results.sort((a, b) => a.latency - b.latency);\n\n const optimalCell = results[0].cell;\n this.activeCell = optimalCell;\n this.saveCachedCell(optimalCell);\n\n logger.info('Optimal cell selected:', {\n region: optimalCell.region,\n latency: results[0].latency,\n });\n }\n\n private async measureLatency(cell: CellEndpoint): Promise<number> {\n const startTime = performance.now();\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 2000);\n\n const response = await fetch(`${cell.url}/health`, {\n method: 'GET',\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return performance.now() - startTime;\n } else {\n return Infinity;\n }\n } catch (error) {\n logger.warn(`Health check failed for ${cell.region}:`, error);\n return Infinity;\n }\n }\n\n private selectCellByPriority(): void {\n const sortedCells = [...this.config.cellEndpoints]\n .filter((cell) => cell.healthy)\n .sort((a, b) => a.priority - b.priority);\n\n if (sortedCells.length > 0) {\n this.activeCell = sortedCells[0];\n this.saveCachedCell(sortedCells[0]);\n logger.info('Cell selected by priority:', sortedCells[0]);\n } else {\n logger.error('No healthy cells available');\n }\n }\n\n private startHealthChecks(): void {\n this.healthCheckInterval = window.setInterval(() => {\n this.performHealthChecks();\n }, 60000);\n }\n\n private async performHealthChecks(): Promise<void> {\n const healthPromises = this.config.cellEndpoints.map(async (cell) => {\n const isHealthy = await this.checkCellHealth(cell);\n cell.healthy = isHealthy;\n return { cell, isHealthy };\n });\n\n const results = await Promise.all(healthPromises);\n\n if (this.activeCell && !this.activeCell.healthy) {\n logger.warn('Active cell unhealthy, selecting new cell');\n await this.selectOptimalCell();\n }\n\n logger.debug('Health check results:', results);\n }\n\n private async checkCellHealth(cell: CellEndpoint): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 3000);\n\n const response = await fetch(`${cell.url}/health`, {\n method: 'GET',\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n return response.ok;\n } catch (error) {\n return false;\n }\n }\n\n async send(events: AegisEvent[]): Promise<SendResult> {\n if (events.length === 0) {\n return { success: true };\n }\n\n const endpoint = this.getActiveEndpoint();\n const payload = this.buildPayload(events);\n\n logger.debug('Sending batch:', { endpoint, eventCount: events.length });\n\n if (document.visibilityState === 'hidden' && typeof navigator.sendBeacon === 'function') {\n const result = this.sendViaBeacon(endpoint, payload);\n return Promise.resolve(result);\n } else {\n return this.sendViaFetch(endpoint, payload);\n }\n }\n\n private getActiveEndpoint(): string {\n if (this.activeCell) {\n return `${this.activeCell.url}/v1/batch`;\n }\n\n if (this.config.apiHost) {\n return `${this.config.apiHost}/v1/batch`;\n }\n\n throw new Error('No active endpoint available');\n }\n\n private buildPayload(events: AegisEvent[]): BatchPayload {\n return {\n batch: events,\n sentAt: new Date().toISOString(),\n writeKey: this.config.writeKey,\n context: this.activeCell\n ? {\n cell: {\n region: this.activeCell.region,\n endpoint: this.activeCell.url,\n },\n }\n : undefined,\n };\n }\n\n private sendViaBeacon(endpoint: string, payload: BatchPayload): SendResult | Promise<SendResult> {\n try {\n const blob = new Blob([JSON.stringify(payload)], {\n type: 'application/json',\n });\n\n const sent = navigator.sendBeacon(endpoint, blob);\n\n if (sent) {\n logger.debug('Batch sent via Beacon');\n return { success: true, endpoint };\n } else {\n logger.warn('Beacon send failed, falling back to fetch');\n return this.sendViaFetch(endpoint, payload);\n }\n } catch (error) {\n logger.error('Beacon send error:', error);\n return {\n success: false,\n error: error as Error,\n endpoint,\n };\n }\n }\n\n private async sendViaFetch(\n endpoint: string,\n payload: BatchPayload,\n attempt: number = 1\n ): Promise<SendResult> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n this.config.requestTimeout\n );\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.writeKey}`,\n },\n body: JSON.stringify(payload),\n keepalive: true,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n const result: BatchResponse = await response.json();\n logger.debug('Batch sent successfully:', result);\n return { success: true, response: result, endpoint };\n } else {\n const errorText = await response.text();\n const error = new Error(\n `HTTP ${response.status}: ${errorText || response.statusText}`\n );\n\n logger.error('Batch send failed:', error);\n\n if (this.shouldRetry(response.status, attempt)) {\n return this.retryRequest(endpoint, payload, attempt);\n }\n\n return { success: false, error, endpoint };\n }\n } catch (error) {\n logger.error('Fetch error:', error);\n\n if (this.shouldRetry(0, attempt)) {\n return this.retryRequest(endpoint, payload, attempt);\n }\n\n return {\n success: false,\n error: error as Error,\n endpoint,\n };\n }\n }\n\n private shouldRetry(statusCode: number, attempt: number): boolean {\n if (!this.config.retryFailedRequests) {\n return false;\n }\n\n if (attempt >= this.config.maxRetries) {\n return false;\n }\n\n if (statusCode === 0) {\n return true;\n }\n\n return statusCode >= 500 || statusCode === 429;\n }\n\n private async retryRequest(\n endpoint: string,\n payload: BatchPayload,\n attempt: number\n ): Promise<SendResult> {\n const delay =\n Math.pow(this.config.retryBackoffMultiplier, attempt) * 1000;\n\n logger.info(`Retrying request in ${delay}ms (attempt ${attempt + 1})`);\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n\n return this.sendViaFetch(endpoint, payload, attempt + 1);\n }\n\n getActiveCell(): CellEndpoint | null {\n return this.activeCell;\n }\n\n getRegionLatencies(): Map<string, number> {\n return new Map(this.regionLatencyMap);\n }\n\n destroy(): void {\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n this.healthCheckInterval = null;\n }\n }\n}\n","const STORAGE_PREFIX = 'aegis_';\n\nexport interface StorageOptions {\n cookieDomain?: string | null;\n secureCookie?: boolean;\n crossDomain?: boolean;\n}\n\nexport class Storage {\n private useLocalStorage: boolean;\n private options: StorageOptions;\n\n constructor(options: StorageOptions = {}) {\n this.options = options;\n this.useLocalStorage = this.isLocalStorageAvailable();\n }\n\n private isLocalStorageAvailable(): boolean {\n try {\n const test = '__aegis_test__';\n localStorage.setItem(test, test);\n localStorage.removeItem(test);\n return true;\n } catch {\n return false;\n }\n }\n\n set(key: string, value: string, expiryDays: number = 365): void {\n const fullKey = STORAGE_PREFIX + key;\n\n if (this.useLocalStorage) {\n try {\n const item = {\n value,\n expiry: Date.now() + expiryDays * 24 * 60 * 60 * 1000,\n };\n localStorage.setItem(fullKey, JSON.stringify(item));\n } catch (error) {\n console.warn('[Aegis Storage] localStorage.setItem failed:', error);\n }\n }\n\n this.setCookie(fullKey, value, expiryDays);\n }\n\n get(key: string): string | null {\n const fullKey = STORAGE_PREFIX + key;\n\n if (this.useLocalStorage) {\n try {\n const itemStr = localStorage.getItem(fullKey);\n if (itemStr) {\n const item = JSON.parse(itemStr);\n if (Date.now() < item.expiry) {\n return item.value;\n } else {\n localStorage.removeItem(fullKey);\n }\n }\n } catch (error) {\n console.warn('[Aegis Storage] localStorage.getItem failed:', error);\n }\n }\n\n return this.getCookie(fullKey);\n }\n\n remove(key: string): void {\n const fullKey = STORAGE_PREFIX + key;\n\n if (this.useLocalStorage) {\n try {\n localStorage.removeItem(fullKey);\n } catch (error) {\n console.warn('[Aegis Storage] localStorage.removeItem failed:', error);\n }\n }\n\n this.deleteCookie(fullKey);\n }\n\n clear(): void {\n if (this.useLocalStorage) {\n try {\n const keys = Object.keys(localStorage);\n keys.forEach((key) => {\n if (key.startsWith(STORAGE_PREFIX)) {\n localStorage.removeItem(key);\n }\n });\n } catch (error) {\n console.warn('[Aegis Storage] localStorage.clear failed:', error);\n }\n }\n\n const cookies = document.cookie.split(';');\n cookies.forEach((cookie) => {\n const key = cookie.split('=')[0].trim();\n if (key.startsWith(STORAGE_PREFIX)) {\n this.deleteCookie(key);\n }\n });\n }\n\n private setCookie(name: string, value: string, days: number): void {\n try {\n const date = new Date();\n date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\n const expires = `expires=${date.toUTCString()}`;\n \n let cookieStr = `${name}=${value};${expires};path=/`;\n \n if (this.options.secureCookie && window.location.protocol === 'https:') {\n cookieStr += ';Secure';\n }\n \n cookieStr += ';SameSite=Lax';\n \n if (this.options.cookieDomain) {\n cookieStr += `;domain=${this.options.cookieDomain}`;\n } else if (this.options.crossDomain) {\n const domain = this.getRootDomain();\n if (domain) {\n cookieStr += `;domain=${domain}`;\n }\n }\n \n document.cookie = cookieStr;\n } catch (error) {\n console.warn('[Aegis Storage] setCookie failed:', error);\n }\n }\n\n private getCookie(name: string): string | null {\n try {\n const nameEQ = name + '=';\n const ca = document.cookie.split(';');\n \n for (let i = 0; i < ca.length; i++) {\n let c = ca[i];\n while (c.charAt(0) === ' ') {\n c = c.substring(1, c.length);\n }\n if (c.indexOf(nameEQ) === 0) {\n return c.substring(nameEQ.length, c.length);\n }\n }\n } catch (error) {\n console.warn('[Aegis Storage] getCookie failed:', error);\n }\n \n return null;\n }\n\n private deleteCookie(name: string): void {\n try {\n let cookieStr = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/`;\n \n if (this.options.cookieDomain) {\n cookieStr += `;domain=${this.options.cookieDomain}`;\n } else if (this.options.crossDomain) {\n const domain = this.getRootDomain();\n if (domain) {\n cookieStr += `;domain=${domain}`;\n }\n }\n \n document.cookie = cookieStr;\n } catch (error) {\n console.warn('[Aegis Storage] deleteCookie failed:', error);\n }\n }\n\n private getRootDomain(): string | null {\n try {\n const hostname = window.location.hostname;\n \n if (/^(\\d{1,3}\\.){3}\\d{1,3}$/.test(hostname)) {\n return null;\n }\n \n if (hostname === 'localhost') {\n return null;\n }\n \n const parts = hostname.split('.');\n \n if (parts.length <= 2) {\n return `.${hostname}`;\n }\n \n return `.${parts.slice(-2).join('.')}`;\n } catch (error) {\n console.warn('[Aegis Storage] getRootDomain failed:', error);\n return null;\n }\n }\n}\n","import { EventContext } from '../types/events';\nimport { parseUTMParameters } from './url-parser';\nimport { AegisConfigInternal } from '../types/config';\nimport type { SessionManager } from '../core/session';\n\nexport function buildContext(config: AegisConfigInternal, session?: SessionManager): EventContext {\n const utm = config.capture_utm ? parseUTMParameters() : undefined;\n const device = detectDevice();\n const os = detectOS();\n const browser = detectBrowser();\n const network = detectNetworkInfo();\n\n const adClickIDs = session?.getAdClickIDs();\n const landingPage = session?.getLandingPage();\n\n return {\n library: {\n name: '@active-reach/web-sdk',\n version: '1.0.0',\n },\n page: {\n path: window.location.pathname,\n referrer: config.capture_referrer ? document.referrer : '',\n search: window.location.search,\n title: document.title,\n url: window.location.href,\n hash: window.location.hash,\n },\n userAgent: navigator.userAgent,\n locale: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n screen: {\n width: window.screen.width,\n height: window.screen.height,\n density: window.devicePixelRatio || 1,\n },\n viewport: {\n width: window.innerWidth,\n height: window.innerHeight,\n },\n ...(utm && Object.keys(utm).length > 0 && { campaign: utm }),\n ...(adClickIDs && Object.keys(adClickIDs).length > 0 && { adClickIDs }),\n ...(landingPage && { landingPage }),\n ...(network && { network }),\n ...(device && { device }),\n ...(os && { os }),\n ...(browser && { browser }),\n ...(config.active_cell && {\n cell: {\n region: config.active_cell.region,\n endpoint: config.active_cell.url,\n },\n }),\n };\n}\n\nfunction detectDevice(): EventContext['device'] {\n const ua = navigator.userAgent;\n\n if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {\n return { type: 'tablet' };\n }\n\n if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) {\n return { type: 'mobile' };\n }\n\n return { type: 'desktop' };\n}\n\nfunction detectOS(): EventContext['os'] {\n const ua = navigator.userAgent;\n\n if (/Windows NT 10/i.test(ua)) return { name: 'Windows', version: '10' };\n if (/Windows NT 6.3/i.test(ua)) return { name: 'Windows', version: '8.1' };\n if (/Windows NT 6.2/i.test(ua)) return { name: 'Windows', version: '8' };\n if (/Windows NT 6.1/i.test(ua)) return { name: 'Windows', version: '7' };\n if (/Windows/i.test(ua)) return { name: 'Windows', version: 'Unknown' };\n\n if (/Mac OS X (\\d+)[._](\\d+)/.test(ua)) {\n const match = ua.match(/Mac OS X (\\d+)[._](\\d+)/);\n return { name: 'macOS', version: `${match![1]}.${match![2]}` };\n }\n if (/Mac/i.test(ua)) return { name: 'macOS', version: 'Unknown' };\n\n if (/Android (\\d+\\.\\d+)/.test(ua)) {\n const match = ua.match(/Android (\\d+\\.\\d+)/);\n return { name: 'Android', version: match![1] };\n }\n if (/Android/i.test(ua)) return { name: 'Android', version: 'Unknown' };\n\n if (/iPhone OS (\\d+)_(\\d+)/.test(ua)) {\n const match = ua.match(/iPhone OS (\\d+)_(\\d+)/);\n return { name: 'iOS', version: `${match![1]}.${match![2]}` };\n }\n if (/iPad.*OS (\\d+)_(\\d+)/.test(ua)) {\n const match = ua.match(/iPad.*OS (\\d+)_(\\d+)/);\n return { name: 'iOS', version: `${match![1]}.${match![2]}` };\n }\n if (/iPhone|iPad/i.test(ua)) return { name: 'iOS', version: 'Unknown' };\n\n if (/Linux/i.test(ua)) return { name: 'Linux', version: 'Unknown' };\n\n return { name: 'Unknown', version: 'Unknown' };\n}\n\nfunction detectBrowser(): EventContext['browser'] {\n const ua = navigator.userAgent;\n\n if (/Edg\\/(\\d+\\.\\d+)/.test(ua)) {\n const match = ua.match(/Edg\\/(\\d+\\.\\d+)/);\n return { name: 'Edge', version: match![1] };\n }\n\n if (/Chrome\\/(\\d+\\.\\d+)/.test(ua) && !/Edg/.test(ua)) {\n const match = ua.match(/Chrome\\/(\\d+\\.\\d+)/);\n return { name: 'Chrome', version: match![1] };\n }\n\n if (/Firefox\\/(\\d+\\.\\d+)/.test(ua)) {\n const match = ua.match(/Firefox\\/(\\d+\\.\\d+)/);\n return { name: 'Firefox', version: match![1] };\n }\n\n if (/Safari\\/(\\d+\\.\\d+)/.test(ua) && !/Chrome/.test(ua)) {\n const match = ua.match(/Version\\/(\\d+\\.\\d+)/);\n return { name: 'Safari', version: match ? match[1] : 'Unknown' };\n }\n\n if (/MSIE (\\d+\\.\\d+)/.test(ua) || /Trident\\//.test(ua)) {\n const match = ua.match(/MSIE (\\d+\\.\\d+)/) || ua.match(/rv:(\\d+\\.\\d+)/);\n return { name: 'Internet Explorer', version: match ? match[1] : 'Unknown' };\n }\n\n return { name: 'Unknown', version: 'Unknown' };\n}\n\nfunction detectNetworkInfo(): EventContext['network'] | undefined {\n try {\n const connection =\n (navigator as any).connection ||\n (navigator as any).mozConnection ||\n (navigator as any).webkitConnection;\n\n if (connection) {\n return {\n effectiveType: connection.effectiveType,\n downlink: connection.downlink,\n rtt: connection.rtt,\n };\n }\n } catch (error) {\n console.warn('[Aegis Device] detectNetworkInfo failed:', error);\n }\n\n return undefined;\n}\n\nexport function isBot(): boolean {\n const ua = navigator.userAgent.toLowerCase();\n const botPatterns = [\n 'bot',\n 'crawl',\n 'spider',\n 'slurp',\n 'mediapartners',\n 'googlebot',\n 'bingbot',\n 'yahoo',\n 'duckduckbot',\n 'baiduspider',\n 'yandex',\n 'facebookexternalhit',\n 'linkedinbot',\n 'twitterbot',\n 'slackbot',\n 'telegrambot',\n 'whatsapp',\n 'pingdom',\n 'uptimerobot',\n ];\n\n return botPatterns.some((pattern) => ua.includes(pattern));\n}\n","export interface UTMParams {\n source?: string;\n medium?: string;\n campaign?: string;\n term?: string;\n content?: string;\n name?: string;\n}\n\nexport function parseUTMParameters(url?: string): UTMParams {\n try {\n const searchParams = url\n ? new URL(url).searchParams\n : new URLSearchParams(window.location.search);\n\n const utm: UTMParams = {};\n\n const utmKeys: Array<keyof UTMParams> = [\n 'source',\n 'medium',\n 'campaign',\n 'term',\n 'content',\n 'name',\n ];\n\n utmKeys.forEach((key) => {\n const value = searchParams.get(`utm_${key}`);\n if (value) {\n utm[key] = value;\n }\n });\n\n return utm;\n } catch (error) {\n console.warn('[Aegis URL Parser] parseUTMParameters failed:', error);\n return {};\n }\n}\n\nexport function parseQueryParameters(url?: string): Record<string, string> {\n try {\n const searchParams = url\n ? new URL(url).searchParams\n : new URLSearchParams(window.location.search);\n\n const params: Record<string, string> = {};\n\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n\n return params;\n } catch (error) {\n console.warn('[Aegis URL Parser] parseQueryParameters failed:', error);\n return {};\n }\n}\n\nexport function getCanonicalURL(): string {\n try {\n const canonical = document.querySelector('link[rel=\"canonical\"]');\n if (canonical && canonical.getAttribute('href')) {\n return canonical.getAttribute('href')!;\n }\n \n return window.location.href;\n } catch (error) {\n console.warn('[Aegis URL Parser] getCanonicalURL failed:', error);\n return window.location.href;\n }\n}\n\nexport function stripQueryParameters(url: string): string {\n try {\n const urlObj = new URL(url);\n return `${urlObj.protocol}//${urlObj.host}${urlObj.pathname}`;\n } catch (error) {\n console.warn('[Aegis URL Parser] stripQueryParameters failed:', error);\n return url;\n }\n}\n\nexport interface AdClickIDs {\n gclid?: string;\n fbclid?: string;\n msclkid?: string;\n ctwa_clid?: string;\n ttclid?: string;\n li_fat_id?: string;\n}\n\nexport function parseAdClickIDs(url?: string): AdClickIDs {\n try {\n const searchParams = url\n ? new URL(url).searchParams\n : new URLSearchParams(window.location.search);\n\n const adClickIDs: AdClickIDs = {};\n\n const clickIDKeys: Array<keyof AdClickIDs> = [\n 'gclid',\n 'fbclid',\n 'msclkid',\n 'ctwa_clid',\n 'ttclid',\n 'li_fat_id',\n ];\n\n clickIDKeys.forEach((key) => {\n const value = searchParams.get(key);\n if (value) {\n adClickIDs[key] = value;\n }\n });\n\n return adClickIDs;\n } catch (error) {\n console.warn('[Aegis URL Parser] parseAdClickIDs failed:', error);\n return {};\n }\n}\n\nexport function hasAdClickIDs(adClickIDs: AdClickIDs): boolean {\n return Object.keys(adClickIDs).length > 0;\n}\n","import { Plugin } from '../types/plugin';\nimport { logger } from '../utils/logger';\n\nexport class PluginRegistry {\n private plugins: Map<string, Plugin> = new Map();\n\n register(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n logger.warn(`Plugin \"${plugin.name}\" already registered, skipping`);\n return;\n }\n\n this.plugins.set(plugin.name, plugin);\n logger.info(`Plugin registered: ${plugin.name} v${plugin.version}`);\n }\n\n unregister(pluginName: string): void {\n const plugin = this.plugins.get(pluginName);\n\n if (!plugin) {\n logger.warn(`Plugin \"${pluginName}\" not found`);\n return;\n }\n\n if (plugin.destroy) {\n try {\n plugin.destroy();\n } catch (error) {\n logger.error(`Error destroying plugin \"${pluginName}\":`, error);\n }\n }\n\n this.plugins.delete(pluginName);\n logger.info(`Plugin unregistered: ${pluginName}`);\n }\n\n get(pluginName: string): Plugin | undefined {\n return this.plugins.get(pluginName);\n }\n\n getAll(): Plugin[] {\n return Array.from(this.plugins.values());\n }\n\n async executeHook<T = any>(\n hookName: keyof Plugin,\n ...args: any[]\n ): Promise<T | undefined> {\n for (const plugin of this.plugins.values()) {\n const hook = plugin[hookName];\n\n if (typeof hook === 'function') {\n try {\n const result = await (hook as Function).apply(plugin, args);\n\n if (result !== undefined) {\n return result as T;\n }\n } catch (error) {\n logger.error(\n `Error executing ${String(hookName)} in plugin \"${plugin.name}\":`,\n error\n );\n\n if (plugin.onError) {\n try {\n plugin.onError(error as Error, { hookName, args });\n } catch (onErrorError) {\n logger.error(\n `Error in onError handler for plugin \"${plugin.name}\":`,\n onErrorError\n );\n }\n }\n }\n }\n }\n\n return undefined;\n }\n\n async executeHookChain<T = any>(\n hookName: keyof Plugin,\n initialValue: T,\n ...additionalArgs: any[]\n ): Promise<T> {\n let value = initialValue;\n\n for (const plugin of this.plugins.values()) {\n const hook = plugin[hookName];\n\n if (typeof hook === 'function') {\n try {\n const result = await (hook as Function).apply(plugin, [\n value,\n ...additionalArgs,\n ]);\n\n if (result !== undefined && result !== null) {\n value = result;\n }\n } catch (error) {\n logger.error(\n `Error executing ${String(hookName)} in plugin \"${plugin.name}\":`,\n error\n );\n\n if (plugin.onError) {\n try {\n plugin.onError(error as Error, { hookName, value, additionalArgs });\n } catch (onErrorError) {\n logger.error(\n `Error in onError handler for plugin \"${plugin.name}\":`,\n onErrorError\n );\n }\n }\n }\n }\n }\n\n return value;\n }\n\n async executeHookParallel<T = any>(\n hookName: keyof Plugin,\n ...args: any[]\n ): Promise<T[]> {\n const promises: Promise<T>[] = [];\n\n for (const plugin of this.plugins.values()) {\n const hook = plugin[hookName];\n\n if (typeof hook === 'function') {\n const promise = (async () => {\n try {\n return await (hook as Function).apply(plugin, args);\n } catch (error) {\n logger.error(\n `Error executing ${String(hookName)} in plugin \"${plugin.name}\":`,\n error\n );\n\n if (plugin.onError) {\n try {\n plugin.onError(error as Error, { hookName, args });\n } catch (onErrorError) {\n logger.error(\n `Error in onError handler for plugin \"${plugin.name}\":`,\n onErrorError\n );\n }\n }\n\n return undefined;\n }\n })();\n\n promises.push(promise);\n }\n }\n\n const results = await Promise.all(promises);\n return results.filter((r) => r !== undefined) as T[];\n }\n\n clear(): void {\n for (const plugin of this.plugins.values()) {\n if (plugin.destroy) {\n try {\n plugin.destroy();\n } catch (error) {\n logger.error(`Error destroying plugin \"${plugin.name}\":`, error);\n }\n }\n }\n\n this.plugins.clear();\n logger.info('All plugins cleared');\n }\n}\n","import { Storage } from './storage';\nimport { logger } from './logger';\n\nexport type ConsentCategory =\n | 'analytics'\n | 'marketing'\n | 'functional'\n | 'necessary';\n\nexport interface ConsentPreferences {\n analytics: boolean;\n marketing: boolean;\n functional: boolean;\n necessary: boolean;\n}\n\nexport type ConsentStatus = 'granted' | 'denied' | 'pending';\n\nexport interface ConsentManagerConfig {\n defaultConsent?: Partial<ConsentPreferences>;\n waitForConsent?: boolean;\n consentStorageKey?: string;\n}\n\nexport class ConsentManager {\n private storage: Storage;\n private config: Required<ConsentManagerConfig>;\n private preferences: ConsentPreferences;\n private listeners: Array<(preferences: ConsentPreferences) => void> = [];\n\n constructor(storage: Storage, config: ConsentManagerConfig = {}) {\n this.storage = storage;\n this.config = {\n defaultConsent: config.defaultConsent || {},\n waitForConsent: config.waitForConsent ?? false,\n consentStorageKey: config.consentStorageKey || 'aegis_consent',\n };\n\n this.preferences = this.loadPreferences();\n }\n\n private loadPreferences(): ConsentPreferences {\n const stored = this.storage.get(this.config.consentStorageKey);\n\n if (stored) {\n try {\n const parsed = JSON.parse(stored);\n logger.info('Loaded consent preferences:', parsed);\n return this.mergeWithDefaults(parsed);\n } catch (error) {\n logger.warn('Failed to parse consent preferences:', error);\n }\n }\n\n return this.getDefaultPreferences();\n }\n\n private getDefaultPreferences(): ConsentPreferences {\n return {\n analytics: this.config.defaultConsent.analytics ?? false,\n marketing: this.config.defaultConsent.marketing ?? false,\n functional: this.config.defaultConsent.functional ?? true,\n necessary: true,\n };\n }\n\n private mergeWithDefaults(\n preferences: Partial<ConsentPreferences>\n ): ConsentPreferences {\n return {\n necessary: true,\n analytics: preferences.analytics ?? this.config.defaultConsent.analytics ?? false,\n marketing: preferences.marketing ?? this.config.defaultConsent.marketing ?? false,\n functional: preferences.functional ?? this.config.defaultConsent.functional ?? true,\n };\n }\n\n private savePreferences(): void {\n try {\n this.storage.set(\n this.config.consentStorageKey,\n JSON.stringify(this.preferences),\n 365\n );\n logger.info('Saved consent preferences:', this.preferences);\n } catch (error) {\n logger.error('Failed to save consent preferences:', error);\n }\n }\n\n setConsent(preferences: Partial<ConsentPreferences>): void {\n const updated = { ...this.preferences, ...preferences };\n updated.necessary = true;\n\n this.preferences = updated;\n this.savePreferences();\n this.notifyListeners();\n\n logger.info('Consent updated:', this.preferences);\n }\n\n grantAll(): void {\n this.setConsent({\n analytics: true,\n marketing: true,\n functional: true,\n necessary: true,\n });\n }\n\n denyAll(): void {\n this.setConsent({\n analytics: false,\n marketing: false,\n functional: false,\n necessary: true,\n });\n }\n\n hasConsent(category: ConsentCategory): boolean {\n return this.preferences[category];\n }\n\n getPreferences(): ConsentPreferences {\n return { ...this.preferences };\n }\n\n getStatus(category: ConsentCategory): ConsentStatus {\n if (this.hasConsent(category)) {\n return 'granted';\n }\n\n const stored = this.storage.get(this.config.consentStorageKey);\n if (!stored && this.config.waitForConsent) {\n return 'pending';\n }\n\n return 'denied';\n }\n\n isAnalyticsEnabled(): boolean {\n return this.hasConsent('analytics');\n }\n\n isMarketingEnabled(): boolean {\n return this.hasConsent('marketing');\n }\n\n onChange(callback: (preferences: ConsentPreferences) => void): () => void {\n this.listeners.push(callback);\n\n return () => {\n const index = this.listeners.indexOf(callback);\n if (index > -1) {\n this.listeners.splice(index, 1);\n }\n };\n }\n\n private notifyListeners(): void {\n this.listeners.forEach((listener) => {\n try {\n listener(this.getPreferences());\n } catch (error) {\n logger.error('Consent listener error:', error);\n }\n });\n }\n\n reset(): void {\n this.storage.remove(this.config.consentStorageKey);\n this.preferences = this.getDefaultPreferences();\n this.notifyListeners();\n logger.info('Consent preferences reset');\n }\n\n integrateOneTrust(): void {\n if (typeof window === 'undefined') return;\n\n const oneTrust = (window as any).OneTrust;\n if (!oneTrust) {\n logger.warn('OneTrust not detected');\n return;\n }\n\n const syncWithOneTrust = () => {\n const activeGroups = (window as any).OnetrustActiveGroups || '';\n\n this.setConsent({\n necessary: true,\n functional: activeGroups.includes('C0003'),\n analytics: activeGroups.includes('C0002'),\n marketing: activeGroups.includes('C0004'),\n });\n\n logger.info('Synced with OneTrust consent');\n };\n\n if ((window as any).OptanonWrapper) {\n const originalWrapper = (window as any).OptanonWrapper;\n (window as any).OptanonWrapper = function () {\n originalWrapper();\n syncWithOneTrust();\n };\n } else {\n (window as any).OptanonWrapper = syncWithOneTrust;\n }\n\n syncWithOneTrust();\n }\n\n integrateCookiebot(): void {\n if (typeof window === 'undefined') return;\n\n const cookiebot = (window as any).Cookiebot;\n if (!cookiebot) {\n logger.warn('Cookiebot not detected');\n return;\n }\n\n const syncWithCookiebot = () => {\n const consent = cookiebot.consent || {};\n\n this.setConsent({\n necessary: true,\n functional: consent.preferences || false,\n analytics: consent.statistics || false,\n marketing: consent.marketing || false,\n });\n\n logger.info('Synced with Cookiebot consent');\n };\n\n window.addEventListener('CookiebotOnAccept', syncWithCookiebot);\n window.addEventListener('CookiebotOnDecline', syncWithCookiebot);\n\n if (cookiebot.consent) {\n syncWithCookiebot();\n }\n }\n\n integrateGoogleConsentMode(): void {\n if (typeof window === 'undefined') return;\n\n const gtag = (window as any).gtag;\n if (!gtag) {\n logger.warn('Google Tag Manager not detected');\n return;\n }\n\n const updateGoogleConsent = () => {\n gtag('consent', 'update', {\n ad_storage: this.preferences.marketing ? 'granted' : 'denied',\n analytics_storage: this.preferences.analytics ? 'granted' : 'denied',\n ad_user_data: this.preferences.marketing ? 'granted' : 'denied',\n ad_personalization: this.preferences.marketing ? 'granted' : 'denied',\n functionality_storage: this.preferences.functional ? 'granted' : 'denied',\n personalization_storage: this.preferences.functional ? 'granted' : 'denied',\n security_storage: 'granted',\n });\n\n logger.info('Updated Google Consent Mode');\n };\n\n this.onChange(updateGoogleConsent);\n updateGoogleConsent();\n }\n}\n","/**\n * E-Commerce helper methods for the Aegis SDK.\n *\n * Provides standardized e-commerce event tracking that maps to the\n * Active Reach Intelligence data governance pipeline.\n *\n * Event names follow the canonical mapper:\n * product_viewed → engagement.product_view\n * product_list_viewed → engagement.product_list_view\n * cart_item_added → cart_item_added\n * cart_item_removed → cart_item_removed\n * cart_viewed → cart_viewed\n * checkout_started → checkout_started\n * checkout_step → checkout_step\n * order_completed → transaction.purchase\n * order_refunded → transaction.refund\n * coupon_applied → coupon_applied\n * coupon_removed → coupon_removed\n * search_performed → search_performed\n * wishlist_item_added → wishlist_item_added\n * promotion_viewed → promotion_viewed\n * promotion_clicked → promotion_clicked\n */\n\nimport type { Aegis } from '../core/analytics';\nimport type {\n EcommerceProduct,\n EcommerceCart,\n EcommerceCheckout,\n EcommerceOrder,\n EcommerceCoupon,\n EcommerceSearch,\n EcommerceProductList,\n EcommerceWishlist,\n EcommercePromotion,\n} from './types';\n\nfunction sumItems(products: EcommerceProduct[]): number {\n return products.reduce((sum, p) => sum + (p.quantity ?? 1), 0);\n}\n\n// Cart abandonment detection is SERVER-SIDE. The SDK fires the canonical\n// e-commerce events (`cart_item_added`, `cart_item_removed`, `cart_viewed`,\n// `transaction.purchase`); a Kafka consumer on cell-plane maintains cart\n// state in Redis (`cart_state:{org}:{contact}:{cart_id}`) and a Celery beat\n// task scans for carts with no activity for N minutes, emitting\n// `cart_abandoned` to BEHAVIORAL_EVENTS_TOPIC.\n//\n// We deliberately do NOT run a JS timer on the client — mobile browsers\n// throttle background timers to ~1Hz and they're unreliable for any\n// abandonment threshold beyond a few seconds. Industry alignment: WebEngage,\n// MoEngage, CleverTap, Bitespeed, Klaviyo all detect server-side.\n//\n// See: `apps/cell-plane/app/workers/cart_state_tracker.py`\n\nfunction mapProducts(products: EcommerceProduct[]) {\n return products.map((p) => ({\n product_id: p.product_id,\n sku: p.sku ?? p.product_id,\n name: p.name,\n price: p.price,\n quantity: p.quantity ?? 1,\n currency: p.currency,\n category: p.category,\n brand: p.brand,\n variant_id: p.variant_id,\n variant_label: p.variant_label,\n position: p.position,\n }));\n}\n\nexport class EcommerceTracker {\n constructor(private aegis: Aegis) {}\n\n // -- Product Discovery --\n\n productViewed(product: EcommerceProduct): void {\n this.aegis.track('product_viewed', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n currency: product.currency ?? 'INR',\n category: product.category,\n brand: product.brand,\n variant_id: product.variant_id,\n variant_label: product.variant_label,\n image_url: product.image_url,\n url: product.url,\n });\n }\n\n productListViewed(list: EcommerceProductList): void {\n this.aegis.track('product_list_viewed', {\n list_id: list.list_id,\n list_name: list.list_name,\n category: list.category,\n products: mapProducts(list.products),\n });\n }\n\n productClicked(product: EcommerceProduct, source?: { list_id?: string; position?: number; section?: string }): void {\n this.aegis.track('product_clicked', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n currency: product.currency ?? 'INR',\n category: product.category,\n brand: product.brand,\n variant_id: product.variant_id,\n list_id: source?.list_id,\n position: source?.position ?? product.position,\n section: source?.section,\n });\n }\n\n productImpressed(product: EcommerceProduct, source?: { list_id?: string; position?: number; section?: string }): void {\n this.aegis.track('product_impression', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n currency: product.currency ?? 'INR',\n category: product.category,\n list_id: source?.list_id,\n position: source?.position ?? product.position,\n section: source?.section,\n });\n }\n\n categoryFiltered(category: string, options?: { previous_category?: string; result_count?: number }): void {\n this.aegis.track('category_filtered', {\n category,\n previous_category: options?.previous_category,\n result_count: options?.result_count,\n });\n }\n\n searchPerformed(search: EcommerceSearch): void {\n this.aegis.track('search_performed', {\n query: search.query,\n results_count: search.results_count,\n filters: search.filters,\n });\n }\n\n // -- Cart --\n\n addToCart(product: EcommerceProduct): void {\n this.aegis.track('cart_item_added', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n quantity: product.quantity ?? 1,\n currency: product.currency ?? 'INR',\n category: product.category,\n brand: product.brand,\n variant_id: product.variant_id,\n variant_label: product.variant_label,\n });\n }\n\n removeFromCart(product: EcommerceProduct): void {\n this.aegis.track('cart_item_removed', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n quantity: product.quantity ?? 1,\n currency: product.currency ?? 'INR',\n variant_id: product.variant_id,\n });\n }\n\n cartViewed(cart: EcommerceCart): void {\n this.aegis.track('cart_viewed', {\n cart_id: cart.cart_id,\n value: cart.value,\n currency: cart.currency ?? 'INR',\n num_items: sumItems(cart.products),\n products: mapProducts(cart.products),\n });\n }\n\n // -- Checkout --\n\n checkoutStarted(checkout: EcommerceCheckout): void {\n this.aegis.track('checkout_started', {\n checkout_id: checkout.checkout_id,\n value: checkout.value,\n currency: checkout.currency ?? 'INR',\n num_items: sumItems(checkout.products),\n coupon: checkout.coupon,\n shipping: checkout.shipping,\n tax: checkout.tax,\n products: mapProducts(checkout.products),\n });\n }\n\n checkoutStep(step: number, options?: Record<string, unknown>): void {\n this.aegis.track('checkout_step', {\n step,\n ...options,\n });\n }\n\n // -- Order --\n\n orderCompleted(order: EcommerceOrder): void {\n this.aegis.track('order_completed', {\n order_id: order.order_id,\n value: order.value,\n revenue: order.revenue ?? order.value,\n currency: order.currency ?? 'INR',\n num_items: sumItems(order.products),\n coupon: order.coupon,\n shipping: order.shipping,\n tax: order.tax,\n discount: order.discount,\n payment_method: order.payment_method,\n products: mapProducts(order.products),\n });\n }\n\n orderRefunded(orderId: string, value?: number, products?: EcommerceProduct[]): void {\n this.aegis.track('order_refunded', {\n order_id: orderId,\n value,\n products: products ? mapProducts(products) : undefined,\n });\n }\n\n // -- Coupons --\n\n couponApplied(coupon: EcommerceCoupon): void {\n this.aegis.track('coupon_applied', { ...coupon });\n }\n\n couponRemoved(coupon: EcommerceCoupon): void {\n this.aegis.track('coupon_removed', { ...coupon });\n }\n\n // -- Wishlist --\n\n wishlistItemAdded(wishlist: EcommerceWishlist): void {\n this.aegis.track('wishlist_item_added', {\n wishlist_id: wishlist.wishlist_id,\n wishlist_name: wishlist.wishlist_name,\n product_id: wishlist.product.product_id,\n sku: wishlist.product.sku ?? wishlist.product.product_id,\n name: wishlist.product.name,\n price: wishlist.product.price,\n variant_id: wishlist.product.variant_id,\n });\n }\n\n // -- Promotions --\n\n promotionViewed(promo: EcommercePromotion): void {\n this.aegis.track('promotion_viewed', { ...promo });\n }\n\n promotionClicked(promo: EcommercePromotion): void {\n this.aegis.track('promotion_clicked', { ...promo });\n }\n}\n\nexport type {\n EcommerceProduct,\n EcommerceCart,\n EcommerceCheckout,\n EcommerceOrder,\n EcommerceCoupon,\n EcommerceSearch,\n EcommerceProductList,\n EcommerceWishlist,\n EcommercePromotion,\n} from './types';\n","/**\n * Token bucket rate limiter for client-side event throttling.\n *\n * Limits per session: burst (default 100) + sustained (default 20/sec).\n * Drops events with a console warning once a burst sustains. Drops are\n * emitted as a single coalesced `aegis.client.rate_limited` meta-event\n * per second so we don't flood ingress with drop notifications.\n *\n * Defaults are deliberately generous — the goal is to prevent runaway\n * loops (a buggy app firing 10k events/sec) without affecting normal use.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface RateLimiterOptions {\n /** Max tokens (burst size). Default 100. */\n burstCapacity?: number;\n /** Sustained rate per second. Default 20. */\n refillPerSecond?: number;\n /** Window in ms over which dropped events are coalesced. Default 1000. */\n dropCoalesceWindowMs?: number;\n /** Optional callback fired with the count of dropped events per coalesce window. */\n onDropBatch?: (droppedCount: number, sampleEventName: string | null) => void;\n}\n\nexport class RateLimiter {\n private tokens: number;\n private readonly capacity: number;\n private readonly refillPerSecond: number;\n private lastRefillMs: number;\n\n private droppedThisWindow = 0;\n private firstDroppedName: string | null = null;\n private windowFlushTimer: ReturnType<typeof setTimeout> | null = null;\n private readonly windowMs: number;\n private readonly onDropBatch?: (droppedCount: number, sampleEventName: string | null) => void;\n\n constructor(options: RateLimiterOptions = {}) {\n this.capacity = Math.max(1, options.burstCapacity ?? 100);\n this.refillPerSecond = Math.max(1, options.refillPerSecond ?? 20);\n this.windowMs = options.dropCoalesceWindowMs ?? 1000;\n this.onDropBatch = options.onDropBatch;\n this.tokens = this.capacity;\n this.lastRefillMs = Date.now();\n }\n\n /**\n * Try to consume 1 token. Returns true if allowed, false if throttled.\n * Throttled events are coalesced into a single onDropBatch callback per window.\n */\n tryConsume(eventName: string): boolean {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n return true;\n }\n\n this.droppedThisWindow += 1;\n if (this.firstDroppedName === null) {\n this.firstDroppedName = eventName;\n logger.warn(\n `[Aegis] Rate limit reached — dropping event \"${eventName}\" and any further events for ${this.windowMs}ms. Burst=${this.capacity}, refill=${this.refillPerSecond}/s.`,\n );\n }\n\n if (!this.windowFlushTimer) {\n this.windowFlushTimer = setTimeout(() => this.flushWindow(), this.windowMs);\n }\n\n return false;\n }\n\n /** Diagnostics — current token count (rounded down). */\n getAvailableTokens(): number {\n this.refill();\n return Math.floor(this.tokens);\n }\n\n /** Cleanup. Idempotent. */\n destroy(): void {\n if (this.windowFlushTimer) {\n clearTimeout(this.windowFlushTimer);\n this.windowFlushTimer = null;\n }\n this.flushWindow();\n }\n\n // ---------------------------------------------------------------------\n\n private refill(): void {\n const now = Date.now();\n const elapsedSec = (now - this.lastRefillMs) / 1000;\n if (elapsedSec <= 0) return;\n\n const newTokens = elapsedSec * this.refillPerSecond;\n this.tokens = Math.min(this.capacity, this.tokens + newTokens);\n this.lastRefillMs = now;\n }\n\n private flushWindow(): void {\n if (this.windowFlushTimer) {\n clearTimeout(this.windowFlushTimer);\n this.windowFlushTimer = null;\n }\n if (this.droppedThisWindow > 0 && this.onDropBatch) {\n try {\n this.onDropBatch(this.droppedThisWindow, this.firstDroppedName);\n } catch (err) {\n logger.warn('[Aegis] RateLimiter.onDropBatch threw:', err);\n }\n }\n this.droppedThisWindow = 0;\n this.firstDroppedName = null;\n }\n}\n","/**\n * MurmurHash3 x86-32 — deterministic, byte-identical with Python `mmh3.hash`.\n *\n * We hand-roll rather than pull a dep because (a) our bundle-budget is\n * aggressive for storefront first-paint, and (b) this is the authoritative\n * cross-language hash for the event-governance bloom filter — any behavior\n * drift between Python and JS produces silent FP-rate spikes in prod.\n *\n * Contract:\n * • Input is a JS string. It is UTF-8 encoded via TextEncoder before hashing.\n * • Output is an unsigned 32-bit integer (0 .. 2^32-1).\n * • Matches `mmh3.hash(s.encode('utf-8'), seed=seed, signed=False)` in\n * Python exactly — verified by libs/shared-types/bloom-test-vectors.json\n * in CI.\n *\n * Reference: Austin Appleby, MurmurHash3 (public domain).\n * https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp\n *\n * Implementation notes:\n * • All arithmetic on 32-bit ints. JS does bitwise ops on 32-bit ints natively;\n * `Math.imul` gives us correct 32-bit multiplication without overflow.\n * • We use `>>> 0` to coerce to unsigned after every step that could produce\n * a negative or >32-bit value.\n * • UTF-8 encoding matters — a naive `charCodeAt` loop would mis-hash any\n * string with non-ASCII characters (e.g. emoji, accented chars) and the\n * Python side would disagree. We always encode via TextEncoder first.\n */\n\nconst C1 = 0xcc9e2d51;\nconst C2 = 0x1b873593;\n\n/**\n * Compute MurmurHash3 x86-32 of a UTF-8 encoded string.\n *\n * @param input The string to hash.\n * @param seed 32-bit unsigned seed.\n * @returns Unsigned 32-bit integer hash.\n */\nexport function murmurhash3_x86_32(input: string, seed: number = 0): number {\n // Encode to UTF-8 bytes — matches Python's `s.encode('utf-8')`.\n const bytes = new TextEncoder().encode(input);\n return murmurhash3_bytes(bytes, seed);\n}\n\n/**\n * Compute MurmurHash3 x86-32 over a byte buffer directly.\n *\n * Exposed for callers that already have UTF-8 bytes and want to skip the\n * encode step (e.g., internal bloom-hash paths).\n */\nexport function murmurhash3_bytes(bytes: Uint8Array, seed: number = 0): number {\n const len = bytes.length;\n const nBlocks = Math.floor(len / 4);\n\n let h1 = seed >>> 0;\n\n // Body — consume 4-byte blocks.\n for (let i = 0; i < nBlocks; i++) {\n const offset = i * 4;\n let k1 =\n bytes[offset] |\n (bytes[offset + 1] << 8) |\n (bytes[offset + 2] << 16) |\n (bytes[offset + 3] << 24);\n\n k1 = Math.imul(k1, C1);\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = Math.imul(k1, C2);\n\n h1 ^= k1;\n h1 = (h1 << 13) | (h1 >>> 19);\n h1 = (Math.imul(h1, 5) + 0xe6546b64) >>> 0;\n }\n\n // Tail — up to 3 trailing bytes.\n const tailStart = nBlocks * 4;\n let k1 = 0;\n const tailLen = len - tailStart;\n if (tailLen === 3) k1 ^= bytes[tailStart + 2] << 16;\n if (tailLen >= 2) k1 ^= bytes[tailStart + 1] << 8;\n if (tailLen >= 1) {\n k1 ^= bytes[tailStart];\n k1 = Math.imul(k1, C1);\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = Math.imul(k1, C2);\n h1 ^= k1;\n }\n\n // Finalization — avalanche (fmix32).\n h1 ^= len;\n h1 ^= h1 >>> 16;\n h1 = Math.imul(h1, 0x85ebca6b);\n h1 ^= h1 >>> 13;\n h1 = Math.imul(h1, 0xc2b2ae35);\n h1 ^= h1 >>> 16;\n\n return h1 >>> 0;\n}\n","/**\n * Bloom filter — wire-compatible with the Python builder in\n * apps/control-plane/app/services/event_governance_bloom.py\n *\n * This SDK-side variant is QUERY-ONLY. The filter is built server-side\n * from the org's registered event-name set, base64-encoded, and shipped\n * to the browser on `/v1/sdk/bootstrap`. The SDK reads it once, uses it\n * to gate `track()` calls, and discards it on the next bootstrap.\n *\n * Wire format:\n * • `m` bits of storage, represented as m/8 bytes, base64-encoded.\n * • Bit `i` is at byte `i >> 3`, bitmask `1 << (i & 7)` — LSB-first.\n * • `m` MUST be a power of two — allows `idx & (m-1)` modulo.\n * • `k` hash functions synthesized via Kirsch-Mitzenmacher from two\n * MurmurHash3 x86-32 hashes with seeds (seedA, seedB):\n * h_i(x) = (h1(x) + i * h2(x)) mod m\n * • Input strings are UTF-8 encoded (handled inside murmurhash3_x86_32).\n */\n\nimport { murmurhash3_x86_32 } from './murmur3';\n\n/** Decode a base64 string to a Uint8Array. Accepts web (atob) and node (Buffer). */\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof atob !== 'undefined') {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n }\n // Node.js fallback — used by tests and SSR integrations.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const B = (globalThis as any).Buffer;\n if (B && typeof B.from === 'function') {\n const buf: Uint8Array = B.from(b64, 'base64');\n // Copy into a plain Uint8Array so callers don't observe Buffer semantics.\n return new Uint8Array(buf);\n }\n throw new Error('No base64 decoder available (neither atob nor Buffer)');\n}\n\nexport interface BloomFilterParams {\n /** Bits in the filter (must be power of 2). */\n m: number;\n /** Number of hash functions (Kirsch-Mitzenmacher synthesized). */\n k: number;\n /** Seed for the first MurmurHash3 call. */\n seedA: number;\n /** Seed for the second MurmurHash3 call. */\n seedB: number;\n}\n\nexport class BloomFilter {\n private readonly buf: Uint8Array;\n private readonly mask: number;\n\n constructor(buf: Uint8Array, private readonly params: BloomFilterParams) {\n if ((params.m & (params.m - 1)) !== 0) {\n throw new Error(`Bloom filter m must be a power of 2, got ${params.m}`);\n }\n if (buf.length !== params.m >> 3) {\n throw new Error(\n `Bloom filter buffer size mismatch: expected ${params.m >> 3} bytes, got ${buf.length}`\n );\n }\n this.buf = buf;\n this.mask = params.m - 1;\n }\n\n /** Build from the wire format (base64 bytes + explicit params). */\n static fromBase64(bloomB64: string, params: BloomFilterParams): BloomFilter {\n const bytes = base64ToBytes(bloomB64);\n return new BloomFilter(bytes, params);\n }\n\n /**\n * Returns true if `name` is probably in the set — possibly with the\n * filter's configured false-positive rate. FALSE is always authoritative.\n *\n * FP here means: SDK thinks a name is already registered when it isn't.\n * That costs one wasted server round-trip (gateway does the exact check\n * and catches it) — strictly safer than a false-negative, which could\n * leak a novel name past the SDK.\n */\n has(name: string): boolean {\n const h1 = murmurhash3_x86_32(name, this.params.seedA);\n const h2 = murmurhash3_x86_32(name, this.params.seedB);\n\n for (let i = 0; i < this.params.k; i++) {\n // >>> 0 at each step to keep arithmetic in unsigned 32-bit land;\n // we can't just take & mask at the end because h1 + i*h2 could\n // overflow past 2^32 when i*h2 is large.\n const combined = (h1 + Math.imul(i, h2)) >>> 0;\n const idx = combined & this.mask;\n const bit = this.buf[idx >> 3] & (1 << (idx & 7));\n if (bit === 0) return false;\n }\n return true;\n }\n}\n","/**\n * NameGovernor — client-side event-name cap enforcement.\n *\n * The governor consumes an `EventGovernanceHint` from the bootstrap response\n * and decides whether to let a `track()` call proceed to the network or drop\n * it locally.\n *\n * Why this exists:\n * Without it, a page that calls `track('new_btn_' + Date.now())` in a\n * render loop would (a) pass the local rate-limiter if within burst, (b)\n * force the gateway to ask control-plane for a verdict on every unique\n * name, and (c) amplify the CP `/event-governance/check` load quadratically\n * in the number of tabs firing the same bug. The bloom filter gives the\n * SDK enough information to drop novel names locally once the org hits\n * its cap, collapsing the amplification to zero.\n *\n * Design constraints:\n * • FAIL-OPEN — missing hint (Enterprise org, Redis outage) lets every\n * name through. The gateway is still the authoritative cap.\n * • FALSE-POSITIVE-SAFE — if the bloom says \"known\" for a name that isn't\n * actually registered, we send to gateway and the gateway's exact check\n * catches it. FPs cost one round trip, not a cap bypass.\n * • LOCAL-MEMO — a novel name that has already charged `remainingNewNames`\n * in this tab must NOT charge again on subsequent calls within the same\n * hint TTL. Without this, `track('new_btn_click')` fired 50 times would\n * drain 50 from the counter and block every OTHER legitimate novel name.\n * See `localNovelNames`.\n *\n * See docs/architecture/RFC_2026_04_SDK_GOVERNANCE_HINTS.md §3.3.\n */\n\nimport { BloomFilter } from './bloom-filter';\n\n/** Shape of the hint delivered by `/v1/sdk/bootstrap`. */\nexport interface EventGovernanceHint {\n bloom_algo: string;\n seed_a: number;\n seed_b: number;\n k: number;\n m: number;\n bloom_b64: string;\n remaining_new_names: number | null;\n /**\n * When true, the server is in its 7-day soft-cap grace window: it accepts\n * novel event names past the cap. SDK must NOT drop locally in this mode —\n * doing so would enforce harder than the server. See\n * apps/control-plane/app/schemas/event_governance_hint.py for the canonical\n * contract.\n */\n grace_active?: boolean;\n ttl_seconds: number;\n}\n\nexport interface DropReport {\n /** Map of event_name → count of local drops since last drain. */\n events: Record<string, number>;\n /** Total events dropped across all names (sum of values). */\n total: number;\n /** When the report window started (ms since epoch). */\n since: number;\n}\n\n/** Matches the `bloom_algo` tag shipped by the current control-plane build. */\nconst SUPPORTED_ALGO = 'mmh3_x86_32_km';\n\n/**\n * Best-effort console.warn — coalesced so a runaway render loop doesn't\n * flood the dev console. We only warn on the FIRST distinct dropped name;\n * subsequent names silently increment the telemetry counter.\n */\nfunction warnOncePerSession(message: string): void {\n if (typeof console === 'undefined' || typeof console.warn !== 'function') return;\n console.warn(message);\n}\n\nexport class NameGovernor {\n private bloom: BloomFilter | null = null;\n private remainingNewNames: number = Infinity;\n private graceActive: boolean = false;\n\n /**\n * Names this SDK instance has seen AS NOVEL and already charged against\n * `remainingNewNames`. Reset on every `ingestHint()` so we don't leak\n * accounting across hint refreshes.\n */\n private localNovelNames: Set<string> = new Set();\n\n /** Coalesced telemetry — flushed to the transport via drainDropReport(). */\n private droppedSinceLastReport: Map<string, number> = new Map();\n private reportWindowStart: number = Date.now();\n private hasWarnedThisSession = false;\n\n /**\n * Ingest a freshly-bootstrapped hint. Call on every successful bootstrap.\n * Passing `null` disables governance (fail-open).\n */\n ingestHint(hint: EventGovernanceHint | null): void {\n if (!hint || hint.bloom_algo !== SUPPORTED_ALGO) {\n // Unknown algo — a newer CP ships a version this SDK can't decode.\n // Silently disable governance; gateway remains authoritative.\n this.bloom = null;\n this.remainingNewNames = Infinity;\n this.graceActive = false;\n this.localNovelNames.clear();\n return;\n }\n\n try {\n this.bloom = BloomFilter.fromBase64(hint.bloom_b64, {\n m: hint.m,\n k: hint.k,\n seedA: hint.seed_a,\n seedB: hint.seed_b,\n });\n } catch {\n // Malformed hint — fail-open. Logged by the caller.\n this.bloom = null;\n }\n\n this.remainingNewNames = hint.remaining_new_names ?? Infinity;\n this.graceActive = hint.grace_active === true;\n this.localNovelNames.clear();\n }\n\n /**\n * Decide whether a `track()` call should proceed.\n *\n * Returns true = send to network (rate-limiter still runs after).\n * Returns false = drop locally; caller should return early.\n */\n shouldSend(eventName: string): boolean {\n // No hint = unlimited plan or fail-open. Send everything.\n if (!this.bloom) return true;\n\n // 7-day soft-cap grace window is active — server accepts novel names\n // past the cap, so SDK must not enforce harder. Fail-open to gateway.\n if (this.graceActive) return true;\n\n // Known name — send.\n if (this.bloom.has(eventName)) return true;\n\n // Already charged in this session — send (gateway has it cached too).\n if (this.localNovelNames.has(eventName)) return true;\n\n // Novel name, within headroom — charge once, send.\n if (this.remainingNewNames > 0) {\n this.localNovelNames.add(eventName);\n this.remainingNewNames -= 1;\n return true;\n }\n\n // Novel name, over the cap — drop locally, record for telemetry.\n const prev = this.droppedSinceLastReport.get(eventName) ?? 0;\n this.droppedSinceLastReport.set(eventName, prev + 1);\n\n // Only warn once per session, only on the first distinct dropped name —\n // a runaway loop will fill droppedSinceLastReport silently.\n if (!this.hasWarnedThisSession) {\n this.hasWarnedThisSession = true;\n warnOncePerSession(\n `[aegis] Event-name cap reached — \"${eventName}\" dropped locally. ` +\n `Upgrade your plan or remove dynamically-generated event names.`\n );\n }\n return false;\n }\n\n /**\n * Snapshot + reset the dropped-names counter. Called by the telemetry\n * beacon on batch flush so the gateway gets visibility into client-side\n * drops for ops dashboards.\n */\n drainDropReport(): DropReport | null {\n if (this.droppedSinceLastReport.size === 0) return null;\n\n const events: Record<string, number> = {};\n let total = 0;\n for (const [name, count] of this.droppedSinceLastReport) {\n events[name] = count;\n total += count;\n }\n\n const since = this.reportWindowStart;\n this.droppedSinceLastReport.clear();\n this.reportWindowStart = Date.now();\n\n return { events, total, since };\n }\n\n // Test-only accessors — not part of public API but easier than reflection.\n /** @internal */\n _debugState(): {\n hasBloom: boolean;\n remaining: number;\n localNovel: number;\n graceActive: boolean;\n } {\n return {\n hasBloom: this.bloom !== null,\n remaining: this.remainingNewNames,\n localNovel: this.localNovelNames.size,\n graceActive: this.graceActive,\n };\n }\n}\n","import {\n AegisConfig,\n AegisConfigInternal,\n DEFAULT_CONFIG,\n CellEndpoint,\n} from '../types/config';\nimport {\n TrackEvent,\n IdentifyEvent,\n PageEvent,\n GroupEvent,\n AliasEvent,\n AegisEvent,\n} from '../types/events';\nimport { Plugin } from '../types/plugin';\nimport { Identity } from '../utils/identity';\nimport { SessionManager } from './session';\nimport { EventQueue } from './queue';\nimport { Transport } from './transport';\nimport { Storage } from '../utils/storage';\nimport { buildContext, isBot } from '../utils/device';\nimport { generateMessageId } from '../utils/uuid';\nimport { logger } from '../utils/logger';\nimport { PluginRegistry } from '../plugins/registry';\nimport { ConsentManager, ConsentPreferences, ConsentCategory } from '../utils/consent';\nimport { parseAdClickIDs, hasAdClickIDs } from '../utils/url-parser';\nimport { EcommerceTracker } from '../ecommerce';\nimport { RateLimiter } from './rate-limiter';\nimport { NameGovernor, EventGovernanceHint } from '../governance';\n\nexport class Aegis {\n private config: AegisConfigInternal | null = null;\n private storage!: Storage;\n private identity!: Identity;\n private session: SessionManager | null = null;\n private queue: EventQueue | null = null;\n private transport: Transport | null = null;\n private plugins: PluginRegistry = new PluginRegistry();\n private initPromise: Promise<void> | null = null;\n private consent: ConsentManager | null = null;\n private _ecommerce: EcommerceTracker | null = null;\n private rateLimiter: RateLimiter | null = null;\n private nameGovernor: NameGovernor = new NameGovernor();\n private _lastPageUrl: string | null = null;\n private _popstateHandler: (() => void) | null = null;\n private _originalPushState: typeof history.pushState | null = null;\n private _originalReplaceState: typeof history.replaceState | null = null;\n\n async init(\n writeKey: string,\n config?: Partial<AegisConfig>\n ): Promise<void> {\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = this._init(writeKey, config);\n return this.initPromise;\n }\n\n private async _init(\n writeKey: string,\n config?: Partial<AegisConfig>\n ): Promise<void> {\n if (this.config?.initialized) {\n logger.warn('SDK already initialized');\n return;\n }\n\n if (this.shouldRespectDNT(config)) {\n logger.info('Do Not Track is enabled, SDK disabled');\n return;\n }\n\n if (isBot()) {\n logger.info('Bot detected, SDK disabled');\n return;\n }\n\n this.config = this.buildConfig(writeKey, config);\n\n if (this.config.debug) {\n logger.enable();\n }\n\n logger.info('Initializing Aegis SDK...', this.config);\n\n this.storage = new Storage({\n cookieDomain: this.config.cookie_domain,\n secureCookie: this.config.secure_cookie,\n crossDomain: this.config.cross_domain_tracking,\n });\n\n this.identity = new Identity(this.storage);\n\n this.consent = new ConsentManager(this.storage, {\n defaultConsent: this.config.default_consent,\n waitForConsent: this.config.wait_for_consent,\n });\n\n if (this.config.integrate_onetrust) {\n this.consent.integrateOneTrust();\n }\n\n if (this.config.integrate_cookiebot) {\n this.consent.integrateCookiebot();\n }\n\n if (this.config.integrate_google_consent_mode) {\n this.consent.integrateGoogleConsentMode();\n }\n\n this.session = new SessionManager(\n this.storage,\n this.config.session_timeout\n );\n\n this.captureAdClickIDsOnInit();\n\n this.transport = new Transport(\n {\n writeKey: this.config.write_key,\n apiHost: this.config.api_host,\n cellEndpoints: this.config.cell_endpoints,\n preferredRegion: this.config.preferred_region,\n autoRegionDetection: this.config.auto_region_detection,\n requestTimeout: this.config.request_timeout,\n retryFailedRequests: this.config.retry_failed_requests,\n maxRetries: this.config.max_retries,\n retryBackoffMultiplier: this.config.retry_backoff_multiplier,\n },\n this.storage\n );\n\n this.config.active_cell = this.transport.getActiveCell();\n\n this.queue = new EventQueue(\n {\n batchSize: this.config.batch_size,\n batchInterval: this.config.batch_interval,\n enableOfflineMode: this.config.enable_offline_mode,\n maxOfflineEvents: this.config.max_offline_events,\n },\n this.transport,\n this.storage\n );\n\n this.rateLimiter = new RateLimiter({\n burstCapacity: this.config.rate_limit_burst,\n refillPerSecond: this.config.rate_limit_per_second,\n onDropBatch: (count, sampleName) => this.emitRateLimitMeta(count, sampleName),\n });\n\n await this.initializePlugins();\n\n if (this.config.auto_page_view) {\n this.page();\n this.startSPATracking();\n }\n\n logger.info('Aegis SDK initialized successfully');\n }\n\n /**\n * SPA navigation tracking — monkey-patches pushState/replaceState and\n * listens for popstate to fire page() on every client-side route change.\n */\n private startSPATracking(): void {\n this._lastPageUrl = window.location.href;\n\n const onRouteChange = () => {\n // Debounce: only fire if URL actually changed\n const currentUrl = window.location.href;\n if (currentUrl === this._lastPageUrl) return;\n this._lastPageUrl = currentUrl;\n\n // Small delay to let the framework update document.title\n setTimeout(() => {\n this.page();\n }, 50);\n };\n\n // Listen for browser back/forward\n this._popstateHandler = onRouteChange;\n window.addEventListener('popstate', this._popstateHandler);\n\n // Monkey-patch pushState and replaceState\n this._originalPushState = history.pushState.bind(history);\n this._originalReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n this._originalPushState!(...args);\n onRouteChange();\n };\n\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n this._originalReplaceState!(...args);\n onRouteChange();\n };\n }\n\n private stopSPATracking(): void {\n if (this._popstateHandler) {\n window.removeEventListener('popstate', this._popstateHandler);\n this._popstateHandler = null;\n }\n\n if (this._originalPushState) {\n history.pushState = this._originalPushState;\n this._originalPushState = null;\n }\n\n if (this._originalReplaceState) {\n history.replaceState = this._originalReplaceState;\n this._originalReplaceState = null;\n }\n }\n\n private buildConfig(\n writeKey: string,\n config?: Partial<AegisConfig>\n ): AegisConfigInternal {\n return {\n ...DEFAULT_CONFIG,\n ...config,\n write_key: writeKey,\n initialized: true,\n } as AegisConfigInternal;\n }\n\n private shouldRespectDNT(config?: Partial<AegisConfig>): boolean {\n const respectDNT = config?.respect_dnt !== false;\n if (!respectDNT) return false;\n\n const dnt =\n navigator.doNotTrack ||\n (window as any).doNotTrack ||\n (navigator as any).msDoNotTrack;\n\n return dnt === '1' || dnt === 'yes';\n }\n\n private captureAdClickIDsOnInit(): void {\n if (!this.session) return;\n\n const adClickIDs = parseAdClickIDs();\n\n if (hasAdClickIDs(adClickIDs)) {\n this.session.setAdClickIDs(adClickIDs, window.location.href);\n logger.info('Ad click IDs captured on page load:', adClickIDs);\n }\n }\n\n private async initializePlugins(): Promise<void> {\n if (!this.config) return;\n\n for (const pluginName of this.config.plugins) {\n logger.debug(`Initializing plugin: ${pluginName}`);\n }\n\n await this.plugins.executeHook('init', this.config);\n }\n\n use(plugin: Plugin): void {\n this.plugins.register(plugin);\n\n if (this.config?.initialized && plugin.init) {\n Promise.resolve(plugin.init(this.config)).catch((error: any) => {\n logger.error(`Failed to initialize plugin \"${plugin.name}\":`, error);\n });\n }\n }\n\n track(eventName: string, properties?: Record<string, any>): void {\n if (!this.assertInitialized()) return;\n\n const event: TrackEvent = {\n type: 'track',\n event: eventName,\n properties: properties || {},\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session!.getSessionId(),\n workspace_id: this.config!.workspace_id || undefined,\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n identify(userId: string, traits?: Record<string, any>): void {\n if (!this.assertInitialized()) return;\n\n this.identity.setUserId(userId, traits);\n\n const event: IdentifyEvent = {\n type: 'identify',\n traits: traits || {},\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: userId,\n sessionId: this.session!.getSessionId(),\n workspace_id: this.config!.workspace_id || undefined,\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n page(name?: string, properties?: Record<string, any>): void {\n if (!this.assertInitialized()) return;\n\n const event: PageEvent = {\n type: 'page',\n name: name || document.title,\n properties: properties || {},\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session!.getSessionId(),\n workspace_id: this.config!.workspace_id || undefined,\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n group(groupId: string, traits?: Record<string, any>): void {\n if (!this.assertInitialized()) return;\n\n const event: GroupEvent = {\n type: 'group',\n groupId,\n traits: traits || {},\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session!.getSessionId(),\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n alias(newUserId: string): void {\n if (!this.assertInitialized()) return;\n\n const { previousId } = this.identity.alias(newUserId);\n\n const event: AliasEvent = {\n type: 'alias',\n previousId,\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: newUserId,\n sessionId: this.session!.getSessionId(),\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n private async captureEvent(event: AegisEvent): Promise<void> {\n if (this.config?.enable_consent_mode && this.consent) {\n if (event.type === 'track' || event.type === 'page') {\n if (!this.consent.hasConsent('analytics')) {\n logger.debug('Event blocked: analytics consent not granted');\n return;\n }\n }\n }\n\n // Event-name governance — drops novel names once the org's unique-event\n // cap is exhausted. Meta events (aegis.client.*) bypass the governor so\n // the telemetry channel stays open even under a cap-exhaustion storm.\n // See governance/name-governor.ts.\n if (event.type === 'track') {\n const trackEvent = event as TrackEvent;\n const isMetaEvent =\n typeof trackEvent.event === 'string' &&\n trackEvent.event.startsWith('aegis.client.');\n if (!isMetaEvent && !this.nameGovernor.shouldSend(trackEvent.event)) {\n return;\n }\n }\n\n if (this.rateLimiter) {\n const eventLabel =\n event.type === 'track' && (event as TrackEvent).event\n ? (event as TrackEvent).event\n : event.type;\n // Meta-events bypass the rate limiter to avoid recursion / lost telemetry.\n const isMetaEvent =\n event.type === 'track' &&\n typeof (event as TrackEvent).event === 'string' &&\n (event as TrackEvent).event.startsWith('aegis.client.');\n if (!isMetaEvent && !this.rateLimiter.tryConsume(eventLabel)) {\n return;\n }\n }\n\n // Auto-inject campaign attribution from UTM context into event properties\n // so downstream consumers (event-ingress, ClickHouse) receive campaign_id\n // without requiring manual mapping by the integrator.\n const ctx = (event as any).context;\n const props = (event as any).properties;\n if (ctx?.campaign && props && !props.campaign_id) {\n const utm = ctx.campaign;\n if (utm.campaign) props.campaign_id = utm.campaign;\n if (utm.source) props.campaign_source = utm.source;\n if (utm.medium) props.campaign_medium = utm.medium;\n if (utm.content) props.campaign_content = utm.content;\n if (utm.term) props.campaign_term = utm.term;\n }\n if (ctx?.adClickIDs && props) {\n const clicks = ctx.adClickIDs;\n const clickId = clicks.gclid || clicks.fbclid || clicks.ctwa_clid || clicks.msclkid || clicks.ttclid;\n if (clickId && !props.campaign_click_id) props.campaign_click_id = clickId;\n }\n\n logger.debug('Capturing event:', event);\n\n const transformedEvent = await this.plugins.executeHookChain(\n 'beforeEventCapture',\n event\n );\n\n if (!transformedEvent) {\n logger.debug('Event cancelled by plugin');\n return;\n }\n\n this.queue!.push(transformedEvent);\n this.session!.incrementEventCount();\n\n await this.plugins.executeHook('afterEventCapture', transformedEvent);\n }\n\n /**\n * Emit a coalesced meta-event reporting client-side rate-limit drops.\n * Bypasses the limiter (see captureEvent guard).\n */\n private emitRateLimitMeta(count: number, sampleEventName: string | null): void {\n if (!this.config?.initialized || !this.session || !this.identity) return;\n const event: TrackEvent = {\n type: 'track',\n event: 'aegis.client.rate_limited',\n properties: {\n dropped_count: count,\n sample_event_name: sampleEventName,\n burst_capacity: this.config.rate_limit_burst,\n refill_per_second: this.config.rate_limit_per_second,\n },\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session.getSessionId(),\n context: buildContext(this.config, this.session),\n };\n this.queue?.push(event);\n }\n\n reset(): void {\n if (!this.assertInitialized()) return;\n\n this.identity.reset();\n logger.info('User identity reset');\n }\n\n /**\n * Ingest the event-governance hint returned from `/v1/sdk/bootstrap`.\n *\n * Callers (Shopify pixel, snippet, react integration) run `bootstrap()`\n * themselves and pass the resulting `eventGovernance` field here so the\n * SDK can self-throttle novel event names before they hit the gateway.\n *\n * Passing null/undefined disables governance (Enterprise plan / outage\n * fail-open). Safe to call before `init()` — the hint is stored and\n * applied as soon as init completes.\n */\n ingestGovernanceHint(hint: EventGovernanceHint | null | undefined): void {\n this.nameGovernor.ingestHint(hint ?? null);\n logger.debug('Governance hint ingested', hint ? {\n k: hint.k,\n m: hint.m,\n remaining: hint.remaining_new_names,\n } : 'disabled');\n }\n\n /**\n * Drain the client-side drop counter and emit a meta-event. Called\n * periodically by the queue flush path so ops dashboards see novel-name\n * amplification patterns in near-real-time.\n */\n private emitGovernanceDropMeta(): void {\n if (!this.config?.initialized || !this.session || !this.identity) return;\n const report = this.nameGovernor.drainDropReport();\n if (!report) return;\n\n const event: TrackEvent = {\n type: 'track',\n event: 'aegis.client.name_governor_dropped',\n properties: {\n dropped_count: report.total,\n distinct_names: Object.keys(report.events).length,\n // Cap the payload — a runaway loop could produce thousands of names;\n // we ship the top 10 for diagnostics and the total for counting.\n sample_names: Object.entries(report.events)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([name, count]) => ({ name, count })),\n window_start: report.since,\n window_end: Date.now(),\n },\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session.getSessionId(),\n context: buildContext(this.config, this.session),\n };\n this.queue?.push(event);\n }\n\n async flush(): Promise<void> {\n if (!this.assertInitialized()) return;\n\n // Emit any coalesced governance-drop telemetry BEFORE flushing so the\n // meta event rides in the same batch as the rest.\n this.emitGovernanceDropMeta();\n await this.queue!.flush();\n }\n\n getAnonymousId(): string | null {\n if (!this.identity) return null;\n return this.identity.getAnonymousId();\n }\n\n getUserId(): string | null {\n if (!this.identity) return null;\n return this.identity.getUserId();\n }\n\n getSessionId(): string | null {\n if (!this.session) return null;\n return this.session.getSessionId();\n }\n\n debug(enable: boolean = true): void {\n if (enable) {\n logger.enable();\n } else {\n logger.disable();\n }\n\n if (this.config) {\n this.config.debug = enable;\n }\n }\n\n setCell(cellEndpoint: CellEndpoint): void {\n if (!this.config) {\n logger.warn('SDK not initialized');\n return;\n }\n\n const existingCell = this.config.cell_endpoints.find(\n (c) => c.region === cellEndpoint.region\n );\n\n if (existingCell) {\n Object.assign(existingCell, cellEndpoint);\n } else {\n this.config.cell_endpoints.push(cellEndpoint);\n }\n\n logger.info('Cell endpoint configured:', cellEndpoint);\n }\n\n getCellInfo() {\n if (!this.transport) return null;\n\n return {\n activeCell: this.transport.getActiveCell(),\n latencies: this.transport.getRegionLatencies(),\n };\n }\n\n setConsent(preferences: Partial<ConsentPreferences>): void {\n if (!this.consent) {\n logger.warn('Consent manager not initialized');\n return;\n }\n\n this.consent.setConsent(preferences);\n logger.info('Consent preferences updated');\n }\n\n grantConsent(category?: ConsentCategory): void {\n if (!this.consent) {\n logger.warn('Consent manager not initialized');\n return;\n }\n\n if (category) {\n this.consent.setConsent({ [category]: true });\n } else {\n this.consent.grantAll();\n }\n }\n\n denyConsent(category?: ConsentCategory): void {\n if (!this.consent) {\n logger.warn('Consent manager not initialized');\n return;\n }\n\n if (category) {\n this.consent.setConsent({ [category]: false });\n } else {\n this.consent.denyAll();\n }\n }\n\n hasConsent(category: ConsentCategory): boolean {\n if (!this.consent) {\n return true;\n }\n\n return this.consent.hasConsent(category);\n }\n\n getConsentPreferences(): ConsentPreferences | null {\n if (!this.consent) {\n return null;\n }\n\n return this.consent.getPreferences();\n }\n\n onConsentChange(callback: (preferences: ConsentPreferences) => void): () => void {\n if (!this.consent) {\n logger.warn('Consent manager not initialized');\n return () => {};\n }\n\n return this.consent.onChange(callback);\n }\n\n private assertInitialized(): boolean {\n if (!this.config?.initialized) {\n logger.warn('SDK not initialized. Call aegis.init() first.');\n return false;\n }\n return true;\n }\n\n get ecommerce(): EcommerceTracker {\n if (!this._ecommerce) {\n this._ecommerce = new EcommerceTracker(this);\n }\n return this._ecommerce;\n }\n\n destroy(): void {\n this.stopSPATracking();\n\n if (this.queue) {\n this.queue.destroy();\n }\n\n if (this.session) {\n this.session.destroy();\n }\n\n if (this.transport) {\n this.transport.destroy();\n }\n\n if (this.rateLimiter) {\n this.rateLimiter.destroy();\n this.rateLimiter = null;\n }\n\n this.plugins.clear();\n\n logger.info('SDK destroyed');\n }\n}\n","/**\n * CarouselCards renderer — a swipeable / autoplaying sequence of product\n * cards. Used for post-purchase upsells, cross-sell, and \"recently viewed\"\n * surfaces. The entire card list is pre-bundled — no network call on\n * trigger; slide advance is pure client state.\n *\n * Data shape (interactive_config, populated at campaign create time and\n * validated server-side):\n * cards: Array<{ image_url?, title, body?, cta_text?, cta_url? }>\n * autoplay_ms?: number // 0 = manual advance only\n * loop?: boolean // wrap to card 0 on last-next\n */\n\nimport type { RenderContext } from './types';\n\ntype Card = {\n image_url?: string;\n title?: string;\n body?: string;\n cta_text?: string;\n cta_url?: string;\n};\n\nconst MAX_CARDS_RENDERED = 10;\n\nexport function renderCarouselCards(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const rawCards = Array.isArray(ic.cards) ? (ic.cards as Card[]) : [];\n const cards = rawCards.slice(0, MAX_CARDS_RENDERED);\n\n if (cards.length === 0) {\n log('carousel_cards rendered with zero cards — skipping', 'warn');\n return;\n }\n\n const autoplay = Number(ic.autoplay_ms) || 0;\n const loop = ic.loop !== false; // default true\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#ffffff');\n const fg = sanitizeColor((campaign.text_color as string) || '#0f172a');\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-carousel-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = `\n position: fixed; left: 0; right: 0; bottom: 0;\n z-index: 99999; padding: 12px 12px 20px;\n background: rgba(0,0,0,0.12); backdrop-filter: blur(8px);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n `;\n\n const card = document.createElement('div');\n card.style.cssText = `\n background: ${bg}; color: ${fg}; border-radius: 16px;\n box-shadow: 0 8px 20px rgba(0,0,0,0.08); padding: 16px;\n max-width: 520px; margin: 0 auto; position: relative;\n `;\n\n const header = document.createElement('div');\n header.style.cssText = 'display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 12px;';\n\n const headerText = document.createElement('div');\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 700; font-size: 15px; margin-bottom: 2px;';\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.75;';\n headerText.appendChild(title);\n headerText.appendChild(body);\n header.appendChild(headerText);\n\n const closeBtn = document.createElement('button');\n closeBtn.textContent = '✕';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 16px; cursor: pointer; opacity: 0.6; padding: 2px 6px;\n `;\n closeBtn.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n });\n header.appendChild(closeBtn);\n card.appendChild(header);\n\n const track = document.createElement('div');\n track.style.cssText = `\n display: flex; gap: 10px; overflow-x: auto; scroll-snap-type: x mandatory;\n scrollbar-width: none; -ms-overflow-style: none; padding-bottom: 4px;\n `;\n (track.style as unknown as { msOverflowStyle?: string }).msOverflowStyle = 'none';\n track.addEventListener('wheel', (e) => {\n if (Math.abs(e.deltaX) < Math.abs(e.deltaY)) return;\n track.scrollLeft += e.deltaX;\n });\n\n cards.forEach((c, i) => {\n const tile = document.createElement('div');\n tile.setAttribute('data-card-index', String(i));\n tile.style.cssText = `\n flex: 0 0 auto; width: 140px; scroll-snap-align: start;\n background: ${fg}0a; border-radius: 12px; padding: 10px;\n display: flex; flex-direction: column; gap: 6px;\n cursor: ${c.cta_url ? 'pointer' : 'default'};\n `;\n if (c.image_url) {\n const img = document.createElement('img');\n const safe = sanitizeUrl(c.image_url);\n if (safe) {\n img.src = safe;\n img.alt = '';\n img.loading = 'lazy';\n img.style.cssText = 'width: 100%; height: 96px; border-radius: 8px; object-fit: cover;';\n tile.appendChild(img);\n }\n }\n if (c.title) {\n const t = document.createElement('div');\n t.textContent = c.title;\n t.style.cssText = 'font-weight: 600; font-size: 13px; line-height: 1.3;';\n tile.appendChild(t);\n }\n if (c.body) {\n const b = document.createElement('div');\n b.textContent = c.body;\n b.style.cssText = 'font-size: 11.5px; opacity: 0.72; line-height: 1.3;';\n tile.appendChild(b);\n }\n if (c.cta_text && c.cta_url) {\n const cta = document.createElement('button');\n cta.textContent = c.cta_text;\n cta.style.cssText = `\n margin-top: auto; background: ${fg}; color: ${bg};\n border: none; padding: 6px 10px; border-radius: 999px;\n font-size: 12px; font-weight: 600; cursor: pointer;\n `;\n const goto = (e: Event) => {\n e.stopPropagation();\n trackEvent(campaign.id, 'clicked');\n const safe = sanitizeUrl(c.cta_url!);\n if (safe) window.location.href = safe;\n };\n cta.addEventListener('click', goto);\n tile.appendChild(cta);\n tile.addEventListener('click', goto);\n }\n track.appendChild(tile);\n });\n card.appendChild(track);\n\n // Dots + autoplay\n const dots = document.createElement('div');\n dots.style.cssText = 'display: flex; justify-content: center; gap: 6px; margin-top: 10px;';\n const dotEls: HTMLSpanElement[] = [];\n cards.forEach(() => {\n const dot = document.createElement('span');\n dot.style.cssText = `\n width: 6px; height: 6px; border-radius: 999px; background: ${fg};\n opacity: 0.25; transition: opacity 0.2s;\n `;\n dotEls.push(dot);\n dots.appendChild(dot);\n });\n card.appendChild(dots);\n\n const setActive = (idx: number) => {\n dotEls.forEach((d, i) => (d.style.opacity = i === idx ? '0.9' : '0.25'));\n };\n setActive(0);\n\n let activeIdx = 0;\n const tiles = track.querySelectorAll<HTMLDivElement>('[data-card-index]');\n const goto = (idx: number) => {\n activeIdx = ((idx % cards.length) + cards.length) % cards.length;\n const el = tiles[activeIdx];\n if (el) {\n el.scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' });\n setActive(activeIdx);\n }\n };\n\n let autoplayTimer: ReturnType<typeof setInterval> | null = null;\n if (autoplay > 0 && cards.length > 1) {\n autoplayTimer = setInterval(() => {\n const next = activeIdx + 1;\n if (next >= cards.length && !loop) {\n if (autoplayTimer) clearInterval(autoplayTimer);\n return;\n }\n goto(next);\n }, autoplay);\n }\n\n overlay.addEventListener('remove', () => {\n if (autoplayTimer) clearInterval(autoplayTimer);\n });\n\n // Observe scroll to keep dots in sync when the user swipes.\n track.addEventListener('scroll', () => {\n const approx = Math.round(track.scrollLeft / 150);\n if (approx !== activeIdx && approx >= 0 && approx < cards.length) {\n activeIdx = approx;\n setActive(activeIdx);\n }\n });\n\n overlay.appendChild(card);\n document.body.appendChild(overlay);\n}\n","/**\n * StickyBar renderer — a pinned notification strip at the top or bottom\n * of the viewport. Used for free-shipping hints, flash-sale banners,\n * cart-reminder strips. Dismissible, optionally auto-hiding.\n *\n * interactive_config:\n * sticky_position: 'top' | 'bottom' (required)\n * sticky_bg_color?: string\n * sticky_dismissible?: boolean default true\n * sticky_auto_hide_ms?: number 0 = never\n */\n\nimport type { RenderContext } from './types';\n\n// Persist per-campaign dismissal across reloads so we don't re-show a\n// bar the user already closed. Scoped per campaign ID; storage key\n// survives navigation but is cleared when the user explicitly clears site data.\nconst DISMISS_STORAGE_PREFIX = 'aegis_sticky_dismissed:';\n\nexport function renderStickyBar(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const position = ic.sticky_position === 'top' ? 'top' : 'bottom';\n const dismissible = ic.sticky_dismissible !== false;\n const autoHide = Number(ic.sticky_auto_hide_ms) || 0;\n\n // Already dismissed this session? Skip silently — the prefetch bundle\n // keeps re-offering it, but the user's explicit close stands until TTL.\n try {\n if (\n typeof localStorage !== 'undefined' &&\n localStorage.getItem(DISMISS_STORAGE_PREFIX + campaign.id)\n ) {\n log(`sticky_bar ${campaign.id} suppressed — user dismissed earlier`);\n return;\n }\n } catch {\n // localStorage blocked — fall through and render\n }\n\n addAnimationStyles();\n\n const bg = sanitizeColor(\n (ic.sticky_bg_color as string) || (campaign.background_color as string) || '#4169e1',\n );\n const fg = sanitizeColor((campaign.text_color as string) || '#ffffff');\n\n const bar = document.createElement('div');\n bar.className = 'aegis-in-app-sticky-bar';\n bar.setAttribute('data-campaign-id', campaign.id);\n\n const positionCss =\n position === 'top'\n ? 'top: 0; left: 0; right: 0; animation: aegisSlideDown 0.3s ease-out;'\n : 'bottom: 0; left: 0; right: 0; animation: aegisSlideInFromBottom 0.3s ease-out;';\n\n bar.style.cssText = `\n position: fixed; ${positionCss}\n background: ${bg}; color: ${fg};\n padding: 10px 14px; z-index: 999998;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n display: flex; align-items: center; gap: 12px; justify-content: center;\n box-shadow: 0 ${position === 'top' ? '2px' : '-2px'} 8px rgba(0,0,0,0.08);\n `;\n\n const label = document.createElement('div');\n label.style.cssText = 'flex: 0 1 auto; font-size: 13px; font-weight: 500; text-align: center;';\n const strong = document.createElement('strong');\n strong.textContent = campaign.title;\n strong.style.cssText = 'margin-right: 6px; font-weight: 700;';\n label.appendChild(strong);\n label.appendChild(document.createTextNode(campaign.body));\n bar.appendChild(label);\n\n if (campaign.action_url && campaign.button_text) {\n const cta = document.createElement('button');\n cta.textContent = campaign.button_text;\n cta.style.cssText = `\n background: ${fg}; color: ${bg};\n border: none; padding: 6px 14px; border-radius: 999px;\n font-size: 12px; font-weight: 700; cursor: pointer; white-space: nowrap;\n `;\n cta.addEventListener('click', () => {\n trackEvent(campaign.id, 'clicked');\n const safe = sanitizeUrl(campaign.action_url!);\n if (safe) window.location.href = safe;\n });\n bar.appendChild(cta);\n }\n\n let autoHideTimer: ReturnType<typeof setTimeout> | null = null;\n const remove = (persist: boolean) => {\n if (autoHideTimer) clearTimeout(autoHideTimer);\n if (persist) {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(DISMISS_STORAGE_PREFIX + campaign.id, '1');\n }\n } catch {\n // swallow — localStorage may be disabled\n }\n }\n bar.remove();\n };\n\n if (dismissible) {\n const close = document.createElement('button');\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Dismiss');\n close.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 16px; cursor: pointer; padding: 0 4px; opacity: 0.75;\n `;\n close.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n remove(true);\n });\n bar.appendChild(close);\n }\n\n if (autoHide > 0) {\n autoHideTimer = setTimeout(() => remove(false), autoHide);\n }\n\n document.body.appendChild(bar);\n}\n","/**\n * ProgressBar renderer — a persistent bar that shows the user's progress\n * toward a reward threshold (free shipping, loyalty tier, referral bonus).\n *\n * Two sources of the current value:\n * 'client' — cheap: read from window.Shopify / WooCommerce / Magento\n * cart globals. Untrusted; fine for visual-only hints.\n * 'sse' — trusted: cell-plane pushes current_value via SSE to the\n * already-shipped realtime server. For cart-gated rewards\n * (must agree with server-side checkout guard), prefer SSE.\n *\n * For Phase 1 we implement CLIENT mode end-to-end. SSE mode reads\n * `window.__aegisProgressSSE[campaign.id]` if populated by a parent app\n * — higher-level integration (the SSE bridge) can push values there.\n *\n * interactive_config:\n * progress_goal_type: 'cart_total' | 'items_in_cart' | 'loyalty_points' | 'referrals'\n * progress_threshold: number\n * progress_reward_text?: string\n * progress_source?: 'client' | 'sse' default 'client'\n */\n\nimport type { RenderContext } from './types';\n\ntype GoalType = 'cart_total' | 'items_in_cart' | 'loyalty_points' | 'referrals';\n\nexport function renderProgressBar(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const goalType = (ic.progress_goal_type as GoalType) || 'cart_total';\n const threshold = Number(ic.progress_threshold);\n if (!(threshold > 0)) {\n log('progress_bar requires a positive progress_threshold — skipping', 'warn');\n return;\n }\n const rewardText =\n (ic.progress_reward_text as string) || (campaign.body as string) || 'Unlocked!';\n const source = ic.progress_source === 'sse' ? 'sse' : 'client';\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#f8fafc');\n const fill = sanitizeColor((campaign.text_color as string) || '#4169e1');\n const fg = '#0f172a';\n\n const bar = document.createElement('div');\n bar.className = 'aegis-in-app-progress-bar';\n bar.setAttribute('data-campaign-id', campaign.id);\n bar.style.cssText = `\n position: fixed; left: 12px; right: 12px; bottom: 12px;\n max-width: 540px; margin: 0 auto;\n background: ${bg}; color: ${fg}; border-radius: 12px;\n padding: 10px 14px; z-index: 999997;\n box-shadow: 0 8px 20px rgba(0,0,0,0.08);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n `;\n\n const label = document.createElement('div');\n label.style.cssText = 'display: flex; justify-content: space-between; font-size: 13px; font-weight: 600; margin-bottom: 6px;';\n\n const leading = document.createElement('span');\n leading.textContent = campaign.title;\n label.appendChild(leading);\n\n const numeric = document.createElement('span');\n numeric.style.cssText = 'opacity: 0.7; font-weight: 500;';\n label.appendChild(numeric);\n bar.appendChild(label);\n\n const shell = document.createElement('div');\n shell.style.cssText = `\n height: 8px; border-radius: 999px; background: ${fill}22;\n overflow: hidden;\n `;\n const fillEl = document.createElement('div');\n fillEl.style.cssText = `\n height: 100%; border-radius: 999px; background: ${fill};\n width: 0%; transition: width 0.4s cubic-bezier(.4,0,.2,1);\n `;\n shell.appendChild(fillEl);\n bar.appendChild(shell);\n\n const footnote = document.createElement('div');\n footnote.style.cssText = 'font-size: 11.5px; opacity: 0.65; margin-top: 6px;';\n bar.appendChild(footnote);\n\n const readCurrentValue = (): number => {\n if (source === 'sse') {\n const hook = (window as unknown as {\n __aegisProgressSSE?: Record<string, number>;\n }).__aegisProgressSSE;\n return (hook && typeof hook[campaign.id] === 'number' ? hook[campaign.id] : 0) as number;\n }\n // client mode — read the platform cart globals the widget manager\n // already normalises (Shopify/Woo/Magento). We peek at the same\n // locations without pulling in AegisWidgetManager's 2k-line module.\n try {\n if (goalType === 'cart_total' || goalType === 'items_in_cart') {\n const win = window as unknown as {\n Shopify?: { checkout?: { total_price?: string | number } };\n aegis_cart?: { cart_total?: number; cart_items?: unknown[] };\n localStorage?: Storage;\n };\n if (win.Shopify?.checkout) {\n const v = parseFloat(String(win.Shopify.checkout.total_price || 0));\n return goalType === 'cart_total' ? v : 0;\n }\n if (win.aegis_cart) {\n if (goalType === 'items_in_cart') {\n return Array.isArray(win.aegis_cart.cart_items) ? win.aegis_cart.cart_items.length : 0;\n }\n return Number(win.aegis_cart.cart_total || 0);\n }\n // Magento cache fallback\n try {\n const cacheStr = window.localStorage?.getItem('mage-cache-storage');\n if (cacheStr) {\n const cache = JSON.parse(cacheStr) as { cart?: { subtotalAmount?: number; items?: unknown[] } };\n const cart = cache.cart;\n if (cart) {\n return goalType === 'cart_total'\n ? Number(cart.subtotalAmount || 0)\n : Array.isArray(cart.items)\n ? cart.items.length\n : 0;\n }\n }\n } catch {\n /* noop */\n }\n }\n // loyalty_points / referrals are expected to flow via SSE/push; in\n // client mode we cannot trust a local counter.\n return 0;\n } catch {\n return 0;\n }\n };\n\n let lastFiredUnlock = false;\n const update = () => {\n const cur = readCurrentValue();\n const pct = Math.max(0, Math.min(100, (cur / threshold) * 100));\n fillEl.style.width = `${pct}%`;\n numeric.textContent = `${cur.toFixed(0)} / ${threshold.toFixed(0)}`;\n if (pct >= 100) {\n footnote.textContent = rewardText;\n if (!lastFiredUnlock) {\n lastFiredUnlock = true;\n trackEvent(campaign.id, 'clicked'); // \"unlocked\" recorded as click\n }\n } else {\n const remaining = Math.max(0, threshold - cur);\n footnote.textContent = `Add ${remaining.toFixed(0)} more to unlock: ${rewardText}`;\n }\n };\n\n update();\n\n // Client-mode cart state changes fire events on the storefront globals\n // (Shopify emits `cart:updated`, Woo emits its own). Poll fallback at\n // 1s — negligible overhead because every tick is synchronous.\n const pollTimer = setInterval(update, 1000);\n const cleanup = () => clearInterval(pollTimer);\n window.addEventListener('beforeunload', cleanup, { once: true });\n bar.addEventListener('remove', cleanup);\n\n document.body.appendChild(bar);\n}\n","/**\n * CoachmarkTour renderer — a guided, multi-step walkthrough anchored to\n * DOM elements via CSS selectors. One tooltip appears at a time with\n * next/back navigation; completion + skip are persisted per contact via\n * localStorage under the `resume_key`, so an abandoned tour resumes on\n * the next visit instead of restarting or re-bothering the user.\n *\n * interactive_config:\n * steps: Array<{\n * anchor_web?: string, // CSS selector for THIS platform\n * anchor_android?: string, // ignored on web\n * anchor_ios?: string, // ignored on web\n * title: string,\n * body: string,\n * placement?: 'top' | 'bottom' | 'left' | 'right',\n * cta_text?: string,\n * }>\n * resume_key: string,\n * allow_skip?: boolean,\n * show_progress_dots?: boolean,\n */\n\nimport type { RenderContext } from './types';\n\ntype Step = {\n anchor_web?: string;\n anchor_android?: string;\n anchor_ios?: string;\n title: string;\n body: string;\n placement?: 'top' | 'bottom' | 'left' | 'right';\n cta_text?: string;\n};\n\nconst RESUME_PREFIX = 'aegis_coachmark_progress:';\n\nfunction readResumeIdx(resumeKey: string): number {\n try {\n if (typeof localStorage === 'undefined') return 0;\n const raw = localStorage.getItem(RESUME_PREFIX + resumeKey);\n const n = raw ? parseInt(raw, 10) : 0;\n return Number.isFinite(n) && n >= 0 ? n : 0;\n } catch {\n return 0;\n }\n}\n\nfunction writeResumeIdx(resumeKey: string, idx: number): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(RESUME_PREFIX + resumeKey, String(idx));\n }\n } catch {\n /* noop */\n }\n}\n\nfunction clearResume(resumeKey: string): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem(RESUME_PREFIX + resumeKey);\n }\n } catch {\n /* noop */\n }\n}\n\nexport function renderCoachmarkTour(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const resumeKey = ic.resume_key as string | undefined;\n if (!resumeKey) {\n log('coachmark_tour requires interactive_config.resume_key — skipping', 'warn');\n return;\n }\n\n const steps = Array.isArray(ic.steps) ? (ic.steps as Step[]) : [];\n if (steps.length === 0) {\n log('coachmark_tour has no steps — skipping', 'warn');\n return;\n }\n\n const allowSkip = ic.allow_skip !== false;\n const showDots = ic.show_progress_dots !== false;\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#0f172a');\n const fg = sanitizeColor((campaign.text_color as string) || '#ffffff');\n\n // Resume or start at 0.\n let current = readResumeIdx(resumeKey);\n if (current >= steps.length) {\n log(`coachmark_tour ${resumeKey} already complete — not re-showing`);\n return;\n }\n\n // Track the single overall impression once per mount.\n trackEvent(campaign.id, 'impression');\n\n let pointerEl: HTMLElement | null = null;\n let tipEl: HTMLElement | null = null;\n let highlightEl: HTMLElement | null = null;\n\n const cleanupOne = () => {\n pointerEl?.remove();\n tipEl?.remove();\n highlightEl?.remove();\n pointerEl = null;\n tipEl = null;\n highlightEl = null;\n };\n\n const finish = (opts: { skipped: boolean }) => {\n cleanupOne();\n if (opts.skipped) {\n trackEvent(campaign.id, 'dismissed');\n } else {\n trackEvent(campaign.id, 'clicked'); // completion\n }\n // Mark tour as complete so we never restart it for this contact.\n writeResumeIdx(resumeKey, steps.length);\n };\n\n const showStep = (idx: number) => {\n cleanupOne();\n const step = steps[idx];\n if (!step) {\n finish({ skipped: false });\n return;\n }\n writeResumeIdx(resumeKey, idx);\n\n const selector = step.anchor_web;\n let anchor: Element | null = null;\n if (selector) {\n try {\n anchor = document.querySelector(selector);\n } catch {\n anchor = null;\n }\n }\n if (!anchor) {\n log(`coachmark step ${idx} — selector '${selector}' not found; advancing`, 'warn');\n showStep(idx + 1);\n return;\n }\n\n const rect = anchor.getBoundingClientRect();\n // Slight highlight around the anchor so the user's eye snaps to it.\n highlightEl = document.createElement('div');\n highlightEl.style.cssText = `\n position: fixed;\n top: ${rect.top - 6}px; left: ${rect.left - 6}px;\n width: ${rect.width + 12}px; height: ${rect.height + 12}px;\n border-radius: 10px; z-index: 999998;\n box-shadow: 0 0 0 2px ${fg}, 0 0 0 9999px rgba(0,0,0,0.4);\n pointer-events: none;\n transition: all 0.2s ease;\n `;\n document.body.appendChild(highlightEl);\n\n const placement = step.placement || 'bottom';\n tipEl = document.createElement('div');\n tipEl.setAttribute('data-campaign-id', campaign.id);\n tipEl.style.cssText = `\n position: fixed; z-index: 999999;\n background: ${bg}; color: ${fg};\n padding: 12px 14px; border-radius: 12px;\n max-width: 260px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.25);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisFadeIn 0.2s ease;\n `;\n\n const titleEl = document.createElement('div');\n titleEl.textContent = step.title;\n titleEl.style.cssText = 'font-weight: 700; font-size: 13px; margin-bottom: 4px;';\n tipEl.appendChild(titleEl);\n\n const bodyEl = document.createElement('div');\n bodyEl.textContent = step.body;\n bodyEl.style.cssText = 'font-size: 12.5px; line-height: 1.4; opacity: 0.9;';\n tipEl.appendChild(bodyEl);\n\n const controls = document.createElement('div');\n controls.style.cssText = 'display: flex; align-items: center; justify-content: space-between; margin-top: 10px; gap: 8px;';\n\n // Dots\n if (showDots) {\n const dots = document.createElement('div');\n dots.style.cssText = 'display: flex; gap: 4px;';\n steps.forEach((_, i) => {\n const d = document.createElement('span');\n d.style.cssText = `\n width: 5px; height: 5px; border-radius: 999px;\n background: ${fg}; opacity: ${i === idx ? '0.95' : '0.3'};\n `;\n dots.appendChild(d);\n });\n controls.appendChild(dots);\n } else {\n controls.appendChild(document.createElement('span'));\n }\n\n const buttons = document.createElement('div');\n buttons.style.cssText = 'display: flex; gap: 6px;';\n\n if (allowSkip && idx < steps.length - 1) {\n const skip = document.createElement('button');\n skip.textContent = 'Skip';\n skip.style.cssText = `\n background: transparent; color: inherit; opacity: 0.7;\n border: none; font-size: 12px; cursor: pointer; padding: 6px 8px;\n `;\n skip.addEventListener('click', () => finish({ skipped: true }));\n buttons.appendChild(skip);\n }\n\n const next = document.createElement('button');\n const isLast = idx === steps.length - 1;\n next.textContent = step.cta_text || (isLast ? 'Done' : 'Next');\n next.style.cssText = `\n background: ${fg}; color: ${bg};\n border: none; padding: 6px 12px; border-radius: 999px;\n font-size: 12px; font-weight: 700; cursor: pointer;\n `;\n next.addEventListener('click', () => {\n if (isLast) {\n finish({ skipped: false });\n } else {\n showStep(idx + 1);\n }\n });\n buttons.appendChild(next);\n\n controls.appendChild(buttons);\n tipEl.appendChild(controls);\n document.body.appendChild(tipEl);\n\n // Position after insertion so we know the tip's own dimensions.\n const tipRect = tipEl.getBoundingClientRect();\n const margin = 12;\n let top = rect.bottom + margin;\n let left = rect.left;\n if (placement === 'top') {\n top = rect.top - tipRect.height - margin;\n } else if (placement === 'left') {\n top = rect.top;\n left = rect.left - tipRect.width - margin;\n } else if (placement === 'right') {\n top = rect.top;\n left = rect.right + margin;\n }\n // Clamp to viewport.\n top = Math.max(8, Math.min(window.innerHeight - tipRect.height - 8, top));\n left = Math.max(8, Math.min(window.innerWidth - tipRect.width - 8, left));\n tipEl.style.top = `${top}px`;\n tipEl.style.left = `${left}px`;\n };\n\n showStep(current);\n\n // If the host page unloads mid-tour, leave the current index persisted so\n // the next session resumes from there. Nothing else to do — writeResumeIdx\n // was called in showStep.\n // Expose a cancel hook so app code can reset the tour from Dev Tools etc.\n (window as unknown as { aegisResetTour?: (key: string) => void }).aegisResetTour = (key: string) => clearResume(key);\n}\n","/**\n * AegisInAppManager - Web SDK In-App Messaging Module\n *\n * HTTP polling architecture with client-side evaluation.\n *\n * Security:\n * - XSS Protection: Uses DOM APIs (createElement, textContent) instead of innerHTML\n * - URL Validation: Prevents javascript: protocol injection\n * - CSP Compatible: No inline styles in HTML strings\n *\n * Architecture (RFC 2026-04-16):\n * - Polls /v1/in-app/active on initialize + on identity change\n * - Caches campaigns locally in memory\n * - Evaluates trigger rules client-side\n * - Tracks events (impression, click, dismiss) asynchronously\n *\n * NOTE: Persistent SSE for downstream delivery is disabled by default\n * (enableSSE=false). Tenant dashboards that need realtime (inbox, chat,\n * live page) open SSE directly via Next.js API routes — not via this SDK.\n * End-user storefronts use polling + Web Push for background delivery.\n */\n\nimport type { RenderContext } from './renderers';\nimport {\n renderCarouselCards,\n renderCoachmarkTour,\n renderProductRecommendation,\n renderProgressBar,\n renderStickyBar,\n} from './renderers';\nimport { Storage } from '../utils/storage';\n\n// Read the SDK's persisted anonymous_id from localStorage/cookie if available.\n// Returns undefined when called server-side (no document/window) or when no\n// id has been minted yet — caller falls through to leaving userId unset.\nfunction readAnonIdFromStorage(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n try {\n const storage = new Storage();\n return storage.get('anon_id') ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface InAppCampaign {\n id: string;\n type:\n | 'modal'\n | 'banner'\n | 'tooltip'\n | 'full_screen'\n | 'half_interstitial'\n | 'alert'\n | 'pip'\n // Preload-first display types (2026-04-22 §5.4 of the expansion plan)\n | 'carousel_cards'\n | 'sticky_bar'\n | 'progress_bar'\n | 'coachmark_tour'\n | 'product_recommendation';\n sub_type?: string;\n title: string;\n body: string;\n image_url?: string;\n video_url?: string;\n action_url?: string;\n button_text?: string;\n background_color?: string;\n text_color?: string;\n priority: number;\n expires_at?: string;\n frequency?: {\n max_impressions?: number;\n max_impressions_per_day?: number;\n cooldown_seconds?: number;\n // Conversion-aware suppression — added by Micro-Intent Engine P0a (2026-04-30).\n // Mirrors cell-plane FrequencyCap. When the host app calls\n // `notifyConversion(goalName)`, every armed campaign whose\n // `suppress_after_conversion_seconds` is set gets silenced for that\n // many seconds (session-scoped via sessionStorage). Prevents the\n // \"showing 10% off to a buyer who just paid full price\" failure mode.\n suppress_after_conversion_seconds?: number;\n suppress_after_dismiss_seconds?: number;\n scope?: 'session' | 'user' | 'user_sku';\n };\n interactive_config?: Record<string, unknown>;\n client_trigger?: {\n type: string;\n config?: Record<string, unknown>;\n };\n assigned_variant_id?: string;\n}\n\nexport interface AegisInAppConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n // Resolved by POST /v1/sdk/bootstrap — required in production. Campaigns\n // with a non-empty `target_properties` list are filtered against this on\n // the server, so passing the wrong id (or omitting it) narrows visible\n // campaigns to the property-agnostic ones only.\n propertyId?: string;\n debugMode?: boolean;\n enableSSE?: boolean;\n /**\n * Callback invoked when the manager receives an in-app campaign with\n * a gamification sub_type (spin_wheel / scratch_card). The facade\n * (AegisMessageRuntime) wires this to the widget-renderer path so\n * interactive campaigns render correctly. When this is undefined,\n * gamification campaigns are logged and skipped.\n */\n onInteractiveCampaign?: (campaign: InAppCampaign) => void;\n}\n\nexport class AegisInAppManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private propertyId?: string;\n private debugMode: boolean;\n private enableSSE: boolean;\n private onInteractiveCampaign?: (campaign: InAppCampaign) => void;\n\n private campaigns: InAppCampaign[] = [];\n private displayedCampaigns = new Set<string>();\n // Conversion-aware suppression — campaign_id -> epoch_ms when suppression expires.\n // Populated by `notifyConversion()` and rehydrated from sessionStorage in\n // `refreshCampaigns()` so a navigation between pages preserves silence.\n private suppressedUntil = new Map<string, number>();\n private eventSource?: EventSource;\n private isInitialized = false;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n // sessionStorage key prefix — one entry per goal so we can introspect what\n // converted and when. Format: { ts: epoch_ms }.\n private static readonly CONVERSION_STORAGE_PREFIX = 'aegis_conv_';\n \n constructor(config: AegisInAppConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n // Fall back to the SDK's persisted anonymous_id (set on first /v1/sdk/bootstrap\n // and reused across the main analytics SDK) so anonymous storefront users\n // get journey-driven in-app messages keyed to the same identity used in\n // /v1/batch payloads. Without this, polling defaults to \"anonymous\" on the\n // server and bucket-misses every per-contact priority queue.\n this.userId = config.userId ?? readAnonIdFromStorage();\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.propertyId = config.propertyId;\n this.debugMode = config.debugMode || false;\n // SSE is disabled by default. Kept as opt-in capability for future tenant\n // dashboards that embed the Aegis SDK and need realtime updates. End-user\n // storefronts must NOT enable this — persistent-per-tab SSE doesn't scale.\n this.enableSSE = config.enableSSE === true;\n this.onInteractiveCampaign = config.onInteractiveCampaign;\n }\n \n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisInApp already initialized');\n return;\n }\n\n // Mark user as returning for subsequent visits\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('aegis_returning_user', '1');\n }\n\n await this.refreshCampaigns();\n\n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n \n this.isInitialized = true;\n this.log('AegisInApp initialized successfully');\n }\n \n updateUserId(userId: string): void {\n this.userId = userId;\n this.refreshCampaigns();\n }\n \n updateContactId(contactId: string): void {\n this.contactId = contactId;\n this.disconnectSSE();\n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n this.refreshCampaigns();\n }\n\n /**\n * Conversion-aware suppression. Call this when the host app observes a\n * goal event (purchase, order_placed, checkout_completed, or any custom\n * goal the workspace has configured per-campaign).\n *\n * For every armed campaign whose `frequency.suppress_after_conversion_seconds`\n * is set, this:\n * 1. Persists the conversion in sessionStorage (so subsequent page\n * loads in the same tab retain silence).\n * 2. Computes an expiry epoch_ms and stores it in `suppressedUntil`.\n * 3. The two campaign-evaluation paths (`tryDisplayNextCampaign`\n * and `onClientEvent`) skip campaigns whose `suppressedUntil`\n * has not yet passed.\n *\n * Scope: only `session` is implemented in P0a. `user` and `user_sku`\n * scopes degrade to session-only with a debug log; the schema accepts\n * them so future expansion is non-breaking.\n *\n * Safe to call repeatedly for the same goal — each call refreshes the\n * sessionStorage timestamp and re-applies suppression to any campaigns\n * loaded since the last call.\n */\n notifyConversion(goalName: string): void {\n if (!goalName) {\n this.log('notifyConversion called with empty goalName; ignored', 'warn');\n return;\n }\n const ts = Date.now();\n if (typeof sessionStorage !== 'undefined') {\n try {\n sessionStorage.setItem(\n `${AegisInAppManager.CONVERSION_STORAGE_PREFIX}${goalName}`,\n JSON.stringify({ ts }),\n );\n } catch {\n // sessionStorage may be disabled (Safari private mode, blocked\n // third-party context). Suppression still applies for the\n // current page lifetime via the in-memory map.\n }\n }\n this.applySuppressionFromCampaigns(ts);\n this.log(`notifyConversion: ${goalName} — suppressing ${this.suppressedUntil.size} armed campaigns`);\n }\n\n /**\n * Compute and store `suppressedUntil` entries for every armed campaign\n * whose `frequency.suppress_after_conversion_seconds` is set. Called by\n * `notifyConversion()` and `refreshCampaigns()` (the latter rehydrates\n * suppression for newly-loaded campaigns when a prior conversion event\n * exists in sessionStorage).\n *\n * `convertedAt` is the epoch_ms of the conversion; pass `Date.now()`\n * when called from `notifyConversion`, or the `ts` recovered from\n * sessionStorage when rehydrating.\n */\n private applySuppressionFromCampaigns(convertedAt: number): void {\n for (const c of this.campaigns) {\n const seconds = c.frequency?.suppress_after_conversion_seconds;\n if (typeof seconds !== 'number' || seconds <= 0) continue;\n const scope = c.frequency?.scope ?? 'session';\n if (scope !== 'session') {\n // P0a only implements session scope. Schema accepts user / user_sku\n // so future work doesn't break wire compatibility, but for now we\n // degrade to session and log.\n this.log(\n `applySuppressionFromCampaigns: scope=${scope} not implemented; degrading to session for campaign ${c.id}`,\n 'warn',\n );\n }\n const expiresAt = convertedAt + seconds * 1000;\n // Take the max so a later/longer suppression wins over an earlier one.\n const existing = this.suppressedUntil.get(c.id);\n if (existing === undefined || existing < expiresAt) {\n this.suppressedUntil.set(c.id, expiresAt);\n }\n }\n }\n\n /**\n * Recover any prior conversion timestamps from sessionStorage and apply\n * suppression to currently-loaded campaigns. Called from\n * `refreshCampaigns()` after `this.campaigns` is populated. This is the\n * mechanism that prevents a converted buyer from seeing a discount popup\n * on the next page load within the same session.\n */\n private rehydrateSuppressionFromStorage(): void {\n if (typeof sessionStorage === 'undefined') return;\n let earliestTs: number | null = null;\n try {\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i);\n if (!key || !key.startsWith(AegisInAppManager.CONVERSION_STORAGE_PREFIX)) continue;\n const raw = sessionStorage.getItem(key);\n if (!raw) continue;\n const parsed = JSON.parse(raw) as { ts?: number };\n if (typeof parsed.ts === 'number') {\n earliestTs = earliestTs === null ? parsed.ts : Math.min(earliestTs, parsed.ts);\n }\n }\n } catch {\n // Malformed entries are silently skipped — suppression simply\n // doesn't apply for them.\n return;\n }\n if (earliestTs !== null) {\n this.applySuppressionFromCampaigns(earliestTs);\n }\n }\n\n /**\n * Returns true if the campaign is currently suppressed (Date.now() is\n * before the stored expiry). Used by both display paths.\n */\n private isSuppressed(campaignId: string): boolean {\n const expiresAt = this.suppressedUntil.get(campaignId);\n if (expiresAt === undefined) return false;\n if (Date.now() >= expiresAt) {\n this.suppressedUntil.delete(campaignId);\n return false;\n }\n return true;\n }\n \n private connectSSE(): void {\n if (this.eventSource) {\n this.disconnectSSE();\n }\n \n if (!this.organizationId) {\n this.log('Cannot connect SSE without organization ID', 'warn');\n return;\n }\n \n const url = new URL('/v1/stream/realtime', this.apiHost);\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Organization-ID': this.organizationId,\n };\n \n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n \n const queryParams = new URLSearchParams();\n Object.entries(headers).forEach(([key, value]) => {\n queryParams.append(key, value);\n });\n \n this.eventSource = new EventSource(`${url}?${queryParams.toString()}`);\n \n this.eventSource.addEventListener('open', () => {\n this.log('SSE connection established');\n this.reconnectAttempts = 0;\n });\n \n this.eventSource.addEventListener('in_app_campaign_updated', (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data);\n this.log(`Received in-app campaign update: ${data.campaign_id}`);\n this.refreshCampaigns();\n } catch (error) {\n this.log(`Error parsing SSE event: ${error}`, 'error');\n }\n });\n \n this.eventSource.addEventListener('heartbeat', (event: MessageEvent) => {\n this.log('SSE heartbeat received');\n });\n \n this.eventSource.addEventListener('error', (error) => {\n this.log('SSE connection error', 'error');\n \n if (this.eventSource?.readyState === EventSource.CLOSED) {\n this.attemptReconnect();\n }\n });\n }\n \n private disconnectSSE(): void {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = undefined;\n this.log('SSE connection closed');\n }\n }\n \n private attemptReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n this.log('Max reconnect attempts reached, giving up', 'warn');\n return;\n }\n \n this.reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);\n \n this.log(`Reconnecting SSE in ${delay}ms (attempt ${this.reconnectAttempts})`);\n \n setTimeout(() => {\n if (this.isInitialized && this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n }, delay);\n }\n \n private async refreshCampaigns(): Promise<void> {\n try {\n // Build URL with client context for server-side targeting (Critical Fix B)\n const context = new URLSearchParams({\n device_type: this.detectDeviceType(),\n page_url: typeof window !== 'undefined' ? window.location.pathname : '/',\n });\n\n // Geo is resolved server-side from IP — no need to send\n context.set('is_new_user', this.isNewUser() ? 'true' : 'false');\n\n const url = `${this.apiHost}/v1/in-app/active?${context.toString()}`;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n\n if (this.userId) {\n headers['X-User-ID'] = this.userId;\n }\n\n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n\n if (this.organizationId) {\n headers['X-Organization-ID'] = this.organizationId;\n }\n\n if (this.propertyId) {\n headers['X-Property-Id'] = this.propertyId;\n }\n\n // Send cached A/B assignments so server can skip re-evaluation (Critical Fix C)\n const abAssignments = this.getABAssignments();\n if (Object.keys(abAssignments).length > 0) {\n headers['X-AB-Assignments'] = btoa(JSON.stringify(abAssignments));\n }\n\n const response = await fetch(url, {\n method: 'GET',\n headers,\n credentials: 'include',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch campaigns: ${response.status}`);\n }\n\n const payload = await response.json();\n // Server returns an array; defensively handle error bodies (HTML\n // from misconfigured gateways, {} from maintenance endpoints, etc.)\n // so a bad response doesn't turn `updateContactId` into a thrower.\n this.campaigns = Array.isArray(payload) ? payload : [];\n\n // Process A/B assignments from server response (Critical Fix C)\n this.processABAssignments(this.campaigns);\n\n // Rehydrate conversion suppression from sessionStorage so a buyer\n // who converted on a prior page load in the same tab does not see\n // a discount popup on this load. Must run after this.campaigns is\n // populated and BEFORE tryDisplayNextCampaign so the first display\n // attempt honors suppression.\n this.rehydrateSuppressionFromStorage();\n\n this.log(`Fetched ${this.campaigns.length} campaigns`);\n\n this.tryDisplayNextCampaign();\n\n } catch (error) {\n this.log(`Error refreshing campaigns: ${error}`, 'error');\n }\n }\n\n // --- Client Context Helpers (Critical Fix B) ---\n\n private detectDeviceType(): 'mobile' | 'desktop' | 'tablet' {\n if (typeof navigator === 'undefined') return 'desktop';\n const ua = navigator.userAgent;\n if (/Mobi|Android/i.test(ua)) return 'mobile';\n if (/iPad|Tablet/i.test(ua)) return 'tablet';\n return 'desktop';\n }\n\n private isNewUser(): boolean {\n if (typeof localStorage === 'undefined') return true;\n return !localStorage.getItem('aegis_returning_user');\n }\n\n // --- A/B Assignment Persistence (Critical Fix C) ---\n\n private getABAssignments(): Record<string, string> {\n if (typeof localStorage === 'undefined') return {};\n try {\n return JSON.parse(localStorage.getItem('aegis_ab_assignments') || '{}');\n } catch {\n return {};\n }\n }\n\n private processABAssignments(campaigns: InAppCampaign[]): void {\n if (typeof localStorage === 'undefined') return;\n const stored = this.getABAssignments();\n for (const campaign of campaigns) {\n if (campaign.assigned_variant_id) {\n stored[campaign.id] = campaign.assigned_variant_id;\n }\n }\n localStorage.setItem('aegis_ab_assignments', JSON.stringify(stored));\n }\n\n private getVariantId(campaignId: string): string | undefined {\n const assignments = this.getABAssignments();\n return assignments[campaignId] ?? undefined;\n }\n \n private tryDisplayNextCampaign(): void {\n // Only auto-display campaigns that DO NOT have a client_trigger.\n // Trigger-gated campaigns wait for the host app to call\n // `onClientEvent()` or for TriggerEngine to fire the matching\n // behavioural event. This preserves the preload-first contract —\n // the campaign is armed but the render is gated.\n // Conversion-aware suppression: campaigns silenced by a prior\n // notifyConversion() call (or rehydrated from sessionStorage) are\n // skipped until their suppression window expires.\n const campaign = this.campaigns.find((c) =>\n !this.displayedCampaigns.has(c.id) && !c.client_trigger && !this.isSuppressed(c.id),\n );\n\n if (campaign) {\n this.displayCampaign(campaign);\n }\n }\n\n /**\n * Evaluate the currently armed campaigns against a client-side event\n * and render any that match their `client_trigger`.\n *\n * Called by the host app (e.g., the EcommerceTracker on product_viewed),\n * or by future TriggerEngine bridges. Safe to call repeatedly for the\n * same event — dedup happens via `displayedCampaigns`.\n *\n * Supported trigger types (align with the cell-plane server-side\n * `display_rules.trigger_type`):\n * - `custom_event` : fire when eventName matches config.event\n * - `product_match` : fire on `product_viewed` when eventData.product_id\n * matches config.product_id (string or string[])\n * - `delay` : client-side setTimeout — evaluated at armeng\n * time (kicked off from `displayCampaign`), not here.\n */\n onClientEvent(eventName: string, eventData: Record<string, unknown> = {}): void {\n for (const c of this.campaigns) {\n if (this.displayedCampaigns.has(c.id)) continue;\n if (!c.client_trigger) continue;\n // Conversion-aware suppression: trigger-gated campaigns silenced by\n // a prior notifyConversion() call are skipped until expiry.\n if (this.isSuppressed(c.id)) continue;\n if (this.matchesClientTrigger(c.client_trigger, eventName, eventData)) {\n this.displayCampaign(c);\n }\n }\n }\n\n private matchesClientTrigger(\n trigger: { type: string; config?: Record<string, unknown> },\n eventName: string,\n eventData: Record<string, unknown>,\n ): boolean {\n const cfg = trigger.config || {};\n switch (trigger.type) {\n case 'custom_event':\n return typeof cfg.event === 'string' && cfg.event === eventName;\n case 'product_match': {\n if (eventName !== 'product_viewed' && eventName !== 'product_view') {\n return false;\n }\n const wantedRaw = cfg.product_id;\n const wanted: string[] = Array.isArray(wantedRaw)\n ? (wantedRaw as string[])\n : typeof wantedRaw === 'string'\n ? [wantedRaw]\n : [];\n if (wanted.length === 0) return false;\n const actual = String(\n eventData.product_id ??\n eventData.productId ??\n (eventData.product as Record<string, unknown> | undefined)?.id ??\n '',\n );\n return wanted.includes(actual);\n }\n default:\n // Unknown or server-evaluated — do not auto-fire from the client.\n return false;\n }\n }\n \n private displayCampaign(campaign: InAppCampaign): void {\n this.displayedCampaigns.add(campaign.id);\n\n // Sub-type routing: interactive types are handled by dedicated renderers\n const interactiveSubTypes = new Set([\n 'spin_wheel', 'scratch_card', 'nps_survey', 'quiz',\n 'countdown_offer', 'star_rating', 'quick_poll',\n ]);\n\n if (campaign.sub_type && interactiveSubTypes.has(campaign.sub_type)) {\n this.renderInteractive(campaign);\n this.trackEvent(campaign.id, 'impression');\n return;\n }\n\n switch (campaign.type) {\n case 'modal':\n this.renderModal(campaign);\n break;\n case 'banner':\n this.renderBanner(campaign);\n break;\n case 'full_screen':\n this.renderFullScreen(campaign);\n break;\n case 'half_interstitial':\n this.renderHalfInterstitial(campaign);\n break;\n case 'alert':\n this.renderAlert(campaign);\n break;\n case 'pip':\n this.renderPIP(campaign);\n break;\n case 'tooltip':\n this.renderTooltip(campaign);\n break;\n // Preload-first display types (2026-04-22). These renderers own their\n // own impression tracking so we don't double-count alongside the\n // trailing `this.trackEvent(... 'impression')` below — return early.\n case 'carousel_cards':\n renderCarouselCards(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n return;\n case 'sticky_bar':\n renderStickyBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n return;\n case 'progress_bar':\n renderProgressBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n return;\n case 'coachmark_tour':\n // coachmark_tour fires its own impression/dismiss/click events\n // from within its state machine — don't double-report here.\n renderCoachmarkTour(this.buildRenderContext(campaign));\n return;\n case 'product_recommendation':\n renderProductRecommendation(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n return;\n }\n\n this.trackEvent(campaign.id, 'impression');\n }\n\n /**\n * Build the shared context passed into the preload-first renderers.\n * Matches the interface in `./renderers/types.ts`. Kept as a private\n * method (rather than inlined at each call-site) so future renderer\n * additions stay consistent and easy to audit.\n */\n private buildRenderContext(campaign: InAppCampaign): RenderContext {\n return {\n campaign,\n trackEvent: (id, evt) => {\n void this.trackEvent(id, evt);\n },\n sanitizeUrl: (url: string) => this.sanitizeUrl(url),\n sanitizeColor: (color: string) => this.sanitizeColor(color),\n log: (msg: string, level?: 'log' | 'warn' | 'error') => this.log(msg, level),\n addAnimationStyles: () => this.addAnimationStyles(),\n };\n }\n\n /**\n * Renders interactive sub-type campaigns (spin wheel, NPS, quiz, etc.)\n * using DOM-safe rendering. These sub-types use the campaign's\n * interactive_config payload for type-specific behavior.\n */\n private renderInteractive(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const bg = this.sanitizeColor(campaign.background_color || '#4169e1');\n const text = this.sanitizeColor(campaign.text_color || '#ffffff');\n\n switch (campaign.sub_type) {\n case 'nps_survey':\n this.renderNPSSurvey(campaign, ic, bg, text);\n break;\n case 'countdown_offer':\n this.renderCountdownOffer(campaign, ic, bg, text);\n break;\n case 'star_rating':\n this.renderStarRating(campaign, ic, bg, text);\n break;\n case 'quick_poll':\n this.renderQuickPoll(campaign, ic, bg, text);\n break;\n case 'quiz':\n this.renderQuiz(campaign, ic, bg, text);\n break;\n case 'spin_wheel':\n case 'scratch_card':\n if (this.onInteractiveCampaign) {\n this.onInteractiveCampaign(campaign);\n } else {\n this.log(\n `${campaign.sub_type} campaign received but no onInteractiveCampaign handler wired — install via AegisMessageRuntime`,\n 'warn',\n );\n }\n break;\n default:\n this.log(`Unknown interactive sub_type: ${campaign.sub_type}`, 'warn');\n this.renderModal(campaign);\n }\n }\n\n // --- Interactive Renderers ---\n\n private renderNPSSurvey(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-nps-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 360px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const question = document.createElement('div');\n question.style.cssText = 'font-size: 16px; font-weight: 700; margin-bottom: 16px;';\n question.textContent = (ic.nps_question as string) || 'How likely are you to recommend us?';\n body.appendChild(question);\n\n const scale = document.createElement('div');\n scale.style.cssText = 'display: flex; gap: 4px; justify-content: center; flex-wrap: wrap; margin-bottom: 12px;';\n for (let i = 0; i <= 10; i++) {\n const btn = document.createElement('span');\n btn.style.cssText = `\n width: 28px; height: 28px; border-radius: 6px; display: flex;\n align-items: center; justify-content: center; font-size: 11px;\n font-weight: 600; cursor: pointer; background: ${text}33; color: ${text};\n transition: transform 0.1s;\n `;\n btn.textContent = String(i);\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n });\n scale.appendChild(btn);\n }\n body.appendChild(scale);\n\n const labels = document.createElement('div');\n labels.style.cssText = 'display: flex; justify-content: space-between; font-size: 11px; opacity: 0.6; margin-bottom: 16px;';\n const notLikely = document.createElement('span');\n notLikely.textContent = 'Not likely';\n const veryLikely = document.createElement('span');\n veryLikely.textContent = 'Very likely';\n labels.appendChild(notLikely);\n labels.appendChild(veryLikely);\n body.appendChild(labels);\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderCountdownOffer(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-countdown-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 20px; font-weight: 700; margin-bottom: 8px;';\n title.textContent = campaign.title || 'Flash Sale';\n body.appendChild(title);\n\n const label = document.createElement('div');\n label.style.cssText = 'font-size: 13px; opacity: 0.8; margin-bottom: 12px;';\n label.textContent = (ic.countdown_label as string) || 'Sale ends in:';\n body.appendChild(label);\n\n // Countdown digits\n const digits = document.createElement('div');\n digits.style.cssText = 'display: flex; gap: 8px; justify-content: center; margin-bottom: 16px;';\n const digitStyle = `padding: 8px 12px; border-radius: 8px; font-size: 24px; font-weight: 700; font-family: monospace; background: ${text}22;`;\n for (const val of ['00', ':', '00', ':', '00']) {\n const el = document.createElement('span');\n if (val === ':') {\n el.style.cssText = 'font-size: 24px; font-weight: 700; align-self: center;';\n } else {\n el.style.cssText = digitStyle;\n }\n el.textContent = val;\n digits.appendChild(el);\n }\n body.appendChild(digits);\n\n // Start countdown from target or 2h default\n const targetStr = ic.countdown_target as string | undefined;\n if (targetStr) {\n const target = new Date(targetStr).getTime();\n const update = () => {\n const diff = Math.max(0, target - Date.now());\n const h = String(Math.floor(diff / 3600000)).padStart(2, '0');\n const m = String(Math.floor((diff % 3600000) / 60000)).padStart(2, '0');\n const s = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0');\n const spans = digits.querySelectorAll('span');\n if (spans.length >= 5) {\n spans[0].textContent = h;\n spans[2].textContent = m;\n spans[4].textContent = s;\n }\n if (diff > 0) requestAnimationFrame(update);\n };\n update();\n }\n\n if (campaign.body) {\n const desc = document.createElement('div');\n desc.style.cssText = 'font-size: 14px; opacity: 0.85; margin-bottom: 16px;';\n desc.textContent = campaign.body;\n body.appendChild(desc);\n }\n\n if (campaign.button_text) {\n const btn = this.createCTAButton(campaign, bg, text);\n body.appendChild(btn);\n }\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderStarRating(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-rating-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 18px; font-weight: 700; margin-bottom: 16px;';\n title.textContent = campaign.title || 'Rate your experience';\n body.appendChild(title);\n\n const stars = document.createElement('div');\n stars.style.cssText = 'display: flex; gap: 8px; justify-content: center; margin-bottom: 16px;';\n const maxStars = (ic.rating_scale as number) || 5;\n for (let i = 1; i <= maxStars; i++) {\n const star = document.createElement('span');\n star.style.cssText = 'font-size: 32px; cursor: pointer; transition: transform 0.1s;';\n star.textContent = '\\u2606'; // ☆\n star.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n });\n star.addEventListener('mouseenter', () => { star.style.transform = 'scale(1.2)'; });\n star.addEventListener('mouseleave', () => { star.style.transform = 'scale(1)'; });\n stars.appendChild(star);\n }\n body.appendChild(stars);\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderQuickPoll(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-poll-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 16px; font-weight: 700; margin-bottom: 16px;';\n title.textContent = campaign.title || 'Quick question';\n body.appendChild(title);\n\n const options = (ic.poll_options as string[]) || [];\n const optionsList = document.createElement('div');\n optionsList.style.cssText = 'display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px;';\n for (const opt of options) {\n const optBtn = document.createElement('button');\n optBtn.style.cssText = `\n padding: 10px 16px; border-radius: 10px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 14px; cursor: pointer;\n text-align: left; transition: background 0.15s;\n `;\n optBtn.textContent = opt;\n optBtn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n });\n optionsList.appendChild(optBtn);\n }\n body.appendChild(optionsList);\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderQuiz(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-quiz-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 360px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 18px; font-weight: 700; margin-bottom: 8px;';\n title.textContent = campaign.title || 'Quiz';\n body.appendChild(title);\n\n const questions = (ic.questions as Array<{ question: string; options: string[] }>) || [];\n let currentQ = 0;\n\n const renderQuestion = () => {\n // Clear previous content except title\n while (body.childNodes.length > 1) {\n body.removeChild(body.lastChild!);\n }\n\n if (currentQ >= questions.length) {\n const result = document.createElement('div');\n result.style.cssText = 'font-size: 16px; margin: 16px 0;';\n result.textContent = (ic.thank_you_message as string) || 'Thanks for completing the quiz!';\n body.appendChild(result);\n this.trackEvent(campaign.id, 'clicked');\n this.addCloseButton(body, overlay, campaign.id);\n return;\n }\n\n const q = questions[currentQ];\n const progress = document.createElement('div');\n progress.style.cssText = 'font-size: 12px; opacity: 0.6; margin-bottom: 12px;';\n progress.textContent = `Question ${currentQ + 1} of ${questions.length}`;\n body.appendChild(progress);\n\n const questionText = document.createElement('div');\n questionText.style.cssText = 'font-size: 14px; font-weight: 600; margin-bottom: 16px;';\n questionText.textContent = q.question;\n body.appendChild(questionText);\n\n const optionsDiv = document.createElement('div');\n optionsDiv.style.cssText = 'display: flex; flex-direction: column; gap: 8px;';\n for (const opt of q.options) {\n const optBtn = document.createElement('button');\n optBtn.style.cssText = `\n padding: 10px 16px; border-radius: 10px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 14px; cursor: pointer;\n text-align: left; transition: background 0.15s;\n `;\n optBtn.textContent = opt;\n optBtn.addEventListener('click', () => {\n currentQ++;\n renderQuestion();\n });\n optionsDiv.appendChild(optBtn);\n }\n body.appendChild(optionsDiv);\n this.addCloseButton(body, overlay, campaign.id);\n };\n\n renderQuestion();\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n // --- Shared Rendering Helpers ---\n\n private createOverlay(className: string): HTMLElement {\n const overlay = document.createElement('div');\n overlay.className = className;\n overlay.style.cssText = `\n position: fixed; top: 0; left: 0; right: 0; bottom: 0;\n background: rgba(0,0,0,0.5); display: flex; align-items: center;\n justify-content: center; z-index: 99999; animation: aegisFadeIn 0.3s ease;\n `;\n return overlay;\n }\n\n private createCTAButton(campaign: InAppCampaign, bg: string, text: string): HTMLElement {\n const btn = document.createElement('button');\n btn.style.cssText = `\n display: inline-block; padding: 10px 28px; border-radius: 999px;\n font-size: 14px; font-weight: 600; cursor: pointer; border: none;\n background: ${text}; color: ${bg}; transition: transform 0.15s;\n `;\n btn.textContent = campaign.button_text || 'OK';\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safeUrl = this.sanitizeUrl(campaign.action_url);\n if (safeUrl) window.open(safeUrl, '_blank');\n }\n });\n return btn;\n }\n\n private addCloseButton(container: HTMLElement, overlay: HTMLElement, campaignId: string): void {\n const close = document.createElement('div');\n close.style.cssText = 'margin-top: 12px; font-size: 12px; opacity: 0.6; cursor: pointer;';\n close.textContent = 'Close';\n close.addEventListener('click', () => {\n this.trackEvent(campaignId, 'dismissed');\n this.removeModal(overlay);\n });\n container.appendChild(close);\n }\n \n private renderBanner(campaign: InAppCampaign): void {\n const banner = document.createElement('div');\n banner.className = 'aegis-in-app-banner';\n banner.setAttribute('data-campaign-id', campaign.id);\n \n banner.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n background: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.text_color || '#ffffff')};\n padding: 16px;\n z-index: 999999;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideDown 0.3s ease-out;\n `;\n \n const contentContainer = document.createElement('div');\n contentContainer.style.cssText = 'flex: 1; display: flex; align-items: center; gap: 12px;';\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 40px; height: 40px; border-radius: 4px; object-fit: cover;';\n contentContainer.appendChild(img);\n }\n }\n \n const textContainer = document.createElement('div');\n textContainer.style.cssText = 'flex: 1;';\n \n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 600; font-size: 14px; margin-bottom: 4px;';\n textContainer.appendChild(title);\n \n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.9;';\n textContainer.appendChild(body);\n \n contentContainer.appendChild(textContainer);\n \n const actionsContainer = document.createElement('div');\n actionsContainer.style.cssText = 'display: flex; align-items: center; gap: 12px; margin-left: 16px;';\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: white;\n color: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-weight: 600;\n cursor: pointer;\n font-size: 13px;\n white-space: nowrap;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n this.removeBanner(banner);\n });\n \n actionsContainer.appendChild(ctaButton);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n background: transparent;\n border: none;\n color: inherit;\n font-size: 20px;\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0.7;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeBanner(banner);\n });\n \n actionsContainer.appendChild(closeButton);\n \n banner.appendChild(contentContainer);\n banner.appendChild(actionsContainer);\n \n this.addAnimationStyles();\n document.body.appendChild(banner);\n }\n \n private renderModal(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-modal-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-in-app-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 8px;\n max-width: 500px;\n width: 90%;\n max-height: 80vh;\n overflow: auto;\n box-shadow: 0 10px 40px rgba(0,0,0,0.2);\n animation: aegisScaleIn 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 200px; object-fit: cover; border-radius: 8px 8px 0 0;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 24px;';\n \n const title = document.createElement('h2');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n content.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0 0 20px 0; font-size: 15px; line-height: 1.5; color: #4a4a4a;';\n content.appendChild(body);\n \n const actions = document.createElement('div');\n actions.style.cssText = 'display: flex; gap: 12px; justify-content: flex-end;';\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.text_color || '#ffffff')};\n border: none;\n padding: 10px 24px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n this.removeModal(overlay);\n });\n \n actions.appendChild(ctaButton);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: transparent;\n border: 1px solid #d0d0d0;\n color: #4a4a4a;\n padding: 10px 24px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n actions.appendChild(closeButton);\n \n content.appendChild(actions);\n modal.appendChild(content);\n overlay.appendChild(modal);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderFullScreen(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-fullscreen-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: ${this.sanitizeColor(campaign.background_color || '#ffffff')};\n color: ${this.sanitizeColor(campaign.text_color || '#1a1a1a')};\n z-index: 1000001;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n animation: aegisFadeIn 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n overflow-y: auto;\n `;\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'max-width: 100%; max-height: 40vh; object-fit: contain; margin-bottom: 32px;';\n overlay.appendChild(img);\n }\n }\n \n const contentContainer = document.createElement('div');\n contentContainer.style.cssText = 'max-width: 600px; text-align: center;';\n \n const title = document.createElement('h1');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 32px; font-weight: 700;';\n contentContainer.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0 0 32px 0; font-size: 18px; line-height: 1.6; opacity: 0.9;';\n contentContainer.appendChild(body);\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(campaign.text_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.background_color || '#ffffff')};\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 18px;\n cursor: pointer;\n margin-bottom: 16px;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n this.removeModal(overlay);\n });\n \n contentContainer.appendChild(ctaButton);\n }\n \n overlay.appendChild(contentContainer);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 20px;\n right: 20px;\n background: transparent;\n border: none;\n color: inherit;\n font-size: 32px;\n cursor: pointer;\n padding: 0;\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0.6;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n overlay.appendChild(closeButton);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderHalfInterstitial(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-half-interstitial-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000000;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-in-app-half-interstitial';\n modal.style.cssText = `\n background: white;\n border-radius: 16px 16px 0 0;\n width: 100%;\n max-width: 600px;\n max-height: 60vh;\n overflow: auto;\n box-shadow: 0 -4px 20px rgba(0,0,0,0.2);\n animation: aegisSlideUp 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 200px; object-fit: cover;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 32px 24px;';\n \n const title = document.createElement('h2');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; line-height: 1.5; color: #4a4a4a;';\n content.appendChild(body);\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.text_color || '#ffffff')};\n border: none;\n padding: 14px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n this.removeModal(overlay);\n });\n \n content.appendChild(ctaButton);\n }\n \n modal.appendChild(content);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: rgba(255,255,255,0.9);\n border: none;\n color: #333;\n font-size: 24px;\n cursor: pointer;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderAlert(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-alert-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.6);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.2s ease-out;\n `;\n \n const alert = document.createElement('div');\n alert.className = 'aegis-in-app-alert';\n alert.style.cssText = `\n background: white;\n border-radius: 12px;\n max-width: 320px;\n width: 85%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n animation: aegisScaleIn 0.2s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n overflow: hidden;\n `;\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 24px 20px; text-align: center;';\n \n const title = document.createElement('h3');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 8px 0; font-size: 18px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0; font-size: 14px; line-height: 1.4; color: #666;';\n content.appendChild(body);\n \n alert.appendChild(content);\n \n const buttonContainer = document.createElement('div');\n buttonContainer.style.cssText = 'display: flex; border-top: 1px solid #e0e0e0;';\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n flex: 1;\n background: transparent;\n border: none;\n border-right: 1px solid #e0e0e0;\n color: #1a73e8;\n padding: 14px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n this.removeModal(overlay);\n });\n \n buttonContainer.appendChild(ctaButton);\n }\n \n const cancelButton = document.createElement('button');\n cancelButton.textContent = 'Cancel';\n cancelButton.style.cssText = `\n flex: 1;\n background: transparent;\n border: none;\n color: #666;\n padding: 14px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n `;\n \n cancelButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n buttonContainer.appendChild(cancelButton);\n \n alert.appendChild(buttonContainer);\n overlay.appendChild(alert);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderPIP(campaign: InAppCampaign): void {\n const pip = document.createElement('div');\n pip.className = 'aegis-in-app-pip';\n pip.setAttribute('data-campaign-id', campaign.id);\n \n pip.style.cssText = `\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 320px;\n background: black;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 8px 24px rgba(0,0,0,0.3);\n z-index: 999999;\n animation: aegisSlideUp 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (campaign.video_url) {\n const video = document.createElement('video');\n const safeUrl = this.sanitizeUrl(campaign.video_url);\n if (safeUrl) {\n video.src = safeUrl;\n video.controls = true;\n video.autoplay = true;\n video.muted = true;\n video.style.cssText = 'width: 100%; display: block;';\n pip.appendChild(video);\n }\n } else if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; display: block;';\n pip.appendChild(img);\n }\n }\n \n const overlay = document.createElement('div');\n overlay.style.cssText = `\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: linear-gradient(to top, rgba(0,0,0,0.9), transparent);\n padding: 40px 16px 16px;\n color: white;\n `;\n \n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-size: 14px; font-weight: 600; margin-bottom: 4px;';\n overlay.appendChild(title);\n \n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 12px; opacity: 0.9;';\n overlay.appendChild(body);\n \n pip.appendChild(overlay);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 8px;\n right: 8px;\n background: rgba(0,0,0,0.6);\n border: none;\n color: white;\n font-size: 18px;\n cursor: pointer;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n pip.style.animation = 'aegisSlideDown 0.3s ease-out';\n setTimeout(() => {\n if (pip.parentNode) {\n pip.parentNode.removeChild(pip);\n }\n }, 300);\n });\n \n pip.appendChild(closeButton);\n \n if (campaign.action_url) {\n pip.style.cursor = 'pointer';\n pip.addEventListener('click', (e) => {\n if (e.target !== closeButton) {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n window.open(safeUrl, '_blank');\n }\n }\n });\n }\n \n this.addAnimationStyles();\n document.body.appendChild(pip);\n }\n \n private removeBanner(banner: HTMLElement): void {\n banner.style.animation = 'aegisSlideUp 0.3s ease-out';\n setTimeout(() => {\n if (banner.parentNode) {\n banner.parentNode.removeChild(banner);\n }\n }, 300);\n }\n \n private removeModal(overlay: HTMLElement): void {\n overlay.style.animation = 'aegisFadeOut 0.3s ease-out';\n setTimeout(() => {\n if (overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n }, 300);\n }\n \n private renderTooltip(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const anchorSelector = (ic.tooltip_anchor_selector as string) || '[data-aegis-tooltip]';\n const preferredPosition = (ic.tooltip_position as string) || 'bottom'; // top | bottom | left | right\n\n const anchor = document.querySelector(anchorSelector);\n if (!anchor) {\n this.log(`Tooltip anchor not found: ${anchorSelector}`, 'warn');\n return;\n }\n\n const bg = this.sanitizeColor(campaign.background_color || '#1a1a1a');\n const textColor = this.sanitizeColor(campaign.text_color || '#ffffff');\n\n // Tooltip container (positioned absolute to body)\n const tooltip = document.createElement('div');\n tooltip.className = 'aegis-in-app-tooltip';\n tooltip.setAttribute('data-campaign-id', campaign.id);\n tooltip.style.cssText = `\n position: absolute; z-index: 1000001; max-width: 280px; width: max-content;\n background: ${bg}; color: ${textColor}; border-radius: 10px; padding: 14px 16px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.18); font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.2s ease-out; pointer-events: auto;\n `;\n\n // Arrow\n const arrow = document.createElement('div');\n arrow.className = 'aegis-tooltip-arrow';\n arrow.style.cssText = `\n position: absolute; width: 10px; height: 10px; background: ${bg};\n transform: rotate(45deg);\n `;\n\n // Close button\n const closeBtn = document.createElement('button');\n closeBtn.textContent = '\\u00d7';\n closeBtn.style.cssText = `\n position: absolute; top: 6px; right: 8px; background: none; border: none;\n color: ${textColor}; opacity: 0.6; font-size: 16px; cursor: pointer; padding: 0; line-height: 1;\n `;\n\n const dismiss = () => {\n tooltip.style.animation = 'aegisFadeOut 0.2s ease-out';\n setTimeout(() => { tooltip.parentNode?.removeChild(tooltip); }, 200);\n this.trackEvent(campaign.id, 'dismissed');\n };\n\n closeBtn.addEventListener('click', (e) => { e.stopPropagation(); dismiss(); });\n\n // Title\n if (campaign.title) {\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-size: 13px; font-weight: 700; margin-bottom: 4px; padding-right: 16px;';\n tooltip.appendChild(title);\n }\n\n // Body\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 12px; line-height: 1.4; opacity: 0.9;';\n tooltip.appendChild(body);\n\n // CTA button\n if (campaign.button_text && campaign.action_url) {\n const cta = document.createElement('a');\n cta.textContent = campaign.button_text;\n cta.href = campaign.action_url;\n cta.style.cssText = `\n display: inline-block; margin-top: 8px; font-size: 12px; font-weight: 600;\n color: ${textColor}; text-decoration: underline; cursor: pointer;\n `;\n cta.addEventListener('click', () => { this.trackEvent(campaign.id, 'clicked'); });\n tooltip.appendChild(cta);\n }\n\n tooltip.appendChild(closeBtn);\n tooltip.appendChild(arrow);\n document.body.appendChild(tooltip);\n\n // Position relative to anchor\n const anchorRect = anchor.getBoundingClientRect();\n const tooltipRect = tooltip.getBoundingClientRect();\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n const gap = 10;\n\n let top = 0;\n let left = 0;\n let arrowTop = '';\n let arrowLeft = '';\n let arrowBottom = '';\n let arrowRight = '';\n\n switch (preferredPosition) {\n case 'top':\n top = anchorRect.top + scrollY - tooltipRect.height - gap;\n left = anchorRect.left + scrollX + (anchorRect.width - tooltipRect.width) / 2;\n arrowBottom = '-5px';\n arrowLeft = `${tooltipRect.width / 2 - 5}px`;\n break;\n case 'left':\n top = anchorRect.top + scrollY + (anchorRect.height - tooltipRect.height) / 2;\n left = anchorRect.left + scrollX - tooltipRect.width - gap;\n arrowRight = '-5px';\n arrowTop = `${tooltipRect.height / 2 - 5}px`;\n break;\n case 'right':\n top = anchorRect.top + scrollY + (anchorRect.height - tooltipRect.height) / 2;\n left = anchorRect.right + scrollX + gap;\n arrowLeft = '-5px';\n arrowTop = `${tooltipRect.height / 2 - 5}px`;\n break;\n default: // bottom\n top = anchorRect.bottom + scrollY + gap;\n left = anchorRect.left + scrollX + (anchorRect.width - tooltipRect.width) / 2;\n arrowTop = '-5px';\n arrowLeft = `${tooltipRect.width / 2 - 5}px`;\n break;\n }\n\n // Clamp to viewport\n left = Math.max(8, Math.min(left, window.innerWidth + scrollX - tooltipRect.width - 8));\n top = Math.max(8, top);\n\n tooltip.style.top = `${top}px`;\n tooltip.style.left = `${left}px`;\n arrow.style.top = arrowTop || '';\n arrow.style.left = arrowLeft || '';\n arrow.style.bottom = arrowBottom || '';\n arrow.style.right = arrowRight || '';\n\n // Dismiss on outside click\n const outsideClickHandler = (e: MouseEvent) => {\n if (!tooltip.contains(e.target as Node) && !anchor.contains(e.target as Node)) {\n document.removeEventListener('click', outsideClickHandler);\n dismiss();\n }\n };\n setTimeout(() => document.addEventListener('click', outsideClickHandler), 100);\n }\n\n private addAnimationStyles(): void {\n if (document.getElementById('aegis-in-app-styles')) {\n return;\n }\n \n const style = document.createElement('style');\n style.id = 'aegis-in-app-styles';\n style.textContent = `\n @keyframes aegisSlideDown {\n from { transform: translateY(-100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes aegisSlideUp {\n from { transform: translateY(0); opacity: 1; }\n to { transform: translateY(-100%); opacity: 0; }\n }\n \n @keyframes aegisFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes aegisFadeOut {\n from { opacity: 1; }\n to { opacity: 0; }\n }\n \n @keyframes aegisScaleIn {\n from { transform: scale(0.9); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n }\n\n /* Bottom-anchored slide IN (opposite of aegisSlideUp which slides OUT).\n Used by the preload-first renderers: sticky_bar (bottom),\n progress_bar, carousel_cards, product_recommendation. */\n @keyframes aegisSlideInFromBottom {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n `;\n \n document.head.appendChild(style);\n }\n \n private sanitizeUrl(url: string): string | null {\n try {\n const parsedUrl = new URL(url, window.location.origin);\n \n if (parsedUrl.protocol === 'javascript:' || parsedUrl.protocol === 'data:') {\n this.log(`Blocked unsafe URL: ${url}`, 'error');\n return null;\n }\n \n return parsedUrl.href;\n } catch (error) {\n this.log(`Invalid URL: ${url}`, 'error');\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n if (/^#[0-9A-Fa-f]{3,6}$/.test(color)) {\n return color;\n }\n \n if (/^rgb\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*\\)$/.test(color)) {\n return color;\n }\n \n if (/^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*[\\d.]+\\s*\\)$/.test(color)) {\n return color;\n }\n \n const namedColors = ['white', 'black', 'red', 'green', 'blue', 'yellow', 'orange', 'purple', 'pink', 'gray', 'transparent'];\n if (namedColors.includes(color.toLowerCase())) {\n return color;\n }\n \n return '#000000';\n }\n \n /**\n * Track in-app event via the standard Event Ingress pipeline.\n *\n * Events flow: SDK → Event Ingress → Kafka → Governance Consumer\n * → Event Engine → ClickHouse (in_app_events + events_with_ttl)\n *\n * The event_type uses the canonical prefix `in_app.` so the event\n * switchboard maps it to the correct canonical form:\n * in_app.impression → engagement.view\n * in_app.clicked → engagement.click\n * in_app.dismissed → engagement.dismiss\n */\n private async trackEvent(campaignId: string, eventType: 'impression' | 'clicked' | 'dismissed'): Promise<void> {\n try {\n // Use the public SDK scheme (/v1/in_app/events) — the gateway has an\n // explicit handler that auths via X-Aegis-Write-Key and forwards to\n // event-switchboard. Direct POST to /api/v1/events bypasses the SDK\n // auth model and hits the JWT preHandler → 401.\n // See docs/architecture/API_ROUTING.md §5.\n const url = `${this.apiHost}/v1/in_app/events`;\n const externalEventId = `inapp_${campaignId}_${eventType}_${Date.now()}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey,\n };\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n\n const body = {\n campaign_id: campaignId,\n event_type: eventType,\n user_id: this.userId,\n contact_id: this.contactId,\n anonymous_id: this.userId,\n platform: 'web',\n metadata: {\n property_id: this.propertyId,\n variant_id: this.getVariantId(campaignId) ?? undefined,\n },\n idempotency_key: externalEventId,\n };\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n credentials: 'include',\n }).catch(error => {\n this.log(`Error tracking event: ${error}`, 'error');\n });\n\n this.log(`Tracked ${eventType} event for campaign ${campaignId}`);\n } catch (error) {\n this.log(`Error tracking event: ${error}`, 'error');\n }\n }\n \n private log(message: string, level: 'log' | 'warn' | 'error' = 'log'): void {\n if (this.debugMode) {\n console[level](`[AegisInApp] ${message}`);\n }\n }\n \n destroy(options?: { clearABState?: boolean }): void {\n this.disconnectSSE();\n\n if (typeof document !== 'undefined') {\n document.querySelectorAll(\n '.aegis-in-app-banner, .aegis-in-app-modal-overlay, .aegis-in-app-fullscreen-overlay, ' +\n '.aegis-in-app-half-interstitial-overlay, .aegis-in-app-alert-overlay, .aegis-in-app-pip, ' +\n '.aegis-in-app-nps-overlay, .aegis-in-app-countdown-overlay, .aegis-in-app-rating-overlay, ' +\n '.aegis-in-app-poll-overlay, .aegis-in-app-quiz-overlay'\n ).forEach(el => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n });\n\n const styles = document.getElementById('aegis-in-app-styles');\n if (styles && styles.parentNode) {\n styles.parentNode.removeChild(styles);\n }\n }\n\n // Optionally clear A/B assignment state\n if (options?.clearABState && typeof localStorage !== 'undefined') {\n localStorage.removeItem('aegis_ab_assignments');\n }\n\n this.isInitialized = false;\n this.log('AegisInApp destroyed');\n }\n}\n","/**\n * ProductRecommendation renderer — personalized product grid/row rendered\n * from `interactive_config.cards[]` that the cell-plane populated at\n * bundle-assembly time. The SDK never calls a product-API at render\n * time — the preload contract is that the recommended products are\n * already in the bundle.\n *\n * The layout is narrower than the generic carousel because product recs\n * should feel like a first-class product grid, not a marketing slider.\n * Three layouts: grid (2-col / 3-col responsive), row (horizontal-scroll),\n * carousel (same as carousel_cards but different framing copy).\n *\n * interactive_config:\n * rec_source?: 'viewed' | 'abandoned' | 'cross_sell' | 'trending' | 'personalized'\n * (metadata only — the actual product list is in `cards[]`)\n * rec_count?: number (display hint; rendering is driven by cards.length)\n * rec_layout?: 'grid' | 'row' | 'carousel' default 'grid'\n * rec_cta_text?: string default 'Shop now'\n * cards: Array<{ image_url?, title?, body?, cta_url?, metadata? }>\n */\n\nimport type { RenderContext } from './types';\n\ntype Card = {\n image_url?: string;\n title?: string;\n body?: string;\n cta_text?: string;\n cta_url?: string;\n metadata?: Record<string, unknown>;\n};\n\nconst MAX_PRODUCTS = 24;\n\nexport function renderProductRecommendation(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const rawCards = Array.isArray(ic.cards) ? (ic.cards as Card[]) : [];\n const cards = rawCards.slice(0, MAX_PRODUCTS);\n if (cards.length === 0) {\n log('product_recommendation rendered with zero products — skipping', 'warn');\n return;\n }\n\n const layout = (ic.rec_layout as string) || 'grid';\n const ctaDefault = (ic.rec_cta_text as string) || 'Shop now';\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#ffffff');\n const fg = sanitizeColor((campaign.text_color as string) || '#0f172a');\n const accent = sanitizeColor('#4169e1');\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-product-rec';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = `\n position: fixed; inset: 0;\n background: rgba(15,23,42,0.55); backdrop-filter: blur(4px);\n display: flex; align-items: flex-end; justify-content: center;\n z-index: 99999; animation: aegisFadeIn 0.25s ease;\n `;\n\n const sheet = document.createElement('div');\n sheet.style.cssText = `\n background: ${bg}; color: ${fg};\n max-width: 560px; width: 100%; max-height: 80vh; overflow-y: auto;\n border-radius: 20px 20px 0 0;\n padding: 18px 16px 22px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n box-shadow: 0 -12px 30px rgba(0,0,0,0.12);\n `;\n\n // Drag handle (decorative, for mobile context)\n const handle = document.createElement('div');\n handle.style.cssText = `\n width: 36px; height: 4px; border-radius: 999px; background: ${fg}1f;\n margin: 0 auto 12px;\n `;\n sheet.appendChild(handle);\n\n const header = document.createElement('div');\n header.style.cssText = 'display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;';\n\n const headerText = document.createElement('div');\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 700; font-size: 16px; margin-bottom: 2px;';\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.7; line-height: 1.4;';\n headerText.appendChild(title);\n headerText.appendChild(body);\n header.appendChild(headerText);\n\n const close = document.createElement('button');\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Close');\n close.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 18px; cursor: pointer; padding: 4px 8px; opacity: 0.7;\n `;\n close.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n });\n header.appendChild(close);\n sheet.appendChild(header);\n\n const grid = document.createElement('div');\n if (layout === 'row' || layout === 'carousel') {\n grid.style.cssText = `\n display: flex; gap: 10px; overflow-x: auto;\n scroll-snap-type: x mandatory; padding: 14px 0 4px;\n `;\n } else {\n grid.style.cssText = `\n display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;\n padding-top: 14px;\n `;\n }\n\n cards.forEach((c) => {\n const tile = document.createElement('div');\n const isRow = layout === 'row' || layout === 'carousel';\n tile.style.cssText = `\n background: ${fg}08; border-radius: 12px;\n padding: 10px; display: flex; flex-direction: column; gap: 6px;\n cursor: ${c.cta_url ? 'pointer' : 'default'};\n ${isRow ? 'flex: 0 0 150px; scroll-snap-align: start;' : ''}\n transition: transform 0.15s ease;\n `;\n\n if (c.image_url) {\n const img = document.createElement('img');\n const safe = sanitizeUrl(c.image_url);\n if (safe) {\n img.src = safe;\n img.alt = '';\n img.loading = 'lazy';\n img.style.cssText = 'width: 100%; aspect-ratio: 1 / 1; border-radius: 8px; object-fit: cover;';\n tile.appendChild(img);\n }\n }\n\n if (c.title) {\n const t = document.createElement('div');\n t.textContent = c.title;\n t.style.cssText = 'font-weight: 600; font-size: 13px; line-height: 1.3;';\n tile.appendChild(t);\n }\n\n // Price lives in metadata.price per the dashboard schema; we show it\n // prominently if present.\n const price = c.metadata && typeof c.metadata === 'object' ? (c.metadata as Record<string, unknown>).price : undefined;\n if (price !== undefined) {\n const p = document.createElement('div');\n p.textContent = String(price);\n p.style.cssText = `color: ${accent}; font-weight: 700; font-size: 13px;`;\n tile.appendChild(p);\n } else if (c.body) {\n const b = document.createElement('div');\n b.textContent = c.body;\n b.style.cssText = 'font-size: 11.5px; opacity: 0.72; line-height: 1.3;';\n tile.appendChild(b);\n }\n\n const cta = document.createElement('button');\n cta.textContent = c.cta_text || ctaDefault;\n cta.style.cssText = `\n margin-top: auto;\n background: ${accent}; color: #fff;\n border: none; padding: 7px 10px; border-radius: 999px;\n font-size: 12px; font-weight: 600; cursor: pointer;\n `;\n const go = (e: Event) => {\n e.stopPropagation();\n trackEvent(campaign.id, 'clicked');\n if (c.cta_url) {\n const safe = sanitizeUrl(c.cta_url);\n if (safe) window.location.href = safe;\n }\n };\n cta.addEventListener('click', go);\n tile.appendChild(cta);\n if (c.cta_url) tile.addEventListener('click', go);\n\n grid.appendChild(tile);\n });\n\n sheet.appendChild(grid);\n overlay.appendChild(sheet);\n\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n }\n });\n\n document.body.appendChild(overlay);\n}\n","/**\n * AegisWidgetManager - Web SDK Widget Module\n * \n * Smart Pull architecture for persistent web widgets.\n * \n * Features:\n * - Gamification (spin wheel, scratch card) with server-side prize generation\n * - Chat bubbles (WhatsApp, support)\n * - Social proof toasts (real-time purchase notifications)\n * - Feedback forms (NPS, surveys)\n * \n * Security:\n * - XSS Protection: Uses DOM APIs instead of innerHTML\n * - Server-side prize generation prevents client manipulation\n * - URL validation prevents javascript: protocol injection\n * \n * Architecture:\n * - Fetches widget configs from /v1/widgets/config on page load\n * - Integrates with TriggerEngine for behavioral triggers\n * - Tracks widget events (show, click, dismiss, submit)\n * - Server-side prize generation for gamification\n */\n\nimport { TriggerEngine } from '../triggers/TriggerEngine';\nimport { Storage } from '../utils/storage';\n\n// Read the SDK's persisted anonymous_id from localStorage/cookie if available.\n// Returns undefined when called server-side or when no id has been minted yet.\n// See AegisInAppManager for the same pattern + canonical contract in\n// docs/architecture/API_ROUTING.md §3.\nfunction readAnonIdFromStorage(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n try {\n const storage = new Storage();\n return storage.get('anon_id') ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface WidgetConfig {\n widget_id: string;\n widget_type: 'chat_bubble' | 'spin_wheel' | 'scratch_card' | 'toast' | 'feedback_form' | 'exit_intent_popup';\n name: string;\n config: Record<string, any>;\n position?: string;\n priority: number;\n trigger_rules?: {\n type: 'exit_intent' | 'scroll_depth' | 'time_on_page' | 'immediate';\n config?: Record<string, any>;\n };\n}\n\nexport interface GamificationPrize {\n prize_label: string;\n prize_value?: string;\n coupon_code?: string;\n play_id: string;\n}\n\nexport interface AegisWidgetConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n debugMode?: boolean;\n triggerEngine?: TriggerEngine;\n /** If true, WidgetManager takes ownership of the TriggerEngine and\n * will call `triggerEngine.stop()` on destroy(). Leave false when\n * the caller shares the engine across managers (e.g. the facade). */\n ownsTriggerEngine?: boolean;\n enablePrefetch?: boolean;\n cssCustomization?: WidgetCSSCustomization;\n onEvent?: (eventType: string, data: any) => void;\n /** Source platform passed as X-Source-Platform header so the API\n * can filter campaigns whose display_rules.sources restricts them\n * to specific integrations (e.g. 'shopify', 'woocommerce'). */\n sourcePlatform?: 'web' | 'shopify' | 'woocommerce' | 'mobile_sdk';\n}\n\nexport interface WidgetCSSCustomization {\n exitIntent?: {\n backgroundColor?: string;\n textColor?: string;\n accentColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n overlayOpacity?: number;\n };\n spinWheel?: {\n backgroundColor?: string;\n textColor?: string;\n accentColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n wheelColors?: string[];\n buttonColor?: string;\n };\n chatBubble?: {\n backgroundColor?: string;\n textColor?: string;\n position?: 'bottom_right' | 'bottom_left' | 'top_right' | 'top_left';\n size?: 'small' | 'medium' | 'large';\n };\n}\n\nexport interface PrefetchWidgetConfig {\n exit_intent?: {\n enabled: boolean;\n type: 'cart_recovery' | 'lead_gen';\n tier?: string;\n title?: string;\n message?: string;\n discount_code?: string;\n discount_percentage?: number;\n cta_text?: string;\n cta_url?: string;\n background_color?: string;\n text_color?: string;\n accent_color?: string;\n show_cart_items?: boolean;\n show_timer?: boolean;\n timer_minutes?: number;\n priority: number;\n mobile_triggers?: {\n scroll_velocity?: boolean;\n scroll_threshold?: number;\n scroll_min_position?: number;\n scroll_cooldown?: number;\n idle_timer?: boolean;\n idle_seconds?: number;\n visibility_change?: boolean;\n back_button?: boolean;\n };\n };\n spin_wheel?: {\n enabled: boolean;\n type: 'lead_gen' | 'cart_recovery';\n title?: string;\n prizes?: any[];\n priority: number;\n };\n}\n\nexport interface CartData {\n cart_id: string;\n cart_total: number;\n cart_currency: string;\n cart_items: Array<{\n product_id: string;\n product_name?: string;\n quantity: number;\n price?: number;\n }>;\n}\n\nexport class AegisWidgetManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private debugMode: boolean;\n private triggerEngine?: TriggerEngine;\n private enablePrefetch: boolean;\n private cssCustomization: WidgetCSSCustomization;\n private onEvent?: (eventType: string, data: any) => void;\n private sourcePlatform?: string;\n\n private widgets: WidgetConfig[] = [];\n private renderedWidgets = new Set<string>();\n private isInitialized = false;\n private isDestroyed = false;\n private ownsTriggerEngine: boolean;\n\n private prefetchWidgetConfigs: PrefetchWidgetConfig = {};\n private cartData?: CartData;\n \n constructor(config: AegisWidgetConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n // Fall back to the SDK's persisted anonymous_id when callers don't pass\n // userId explicitly. Without this, /v1/widgets/config requests omit\n // X-User-ID and the cell-plane buckets the call into \"anonymous\", which\n // misses any user-targeted widget configs. Mirror in AegisInAppManager.\n this.userId = config.userId ?? readAnonIdFromStorage();\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.debugMode = config.debugMode || false;\n this.triggerEngine = config.triggerEngine;\n this.ownsTriggerEngine = config.ownsTriggerEngine === true;\n this.enablePrefetch = config.enablePrefetch !== false;\n this.cssCustomization = config.cssCustomization || {};\n this.onEvent = config.onEvent;\n this.sourcePlatform = config.sourcePlatform;\n }\n \n updateCSSCustomization(customization: WidgetCSSCustomization): void {\n this.cssCustomization = { ...this.cssCustomization, ...customization };\n this.log('CSS customization updated');\n }\n\n /**\n * Swap the identity that outgoing widget requests are attributed to.\n * Safe to call at any time; if prefetch is enabled and the manager\n * has already initialised, this will re-fetch the per-contact widget\n * configs so subsequent renders target the new identity. Does NOT\n * re-render already-visible widgets — a full teardown requires destroy().\n */\n async updateContactId(contactId: string | undefined): Promise<void> {\n if (this.contactId === contactId) return;\n this.contactId = contactId;\n this.log(`Contact ID updated → ${contactId ?? '(cleared)'}`);\n if (this.isInitialized && !this.isDestroyed && this.enablePrefetch && contactId) {\n await this.fetchPrefetchConfigs();\n this.preloadWidgetAssets();\n }\n }\n\n /**\n * Render an in-app campaign whose sub_type routes it to the\n * gamification-widget code path (spin_wheel / scratch_card).\n * InAppCampaign is adapted to the minimal WidgetConfig shape that\n * the internal renderers already understand — no rewrite needed.\n *\n * AegisMessageRuntime wires this method as AegisInAppManager's\n * `onInteractiveCampaign` callback so impressions from the inbox\n * prefetch bundle actually land on screen.\n */\n renderInteractiveCampaign(campaign: {\n id: string;\n title: string;\n sub_type?: string;\n priority?: number;\n interactive_config?: Record<string, unknown>;\n }): void {\n if (this.isDestroyed) return;\n if (typeof document === 'undefined') return;\n const subType = campaign.sub_type;\n if (subType !== 'spin_wheel' && subType !== 'scratch_card') {\n this.log(`renderInteractiveCampaign: unsupported sub_type \"${subType}\"`, true);\n return;\n }\n const widget: WidgetConfig = {\n widget_id: campaign.id,\n widget_type: subType,\n name: campaign.title,\n config: (campaign.interactive_config ?? {}) as Record<string, any>,\n priority: campaign.priority ?? 0,\n };\n if (this.renderedWidgets.has(widget.widget_id)) return;\n this.renderedWidgets.add(widget.widget_id);\n if (subType === 'spin_wheel') {\n this.renderSpinWheel(widget);\n } else {\n this.renderScratchCard(widget);\n }\n }\n\n /**\n * Tear down everything the manager installed: trigger listeners (if\n * we own the TriggerEngine), injected style sheets, and any rendered\n * widget roots. Further render attempts from in-flight triggers are\n * short-circuited by the `isDestroyed` flag.\n */\n destroy(): void {\n if (this.isDestroyed) return;\n this.isDestroyed = true;\n\n if (this.triggerEngine && this.ownsTriggerEngine) {\n this.triggerEngine.stop();\n }\n\n if (typeof document !== 'undefined') {\n const animationStyle = document.getElementById('aegis-widget-animations');\n animationStyle?.remove();\n document.querySelectorAll('[data-aegis-widget-root]').forEach((node) => {\n node.remove();\n });\n }\n\n this.renderedWidgets.clear();\n this.widgets = [];\n this.isInitialized = false;\n this.log('AegisWidgets destroyed');\n }\n \n private emitEvent(eventType: string, data: any): void {\n if (this.onEvent) {\n try {\n this.onEvent(eventType, data);\n } catch (error) {\n this.log(`Error in event callback: ${error}`, true);\n }\n }\n }\n \n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisWidgets already initialized');\n return;\n }\n \n if (this.enablePrefetch && this.contactId) {\n await this.fetchPrefetchConfigs();\n this.preloadWidgetAssets();\n }\n \n await this.fetchWidgets();\n \n this.renderImmediateWidgets();\n \n this.setupTriggerListeners();\n \n this.setupExitIntentWithPrefetch();\n \n this.isInitialized = true;\n this.log('AegisWidgets initialized successfully');\n }\n \n setCartData(cartData: CartData): void {\n this.cartData = cartData;\n this.log(`Cart data updated: ${cartData.cart_items.length} items, total: ${cartData.cart_currency} ${cartData.cart_total}`);\n }\n \n private detectPlatformCart(): CartData | null {\n const shopifyCart = this.normalizeShopifyCart();\n if (shopifyCart) {\n this.log('Detected Shopify cart via browser globals');\n return shopifyCart;\n }\n \n const wooCart = this.normalizeWooCart();\n if (wooCart) {\n this.log('Detected WooCommerce cart via injected data');\n return wooCart;\n }\n \n const magentoCart = this.normalizeMagentoCart();\n if (magentoCart) {\n this.log('Detected Magento cart via localStorage');\n return magentoCart;\n }\n \n if (this.cartData) {\n this.log('Using manually set cart data');\n return this.cartData;\n }\n \n return null;\n }\n \n private normalizeShopifyCart(): CartData | null {\n try {\n if (typeof window === 'undefined') return null;\n \n const win = window as any;\n \n if (win.Shopify?.checkout) {\n const checkout = win.Shopify.checkout;\n return {\n cart_id: checkout.token || `shopify_${Date.now()}`,\n cart_total: parseFloat(checkout.total_price) || 0,\n cart_currency: checkout.currency || 'USD',\n cart_items: (checkout.line_items || []).map((item: any) => ({\n product_id: String(item.product_id || item.id),\n product_name: item.title || item.product_title,\n quantity: item.quantity || 1,\n price: parseFloat(item.price) || 0\n }))\n };\n }\n \n const cartJsonEl = document.getElementById('cart-json');\n if (cartJsonEl?.textContent) {\n const cart = JSON.parse(cartJsonEl.textContent);\n return {\n cart_id: cart.token || `shopify_${Date.now()}`,\n cart_total: (cart.total_price || 0) / 100,\n cart_currency: cart.currency || 'USD',\n cart_items: (cart.items || []).map((item: any) => ({\n product_id: String(item.product_id || item.id),\n product_name: item.product_title || item.title,\n quantity: item.quantity || 1,\n price: (item.price || 0) / 100\n }))\n };\n }\n \n return null;\n } catch (error) {\n this.log(`Error detecting Shopify cart: ${error}`, true);\n return null;\n }\n }\n \n private normalizeWooCart(): CartData | null {\n try {\n if (typeof window === 'undefined') return null;\n \n const win = window as any;\n \n if (win.aegis_cart) {\n const cart = win.aegis_cart;\n return {\n cart_id: cart.cart_id || `woo_${Date.now()}`,\n cart_total: parseFloat(cart.cart_total) || 0,\n cart_currency: cart.cart_currency || 'USD',\n cart_items: (cart.cart_items || []).map((item: any) => ({\n product_id: String(item.product_id),\n product_name: item.product_name,\n quantity: item.quantity || 1,\n price: parseFloat(item.price) || 0\n }))\n };\n }\n \n return null;\n } catch (error) {\n this.log(`Error detecting WooCommerce cart: ${error}`, true);\n return null;\n }\n }\n \n private normalizeMagentoCart(): CartData | null {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return null;\n \n const mageCacheStr = localStorage.getItem('mage-cache-storage');\n if (!mageCacheStr) return null;\n \n const mageCache = JSON.parse(mageCacheStr);\n if (!mageCache?.cart) return null;\n \n const cart = mageCache.cart;\n \n return {\n cart_id: cart.quote_id || cart.id || `magento_${Date.now()}`,\n cart_total: parseFloat(cart.subtotalAmount || cart.subtotal || 0),\n cart_currency: cart.currencyCode || 'USD',\n cart_items: (cart.items || []).map((item: any) => ({\n product_id: String(item.item_id || item.product_id),\n product_name: item.product_name || item.name,\n quantity: item.qty || 1,\n price: parseFloat(item.product_price_value || item.price || 0)\n }))\n };\n } catch (error) {\n this.log(`Error detecting Magento cart: ${error}`, true);\n return null;\n }\n }\n \n private preloadWidgetAssets(): void {\n try {\n const exitIntentConfig = this.prefetchWidgetConfigs.exit_intent;\n if (exitIntentConfig?.enabled) {\n const imageUrl = (exitIntentConfig as any).image_url;\n if (imageUrl) {\n const img = new Image();\n img.src = imageUrl;\n this.log(`Preloading exit intent image: ${imageUrl}`);\n }\n }\n \n const spinWheelConfig = this.prefetchWidgetConfigs.spin_wheel;\n if (spinWheelConfig?.enabled) {\n const imageUrl = (spinWheelConfig as any).image_url;\n if (imageUrl) {\n const img = new Image();\n img.src = imageUrl;\n this.log(`Preloading spin wheel image: ${imageUrl}`);\n }\n }\n } catch (error) {\n this.log(`Error preloading widget assets: ${error}`, true);\n }\n }\n \n private async fetchPrefetchConfigs(): Promise<void> {\n try {\n const startTime = performance.now();\n const url = `${this.apiHost}/v1/widgets/config/prefetch`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n };\n \n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, { headers, credentials: 'include' });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch prefetch configs: ${response.status}`);\n }\n \n this.prefetchWidgetConfigs = await response.json();\n \n const elapsed = performance.now() - startTime;\n this.log(`Fetched prefetch widget configs in ${elapsed.toFixed(2)}ms`);\n \n } catch (error) {\n this.log(`Error fetching prefetch configs: ${error}`, true);\n }\n }\n \n private async fetchWidgets(): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/widgets/config`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Platform': 'web',\n 'X-Device-Type': this.getDeviceType()\n };\n\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.sourcePlatform) headers['X-Source-Platform'] = this.sourcePlatform;\n \n const response = await fetch(url, { headers, credentials: 'include' });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch widgets: ${response.status}`);\n }\n \n this.widgets = await response.json();\n \n this.log(`Fetched ${this.widgets.length} widgets`);\n \n } catch (error) {\n this.log(`Error fetching widgets: ${error}`, true);\n }\n }\n \n private renderImmediateWidgets(): void {\n const immediateWidgets = this.widgets.filter(w => \n !w.trigger_rules || w.trigger_rules.type === 'immediate'\n );\n \n immediateWidgets.forEach(widget => this.renderWidget(widget));\n }\n \n private setupTriggerListeners(): void {\n if (!this.triggerEngine) {\n this.log('TriggerEngine not provided, skipping trigger-based widgets');\n return;\n }\n \n this.widgets.forEach(widget => {\n if (!widget.trigger_rules) return;\n \n const { type, config } = widget.trigger_rules;\n \n switch (type) {\n case 'exit_intent':\n this.triggerEngine!.registerExitIntent();\n this.triggerEngine!.on('exit_intent', () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n \n case 'scroll_depth':\n const depthPercent = (config as any)?.depth_percent || 50;\n this.triggerEngine!.registerScrollDepth(depthPercent);\n this.triggerEngine!.on(`scroll_depth_${depthPercent}`, () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n \n case 'time_on_page':\n const seconds = (config as any)?.seconds || 30;\n this.triggerEngine!.registerTimeOnPage(seconds);\n this.triggerEngine!.on(`time_on_page_${seconds}`, () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n }\n });\n }\n \n private setupExitIntentWithPrefetch(): void {\n if (!this.enablePrefetch || !this.triggerEngine) {\n return;\n }\n \n const spinWheelConfig = this.prefetchWidgetConfigs.spin_wheel;\n const exitIntentConfig = this.prefetchWidgetConfigs.exit_intent;\n \n if (spinWheelConfig && spinWheelConfig.enabled) {\n const isMobile = this.isMobileDevice();\n const mobileConfig = exitIntentConfig?.mobile_triggers || {};\n \n const handleSpinWheelIntent = () => {\n const widgetId = `prefetch_spin_wheel_${Date.now()}`;\n \n if (this.renderedWidgets.has(widgetId)) {\n return;\n }\n \n this.renderedWidgets.add(widgetId);\n \n const detectedCart = this.detectPlatformCart();\n \n if (spinWheelConfig.type === 'cart_recovery' && detectedCart) {\n this.cartData = detectedCart;\n this.renderSpinWheelWidget(widgetId, spinWheelConfig);\n this.sendCartAbandonmentBeacon();\n } else if (spinWheelConfig.type === 'lead_gen') {\n this.renderSpinWheelWidget(widgetId, spinWheelConfig);\n }\n };\n \n if (isMobile) {\n const scrollVelocityEnabled = mobileConfig.scroll_velocity !== false;\n if (scrollVelocityEnabled) {\n this.triggerEngine.registerScrollVelocity({\n threshold: mobileConfig.scroll_threshold || 0.5,\n minScrollPosition: mobileConfig.scroll_min_position || 100,\n cooldown: mobileConfig.scroll_cooldown || 5000\n });\n this.triggerEngine.on('mobile_exit_intent', handleSpinWheelIntent);\n this.log('Registered mobile scroll velocity trigger for spin wheel');\n }\n \n const idleTimerEnabled = mobileConfig.idle_timer !== false;\n if (idleTimerEnabled) {\n const idleSeconds = mobileConfig.idle_seconds || 15;\n this.triggerEngine.registerInactivity(idleSeconds);\n this.triggerEngine.on(`inactivity_${idleSeconds}`, handleSpinWheelIntent);\n this.log(`Registered mobile idle timer trigger for spin wheel: ${idleSeconds}s`);\n }\n \n const visibilityChangeEnabled = mobileConfig.visibility_change !== false;\n if (visibilityChangeEnabled) {\n const detectedCart = this.detectPlatformCart();\n if (detectedCart && detectedCart.cart_items && detectedCart.cart_items.length > 0) {\n this.triggerEngine.registerVisibilityChange();\n this.triggerEngine.on('visibility_hidden', handleSpinWheelIntent);\n this.log('Registered mobile visibility change trigger for spin wheel (cart detected)');\n }\n }\n \n const backButtonEnabled = mobileConfig.back_button === true;\n if (backButtonEnabled) {\n this.triggerEngine.registerBackButton();\n this.triggerEngine.on('back_button', handleSpinWheelIntent);\n this.log('Registered mobile back button trigger for spin wheel');\n }\n \n this.log(`Setup mobile spin wheel: type=${spinWheelConfig.type}, priority=${spinWheelConfig.priority}`);\n } else {\n this.triggerEngine.registerExitIntent();\n this.triggerEngine.on('exit_intent', handleSpinWheelIntent);\n this.log(`Setup desktop spin wheel exit intent: type=${spinWheelConfig.type}, priority=${spinWheelConfig.priority}`);\n }\n \n return;\n }\n \n if (!exitIntentConfig || !exitIntentConfig.enabled) {\n this.log('No exit intent config found in prefetch');\n return;\n }\n \n const isMobile = this.isMobileDevice();\n const mobileConfig = exitIntentConfig.mobile_triggers || {};\n \n const handleExitIntent = () => {\n const widgetId = `prefetch_exit_intent_${Date.now()}`;\n \n if (this.renderedWidgets.has(widgetId)) {\n return;\n }\n \n this.renderedWidgets.add(widgetId);\n \n const detectedCart = this.detectPlatformCart();\n \n if (exitIntentConfig.type === 'cart_recovery' && detectedCart) {\n this.cartData = detectedCart;\n this.renderCartRecoveryPopup(widgetId, exitIntentConfig);\n this.sendCartAbandonmentBeacon();\n } else if (exitIntentConfig.type === 'lead_gen') {\n this.renderLeadGenPopup(widgetId, exitIntentConfig);\n } else {\n this.log('Unknown exit intent type or missing cart data');\n }\n };\n \n if (isMobile) {\n const scrollVelocityEnabled = mobileConfig.scroll_velocity !== false;\n if (scrollVelocityEnabled) {\n this.triggerEngine.registerScrollVelocity({\n threshold: mobileConfig.scroll_threshold || 0.5,\n minScrollPosition: mobileConfig.scroll_min_position || 100,\n cooldown: mobileConfig.scroll_cooldown || 5000\n });\n this.triggerEngine.on('mobile_exit_intent', handleExitIntent);\n this.log('Registered mobile scroll velocity trigger');\n }\n \n const idleTimerEnabled = mobileConfig.idle_timer !== false;\n if (idleTimerEnabled) {\n const idleSeconds = mobileConfig.idle_seconds || 15;\n this.triggerEngine.registerInactivity(idleSeconds);\n this.triggerEngine.on(`inactivity_${idleSeconds}`, handleExitIntent);\n this.log(`Registered mobile idle timer trigger: ${idleSeconds}s`);\n }\n \n const visibilityChangeEnabled = mobileConfig.visibility_change !== false;\n if (visibilityChangeEnabled) {\n const detectedCart = this.detectPlatformCart();\n if (detectedCart && detectedCart.cart_items && detectedCart.cart_items.length > 0) {\n this.triggerEngine.registerVisibilityChange();\n this.triggerEngine.on('visibility_hidden', handleExitIntent);\n this.log('Registered mobile visibility change trigger (cart detected)');\n } else {\n this.log('Skipped visibility change trigger (no cart items)');\n }\n }\n \n const backButtonEnabled = mobileConfig.back_button === true;\n if (backButtonEnabled) {\n this.triggerEngine.registerBackButton();\n this.triggerEngine.on('back_button', handleExitIntent);\n this.log('Registered mobile back button trigger (aggressive mode)');\n }\n \n this.log(`Setup mobile exit intent: type=${exitIntentConfig.type}, priority=${exitIntentConfig.priority}`);\n } else {\n this.triggerEngine.registerExitIntent();\n this.triggerEngine.on('exit_intent', handleExitIntent);\n this.log(`Setup desktop exit intent: type=${exitIntentConfig.type}, priority=${exitIntentConfig.priority}`);\n }\n }\n \n private sendCartAbandonmentBeacon(): void {\n if (!this.cartData) {\n this.log('No cart data available for beacon', true);\n return;\n }\n \n const beaconData = {\n organization_id: this.organizationId || 'default',\n contact_id: this.contactId,\n cart_id: this.cartData.cart_id,\n cart_total: this.cartData.cart_total,\n cart_currency: this.cartData.cart_currency,\n cart_items: this.cartData.cart_items,\n user_email: this.userId,\n abandoned_at: new Date().toISOString(),\n page_url: window.location.href,\n referrer: document.referrer\n };\n \n const beaconUrl = `${this.apiHost}/v1/widgets/beacon/cart-abandoned`;\n \n if (navigator.sendBeacon) {\n const blob = new Blob([JSON.stringify(beaconData)], { type: 'application/json' });\n const sent = navigator.sendBeacon(beaconUrl, blob);\n \n if (sent) {\n this.log('Cart abandonment beacon sent successfully');\n } else {\n this.log('Failed to send cart abandonment beacon', true);\n }\n } else {\n fetch(beaconUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey\n },\n body: JSON.stringify(beaconData),\n keepalive: true,\n credentials: 'include',\n }).catch(err => {\n this.log(`Error sending cart abandonment via fetch: ${err}`, true);\n });\n }\n }\n \n private renderWidget(widget: WidgetConfig): void {\n if (this.isDestroyed) return;\n if (this.renderedWidgets.has(widget.widget_id)) {\n return;\n }\n\n this.renderedWidgets.add(widget.widget_id);\n \n switch (widget.widget_type) {\n case 'chat_bubble':\n this.renderChatBubble(widget);\n break;\n case 'spin_wheel':\n this.renderSpinWheel(widget);\n break;\n case 'scratch_card':\n this.renderScratchCard(widget);\n break;\n case 'toast':\n this.renderToast(widget);\n break;\n case 'feedback_form':\n this.renderFeedbackForm(widget);\n break;\n case 'exit_intent_popup':\n this.renderExitIntentPopup(widget);\n break;\n default:\n this.log(`Unknown widget type: ${widget.widget_type}`, true);\n }\n \n this.trackEvent(widget.widget_id, 'show');\n }\n \n private renderChatBubble(widget: WidgetConfig): void {\n const { text, icon_url, link_url, background_color, text_color } = widget.config;\n const position = widget.position || 'bottom_right';\n \n const bubble = document.createElement('div');\n bubble.className = 'aegis-chat-bubble';\n bubble.setAttribute('data-widget-id', widget.widget_id);\n \n const positionStyles: Record<string, string> = {\n bottom_right: 'bottom: 20px; right: 20px;',\n bottom_left: 'bottom: 20px; left: 20px;',\n top_right: 'top: 20px; right: 20px;',\n top_left: 'top: 20px; left: 20px;'\n };\n \n bubble.style.cssText = `\n position: fixed;\n ${positionStyles[position] || positionStyles.bottom_right}\n background: ${this.sanitizeColor(background_color || '#25D366')};\n color: ${this.sanitizeColor(text_color || '#ffffff')};\n padding: 16px 24px;\n border-radius: 50px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n cursor: pointer;\n z-index: 999999;\n display: flex;\n align-items: center;\n gap: 12px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n font-weight: 600;\n font-size: 14px;\n animation: aegisBubbleIn 0.3s ease-out;\n `;\n \n if (icon_url) {\n const icon = document.createElement('img');\n const safeUrl = this.sanitizeUrl(icon_url);\n if (safeUrl) {\n icon.src = safeUrl;\n icon.alt = '';\n icon.style.cssText = 'width: 24px; height: 24px;';\n bubble.appendChild(icon);\n }\n }\n \n const textEl = document.createElement('span');\n textEl.textContent = text || 'Chat with us';\n bubble.appendChild(textEl);\n \n bubble.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'click');\n const safeUrl = this.sanitizeUrl(link_url);\n if (safeUrl) {\n window.open(safeUrl, '_blank');\n }\n });\n \n this.addAnimationStyles();\n bubble.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(bubble);\n }\n \n private renderSpinWheel(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-gamification-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-spin-wheel-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'Spin to Win!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Try your luck and win exclusive prizes!';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n modal.appendChild(description);\n \n // Draw an SVG wheel that honours the tenant's configured segments.\n // Each segment's `color` + `label` is painted as a pie slice; falls\n // back to a 4-color placeholder if no segments are provided.\n const segments: Array<{ label: string; color?: string }> = Array.isArray(\n (widget.config as any).segments,\n )\n ? (widget.config as any).segments\n : [\n { label: 'Prize 1', color: '#ff6b6b' },\n { label: 'Prize 2', color: '#feca57' },\n { label: 'Prize 3', color: '#48dbfb' },\n { label: 'Prize 4', color: '#ff6348' },\n ];\n\n const SVG_NS = 'http://www.w3.org/2000/svg';\n const wheel = document.createElementNS(SVG_NS, 'svg');\n wheel.setAttribute('viewBox', '-160 -160 320 320');\n wheel.setAttribute('width', '300');\n wheel.setAttribute('height', '300');\n wheel.style.cssText = 'margin: 0 auto 24px; display: block;';\n\n const n = segments.length;\n const anglePer = (2 * Math.PI) / n;\n const radius = 140;\n for (let i = 0; i < n; i++) {\n const start = i * anglePer - Math.PI / 2;\n const end = start + anglePer;\n const x1 = Math.cos(start) * radius;\n const y1 = Math.sin(start) * radius;\n const x2 = Math.cos(end) * radius;\n const y2 = Math.sin(end) * radius;\n const largeArc = anglePer > Math.PI ? 1 : 0;\n const path = document.createElementNS(SVG_NS, 'path');\n path.setAttribute(\n 'd',\n `M 0 0 L ${x1.toFixed(2)} ${y1.toFixed(2)} A ${radius} ${radius} 0 ${largeArc} 1 ${x2.toFixed(2)} ${y2.toFixed(2)} Z`,\n );\n path.setAttribute('fill', this.sanitizeColor(segments[i].color || '#cccccc'));\n path.setAttribute('stroke', '#ffffff');\n path.setAttribute('stroke-width', '2');\n wheel.appendChild(path);\n\n const labelAngle = start + anglePer / 2;\n const lx = Math.cos(labelAngle) * radius * 0.65;\n const ly = Math.sin(labelAngle) * radius * 0.65;\n const text = document.createElementNS(SVG_NS, 'text');\n text.setAttribute('x', lx.toFixed(2));\n text.setAttribute('y', ly.toFixed(2));\n text.setAttribute('fill', '#ffffff');\n text.setAttribute('font-size', '13');\n text.setAttribute('font-weight', '600');\n text.setAttribute('text-anchor', 'middle');\n text.setAttribute('dominant-baseline', 'middle');\n text.textContent = segments[i].label || `#${i + 1}`;\n wheel.appendChild(text);\n }\n modal.appendChild(wheel);\n \n const spinButton = document.createElement('button');\n spinButton.textContent = 'SPIN NOW!';\n spinButton.style.cssText = `\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n margin-bottom: 16px;\n `;\n \n spinButton.addEventListener('click', async () => {\n spinButton.disabled = true;\n spinButton.textContent = 'SPINNING...';\n \n try {\n const prize = await this.generatePrize(widget.config.config_id);\n\n wheel.style.animation = 'aegisSpin 2s ease-out';\n\n setTimeout(() => {\n this.showPrizeResult(modal, prize);\n }, 2000);\n \n } catch (error) {\n this.log(`Error generating prize: ${error}`, true);\n spinButton.disabled = false;\n spinButton.textContent = 'TRY AGAIN';\n }\n });\n \n modal.appendChild(spinButton);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderSpinWheelWidget(widgetId: string, config: NonNullable<PrefetchWidgetConfig['spin_wheel']>): void {\n if (this.isDestroyed) return;\n const cart = this.detectPlatformCart();\n \n if (config.type === 'cart_recovery' && !cart) {\n this.log('Spin wheel requires cart, but none detected');\n return;\n }\n \n if (cart) {\n this.cartData = cart;\n }\n \n const customization = this.cssCustomization.spinWheel || {};\n const accentColor = customization.accentColor || (config as any).accent_color || '#FF6B6B';\n const backgroundColor = customization.backgroundColor || (config as any).background_color || '#FFFFFF';\n const textColor = customization.textColor || (config as any).text_color || '#333333';\n const buttonColor = customization.buttonColor || (config as any).button_color || accentColor;\n const wheelColors = customization.wheelColors || ['#FF6B6B', '#4ECDC4', '#FFE66D', '#95E1D3'];\n \n const overlay = document.createElement('div');\n overlay.className = 'aegis-spin-wheel-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.7);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 999999;\n animation: aegisFadeIn 0.3s ease;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-spin-wheel-modal';\n modal.style.cssText = `\n background: ${this.sanitizeColor(backgroundColor)};\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n position: relative;\n animation: aegisScaleIn 0.4s ease;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n const closeBtn = document.createElement('button');\n closeBtn.innerHTML = '✕';\n closeBtn.className = 'aegis-spin-wheel-close';\n closeBtn.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #999;\n `;\n closeBtn.onclick = () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'spin_wheel' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n };\n modal.appendChild(closeBtn);\n \n const title = document.createElement('h2');\n title.textContent = this.interpolateCartVariables((config as any).title || 'Spin to Win!');\n title.style.cssText = `\n margin: 0 0 16px 0;\n font-size: 28px;\n font-weight: bold;\n text-align: center;\n color: ${this.sanitizeColor(textColor)};\n `;\n modal.appendChild(title);\n \n if (cart) {\n const subtitle = document.createElement('p');\n subtitle.textContent = `Complete your ${cart.cart_currency} ${cart.cart_total.toFixed(2)} order and save!`;\n subtitle.style.cssText = `\n margin: 0 0 24px 0;\n font-size: 16px;\n text-align: center;\n color: #666;\n `;\n modal.appendChild(subtitle);\n }\n \n const wheelContainer = document.createElement('div');\n wheelContainer.className = 'aegis-wheel-container';\n wheelContainer.style.cssText = `\n width: 300px;\n height: 300px;\n margin: 0 auto 24px auto;\n background: conic-gradient(\n from 0deg,\n ${wheelColors[0]} 0deg 90deg,\n ${wheelColors[1]} 90deg 180deg,\n ${wheelColors[2]} 180deg 270deg,\n ${wheelColors[3]} 270deg 360deg\n );\n border-radius: 50%;\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n \n const form = document.createElement('form');\n form.className = 'aegis-spin-form';\n form.style.cssText = 'display: block;';\n \n const phoneInput = document.createElement('input');\n phoneInput.type = 'tel';\n phoneInput.placeholder = 'Enter your phone number';\n phoneInput.required = true;\n phoneInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(phoneInput);\n \n const emailInput = document.createElement('input');\n emailInput.type = 'email';\n emailInput.placeholder = 'Enter your email (optional)';\n emailInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(emailInput);\n \n const nameInput = document.createElement('input');\n nameInput.type = 'text';\n nameInput.placeholder = 'Enter your name (optional)';\n nameInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(nameInput);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Spin the Wheel!';\n submitButton.style.cssText = `\n width: 100%;\n padding: 14px;\n background: ${this.sanitizeColor(buttonColor)};\n color: white;\n border: none;\n border-radius: 8px;\n font-size: 16px;\n font-weight: 700;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n const errorMessage = document.createElement('div');\n errorMessage.className = 'aegis-spin-error';\n errorMessage.style.cssText = `\n color: #d32f2f;\n font-size: 14px;\n margin-top: 12px;\n text-align: center;\n display: none;\n `;\n form.appendChild(errorMessage);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n const phone = phoneInput.value.trim();\n const email = emailInput.value.trim();\n const name = nameInput.value.trim();\n \n if (!this.validatePhone(phone)) {\n errorMessage.textContent = 'Please enter a valid phone number (e.g., +1234567890)';\n errorMessage.style.display = 'block';\n return;\n }\n \n if (email && !this.validateEmail(email)) {\n errorMessage.textContent = 'Please enter a valid email address';\n errorMessage.style.display = 'block';\n return;\n }\n \n errorMessage.style.display = 'none';\n submitButton.disabled = true;\n submitButton.textContent = 'Spinning...';\n \n wheelContainer.style.animation = 'aegisSpin 2s ease-out';\n \n setTimeout(async () => {\n try {\n const prize = await this.submitSpinWheel({\n phone,\n email,\n name,\n cart,\n widgetId\n });\n \n this.showSpinWheelPrize(modal, prize);\n this.trackEvent(widgetId, 'submit', {\n type: 'spin_wheel',\n prize_label: prize.prize_label,\n has_email: !!email\n });\n \n } catch (error) {\n this.log(`Error submitting spin wheel: ${error}`, true);\n errorMessage.textContent = 'Failed to submit. Please try again.';\n errorMessage.style.display = 'block';\n submitButton.disabled = false;\n submitButton.textContent = 'Spin the Wheel!';\n wheelContainer.style.animation = '';\n }\n }, 2000);\n });\n \n modal.appendChild(wheelContainer);\n modal.appendChild(form);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'spin_wheel' });\n }\n \n private validatePhone(phone: string): boolean {\n const e164Regex = /^\\+?[1-9]\\d{1,14}$/;\n return e164Regex.test(phone.replace(/[\\s()-]/g, ''));\n }\n \n private validateEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n }\n \n private async submitSpinWheel(data: {\n phone: string;\n email: string;\n name: string;\n cart: CartData | null;\n widgetId: string;\n }): Promise<GamificationPrize> {\n const url = `${this.apiHost}/v1/widgets/spin-wheel/submit`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const geoRegion = this.detectGeoRegion();\n const deviceType = this.getDeviceType();\n const utmParams = this.getUTMParams();\n \n const body: any = {\n phone: data.phone.replace(/[\\s()-]/g, ''),\n email: data.email || undefined,\n name: data.name || undefined,\n cart_id: data.cart?.cart_id || `web_${Date.now()}`,\n cart_token: data.cart?.cart_id,\n cart_total: data.cart?.cart_total || 0,\n cart_currency: data.cart?.cart_currency || 'USD',\n cart_items: data.cart?.cart_items || [],\n cart_url: window.location.href,\n platform: 'web',\n geo_region: geoRegion,\n device_type: deviceType,\n session_id: this.getSessionId() || undefined,\n anonymous_id: this.getAnonymousId() || undefined,\n utm_source: utmParams.utm_source,\n utm_medium: utmParams.utm_medium,\n utm_campaign: utmParams.utm_campaign\n };\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n credentials: 'include',\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to submit spin wheel: ${response.status} - ${errorText}`);\n }\n \n return await response.json();\n }\n \n private showSpinWheelPrize(modal: HTMLElement, prize: GamificationPrize): void {\n modal.innerHTML = '';\n \n const resultContainer = document.createElement('div');\n resultContainer.style.cssText = 'text-align: center; padding: 40px 20px;';\n \n const emoji = document.createElement('div');\n emoji.textContent = '🎉';\n emoji.style.cssText = 'font-size: 60px; margin-bottom: 20px;';\n resultContainer.appendChild(emoji);\n \n const title = document.createElement('h2');\n title.textContent = 'Congratulations!';\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 28px; font-weight: 700; color: #1a73e8;';\n resultContainer.appendChild(title);\n \n const prizeLabel = document.createElement('p');\n prizeLabel.textContent = prize.prize_label;\n prizeLabel.style.cssText = 'margin: 0 0 20px 0; font-size: 20px; font-weight: 600; color: #333;';\n resultContainer.appendChild(prizeLabel);\n \n if (prize.coupon_code) {\n const couponContainer = document.createElement('div');\n couponContainer.style.cssText = `\n background: #f5f5f5;\n padding: 16px;\n border-radius: 8px;\n margin-bottom: 20px;\n border: 2px dashed #1a73e8;\n `;\n \n const couponLabel = document.createElement('div');\n couponLabel.textContent = 'Your coupon code:';\n couponLabel.style.cssText = 'font-size: 12px; color: #666; margin-bottom: 8px;';\n couponContainer.appendChild(couponLabel);\n \n const couponCode = document.createElement('div');\n couponCode.textContent = prize.coupon_code;\n couponCode.style.cssText = 'font-size: 24px; font-weight: 700; color: #1a73e8; letter-spacing: 2px;';\n couponContainer.appendChild(couponCode);\n \n resultContainer.appendChild(couponContainer);\n }\n \n const message = document.createElement('p');\n message.textContent = 'Check your WhatsApp/SMS for your discount code and cart link!';\n message.style.cssText = 'margin: 0 0 20px 0; font-size: 14px; color: #666;';\n resultContainer.appendChild(message);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n \n closeButton.addEventListener('click', () => {\n const overlay = modal.parentElement;\n if (overlay && document.body.contains(overlay)) {\n document.body.removeChild(overlay);\n }\n });\n \n resultContainer.appendChild(closeButton);\n modal.appendChild(resultContainer);\n }\n \n private detectGeoRegion(): string {\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n \n if (timezone.includes('America')) return 'north_america';\n if (timezone.includes('Europe')) return 'europe';\n if (timezone.includes('Asia/Kolkata') || timezone.includes('Asia/Calcutta')) return 'india';\n if (timezone.includes('Asia/Singapore') || timezone.includes('Asia/Bangkok') || timezone.includes('Asia/Jakarta')) return 'southeast_asia';\n if (timezone.includes('Asia/Dubai') || timezone.includes('Asia/Riyadh')) return 'middle_east';\n if (timezone.includes('America') && (timezone.includes('Sao_Paulo') || timezone.includes('Buenos_Aires'))) return 'latin_america';\n if (timezone.includes('Australia') || timezone.includes('Pacific/Auckland')) return 'oceania';\n \n return 'north_america';\n }\n \n private getUTMParams(): { utm_source?: string; utm_medium?: string; utm_campaign?: string } {\n const params = new URLSearchParams(window.location.search);\n return {\n utm_source: params.get('utm_source') || undefined,\n utm_medium: params.get('utm_medium') || undefined,\n utm_campaign: params.get('utm_campaign') || undefined\n };\n }\n \n private getSessionId(): string | null {\n return sessionStorage.getItem('aegis_session_id');\n }\n \n private getAnonymousId(): string | null {\n return localStorage.getItem('aegis_anonymous_id');\n }\n \n private renderScratchCard(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-gamification-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-scratch-card-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'Scratch & Win!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Scratch to reveal your prize!';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n modal.appendChild(description);\n \n const canvas = document.createElement('canvas');\n canvas.width = 300;\n canvas.height = 200;\n canvas.style.cssText = `\n border-radius: 8px;\n cursor: pointer;\n margin: 0 auto 24px;\n display: block;\n box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n `;\n modal.appendChild(canvas);\n \n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.fillStyle = '#c0c0c0';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.fillStyle = '#888';\n ctx.font = '20px Arial';\n ctx.textAlign = 'center';\n ctx.fillText('Scratch here!', canvas.width / 2, canvas.height / 2);\n \n let isScratching = false;\n \n const scratch = (x: number, y: number) => {\n ctx.globalCompositeOperation = 'destination-out';\n ctx.beginPath();\n ctx.arc(x, y, 20, 0, Math.PI * 2);\n ctx.fill();\n };\n \n canvas.addEventListener('mousedown', () => { isScratching = true; });\n canvas.addEventListener('mouseup', () => { isScratching = false; });\n canvas.addEventListener('mousemove', (e) => {\n if (isScratching) {\n const rect = canvas.getBoundingClientRect();\n scratch(e.clientX - rect.left, e.clientY - rect.top);\n }\n });\n }\n \n const scratchButton = document.createElement('button');\n scratchButton.textContent = 'REVEAL PRIZE';\n scratchButton.style.cssText = `\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n color: white;\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n `;\n \n scratchButton.addEventListener('click', async () => {\n scratchButton.disabled = true;\n scratchButton.textContent = 'REVEALING...';\n \n try {\n const prize = await this.generatePrize(widget.config.config_id);\n this.showPrizeResult(modal, prize);\n } catch (error) {\n this.log(`Error generating prize: ${error}`, true);\n scratchButton.disabled = false;\n scratchButton.textContent = 'TRY AGAIN';\n }\n });\n \n modal.appendChild(scratchButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderToast(widget: WidgetConfig): void {\n const { message, icon, duration } = widget.config;\n const position = widget.position || 'bottom_left';\n \n const toast = document.createElement('div');\n toast.className = 'aegis-toast';\n toast.setAttribute('data-widget-id', widget.widget_id);\n \n const positionStyles: Record<string, string> = {\n bottom_left: 'bottom: 20px; left: 20px;',\n bottom_right: 'bottom: 20px; right: 20px;',\n top_left: 'top: 20px; left: 20px;',\n top_right: 'top: 20px; right: 20px;'\n };\n \n toast.style.cssText = `\n position: fixed;\n ${positionStyles[position] || positionStyles.bottom_left}\n background: white;\n padding: 16px 20px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n z-index: 999998;\n display: flex;\n align-items: center;\n gap: 12px;\n max-width: 350px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisToastIn 0.3s ease-out;\n `;\n \n if (icon) {\n const iconEl = document.createElement('div');\n iconEl.textContent = icon;\n iconEl.style.cssText = 'font-size: 20px;';\n toast.appendChild(iconEl);\n }\n \n const messageEl = document.createElement('div');\n messageEl.textContent = message || 'Someone just made a purchase!';\n messageEl.style.cssText = 'flex: 1; font-size: 13px; color: #333;';\n toast.appendChild(messageEl);\n \n this.addAnimationStyles();\n toast.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(toast);\n \n setTimeout(() => {\n toast.style.animation = 'aegisToastOut 0.3s ease-out';\n setTimeout(() => {\n if (document.body.contains(toast)) {\n document.body.removeChild(toast);\n }\n this.renderedWidgets.delete(widget.widget_id);\n }, 300);\n }, duration || 5000);\n }\n \n private renderFeedbackForm(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-feedback-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 400px;\n background: white;\n box-shadow: -4px 0 20px rgba(0,0,0,0.15);\n z-index: 1000000;\n padding: 32px;\n overflow-y: auto;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInRight 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'We value your feedback!';\n title.style.cssText = 'margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n overlay.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Help us improve your experience.';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n overlay.appendChild(description);\n \n const form = document.createElement('form');\n \n const label = document.createElement('label');\n label.textContent = 'How likely are you to recommend us? (0-10)';\n label.style.cssText = 'display: block; font-size: 14px; font-weight: 600; margin-bottom: 8px; color: #333;';\n form.appendChild(label);\n \n const input = document.createElement('input');\n input.type = 'number';\n input.min = '0';\n input.max = '10';\n input.style.cssText = `\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n margin-bottom: 16px;\n `;\n form.appendChild(input);\n \n const textareaLabel = document.createElement('label');\n textareaLabel.textContent = 'Tell us more (optional)';\n textareaLabel.style.cssText = 'display: block; font-size: 14px; font-weight: 600; margin-bottom: 8px; color: #333;';\n form.appendChild(textareaLabel);\n \n const textarea = document.createElement('textarea');\n textarea.rows = 4;\n textarea.style.cssText = `\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n resize: vertical;\n margin-bottom: 16px;\n font-family: inherit;\n `;\n form.appendChild(textarea);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Submit Feedback';\n submitButton.style.cssText = `\n width: 100%;\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px;\n border-radius: 6px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n \n try {\n await this.submitFeedback(widget.widget_id, {\n score: parseInt(input.value),\n comment: textarea.value\n });\n \n overlay.innerHTML = '<div style=\"text-align: center; padding: 60px 20px;\"><h3 style=\"margin: 0 0 12px 0; color: #1a73e8;\">Thank you!</h3><p style=\"margin: 0; color: #666;\">Your feedback helps us improve.</p></div>';\n \n setTimeout(() => {\n document.body.removeChild(overlay);\n }, 2000);\n \n } catch (error) {\n this.log(`Error submitting feedback: ${error}`, true);\n submitButton.disabled = false;\n submitButton.textContent = 'Submit Feedback';\n }\n });\n \n overlay.appendChild(form);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n overlay.appendChild(closeButton);\n \n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderExitIntentPopup(widget: WidgetConfig): void {\n const { title, description, cta_text, cta_url, image_url } = widget.config;\n \n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-exit-popup-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n max-width: 600px;\n width: 90%;\n overflow: hidden;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 250px; object-fit: cover;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 32px;';\n \n const titleEl = document.createElement('h2');\n titleEl.textContent = title || 'Wait! Don\\'t leave yet!';\n titleEl.style.cssText = 'margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(titleEl);\n \n const descEl = document.createElement('p');\n descEl.textContent = description || 'Get 10% off your first order!';\n descEl.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; color: #666; line-height: 1.5;';\n content.appendChild(descEl);\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n content.appendChild(ctaButton);\n }\n \n modal.appendChild(content);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: white;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #666;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private async generatePrize(configId: string): Promise<GamificationPrize> {\n const url = `${this.apiHost}/v1/widgets/gamification/generate-prize`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({ config_id: configId }),\n credentials: 'include',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to generate prize: ${response.status}`);\n }\n \n return await response.json();\n }\n \n private showPrizeResult(modal: HTMLElement, prize: GamificationPrize): void {\n modal.innerHTML = '';\n \n const resultContainer = document.createElement('div');\n resultContainer.style.cssText = 'text-align: center; padding: 40px 20px;';\n \n const emoji = document.createElement('div');\n emoji.textContent = '🎉';\n emoji.style.cssText = 'font-size: 60px; margin-bottom: 20px;';\n resultContainer.appendChild(emoji);\n \n const title = document.createElement('h2');\n title.textContent = 'Congratulations!';\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 28px; font-weight: 700; color: #1a73e8;';\n resultContainer.appendChild(title);\n \n const prizeLabel = document.createElement('p');\n prizeLabel.textContent = prize.prize_label;\n prizeLabel.style.cssText = 'margin: 0 0 20px 0; font-size: 20px; font-weight: 600; color: #333;';\n resultContainer.appendChild(prizeLabel);\n \n if (prize.coupon_code) {\n const couponContainer = document.createElement('div');\n couponContainer.style.cssText = `\n background: #f5f5f5;\n padding: 16px;\n border-radius: 8px;\n margin-bottom: 20px;\n border: 2px dashed #1a73e8;\n `;\n \n const couponLabel = document.createElement('div');\n couponLabel.textContent = 'Your coupon code:';\n couponLabel.style.cssText = 'font-size: 12px; color: #666; margin-bottom: 8px;';\n couponContainer.appendChild(couponLabel);\n \n const couponCode = document.createElement('div');\n couponCode.textContent = prize.coupon_code;\n couponCode.style.cssText = 'font-size: 24px; font-weight: 700; color: #1a73e8; letter-spacing: 2px;';\n couponContainer.appendChild(couponCode);\n \n resultContainer.appendChild(couponContainer);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n \n closeButton.addEventListener('click', () => {\n const overlay = modal.parentElement;\n if (overlay && document.body.contains(overlay)) {\n document.body.removeChild(overlay);\n }\n });\n \n resultContainer.appendChild(closeButton);\n modal.appendChild(resultContainer);\n }\n \n private async submitFeedback(widgetId: string, data: Record<string, any>): Promise<void> {\n const url = `${this.apiHost}/v1/widgets/track-event`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n widget_id: widgetId,\n event_type: 'submit',\n event_data: data\n }),\n credentials: 'include',\n });\n \n if (!response.ok) {\n throw new Error(`Failed to submit feedback: ${response.status}`);\n }\n }\n \n private async trackEvent(widgetId: string, eventType: string, metadata?: Record<string, any>): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/widgets/track-event`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n widget_id: widgetId,\n event_type: eventType,\n event_data: metadata || {}\n }),\n credentials: 'include',\n });\n\n } catch (error) {\n this.log(`Error tracking widget event: ${error}`, true);\n }\n }\n \n private sanitizeUrl(url?: string): string | null {\n if (!url) return null;\n \n try {\n const parsed = new URL(url, window.location.href);\n if (parsed.protocol === 'javascript:' || parsed.protocol === 'data:') {\n this.log(`Blocked dangerous URL: ${url}`, true);\n return null;\n }\n return parsed.href;\n } catch {\n this.log(`Invalid URL: ${url}`, true);\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n if (/^#[0-9A-F]{3,8}$/i.test(color)) {\n return color;\n }\n \n if (/^rgb\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*\\)$/i.test(color)) {\n return color;\n }\n \n if (/^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*[\\d.]+\\s*\\)$/i.test(color)) {\n return color;\n }\n \n return '#1a73e8';\n }\n \n private getDeviceType(): string {\n const ua = navigator.userAgent;\n if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {\n return 'tablet';\n }\n if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) {\n return 'mobile';\n }\n return 'desktop';\n }\n \n private isMobileDevice(): boolean {\n const deviceType = this.getDeviceType();\n return deviceType === 'mobile' || deviceType === 'tablet';\n }\n \n private addAnimationStyles(): void {\n if (document.getElementById('aegis-widget-animations')) {\n return;\n }\n \n const style = document.createElement('style');\n style.id = 'aegis-widget-animations';\n style.textContent = `\n @keyframes aegisFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes aegisScaleIn {\n from { transform: scale(0.8); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n }\n \n @keyframes aegisBubbleIn {\n from { transform: translateY(20px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes aegisToastIn {\n from { transform: translateX(-100%); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n }\n \n @keyframes aegisToastOut {\n from { transform: translateX(0); opacity: 1; }\n to { transform: translateX(-100%); opacity: 0; }\n }\n \n @keyframes aegisSlideInRight {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n \n @keyframes aegisSpin {\n from { transform: rotate(0deg); }\n to { transform: rotate(1440deg); }\n }\n `;\n document.head.appendChild(style);\n }\n \n private renderCartRecoveryPopup(widgetId: string, config: NonNullable<PrefetchWidgetConfig['exit_intent']>): void {\n if (this.isDestroyed) return;\n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n overlay.setAttribute('data-aegis-widget-root', '');\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-cart-recovery-modal';\n modal.style.cssText = `\n background: ${this.sanitizeColor(config.background_color || '#FFFFFF')};\n color: ${this.sanitizeColor(config.text_color || '#333333')};\n border-radius: 16px;\n max-width: 600px;\n width: 90%;\n padding: 40px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n position: relative;\n `;\n \n const title = document.createElement('h2');\n const titleText = this.interpolateCartVariables(config.title || 'Complete Your Order');\n title.textContent = titleText;\n title.style.cssText = `margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: ${this.sanitizeColor(config.accent_color || '#FF6B00')};`;\n modal.appendChild(title);\n \n const message = document.createElement('p');\n const messageText = this.interpolateCartVariables(config.message || 'Your cart is waiting for you!');\n message.textContent = messageText;\n message.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; line-height: 1.5;';\n modal.appendChild(message);\n \n if (config.show_cart_items && this.cartData) {\n const cartItems = document.createElement('div');\n cartItems.style.cssText = 'margin: 0 0 24px 0; padding: 16px; background: rgba(0,0,0,0.05); border-radius: 8px;';\n \n const cartTitle = document.createElement('div');\n cartTitle.textContent = `${this.cartData.cart_items.length} items in your cart`;\n cartTitle.style.cssText = 'font-weight: 600; margin-bottom: 12px;';\n cartItems.appendChild(cartTitle);\n \n this.cartData.cart_items.slice(0, 3).forEach(item => {\n const itemDiv = document.createElement('div');\n itemDiv.textContent = `${item.quantity}× ${item.product_name || item.product_id}`;\n itemDiv.style.cssText = 'font-size: 14px; margin-bottom: 4px;';\n cartItems.appendChild(itemDiv);\n });\n \n modal.appendChild(cartItems);\n }\n \n if (config.discount_code) {\n const discountBox = document.createElement('div');\n discountBox.style.cssText = `\n margin: 0 0 24px 0;\n padding: 16px;\n background: ${this.sanitizeColor(config.accent_color || '#FF6B00')};\n color: white;\n border-radius: 8px;\n text-align: center;\n font-weight: 700;\n font-size: 18px;\n `;\n discountBox.textContent = `Use code: ${config.discount_code} for ${config.discount_percentage || 10}% off!`;\n modal.appendChild(discountBox);\n }\n \n if (config.show_timer && config.timer_minutes) {\n const timer = document.createElement('div');\n timer.style.cssText = 'margin: 0 0 24px 0; text-align: center; font-size: 14px; color: #999;';\n timer.textContent = `⏰ Offer expires in ${config.timer_minutes} minutes`;\n modal.appendChild(timer);\n }\n \n const ctaButton = document.createElement('button');\n ctaButton.textContent = config.cta_text || 'Complete Checkout';\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(config.accent_color || '#FF6B00')};\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'click', { type: 'cart_recovery' });\n const checkoutUrl = this.sanitizeUrl(config.cta_url || '/checkout');\n if (checkoutUrl) {\n window.location.href = checkoutUrl;\n }\n });\n \n modal.appendChild(ctaButton);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'cart_recovery' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n });\n \n modal.appendChild(closeButton);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'cart_recovery', tier: config.tier });\n }\n \n private renderLeadGenPopup(widgetId: string, config: NonNullable<PrefetchWidgetConfig['exit_intent']>): void {\n if (this.isDestroyed) return;\n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n overlay.setAttribute('data-aegis-widget-root', '');\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-leadgen-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n max-width: 500px;\n width: 90%;\n padding: 40px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n position: relative;\n `;\n \n const title = document.createElement('h2');\n title.textContent = config.title || 'Get 10% Off Your First Order!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const message = document.createElement('p');\n message.textContent = config.message || 'Subscribe to our newsletter and get an exclusive discount code.';\n message.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; color: #666;';\n modal.appendChild(message);\n \n const form = document.createElement('form');\n \n const emailInput = document.createElement('input');\n emailInput.type = 'email';\n emailInput.placeholder = 'Enter your email';\n emailInput.required = true;\n emailInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 16px;\n box-sizing: border-box;\n `;\n form.appendChild(emailInput);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Get My Discount';\n submitButton.style.cssText = `\n width: 100%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n \n try {\n await this.trackEvent(widgetId, 'submit', { \n type: 'lead_gen',\n email: emailInput.value \n });\n \n modal.innerHTML = `\n <div style=\"text-align: center; padding: 20px;\">\n <div style=\"font-size: 48px; margin-bottom: 16px;\">✅</div>\n <h3 style=\"margin: 0 0 12px 0; color: #1a73e8;\">Thank You!</h3>\n <p style=\"margin: 0; color: #666;\">Check your email for your discount code!</p>\n </div>\n `;\n \n setTimeout(() => {\n document.body.removeChild(overlay);\n }, 2500);\n \n } catch (error) {\n this.log(`Error submitting lead gen form: ${error}`, true);\n submitButton.disabled = false;\n submitButton.textContent = 'Get My Discount';\n }\n });\n \n modal.appendChild(form);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'lead_gen' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n });\n \n modal.appendChild(closeButton);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'lead_gen' });\n }\n \n private interpolateCartVariables(template: string): string {\n if (!this.cartData) return template;\n \n return template\n .replace(/\\{\\{cart_total\\}\\}/g, `${this.cartData.cart_currency} ${this.cartData.cart_total.toFixed(2)}`)\n .replace(/\\{\\{cart_currency\\}\\}/g, this.cartData.cart_currency)\n .replace(/\\{\\{cart_items_count\\}\\}/g, this.cartData.cart_items.length.toString());\n }\n \n private log(message: string, isError: boolean = false): void {\n if (this.debugMode || isError) {\n const method = isError ? 'error' : 'log';\n console[method](`[AegisWidgets] ${message}`);\n }\n }\n}\n","/**\n * TriggerEngine - Client-Side Trigger Evaluation\n * \n * Evaluates behavioral triggers that require real-time client state:\n * - Scroll depth (e.g., user scrolled >= 50%)\n * - Time on page (e.g., >= 30 seconds on current page)\n * - Exit intent (mouse leaving viewport toward browser controls)\n * - Inactivity (no user interaction for X seconds)\n * - Scroll velocity (mobile exit intent - fast upward scroll)\n * - Visibility change (tab/app switching)\n * - Back button (history navigation)\n * \n * Architecture:\n * - Server evaluates historical triggers (event counts, segments)\n * - Client evaluates behavioral triggers (scroll, time, exit intent)\n * - Zero latency - no server round trip needed\n * \n * Usage:\n * const trigger = new TriggerEngine();\n * trigger.on('scroll_depth_50', (data) => {\n * console.log('User scrolled to 50%', data);\n * });\n * trigger.start();\n */\n\nexport interface TriggerRule {\n type: 'scroll_depth' | 'time_on_page' | 'exit_intent' | 'inactivity' | 'scroll_velocity' | 'visibility_change' | 'back_button';\n config: ScrollDepthConfig | TimeOnPageConfig | ExitIntentConfig | InactivityConfig | ScrollVelocityConfig | VisibilityChangeConfig | BackButtonConfig;\n}\n\nexport interface ScrollDepthConfig {\n depth_percent: number;\n}\n\nexport interface TimeOnPageConfig {\n seconds: number;\n}\n\nexport interface ExitIntentConfig {\n enabled: boolean;\n}\n\nexport interface InactivityConfig {\n idle_seconds: number;\n}\n\nexport interface ScrollVelocityConfig {\n threshold: number;\n minScrollPosition: number;\n cooldown: number;\n}\n\nexport interface VisibilityChangeConfig {\n enabled: boolean;\n}\n\nexport interface BackButtonConfig {\n enabled: boolean;\n}\n\nexport interface TriggerEvent {\n type: string;\n data: Record<string, any>;\n timestamp: number;\n}\n\ntype TriggerCallback = (event: TriggerEvent) => void;\n\nexport class TriggerEngine {\n private listeners: Map<string, Set<TriggerCallback>> = new Map();\n private isStarted = false;\n \n private scrollDepthTargets = new Set<number>();\n private scrollDepthReached = new Set<number>();\n \n private timeOnPageTargets = new Map<number, number>();\n private pageLoadTime?: number;\n \n private exitIntentEnabled = false;\n private exitIntentFired = false;\n \n private inactivityTargets = new Map<number, number>();\n private lastActivityTime = Date.now();\n private inactivityCheckInterval?: number;\n \n private scrollVelocityEnabled = false;\n private scrollVelocityFired = false;\n private scrollVelocityConfig: ScrollVelocityConfig = {\n threshold: 0.5,\n minScrollPosition: 100,\n cooldown: 5000\n };\n private lastScrollY = 0;\n private lastScrollTime = Date.now();\n private scrollVelocityCooldownTimer?: number;\n \n private visibilityChangeEnabled = false;\n \n private backButtonEnabled = false;\n private backButtonFired = false;\n \n constructor() {}\n \n on(eventType: string, callback: TriggerCallback): void {\n if (!this.listeners.has(eventType)) {\n this.listeners.set(eventType, new Set());\n }\n this.listeners.get(eventType)!.add(callback);\n }\n \n off(eventType: string, callback: TriggerCallback): void {\n const callbacks = this.listeners.get(eventType);\n if (callbacks) {\n callbacks.delete(callback);\n }\n }\n \n registerScrollDepth(depthPercent: number): void {\n this.scrollDepthTargets.add(depthPercent);\n }\n \n registerTimeOnPage(seconds: number): void {\n if (!this.timeOnPageTargets.has(seconds)) {\n const timerId = window.setTimeout(() => {\n this.emit(`time_on_page_${seconds}`, {\n seconds,\n page_url: window.location.href\n });\n this.timeOnPageTargets.delete(seconds);\n }, seconds * 1000);\n \n this.timeOnPageTargets.set(seconds, timerId);\n }\n }\n \n registerExitIntent(): void {\n this.exitIntentEnabled = true;\n }\n \n registerInactivity(idleSeconds: number): void {\n if (!this.inactivityTargets.has(idleSeconds)) {\n const timerId = window.setTimeout(() => {\n const idleTime = (Date.now() - this.lastActivityTime) / 1000;\n \n if (idleTime >= idleSeconds) {\n this.emit(`inactivity_${idleSeconds}`, {\n idle_seconds: idleSeconds,\n actual_idle_time: idleTime\n });\n }\n \n this.inactivityTargets.delete(idleSeconds);\n }, idleSeconds * 1000);\n \n this.inactivityTargets.set(idleSeconds, timerId);\n }\n }\n \n registerScrollVelocity(config?: Partial<ScrollVelocityConfig>): void {\n this.scrollVelocityEnabled = true;\n \n if (config) {\n this.scrollVelocityConfig = {\n threshold: config.threshold ?? this.scrollVelocityConfig.threshold,\n minScrollPosition: config.minScrollPosition ?? this.scrollVelocityConfig.minScrollPosition,\n cooldown: config.cooldown ?? this.scrollVelocityConfig.cooldown\n };\n }\n }\n \n registerVisibilityChange(): void {\n this.visibilityChangeEnabled = true;\n }\n \n registerBackButton(): void {\n this.backButtonEnabled = true;\n }\n \n start(): void {\n if (this.isStarted) {\n return;\n }\n \n this.pageLoadTime = Date.now();\n this.lastActivityTime = Date.now();\n this.lastScrollY = window.scrollY || 0;\n this.lastScrollTime = Date.now();\n \n if (this.scrollDepthTargets.size > 0) {\n this.attachScrollListener();\n }\n \n if (this.exitIntentEnabled) {\n this.attachExitIntentListener();\n }\n \n if (this.scrollVelocityEnabled) {\n this.attachScrollVelocityListener();\n }\n \n if (this.visibilityChangeEnabled) {\n this.attachVisibilityChangeListener();\n }\n \n if (this.backButtonEnabled) {\n this.attachBackButtonListener();\n }\n \n this.attachActivityListeners();\n \n this.startInactivityCheck();\n \n this.isStarted = true;\n }\n \n stop(): void {\n if (!this.isStarted) {\n return;\n }\n \n this.removeScrollListener();\n this.removeExitIntentListener();\n this.removeScrollVelocityListener();\n this.removeVisibilityChangeListener();\n this.removeBackButtonListener();\n this.removeActivityListeners();\n \n this.timeOnPageTargets.forEach(timerId => clearTimeout(timerId));\n this.timeOnPageTargets.clear();\n \n this.inactivityTargets.forEach(timerId => clearTimeout(timerId));\n this.inactivityTargets.clear();\n \n if (this.inactivityCheckInterval) {\n clearInterval(this.inactivityCheckInterval);\n this.inactivityCheckInterval = undefined;\n }\n \n if (this.scrollVelocityCooldownTimer) {\n clearTimeout(this.scrollVelocityCooldownTimer);\n this.scrollVelocityCooldownTimer = undefined;\n }\n \n this.isStarted = false;\n }\n \n reset(): void {\n this.scrollDepthReached.clear();\n this.exitIntentFired = false;\n this.scrollVelocityFired = false;\n this.backButtonFired = false;\n this.pageLoadTime = Date.now();\n this.lastActivityTime = Date.now();\n this.lastScrollY = window.scrollY || 0;\n this.lastScrollTime = Date.now();\n \n if (this.scrollVelocityCooldownTimer) {\n clearTimeout(this.scrollVelocityCooldownTimer);\n this.scrollVelocityCooldownTimer = undefined;\n }\n }\n \n private attachScrollListener(): void {\n window.addEventListener('scroll', this.handleScroll, { passive: true });\n this.handleScroll();\n }\n \n private removeScrollListener(): void {\n window.removeEventListener('scroll', this.handleScroll);\n }\n \n private handleScroll = (): void => {\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;\n const scrollPercent = scrollHeight > 0 ? (scrollTop / scrollHeight) * 100 : 0;\n \n for (const targetDepth of this.scrollDepthTargets) {\n if (scrollPercent >= targetDepth && !this.scrollDepthReached.has(targetDepth)) {\n this.scrollDepthReached.add(targetDepth);\n \n this.emit(`scroll_depth_${targetDepth}`, {\n depth_percent: targetDepth,\n actual_percent: scrollPercent,\n scroll_top: scrollTop,\n scroll_height: scrollHeight\n });\n }\n }\n };\n \n private attachExitIntentListener(): void {\n document.addEventListener('mouseleave', this.handleExitIntent);\n }\n \n private removeExitIntentListener(): void {\n document.removeEventListener('mouseleave', this.handleExitIntent);\n }\n \n private handleExitIntent = (event: MouseEvent): void => {\n if (this.exitIntentFired) {\n return;\n }\n \n if (event.clientY < 10) {\n this.exitIntentFired = true;\n \n this.emit('exit_intent', {\n client_y: event.clientY,\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n }\n };\n \n private attachScrollVelocityListener(): void {\n window.addEventListener('scroll', this.handleScrollVelocity, { passive: true });\n }\n \n private removeScrollVelocityListener(): void {\n window.removeEventListener('scroll', this.handleScrollVelocity);\n }\n \n private handleScrollVelocity = (): void => {\n if (this.scrollVelocityFired) {\n return;\n }\n \n const currentY = window.scrollY || document.documentElement.scrollTop;\n const currentTime = Date.now();\n const timeDiff = currentTime - this.lastScrollTime;\n \n if (timeDiff > 100) {\n const distance = this.lastScrollY - currentY;\n const velocity = Math.abs(distance / timeDiff);\n \n if (\n distance > 0 &&\n velocity > this.scrollVelocityConfig.threshold &&\n currentY > this.scrollVelocityConfig.minScrollPosition\n ) {\n this.scrollVelocityFired = true;\n \n this.emit('mobile_exit_intent', {\n scroll_velocity: velocity,\n scroll_distance: distance,\n current_position: currentY,\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n \n this.scrollVelocityCooldownTimer = window.setTimeout(() => {\n this.scrollVelocityFired = false;\n }, this.scrollVelocityConfig.cooldown);\n }\n \n this.lastScrollY = currentY;\n this.lastScrollTime = currentTime;\n }\n };\n \n private attachVisibilityChangeListener(): void {\n document.addEventListener('visibilitychange', this.handleVisibilityChange);\n }\n \n private removeVisibilityChangeListener(): void {\n document.removeEventListener('visibilitychange', this.handleVisibilityChange);\n }\n \n private handleVisibilityChange = (): void => {\n if (document.hidden) {\n this.emit('visibility_hidden', {\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n } else {\n this.emit('visibility_visible', {\n page_url: window.location.href\n });\n }\n };\n \n private attachBackButtonListener(): void {\n if (typeof window !== 'undefined' && window.history) {\n window.history.pushState(null, '', window.location.href);\n window.addEventListener('popstate', this.handleBackButton);\n }\n }\n \n private removeBackButtonListener(): void {\n window.removeEventListener('popstate', this.handleBackButton);\n }\n \n private handleBackButton = (): void => {\n if (this.backButtonFired) {\n return;\n }\n \n this.backButtonFired = true;\n \n window.history.pushState(null, '', window.location.href);\n \n this.emit('back_button', {\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n };\n \n private attachActivityListeners(): void {\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n events.forEach(event => {\n document.addEventListener(event, this.handleActivity, { passive: true });\n });\n }\n \n private removeActivityListeners(): void {\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n events.forEach(event => {\n document.removeEventListener(event, this.handleActivity);\n });\n }\n \n private handleActivity = (): void => {\n this.lastActivityTime = Date.now();\n };\n \n private startInactivityCheck(): void {\n this.inactivityCheckInterval = window.setInterval(() => {\n const idleTime = (Date.now() - this.lastActivityTime) / 1000;\n \n for (const [idleSeconds] of this.inactivityTargets) {\n if (idleTime >= idleSeconds) {\n this.emit(`inactivity_${idleSeconds}`, {\n idle_seconds: idleSeconds,\n actual_idle_time: idleTime\n });\n \n const timerId = this.inactivityTargets.get(idleSeconds);\n if (timerId) {\n clearTimeout(timerId);\n this.inactivityTargets.delete(idleSeconds);\n }\n }\n }\n }, 1000);\n }\n \n private emit(eventType: string, data: Record<string, any>): void {\n const event: TriggerEvent = {\n type: eventType,\n data,\n timestamp: Date.now()\n };\n \n const callbacks = this.listeners.get(eventType);\n if (callbacks) {\n callbacks.forEach(callback => {\n try {\n callback(event);\n } catch (error) {\n console.error(`Error in trigger callback for ${eventType}:`, error);\n }\n });\n }\n \n const wildcardCallbacks = this.listeners.get('*');\n if (wildcardCallbacks) {\n wildcardCallbacks.forEach(callback => {\n try {\n callback(event);\n } catch (error) {\n console.error(`Error in wildcard trigger callback:`, error);\n }\n });\n }\n }\n}\n","/**\n * SDK Bootstrap\n *\n * Strict origin-assertion handshake against the control-plane. Called once\n * at SDK init — resolves writeKey → propertyId, asserts origin, and returns\n * the VAPID public key + first-party cookie id the SDK needs for the rest\n * of the session.\n *\n * A failed bootstrap (401/403) aborts SDK init — the SDK refuses to emit\n * events or request push permission against an origin it cannot prove it\n * owns.\n *\n * See docs/architecture/SUBSCRIPTION_PROPERTY_ARCHITECTURE.md §5.\n */\n\nconst COOKIE_NAME = 'aegis_fpc';\nconst COOKIE_MAX_AGE_DAYS = 365 * 2;\n\nexport interface BootstrapRequest {\n writeKey: string;\n currentOrigin?: string;\n firstPartyCookieId?: string;\n attestationToken?: string;\n userAgent?: string;\n}\n\nimport type { EventGovernanceHint } from '../governance';\n\nexport interface BootstrapResult {\n propertyId: string;\n organizationId: string;\n workspaceId: string;\n propertyType: 'shopify_store' | 'hosted_commerce' | 'custom_website' | 'mobile_app';\n vapidPublicKey: string | null;\n allowedOrigins: string[];\n pushEnabled: boolean;\n inAppEnabled: boolean;\n transportMode: string;\n firstPartyCookieId: string;\n /**\n * Event-governance hint for SDK-side unique-event-name cap enforcement.\n * Null = Enterprise plan / CP outage / org has no cap. Safe to pass\n * directly to `aegis.ingestGovernanceHint()`.\n */\n eventGovernance: EventGovernanceHint | null;\n}\n\nexport class BootstrapError extends Error {\n constructor(public readonly status: number, message: string) {\n super(message);\n this.name = 'BootstrapError';\n }\n}\n\n/**\n * Read the first-party cookie id from document.cookie. Returns null if\n * unset — caller should pass undefined so the server issues a fresh one.\n */\nexport function readFirstPartyCookie(): string | null {\n if (typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${COOKIE_NAME}=([^;]+)`));\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n/**\n * Persist the first-party cookie id returned by the server. Stored as a\n * first-party cookie (readable by JS — it's not a secret, it's a device\n * id) so that the same browser hitting a second origin on the same\n * registrable domain gets the same cookie back.\n */\nexport function writeFirstPartyCookie(cookieId: string): void {\n if (typeof document === 'undefined') return;\n const expires = new Date();\n expires.setDate(expires.getDate() + COOKIE_MAX_AGE_DAYS);\n // Derive the registrable-domain boundary where possible so the cookie is\n // shared across subdomains (e.g., shop.sweettruths.com + www.sweettruths.com).\n // We conservatively use the current host without a leading dot —\n // browsers scope the cookie to that host. For cross-registrable-domain\n // siblings (Shopify myshopify.com + actii.me), each domain gets its own\n // cookie, which is the expected per-origin behavior.\n document.cookie =\n `${COOKIE_NAME}=${encodeURIComponent(cookieId)};` +\n `expires=${expires.toUTCString()};` +\n `path=/;SameSite=Lax`;\n // Also mirror into localStorage so the SDK can read it synchronously at\n // init time even in environments where document.cookie is delayed.\n try {\n window.localStorage.setItem(COOKIE_NAME, cookieId);\n } catch {\n // private mode / storage disabled — cookie alone is sufficient\n }\n}\n\n/**\n * Perform the bootstrap handshake.\n *\n * @throws BootstrapError on 4xx — the SDK should stop init and surface the\n * error to the console. 5xx are retried once.\n */\nexport async function bootstrap(\n apiHost: string,\n req: BootstrapRequest\n): Promise<BootstrapResult> {\n const body: Record<string, unknown> = { writeKey: req.writeKey };\n if (req.currentOrigin) body.currentOrigin = req.currentOrigin;\n if (req.firstPartyCookieId) body.firstPartyCookieId = req.firstPartyCookieId;\n if (req.attestationToken) body.attestationToken = req.attestationToken;\n if (req.userAgent) body.userAgent = req.userAgent;\n\n const url = `${apiHost.replace(/\\/$/, '')}/v1/sdk/bootstrap`;\n\n const doFetch = async (): Promise<Response> =>\n fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n credentials: 'omit',\n });\n\n let resp = await doFetch();\n if (resp.status >= 500) {\n await new Promise((r) => setTimeout(r, 750));\n resp = await doFetch();\n }\n\n if (resp.status === 401) {\n throw new BootstrapError(401, 'writeKey not recognized or revoked');\n }\n if (resp.status === 403) {\n throw new BootstrapError(403, 'Origin validation failed — this writeKey is bound to a different property');\n }\n if (!resp.ok) {\n throw new BootstrapError(resp.status, `Bootstrap failed: HTTP ${resp.status}`);\n }\n\n const json = (await resp.json()) as BootstrapResult;\n writeFirstPartyCookie(json.firstPartyCookieId);\n return json;\n}\n\n/**\n * Derive a deterministic device fingerprint from the first-party cookie id\n * and a few stable UA parts. This is the value sent on every push-subscribe\n * call — its stability lets the backend UPSERT on (property_id, fingerprint)\n * across re-subscribes and VAPID rotations.\n */\nexport async function deriveDeviceFingerprint(firstPartyCookieId: string): Promise<string> {\n const ua = typeof navigator !== 'undefined' ? navigator.userAgent : '';\n const platform = typeof navigator !== 'undefined' ? (navigator.platform || '') : '';\n const language = typeof navigator !== 'undefined' ? (navigator.language || '') : '';\n const input = `${firstPartyCookieId}|${ua}|${platform}|${language}`;\n\n // Prefer subtle.crypto — available in all push-capable browsers.\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n const bytes = new TextEncoder().encode(input);\n const hash = await crypto.subtle.digest('SHA-256', bytes);\n const hex = Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return hex;\n }\n\n // Last-resort fallback — basic 32-bit FNV hash (non-cryptographic but\n // stable). Push-capable browsers always have subtle.crypto so this path\n // is practically unreachable; included only for completeness.\n let h = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return `fnv-${h.toString(16)}`;\n}\n","import { Aegis } from './core/analytics';\nimport { AegisMessageRuntime } from './runtime';\nimport { AegisPlacementManager } from './placements/AegisPlacementManager';\nimport { TriggerEngine } from './triggers';\nimport { bootstrap } from './core/bootstrap';\n\ndeclare global {\n interface Window {\n aegis: any;\n Aegis: typeof Aegis;\n AegisMessageRuntime: typeof AegisMessageRuntime;\n AegisPlacementManager: typeof AegisPlacementManager;\n TriggerEngine: typeof TriggerEngine;\n /**\n * `/v1/sdk/bootstrap` handshake. Exposed for integrations that embed the\n * CDN bundle and need to retrieve `eventGovernance`, `vapidPublicKey`, etc.\n * Added in SDK 1.4.0 alongside SDK-side event-governance.\n */\n aegisBootstrap: typeof bootstrap;\n }\n}\n\nconst globalName = 'aegis';\nconst existingQueue: any = window[globalName] || [];\n\nconst instance = new Aegis();\n\nif (Array.isArray(existingQueue)) {\n const loadOptions = (existingQueue as any)._loadOptions;\n\n existingQueue.forEach((item: any) => {\n if (!Array.isArray(item)) {\n return;\n }\n\n const [method, ...args] = item;\n\n if (typeof instance[method as keyof Aegis] === 'function') {\n try {\n (instance[method as keyof Aegis] as Function).apply(instance, args);\n } catch (error) {\n console.error(`[Aegis SDK] Error executing queued method \"${method}\":`, error);\n }\n } else {\n console.warn(`[Aegis SDK] Unknown method \"${method}\"`);\n }\n });\n\n if (loadOptions?.key) {\n instance.init(loadOptions.key, loadOptions.options).catch((error) => {\n console.error('[Aegis SDK] Initialization failed:', error);\n });\n }\n}\n\nwindow[globalName] = instance;\nwindow.Aegis = Aegis;\nwindow.AegisMessageRuntime = AegisMessageRuntime;\nwindow.AegisPlacementManager = AegisPlacementManager;\nwindow.TriggerEngine = TriggerEngine;\nwindow.aegisBootstrap = bootstrap;\n\nexport default instance;\n","/**\n * AegisMessageRuntime — unified facade for in-app messaging.\n *\n * The sole public entry point for all 20 in-app types (announce +\n * collect + assist buckets) plus the legacy gamification surface\n * (chat_bubble / toast / exit_intent_popup configured via\n * /v1/widgets/config). Under the hood it composes an\n * `AegisInAppManager` + `AegisWidgetManager`; callers never touch them\n * directly.\n *\n * Public API:\n * new AegisMessageRuntime({ writeKey, apiHost, ... })\n * await runtime.initialize()\n * await runtime.updateContactId(id)\n * runtime.onClientEvent(eventName, data)\n * runtime.destroy()\n *\n * Internal wiring: spin_wheel + scratch_card campaigns land in the\n * inbox prefetch bundle but need DOM renderers that live in\n * WidgetManager. The facade passes an `onInteractiveCampaign` callback\n * into the InAppManager constructor; the callback forwards to\n * `widgets.renderInteractiveCampaign(campaign)` — no CustomEvent bus,\n * no listeners, no registration-order bugs.\n */\n\nimport { AegisInAppManager, type AegisInAppConfig, type InAppCampaign } from '../inapp';\nimport { AegisWidgetManager, type AegisWidgetConfig } from '../widgets';\nimport { TriggerEngine } from '../triggers/TriggerEngine';\n\nexport interface AegisMessageRuntimeConfig extends AegisInAppConfig {\n /** If set, a `TriggerEngine` from the SDK is wired to the WidgetManager\n * for its exit-intent / scroll-velocity / inactivity handlers. Leave\n * undefined to have the runtime construct one internally. */\n triggerEngine?: AegisWidgetConfig['triggerEngine'];\n /** WidgetManager prefetch toggle. Defaults to true — matches the\n * existing behaviour where spin_wheel / scratch_card prefetch their\n * configs from `/v1/widgets/config/prefetch`. */\n enableWidgetPrefetch?: boolean;\n /** Source platform for gamification attribution (shopify / woocommerce\n * / magento / mobile_sdk / web). Passed through to WidgetManager. */\n sourcePlatform?: AegisWidgetConfig['sourcePlatform'];\n}\n\n/**\n * One runtime, all in-app types. Consumers should prefer this over\n * importing AegisInAppManager / AegisWidgetManager directly. Those two\n * classes remain exported for a deprecation window — see `./deprecated.ts`.\n */\nexport class AegisMessageRuntime {\n readonly inApp: AegisInAppManager;\n readonly widgets: AegisWidgetManager;\n private initialized = false;\n private ownedTriggerEngine: TriggerEngine | null = null;\n\n constructor(config: AegisMessageRuntimeConfig) {\n const triggerEngine = config.triggerEngine ?? new TriggerEngine();\n const ownsTriggerEngine = !config.triggerEngine;\n if (ownsTriggerEngine) this.ownedTriggerEngine = triggerEngine;\n\n this.widgets = new AegisWidgetManager({\n writeKey: config.writeKey,\n apiHost: config.apiHost,\n userId: config.userId,\n contactId: config.contactId,\n organizationId: config.organizationId,\n debugMode: config.debugMode,\n triggerEngine,\n ownsTriggerEngine,\n enablePrefetch: config.enableWidgetPrefetch !== false,\n sourcePlatform: config.sourcePlatform,\n });\n\n this.inApp = new AegisInAppManager({\n writeKey: config.writeKey,\n apiHost: config.apiHost,\n userId: config.userId,\n contactId: config.contactId,\n organizationId: config.organizationId,\n propertyId: config.propertyId,\n debugMode: config.debugMode,\n enableSSE: config.enableSSE,\n // Route gamification sub_types straight to the widget renderer —\n // replaces the old CustomEvent('aegis:render-widget') bridge which\n // had no listener and silently dropped impressions.\n onInteractiveCampaign: (campaign) => {\n this.widgets.renderInteractiveCampaign(campaign);\n },\n });\n }\n\n /**\n * Boots both managers in parallel. Safe to call multiple times — the\n * second + subsequent calls are no-ops.\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n this.initialized = true;\n await Promise.all([\n this.inApp.initialize(),\n this.widgets.initialize(),\n ]);\n }\n\n /**\n * Both managers carry contactId. Updates both so the server-side\n * targeting pipeline sees the identity for campaign eligibility AND\n * the widget prefetch includes per-contact segment configs. The\n * widgets call is async (may re-fetch prefetch configs) but we don't\n * wait — callers that care about the fetched state await on the\n * returned promise.\n */\n async updateContactId(contactId: string): Promise<void> {\n this.inApp.updateContactId?.(contactId);\n await this.widgets.updateContactId(contactId);\n }\n\n /**\n * Forward a client-side event (product_viewed, cart_idle_90s, etc.)\n * to the in-app manager's client-trigger evaluator. The WidgetManager\n * has its own TriggerEngine wiring (exit-intent, scroll-velocity) so\n * we don't forward there — events it cares about arrive through that\n * channel already.\n */\n onClientEvent(eventName: string, eventData: Record<string, unknown> = {}): void {\n this.inApp.onClientEvent?.(eventName, eventData);\n }\n\n /**\n * Conversion-aware suppression — call when the host app observes a\n * goal event (purchase / order_completed / checkout_completed / custom).\n *\n * Forwards to AegisInAppManager.notifyConversion() which:\n * - Persists the conversion in sessionStorage so subsequent page loads\n * in the same tab keep armed campaigns silenced.\n * - For every armed campaign whose\n * `frequency.suppress_after_conversion_seconds` is set, computes an\n * expiry epoch_ms and silences it until then.\n *\n * Storefronts integrate via the React provider's useCommerceEvents\n * helper which calls this after `ecom.orderCompleted(...)`. Direct SDK\n * users call it themselves.\n *\n * Added by Micro-Intent Engine P0a Task 6 (2026-04-30).\n */\n notifyConversion(goalName: string): void {\n this.inApp.notifyConversion?.(goalName);\n }\n\n /**\n * Tear down both managers. Used by React component unmounts + during\n * identity switches where we want a full reset. If the facade created\n * its own TriggerEngine, WidgetManager.destroy() will stop it;\n * caller-supplied engines are left alone.\n */\n destroy(): void {\n this.inApp.destroy?.();\n this.widgets.destroy();\n this.ownedTriggerEngine = null;\n this.initialized = false;\n }\n\n /**\n * Current armed campaigns visible to the InAppManager. Accessible for\n * the Prefetch Inspector and for debugging. WidgetManager's prefetched\n * spin_wheel / scratch_card configs are NOT in this list — they live\n * in `this.widgets` and have their own lifecycle.\n */\n getCampaigns(): InAppCampaign[] {\n // AegisInAppManager keeps `campaigns` as a private field. Expose it\n // via bracket access; the field is stable as of SDK 1.5.0. Once\n // Phase 7c unifies render paths this becomes a first-class getter.\n return ((this.inApp as unknown as { campaigns?: InAppCampaign[] }).campaigns) ?? [];\n }\n}\n","/**\n * AegisPlacementManager - Web SDK Placement Module\n * \n * Real-time SSE architecture for inline content placements.\n * \n * Security:\n * - XSS Protection: Uses DOMPurify (when available) with allowlisted tags/attrs; safe text-only fallback\n * - URL Validation: Prevents javascript: protocol injection\n * - CSP Compatible: No inline styles in HTML strings\n * \n * Architecture:\n * - Connects to SSE endpoint for real-time placement updates\n * - Initial fetch on load, then SSE for updates\n * - Caches placement content locally in memory\n * - Renders content into pre-defined UI slots (inline, not overlay)\n * - Tracks events (impression, click, conversion) asynchronously\n * \n * Key Differences from In-App Messages:\n * - INLINE content (part of layout), not overlays\n * - Content rendered immediately on slot registration\n * - No trigger rules (shown when slot loads)\n * - Supports banner, card, carousel, video, HTML content types\n */\n\nexport interface PlacementContent {\n placement_id: string;\n variant_id: string;\n content_type: 'banner' | 'card' | 'carousel' | 'video' | 'html' | 'dynamic_injection';\n content: Record<string, any>;\n css_selector?: string;\n injection_mode?: 'replace' | 'append' | 'prepend';\n}\n\nexport interface PlacementSlot {\n placementId: string;\n containerId: string;\n fallbackContent?: string;\n onRender?: (content: PlacementContent) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface AegisPlacementConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n debugMode?: boolean;\n enableSSE?: boolean;\n}\n\nexport class AegisPlacementManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private debugMode: boolean;\n private enableSSE: boolean;\n \n private placements: Map<string, PlacementContent> = new Map();\n private slots: Map<string, PlacementSlot> = new Map();\n private renderedSlots = new Set<string>();\n private eventSource?: EventSource;\n private isInitialized = false;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n \n constructor(config: AegisPlacementConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n this.userId = config.userId;\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.debugMode = config.debugMode || false;\n this.enableSSE = config.enableSSE !== false;\n }\n \n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisPlacements already initialized');\n return;\n }\n \n await this.refreshPlacements();\n \n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n \n this.isInitialized = true;\n this.log('AegisPlacements initialized successfully');\n }\n \n register(placementId: string, options: Omit<PlacementSlot, 'placementId'>): void {\n const slot: PlacementSlot = {\n placementId,\n ...options\n };\n \n this.slots.set(placementId, slot);\n this.log(`Registered placement slot: ${placementId}`);\n \n const existingContent = this.placements.get(placementId);\n if (existingContent) {\n this.renderSlot(slot, existingContent);\n } else if (options.fallbackContent) {\n this.renderFallback(slot);\n }\n }\n \n unregister(placementId: string): void {\n this.slots.delete(placementId);\n this.renderedSlots.delete(placementId);\n this.log(`Unregistered placement slot: ${placementId}`);\n }\n \n async refreshPlacements(): Promise<void> {\n try {\n const placementIds = Array.from(this.slots.keys());\n \n if (placementIds.length === 0) {\n this.log('No registered slots, skipping refresh');\n return;\n }\n \n const url = `${this.apiHost}/v1/placements/content?placement_ids=${placementIds.join(',')}`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Type': this.getDeviceType(),\n 'X-Platform': 'web'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, { headers });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch placements: ${response.status}`);\n }\n \n const data = await response.json();\n \n this.placements.clear();\n \n for (const placement of data.placements || []) {\n this.placements.set(placement.placement_id, placement);\n }\n \n this.renderAllSlots();\n \n this.log(`Refreshed ${this.placements.size} placements`);\n \n } catch (error) {\n this.log(`Error refreshing placements: ${error}`, true);\n }\n }\n \n private renderAllSlots(): void {\n for (const [placementId, slot] of this.slots.entries()) {\n const content = this.placements.get(placementId);\n \n if (content) {\n this.renderSlot(slot, content);\n } else if (slot.fallbackContent) {\n this.renderFallback(slot);\n }\n }\n }\n \n private renderSlot(slot: PlacementSlot, content: PlacementContent): void {\n try {\n if (content.content_type === 'dynamic_injection') {\n this.renderDynamicInjection(content);\n } else {\n const container = document.getElementById(slot.containerId);\n \n if (!container) {\n this.log(`Container not found: ${slot.containerId}`, true);\n return;\n }\n \n container.innerHTML = '';\n \n switch (content.content_type) {\n case 'banner':\n this.renderBanner(container, content);\n break;\n case 'card':\n this.renderCard(container, content);\n break;\n case 'carousel':\n this.renderCarousel(container, content);\n break;\n case 'video':\n this.renderVideo(container, content);\n break;\n case 'html':\n this.renderHTML(container, content);\n break;\n default:\n this.log(`Unknown content type: ${content.content_type}`, true);\n return;\n }\n }\n \n if (!this.renderedSlots.has(slot.placementId)) {\n this.trackEvent(content.placement_id, content.variant_id, 'impression');\n this.renderedSlots.add(slot.placementId);\n }\n \n if (slot.onRender) {\n slot.onRender(content);\n }\n \n this.log(`Rendered placement: ${content.placement_id} (${content.content_type})`);\n \n } catch (error) {\n this.log(`Error rendering placement: ${error}`, true);\n \n if (slot.onError) {\n slot.onError(error as Error);\n }\n }\n }\n \n private renderBanner(container: HTMLElement, content: PlacementContent): void {\n const { title, body, image_url, cta_text, cta_url, background_color, text_color } = content.content;\n \n const banner = document.createElement('div');\n banner.className = 'aegis-placement-banner';\n banner.style.cssText = `\n background: ${this.sanitizeColor(background_color || '#1a73e8')};\n color: ${this.sanitizeColor(text_color || '#ffffff')};\n padding: 24px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n gap: 16px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 80px; height: 80px; border-radius: 8px; object-fit: cover;';\n banner.appendChild(img);\n }\n }\n \n const textContainer = document.createElement('div');\n textContainer.style.cssText = 'flex: 1;';\n \n if (title) {\n const titleEl = document.createElement('div');\n titleEl.textContent = title;\n titleEl.style.cssText = 'font-size: 18px; font-weight: 600; margin-bottom: 8px;';\n textContainer.appendChild(titleEl);\n }\n \n if (body) {\n const bodyEl = document.createElement('div');\n bodyEl.textContent = body;\n bodyEl.style.cssText = 'font-size: 14px; opacity: 0.9;';\n textContainer.appendChild(bodyEl);\n }\n \n banner.appendChild(textContainer);\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: white;\n color: ${this.sanitizeColor(background_color || '#1a73e8')};\n border: none;\n padding: 12px 24px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n white-space: nowrap;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n banner.appendChild(ctaButton);\n }\n \n container.appendChild(banner);\n }\n \n private renderCard(container: HTMLElement, content: PlacementContent): void {\n const { title, body, image_url, cta_text, cta_url } = content.content;\n \n const card = document.createElement('div');\n card.className = 'aegis-placement-card';\n card.style.cssText = `\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = title || '';\n img.style.cssText = 'width: 100%; height: 200px; object-fit: cover;';\n card.appendChild(img);\n }\n }\n \n const cardBody = document.createElement('div');\n cardBody.style.cssText = 'padding: 20px;';\n \n if (title) {\n const titleEl = document.createElement('h3');\n titleEl.textContent = title;\n titleEl.style.cssText = 'margin: 0 0 12px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n cardBody.appendChild(titleEl);\n }\n \n if (body) {\n const bodyEl = document.createElement('p');\n bodyEl.textContent = body;\n bodyEl.style.cssText = 'margin: 0 0 16px 0; font-size: 14px; color: #666; line-height: 1.5;';\n cardBody.appendChild(bodyEl);\n }\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 10px 20px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n cardBody.appendChild(ctaButton);\n }\n \n card.appendChild(cardBody);\n container.appendChild(card);\n }\n \n private renderCarousel(container: HTMLElement, content: PlacementContent): void {\n const { items } = content.content;\n \n if (!Array.isArray(items) || items.length === 0) {\n this.log('Carousel items empty or invalid', true);\n return;\n }\n \n const carousel = document.createElement('div');\n carousel.className = 'aegis-placement-carousel';\n carousel.style.cssText = `\n display: flex;\n gap: 16px;\n overflow-x: auto;\n padding: 8px 0;\n scroll-behavior: smooth;\n -webkit-overflow-scrolling: touch;\n `;\n \n for (const item of items) {\n const carouselItem = document.createElement('div');\n carouselItem.style.cssText = `\n flex: 0 0 250px;\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n overflow: hidden;\n cursor: pointer;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (item.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(item.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = item.title || '';\n img.style.cssText = 'width: 100%; height: 150px; object-fit: cover;';\n carouselItem.appendChild(img);\n }\n }\n \n const itemContent = document.createElement('div');\n itemContent.style.cssText = 'padding: 12px;';\n \n if (item.title) {\n const title = document.createElement('div');\n title.textContent = item.title;\n title.style.cssText = 'font-size: 14px; font-weight: 600; margin-bottom: 4px; color: #1a1a1a;';\n itemContent.appendChild(title);\n }\n \n if (item.price) {\n const price = document.createElement('div');\n price.textContent = item.price;\n price.style.cssText = 'font-size: 16px; font-weight: 700; color: #1a73e8;';\n itemContent.appendChild(price);\n }\n \n carouselItem.appendChild(itemContent);\n \n if (item.url) {\n carouselItem.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click', { item_index: items.indexOf(item) });\n const safeUrl = this.sanitizeUrl(item.url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n }\n \n carousel.appendChild(carouselItem);\n }\n \n container.appendChild(carousel);\n }\n \n private renderVideo(container: HTMLElement, content: PlacementContent): void {\n const { video_url, poster_url, autoplay, muted } = content.content;\n \n if (!video_url) {\n this.log('Video URL missing', true);\n return;\n }\n \n const safeVideoUrl = this.sanitizeUrl(video_url);\n if (!safeVideoUrl) {\n this.log('Invalid video URL', true);\n return;\n }\n \n const video = document.createElement('video');\n video.src = safeVideoUrl;\n video.controls = true;\n video.autoplay = autoplay || false;\n video.muted = muted || false;\n video.style.cssText = 'width: 100%; border-radius: 8px;';\n \n if (poster_url) {\n const safePosterUrl = this.sanitizeUrl(poster_url);\n if (safePosterUrl) {\n video.poster = safePosterUrl;\n }\n }\n \n video.addEventListener('play', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click', { action: 'video_play' });\n });\n \n container.appendChild(video);\n }\n \n private renderHTML(container: HTMLElement, content: PlacementContent): void {\n const { html } = content.content;\n \n if (!html) {\n this.log('HTML content missing', true);\n return;\n }\n \n const wrapper = document.createElement('div');\n wrapper.className = 'aegis-placement-html';\n wrapper.innerHTML = this.sanitizeHTML(html);\n \n const links = wrapper.querySelectorAll('a');\n links.forEach((link) => {\n link.addEventListener('click', (e) => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n });\n });\n \n container.appendChild(wrapper);\n }\n \n private renderDynamicInjection(content: PlacementContent): void {\n const { html } = content.content;\n const cssSelector = content.css_selector;\n const injectionMode = content.injection_mode || 'replace';\n \n if (!cssSelector) {\n this.log('CSS selector missing for dynamic injection', true);\n return;\n }\n \n if (!html) {\n this.log('HTML content missing for dynamic injection', true);\n return;\n }\n \n let targetElement: HTMLElement | null = null;\n \n try {\n targetElement = document.querySelector(cssSelector);\n } catch (error) {\n this.log(`Invalid CSS selector: ${cssSelector}`, true);\n return;\n }\n \n if (!targetElement) {\n this.log(`Target element not found for selector: ${cssSelector}`, true);\n return;\n }\n \n const wrapper = document.createElement('div');\n wrapper.className = 'aegis-dynamic-injection';\n wrapper.setAttribute('data-placement-id', content.placement_id);\n wrapper.setAttribute('data-variant-id', content.variant_id);\n wrapper.innerHTML = this.sanitizeHTML(html);\n \n const links = wrapper.querySelectorAll('a');\n links.forEach((link) => {\n link.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n });\n });\n \n switch (injectionMode) {\n case 'replace':\n targetElement.innerHTML = '';\n targetElement.appendChild(wrapper);\n this.log(`Replaced content in ${cssSelector}`, false);\n break;\n \n case 'append':\n targetElement.appendChild(wrapper);\n this.log(`Appended content to ${cssSelector}`, false);\n break;\n \n case 'prepend':\n targetElement.insertBefore(wrapper, targetElement.firstChild);\n this.log(`Prepended content to ${cssSelector}`, false);\n break;\n \n default:\n this.log(`Unknown injection mode: ${injectionMode}`, true);\n return;\n }\n \n this.log(`Dynamically injected content for ${content.placement_id} into ${cssSelector} (${injectionMode})`);\n }\n \n private renderFallback(slot: PlacementSlot): void {\n if (!slot.fallbackContent) return;\n \n const container = document.getElementById(slot.containerId);\n if (!container) return;\n \n container.innerHTML = slot.fallbackContent;\n this.log(`Rendered fallback content for: ${slot.placementId}`);\n }\n \n private async trackEvent(\n placementId: string,\n variantId: string,\n eventType: 'impression' | 'click' | 'conversion',\n metadata: Record<string, any> = {}\n ): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/placements/track`;\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Type': this.getDeviceType(),\n 'X-Platform': 'web'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const body = {\n placement_id: placementId,\n variant_id: variantId,\n event_type: eventType,\n metadata: {\n device_type: this.getDeviceType(),\n platform: 'web',\n ...metadata\n }\n };\n \n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body)\n }).catch(err => this.log(`Track event failed: ${err}`, true));\n \n this.log(`Tracked ${eventType}: ${placementId}`);\n \n } catch (error) {\n this.log(`Error tracking event: ${error}`, true);\n }\n }\n \n private connectSSE(): void {\n if (this.eventSource) {\n this.disconnectSSE();\n }\n \n if (!this.organizationId) {\n this.log('Cannot connect SSE without organization ID', true);\n return;\n }\n \n const url = new URL('/v1/stream/realtime', this.apiHost);\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Organization-ID': this.organizationId,\n };\n \n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n \n const queryParams = new URLSearchParams();\n Object.entries(headers).forEach(([key, value]) => {\n queryParams.append(key, value);\n });\n \n this.eventSource = new EventSource(`${url}?${queryParams.toString()}`);\n \n this.eventSource.addEventListener('open', () => {\n this.log('SSE connection established');\n this.reconnectAttempts = 0;\n });\n \n this.eventSource.addEventListener('placement_content_updated', (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data);\n this.log(`Received placement content update: ${data.placement_id}`);\n this.refreshPlacements();\n } catch (error) {\n this.log(`Error parsing SSE event: ${error}`, true);\n }\n });\n \n this.eventSource.addEventListener('heartbeat', (event: MessageEvent) => {\n this.log('SSE heartbeat received');\n });\n \n this.eventSource.addEventListener('error', (error) => {\n this.log('SSE connection error', true);\n \n if (this.eventSource?.readyState === EventSource.CLOSED) {\n this.attemptReconnect();\n }\n });\n }\n \n private disconnectSSE(): void {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = undefined;\n this.log('SSE connection closed');\n }\n }\n \n private attemptReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n this.log('Max reconnect attempts reached, giving up', true);\n return;\n }\n \n this.reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);\n \n this.log(`Reconnecting SSE in ${delay}ms (attempt ${this.reconnectAttempts})`);\n \n setTimeout(() => {\n if (this.isInitialized && this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n }, delay);\n }\n \n private getDeviceType(): string {\n const width = window.innerWidth;\n if (width < 768) return 'mobile_web';\n if (width < 1024) return 'tablet_web';\n return 'desktop_web';\n }\n \n private sanitizeUrl(url: string): string | null {\n try {\n const parsed = new URL(url, window.location.href);\n \n if (parsed.protocol === 'javascript:' || parsed.protocol === 'data:') {\n this.log(`Blocked unsafe URL protocol: ${parsed.protocol}`, true);\n return null;\n }\n \n return parsed.href;\n } catch {\n this.log(`Invalid URL: ${url}`, true);\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n const hexPattern = /^#[0-9A-Fa-f]{3,6}$/;\n const rgbPattern = /^rgba?\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*(,\\s*[\\d.]+\\s*)?\\)$/;\n const namedColors = ['white', 'black', 'red', 'blue', 'green', 'yellow', 'transparent'];\n \n if (hexPattern.test(color) || rgbPattern.test(color) || namedColors.includes(color.toLowerCase())) {\n return color;\n }\n \n this.log(`Invalid color: ${color}`, true);\n return '#000000';\n }\n \n private sanitizeHTML(html: string): string {\n // Use DOMPurify if available (recommended for production)\n const purify = (window as unknown as Record<string, unknown>).DOMPurify as\n | { sanitize: (dirty: string, cfg?: Record<string, unknown>) => string }\n | undefined;\n\n if (purify?.sanitize) {\n return purify.sanitize(html, {\n ALLOWED_TAGS: [\n 'a', 'b', 'br', 'div', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'i', 'img', 'li', 'ol', 'p', 'span', 'strong', 'u', 'ul', 'table',\n 'thead', 'tbody', 'tr', 'th', 'td', 'blockquote', 'hr', 'figure',\n 'figcaption', 'picture', 'source', 'video', 'section', 'article',\n ],\n ALLOWED_ATTR: [\n 'href', 'target', 'rel', 'src', 'alt', 'width', 'height', 'class',\n 'id', 'style', 'title', 'loading', 'srcset', 'sizes', 'type',\n 'media', 'controls', 'poster',\n ],\n ALLOW_DATA_ATTR: false,\n });\n }\n\n // Built-in fallback: strip all tags via DOM parsing, then re-allow safe subset\n this.log(\n 'DOMPurify not found — falling back to built-in sanitizer. ' +\n 'For full HTML placement support, add <script src=\"https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.4/purify.min.js\"></script>',\n false\n );\n const tempDiv = document.createElement('div');\n tempDiv.textContent = html;\n return tempDiv.innerHTML;\n }\n \n private log(message: string, isError = false): void {\n if (this.debugMode || isError) {\n console[isError ? 'error' : 'log'](`[AegisPlacements] ${message}`);\n }\n }\n \n destroy(): void {\n this.disconnectSSE();\n this.slots.clear();\n this.placements.clear();\n this.renderedSlots.clear();\n this.isInitialized = false;\n this.log('AegisPlacements destroyed');\n }\n}\n"],"names":["DEFAULT_CONFIG","workspace_id","batch_size","batch_interval","capture_utm","capture_referrer","auto_page_view","session_timeout","debug","respect_dnt","cross_domain_tracking","secure_cookie","enable_offline_mode","max_offline_events","retry_failed_requests","max_retries","retry_backoff_multiplier","request_timeout","rate_limit_burst","rate_limit_per_second","auto_region_detection","wait_for_consent","enable_consent_mode","integrate_onetrust","integrate_cookiebot","integrate_google_consent_mode","default_consent","analytics","marketing","functional","initialized","api_host","cell_endpoints","preferred_region","cookie_domain","plugins","active_cell","generateUUID","crypto","randomUUID","replace","c","r","Math","random","toString","generateMessageId","Date","now","slice","logger","constructor","this","enabled","prefix","enable","disable","isEnabled","message","args","info","console","warn","error","Identity","storage","userId","traits","anonymousId","getOrCreateAnonymousId","loadUserIdentity","id","get","set","storedUserId","storedTraits","JSON","parse","getAnonymousId","setUserId","setTraits","getUserId","stringify","getTraits","reset","remove","alias","newUserId","previousId","getState","SessionManager","sessionTimeoutMinutes","eventCount","checkInterval","activityThrottle","lastActivityUpdate","adClickIDs","sessionTimeout","lastActivityTime","sessionStartTime","session","loadSession","sessionId","startTime","landingPage","createNewSession","startActivityTracking","startExpiryCheck","sessionData","newSessionId","persistSession","activityHandler","onActivity","forEach","event","window","addEventListener","passive","document","visibilityState","setInterval","checkSessionExpiry","getSessionId","incrementEventCount","getSessionDuration","getEventCount","setAdClickIDs","Object","keys","length","getAdClickIDs","getLandingPage","destroy","clearInterval","EventQueue","config","transport","buffer","flushInterval","isFlushing","offlineQueue","isOnline","navigator","onLine","enableOfflineMode","loadOfflineQueue","setupOnlineListener","startFlushTimer","setupUnloadHandlers","offlineData","events","Array","isArray","maxOfflineEvents","flushOfflineQueue","saveOfflineQueue","data","flush","send","success","push","type","batchSize","addToOfflineQueue","shift","result","unshift","batchInterval","flushBeforeUnload","persistBufferToOfflineQueue","getQueueSize","getOfflineQueueSize","clear","Transport","activeCell","healthCheckInterval","regionLatencyMap","Map","cellEndpoints","initializeCellularArchitecture","cachedCell","loadCachedCell","isCellHealthy","selectOptimalCell","startHealthChecks","cached","saveCachedCell","cell","healthy","some","region","url","preferredRegion","preferredCell","find","autoRegionDetection","detectOptimalRegion","selectCellByPriority","healthyCells","filter","latencyPromises","map","async","latency","measureLatency","results","Promise","all","sort","a","b","optimalCell","performance","controller","AbortController","timeoutId","setTimeout","abort","response","fetch","method","signal","clearTimeout","ok","Infinity","sortedCells","priority","performHealthChecks","healthPromises","isHealthy","checkCellHealth","endpoint","getActiveEndpoint","payload","buildPayload","sendBeacon","sendViaBeacon","resolve","sendViaFetch","apiHost","Error","batch","sentAt","toISOString","writeKey","context","blob","Blob","attempt","requestTimeout","headers","Authorization","body","keepalive","json","errorText","text","status","statusText","shouldRetry","retryRequest","statusCode","retryFailedRequests","maxRetries","delay","pow","retryBackoffMultiplier","getActiveCell","getRegionLatencies","STORAGE_PREFIX","Storage","options","useLocalStorage","isLocalStorageAvailable","test","localStorage","setItem","removeItem","key","value","expiryDays","fullKey","item","expiry","setCookie","itemStr","getItem","getCookie","deleteCookie","startsWith","cookie","split","trim","name","days","date","setTime","getTime","cookieStr","toUTCString","secureCookie","location","protocol","cookieDomain","crossDomain","domain","getRootDomain","nameEQ","ca","i","charAt","substring","indexOf","hostname","parts","join","buildContext","utm","searchParams","URL","URLSearchParams","search","parseUTMParameters","device","ua","userAgent","detectDevice","os","version","match","detectOS","browser","detectBrowser","network","connection","mozConnection","webkitConnection","effectiveType","downlink","rtt","detectNetworkInfo","library","page","path","pathname","referrer","title","href","hash","locale","language","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","screen","width","height","density","devicePixelRatio","viewport","innerWidth","innerHeight","campaign","PluginRegistry","register","plugin","has","unregister","pluginName","delete","getAll","from","values","executeHook","hookName","hook","apply","String","onError","onErrorError","executeHookChain","initialValue","additionalArgs","executeHookParallel","promises","promise","ConsentManager","listeners","defaultConsent","waitForConsent","consentStorageKey","preferences","loadPreferences","stored","parsed","mergeWithDefaults","getDefaultPreferences","necessary","savePreferences","setConsent","updated","notifyListeners","grantAll","denyAll","hasConsent","category","getPreferences","getStatus","isAnalyticsEnabled","isMarketingEnabled","onChange","callback","index","splice","listener","integrateOneTrust","OneTrust","syncWithOneTrust","activeGroups","OnetrustActiveGroups","includes","OptanonWrapper","originalWrapper","integrateCookiebot","cookiebot","Cookiebot","syncWithCookiebot","consent","statistics","integrateGoogleConsentMode","gtag","updateGoogleConsent","ad_storage","analytics_storage","ad_user_data","ad_personalization","functionality_storage","personalization_storage","security_storage","sumItems","products","reduce","sum","p","quantity","mapProducts","product_id","sku","price","currency","brand","variant_id","variant_label","position","EcommerceTracker","aegis","productViewed","product","track","image_url","productListViewed","list","list_id","list_name","productClicked","source","section","productImpressed","categoryFiltered","previous_category","result_count","searchPerformed","query","results_count","filters","addToCart","removeFromCart","cartViewed","cart","cart_id","num_items","checkoutStarted","checkout","checkout_id","coupon","shipping","tax","checkoutStep","step","orderCompleted","order","order_id","revenue","discount","payment_method","orderRefunded","orderId","couponApplied","couponRemoved","wishlistItemAdded","wishlist","wishlist_id","wishlist_name","promotionViewed","promo","promotionClicked","RateLimiter","droppedThisWindow","firstDroppedName","windowFlushTimer","capacity","max","burstCapacity","refillPerSecond","windowMs","dropCoalesceWindowMs","onDropBatch","tokens","lastRefillMs","tryConsume","eventName","refill","flushWindow","getAvailableTokens","floor","elapsedSec","newTokens","min","err","C1","C2","murmurhash3_x86_32","input","seed","bytes","len","nBlocks","h1","offset","k1","imul","tailStart","tailLen","murmurhash3_bytes","TextEncoder","encode","BloomFilter","buf","params","m","mask","fromBase64","bloomB64","b64","atob","bin","out","Uint8Array","charCodeAt","B","globalThis","Buffer","base64ToBytes","seedA","h2","seedB","k","idx","NameGovernor","bloom","remainingNewNames","graceActive","localNovelNames","Set","droppedSinceLastReport","reportWindowStart","hasWarnedThisSession","ingestHint","hint","bloom_algo","bloom_b64","seed_a","seed_b","remaining_new_names","grace_active","shouldSend","add","prev","drainDropReport","size","total","count","since","_debugState","hasBloom","remaining","localNovel","Aegis","queue","initPromise","_ecommerce","rateLimiter","nameGovernor","_lastPageUrl","_popstateHandler","_originalPushState","_originalReplaceState","init","_init","_a","shouldRespectDNT","toLowerCase","pattern","isBot","buildConfig","identity","captureAdClickIDsOnInit","write_key","sampleName","emitRateLimitMeta","initializePlugins","startSPATracking","onRouteChange","currentUrl","history","pushState","bind","replaceState","stopSPATracking","removeEventListener","dnt","doNotTrack","msDoNotTrack","parseAdClickIDs","hasAdClickIDs","use","catch","properties","assertInitialized","messageId","timestamp","captureEvent","identify","group","groupId","trackEvent","eventLabel","ctx","props","campaign_id","campaign_source","medium","campaign_medium","content","campaign_content","term","campaign_term","clicks","clickId","gclid","fbclid","ctwa_clid","msclkid","ttclid","campaign_click_id","transformedEvent","sampleEventName","dropped_count","sample_event_name","burst_capacity","refill_per_second","_b","ingestGovernanceHint","emitGovernanceDropMeta","report","distinct_names","sample_names","entries","window_start","window_end","setCell","cellEndpoint","existingCell","assign","getCellInfo","latencies","grantConsent","denyConsent","getConsentPreferences","onConsentChange","ecommerce","renderCarouselCards","sanitizeUrl","sanitizeColor","log","addAnimationStyles","ic","interactive_config","cards","autoplay","Number","autoplay_ms","loop","bg","background_color","fg","text_color","overlay","createElement","className","setAttribute","style","cssText","card","header","headerText","textContent","appendChild","closeBtn","msOverflowStyle","e","abs","deltaX","deltaY","scrollLeft","tile","cta_url","img","safe","src","alt","loading","t","cta_text","cta","goto","stopPropagation","dots","dotEls","dot","setActive","d","opacity","activeIdx","tiles","querySelectorAll","autoplayTimer","next","el","scrollIntoView","behavior","inline","block","approx","round","DISMISS_STORAGE_PREFIX","renderProgressBar","goalType","progress_goal_type","threshold","progress_threshold","rewardText","progress_reward_text","progress_source","fill","bar","label","leading","numeric","shell","fillEl","footnote","lastFiredUnlock","update","cur","__aegisProgressSSE","win","Shopify","v","parseFloat","total_price","aegis_cart","cart_items","cart_total","cacheStr","subtotalAmount","items","readCurrentValue","pct","toFixed","pollTimer","cleanup","once","RESUME_PREFIX","writeResumeIdx","resumeKey","renderCoachmarkTour","resume_key","steps","allowSkip","allow_skip","showDots","show_progress_dots","current","raw","n","parseInt","isFinite","readResumeIdx","pointerEl","tipEl","highlightEl","cleanupOne","finish","opts","skipped","showStep","selector","anchor_web","anchor","querySelector","rect","getBoundingClientRect","top","left","placement","titleEl","bodyEl","controls","_","buttons","skip","isLast","tipRect","bottom","right","aegisResetTour","clearResume","_AegisInAppManager","campaigns","displayedCampaigns","suppressedUntil","isInitialized","reconnectAttempts","maxReconnectAttempts","readAnonIdFromStorage","contactId","organizationId","propertyId","debugMode","enableSSE","onInteractiveCampaign","initialize","refreshCampaigns","connectSSE","updateUserId","updateContactId","disconnectSSE","notifyConversion","goalName","ts","sessionStorage","CONVERSION_STORAGE_PREFIX","applySuppressionFromCampaigns","convertedAt","seconds","frequency","suppress_after_conversion_seconds","scope","expiresAt","existing","rehydrateSuppressionFromStorage","earliestTs","isSuppressed","campaignId","eventSource","queryParams","append","EventSource","readyState","CLOSED","attemptReconnect","close","device_type","detectDeviceType","page_url","isNewUser","abAssignments","getABAssignments","btoa","credentials","processABAssignments","tryDisplayNextCampaign","assigned_variant_id","getVariantId","client_trigger","displayCampaign","onClientEvent","eventData","matchesClientTrigger","trigger","cfg","wantedRaw","wanted","actual","productId","interactiveSubTypes","sub_type","renderInteractive","renderModal","renderBanner","renderFullScreen","renderHalfInterstitial","renderAlert","renderPIP","renderTooltip","buildRenderContext","sticky_position","dismissible","sticky_dismissible","autoHide","sticky_auto_hide_ms","sticky_bg_color","positionCss","strong","createTextNode","action_url","button_text","autoHideTimer","persist","renderStickyBar","layout","rec_layout","ctaDefault","rec_cta_text","accent","sheet","handle","grid","isRow","metadata","go","target","renderProductRecommendation","evt","color","msg","level","renderNPSSurvey","renderCountdownOffer","renderStarRating","renderQuickPoll","renderQuiz","createOverlay","modal","question","nps_question","scale","btn","labels","notLikely","veryLikely","addCloseButton","countdown_label","digits","digitStyle","val","targetStr","countdown_target","diff","h","padStart","s","spans","requestAnimationFrame","desc","createCTAButton","stars","maxStars","rating_scale","star","transform","poll_options","optionsList","opt","optBtn","questions","currentQ","renderQuestion","childNodes","removeChild","lastChild","thank_you_message","q","progress","questionText","optionsDiv","safeUrl","open","container","removeModal","banner","contentContainer","textContainer","actionsContainer","ctaButton","removeBanner","closeButton","actions","alert","buttonContainer","cancelButton","pip","video_url","video","muted","animation","parentNode","cursor","anchorSelector","tooltip_anchor_selector","preferredPosition","tooltip_position","textColor","tooltip","arrow","dismiss","anchorRect","tooltipRect","scrollX","scrollY","arrowTop","arrowLeft","arrowBottom","arrowRight","outsideClickHandler","contains","getElementById","head","parsedUrl","origin","eventType","externalEventId","event_type","user_id","contact_id","anonymous_id","platform","property_id","idempotency_key","styles","clearABState","AegisInAppManager","AegisWidgetManager","widgets","renderedWidgets","isDestroyed","prefetchWidgetConfigs","triggerEngine","ownsTriggerEngine","enablePrefetch","cssCustomization","onEvent","sourcePlatform","updateCSSCustomization","customization","fetchPrefetchConfigs","preloadWidgetAssets","renderInteractiveCampaign","subType","widget","widget_id","widget_type","renderSpinWheel","renderScratchCard","stop","animationStyle","node","emitEvent","fetchWidgets","renderImmediateWidgets","setupTriggerListeners","setupExitIntentWithPrefetch","setCartData","cartData","cart_currency","detectPlatformCart","shopifyCart","normalizeShopifyCart","wooCart","normalizeWooCart","magentoCart","normalizeMagentoCart","token","line_items","product_name","product_title","cartJsonEl","mageCacheStr","mageCache","quote_id","subtotal","currencyCode","item_id","qty","product_price_value","exitIntentConfig","exit_intent","imageUrl","Image","spinWheelConfig","spin_wheel","elapsed","getDeviceType","w","trigger_rules","renderWidget","registerExitIntent","on","depthPercent","depth_percent","registerScrollDepth","registerTimeOnPage","isMobile","isMobileDevice","mobileConfig","mobile_triggers","handleSpinWheelIntent","widgetId","detectedCart","renderSpinWheelWidget","sendCartAbandonmentBeacon","scroll_velocity","registerScrollVelocity","scroll_threshold","minScrollPosition","scroll_min_position","cooldown","scroll_cooldown","idle_timer","idleSeconds","idle_seconds","registerInactivity","visibility_change","registerVisibilityChange","back_button","registerBackButton","handleExitIntent","renderCartRecoveryPopup","renderLeadGenPopup","beaconData","organization_id","user_email","abandoned_at","beaconUrl","renderChatBubble","renderToast","renderFeedbackForm","renderExitIntentPopup","icon_url","link_url","bubble","positionStyles","bottom_right","bottom_left","top_right","top_left","icon","textEl","description","segments","SVG_NS","wheel","createElementNS","anglePer","PI","radius","start","end","x1","cos","y1","sin","x2","y2","largeArc","labelAngle","lx","ly","spinButton","disabled","prize","generatePrize","config_id","showPrizeResult","spinWheel","accentColor","accent_color","backgroundColor","buttonColor","button_color","wheelColors","innerHTML","onclick","interpolateCartVariables","subtitle","wheelContainer","form","phoneInput","placeholder","required","emailInput","nameInput","submitButton","errorMessage","preventDefault","phone","email","validatePhone","validateEmail","display","submitSpinWheel","showSpinWheelPrize","prize_label","has_email","geoRegion","detectGeoRegion","deviceType","utmParams","getUTMParams","cart_token","_c","_d","_e","cart_url","geo_region","session_id","utm_source","utm_medium","utm_campaign","resultContainer","emoji","prizeLabel","coupon_code","couponContainer","couponLabel","couponCode","parentElement","canvas","getContext","fillStyle","fillRect","font","textAlign","fillText","isScratching","scratch","x","y","globalCompositeOperation","beginPath","arc","clientX","clientY","scratchButton","duration","toast","iconEl","messageEl","textareaLabel","textarea","rows","submitFeedback","score","comment","descEl","configId","event_data","titleText","messageText","show_cart_items","cartItems","cartTitle","itemDiv","discount_code","discountBox","discount_percentage","show_timer","timer_minutes","timer","checkoutUrl","tier","template","isError","TriggerEngine","isStarted","scrollDepthTargets","scrollDepthReached","timeOnPageTargets","exitIntentEnabled","exitIntentFired","inactivityTargets","scrollVelocityEnabled","scrollVelocityFired","scrollVelocityConfig","lastScrollY","lastScrollTime","visibilityChangeEnabled","backButtonEnabled","backButtonFired","handleScroll","scrollTop","pageYOffset","documentElement","scrollHeight","scrollPercent","targetDepth","emit","actual_percent","scroll_top","scroll_height","client_y","time_on_page","pageLoadTime","handleScrollVelocity","currentY","currentTime","timeDiff","distance","velocity","scroll_distance","current_position","scrollVelocityCooldownTimer","handleVisibilityChange","hidden","handleBackButton","handleActivity","off","callbacks","timerId","idleTime","actual_idle_time","attachScrollListener","attachExitIntentListener","attachScrollVelocityListener","attachVisibilityChangeListener","attachBackButtonListener","attachActivityListeners","startInactivityCheck","removeScrollListener","removeExitIntentListener","removeScrollVelocityListener","removeVisibilityChangeListener","removeBackButtonListener","removeActivityListeners","inactivityCheckInterval","wildcardCallbacks","COOKIE_NAME","BootstrapError","super","globalName","existingQueue","instance","loadOptions","_loadOptions","AegisMessageRuntime","ownedTriggerEngine","enableWidgetPrefetch","inApp","call","getCampaigns","AegisPlacementManager","placements","slots","renderedSlots","refreshPlacements","placementId","slot","existingContent","renderSlot","fallbackContent","renderFallback","placementIds","placement_id","renderAllSlots","content_type","renderDynamicInjection","containerId","renderCard","renderCarousel","renderVideo","renderHTML","onRender","cardBody","carousel","carouselItem","itemContent","item_index","poster_url","safeVideoUrl","safePosterUrl","poster","action","html","wrapper","sanitizeHTML","link","cssSelector","css_selector","injectionMode","injection_mode","targetElement","insertBefore","firstChild","variantId","purify","DOMPurify","sanitize","ALLOWED_TAGS","ALLOWED_ATTR","ALLOW_DATA_ATTR","tempDiv","aegisBootstrap","req","currentOrigin","firstPartyCookieId","attestationToken","doFetch","resp","cookieId","expires","setDate","getDate","encodeURIComponent","writeFirstPartyCookie"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"aegis.min.js","sources":["../src/types/config.ts","../src/utils/uuid.ts","../src/utils/logger.ts","../src/utils/identity.ts","../src/core/session.ts","../src/core/queue.ts","../src/core/transport.ts","../src/utils/storage.ts","../src/utils/device.ts","../src/utils/url-parser.ts","../src/plugins/registry.ts","../src/utils/consent.ts","../src/ecommerce/index.ts","../src/core/rate-limiter.ts","../src/governance/murmur3.ts","../src/governance/bloom-filter.ts","../src/governance/name-governor.ts","../src/core/analytics.ts","../src/inapp/renderers/carousel-cards.ts","../src/inapp/renderers/sticky-bar.ts","../src/inapp/renderers/progress-bar.ts","../src/inapp/renderers/coachmark-tour.ts","../src/inapp/AegisInAppManager.ts","../src/inapp/renderers/product-recommendation.ts","../src/widgets/AegisWidgetManager.ts","../src/triggers/TriggerEngine.ts","../src/core/bootstrap.ts","../src/cdn.ts","../src/runtime/AegisMessageRuntime.ts","../src/placements/AegisPlacementManager.ts"],"sourcesContent":["export type CellRegion = 'us-east' | 'us-west' | 'eu-central' | 'ap-south' | 'ap-southeast';\n\nexport interface CellEndpoint {\n region: CellRegion;\n url: string;\n priority: number;\n healthy: boolean;\n}\n\nexport interface AegisConfig {\n write_key: string;\n\n workspace_id?: string;\n \n api_host?: string;\n \n cell_endpoints?: CellEndpoint[];\n \n preferred_region?: CellRegion;\n \n auto_region_detection?: boolean;\n \n batch_size?: number;\n \n batch_interval?: number;\n \n capture_utm?: boolean;\n \n capture_referrer?: boolean;\n \n auto_page_view?: boolean;\n \n session_timeout?: number;\n \n debug?: boolean;\n \n respect_dnt?: boolean;\n \n cross_domain_tracking?: boolean;\n \n cookie_domain?: string;\n \n secure_cookie?: boolean;\n \n enable_offline_mode?: boolean;\n \n max_offline_events?: number;\n \n retry_failed_requests?: boolean;\n \n max_retries?: number;\n \n retry_backoff_multiplier?: number;\n \n request_timeout?: number;\n\n /** Client-side rate limiter — burst (token bucket capacity). Default 100. */\n rate_limit_burst?: number;\n\n /** Client-side rate limiter — sustained tokens per second. Default 20. */\n rate_limit_per_second?: number;\n\n plugins?: string[];\n\n wait_for_consent?: boolean;\n\n default_consent?: {\n analytics?: boolean;\n marketing?: boolean;\n functional?: boolean;\n };\n\n enable_consent_mode?: boolean;\n\n integrate_onetrust?: boolean;\n\n integrate_cookiebot?: boolean;\n\n integrate_google_consent_mode?: boolean;\n\n /** Push notification configuration. When provided, AegisWebPush is initialized. */\n push?: {\n /** VAPID public key for Web Push subscription. */\n vapidPublicKey: string;\n /** Automatically prompt for push permission after SDK init. Default: false. */\n autoPrompt?: boolean;\n /** Delay in ms before showing auto-prompt. Default: 5000. */\n promptDelay?: number;\n /** Path to the service worker file. Default: '/aegis-sw.js'. */\n serviceWorkerPath?: string;\n /** Scope for the service worker registration. Default: '/'. Critical for e-commerce platforms. */\n serviceWorkerScope?: string;\n };\n}\n\nexport interface AegisConfigInternal extends Required<Omit<AegisConfig, 'api_host' | 'cell_endpoints' | 'preferred_region' | 'cookie_domain' | 'plugins' | 'default_consent' | 'workspace_id'>> {\n initialized: boolean;\n workspace_id: string | null;\n api_host: string | null;\n cell_endpoints: CellEndpoint[];\n preferred_region: CellRegion | null;\n cookie_domain: string | null;\n plugins: string[];\n active_cell: CellEndpoint | null;\n default_consent: {\n analytics: boolean;\n marketing: boolean;\n functional: boolean;\n };\n}\n\nexport const DEFAULT_CONFIG: Partial<AegisConfigInternal> = {\n workspace_id: null,\n batch_size: 10,\n batch_interval: 1000,\n capture_utm: true,\n capture_referrer: true,\n auto_page_view: false,\n session_timeout: 30,\n debug: false,\n respect_dnt: true,\n cross_domain_tracking: false,\n secure_cookie: true,\n enable_offline_mode: true,\n max_offline_events: 100,\n retry_failed_requests: true,\n max_retries: 3,\n retry_backoff_multiplier: 2,\n request_timeout: 5000,\n rate_limit_burst: 100,\n rate_limit_per_second: 20,\n auto_region_detection: true,\n wait_for_consent: false,\n enable_consent_mode: false,\n integrate_onetrust: false,\n integrate_cookiebot: false,\n integrate_google_consent_mode: false,\n default_consent: {\n analytics: false,\n marketing: false,\n functional: true,\n },\n initialized: false,\n api_host: null,\n cell_endpoints: [],\n preferred_region: null,\n cookie_domain: null,\n plugins: [],\n active_cell: null,\n};\n","export function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\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\nexport function generateSessionId(): string {\n return `sess_${Date.now()}_${generateUUID().slice(0, 8)}`;\n}\n\nexport function generateMessageId(): string {\n return `msg_${Date.now()}_${generateUUID().slice(0, 8)}`;\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nclass Logger {\n private enabled: boolean = false;\n private prefix: string = '[Aegis SDK]';\n\n enable(): void {\n this.enabled = true;\n }\n\n disable(): void {\n this.enabled = false;\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n debug(message: string, ...args: any[]): void {\n if (!this.enabled) return;\n console.debug(`${this.prefix} ${message}`, ...args);\n }\n\n info(message: string, ...args: any[]): void {\n if (!this.enabled) return;\n console.info(`${this.prefix} ${message}`, ...args);\n }\n\n warn(message: string, ...args: any[]): void {\n console.warn(`${this.prefix} ${message}`, ...args);\n }\n\n error(message: string, ...args: any[]): void {\n console.error(`${this.prefix} ${message}`, ...args);\n }\n}\n\nexport const logger = new Logger();\n","import { generateUUID } from './uuid';\nimport { Storage } from './storage';\nimport { logger } from './logger';\n\nexport interface IdentityState {\n anonymousId: string;\n userId: string | null;\n traits: Record<string, any>;\n}\n\nexport class Identity {\n private storage: Storage;\n private anonymousId: string;\n private userId: string | null = null;\n private traits: Record<string, any> = {};\n\n constructor(storage: Storage) {\n this.storage = storage;\n this.anonymousId = this.getOrCreateAnonymousId();\n this.loadUserIdentity();\n }\n\n private getOrCreateAnonymousId(): string {\n let id = this.storage.get('anon_id');\n\n if (!id) {\n id = generateUUID();\n this.storage.set('anon_id', id, 365);\n logger.debug('Created new anonymous ID:', id);\n } else {\n logger.debug('Loaded existing anonymous ID:', id);\n }\n\n return id;\n }\n\n private loadUserIdentity(): void {\n const storedUserId = this.storage.get('user_id');\n const storedTraits = this.storage.get('user_traits');\n\n if (storedUserId) {\n this.userId = storedUserId;\n logger.debug('Loaded user ID:', storedUserId);\n }\n\n if (storedTraits) {\n try {\n this.traits = JSON.parse(storedTraits);\n logger.debug('Loaded user traits:', this.traits);\n } catch (error) {\n logger.warn('Failed to parse stored traits:', error);\n this.traits = {};\n }\n }\n }\n\n getAnonymousId(): string {\n return this.anonymousId;\n }\n\n setUserId(userId: string, traits?: Record<string, any>): void {\n this.userId = userId;\n this.storage.set('user_id', userId, 365);\n logger.info('User identified:', userId);\n\n if (traits) {\n this.setTraits(traits);\n }\n }\n\n getUserId(): string | null {\n return this.userId;\n }\n\n setTraits(traits: Record<string, any>): void {\n this.traits = { ...this.traits, ...traits };\n this.storage.set('user_traits', JSON.stringify(this.traits), 365);\n logger.debug('User traits updated:', this.traits);\n }\n\n getTraits(): Record<string, any> {\n return { ...this.traits };\n }\n\n reset(): void {\n this.userId = null;\n this.traits = {};\n this.anonymousId = generateUUID();\n\n this.storage.remove('user_id');\n this.storage.remove('user_traits');\n this.storage.set('anon_id', this.anonymousId, 365);\n\n logger.info('Identity reset, new anonymous ID:', this.anonymousId);\n }\n\n alias(newUserId: string): { previousId: string; newUserId: string } {\n const previousId = this.userId || this.anonymousId;\n\n this.setUserId(newUserId);\n\n logger.info('User aliased:', { previousId, newUserId });\n\n return { previousId, newUserId };\n }\n\n getState(): IdentityState {\n return {\n anonymousId: this.anonymousId,\n userId: this.userId,\n traits: this.getTraits(),\n };\n }\n}\n","import { Storage } from '../utils/storage';\nimport { generateSessionId } from '../utils/uuid';\nimport { logger } from '../utils/logger';\nimport { AdClickIDs } from '../utils/url-parser';\n\nexport interface SessionState {\n sessionId: string;\n startTime: number;\n lastActivityTime: number;\n eventCount: number;\n adClickIDs?: AdClickIDs;\n landingPage?: string;\n}\n\nexport class SessionManager {\n private storage: Storage;\n private sessionId: string;\n private sessionTimeout: number;\n private lastActivityTime: number;\n private sessionStartTime: number;\n private eventCount: number = 0;\n private checkInterval: number | null = null;\n private activityThrottle: number = 1000;\n private lastActivityUpdate: number = 0;\n private adClickIDs: AdClickIDs = {};\n private landingPage?: string;\n\n constructor(storage: Storage, sessionTimeoutMinutes: number = 30) {\n this.storage = storage;\n this.sessionTimeout = sessionTimeoutMinutes * 60 * 1000;\n this.lastActivityTime = Date.now();\n this.sessionStartTime = Date.now();\n\n const session = this.loadSession();\n if (session) {\n this.sessionId = session.sessionId;\n this.sessionStartTime = session.startTime;\n this.lastActivityTime = session.lastActivityTime;\n this.eventCount = session.eventCount;\n this.adClickIDs = session.adClickIDs || {};\n this.landingPage = session.landingPage;\n logger.debug('Session loaded:', session);\n } else {\n this.sessionId = this.createNewSession();\n }\n\n this.startActivityTracking();\n this.startExpiryCheck();\n }\n\n private loadSession(): SessionState | null {\n const sessionData = this.storage.get('session');\n\n if (!sessionData) {\n return null;\n }\n\n try {\n const session: SessionState = JSON.parse(sessionData);\n const elapsed = Date.now() - session.lastActivityTime;\n\n if (elapsed < this.sessionTimeout) {\n return session;\n } else {\n logger.debug('Session expired, creating new session');\n this.storage.remove('session');\n return null;\n }\n } catch (error) {\n logger.warn('Failed to parse session data:', error);\n this.storage.remove('session');\n return null;\n }\n }\n\n private createNewSession(): string {\n const newSessionId = generateSessionId();\n this.sessionStartTime = Date.now();\n this.lastActivityTime = Date.now();\n this.eventCount = 0;\n\n this.persistSession();\n logger.info('New session created:', newSessionId);\n\n return newSessionId;\n }\n\n private persistSession(): void {\n const sessionData: SessionState = {\n sessionId: this.sessionId,\n startTime: this.sessionStartTime,\n lastActivityTime: this.lastActivityTime,\n eventCount: this.eventCount,\n adClickIDs: this.adClickIDs,\n landingPage: this.landingPage,\n };\n\n this.storage.set('session', JSON.stringify(sessionData));\n }\n\n private startActivityTracking(): void {\n const events = ['click', 'scroll', 'keypress', 'mousemove', 'touchstart'];\n\n const activityHandler = () => this.onActivity();\n\n events.forEach((event) => {\n window.addEventListener(event, activityHandler, { passive: true });\n });\n\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n this.onActivity();\n }\n });\n }\n\n private startExpiryCheck(): void {\n this.checkInterval = window.setInterval(() => {\n this.checkSessionExpiry();\n }, 60000);\n }\n\n private onActivity(): void {\n const now = Date.now();\n const timeSinceLastUpdate = now - this.lastActivityUpdate;\n\n if (timeSinceLastUpdate < this.activityThrottle) {\n return;\n }\n\n this.lastActivityUpdate = now;\n const timeSinceLastActivity = now - this.lastActivityTime;\n\n if (timeSinceLastActivity > this.sessionTimeout) {\n logger.info('Session expired due to inactivity, creating new session');\n this.sessionId = this.createNewSession();\n } else {\n this.lastActivityTime = now;\n this.persistSession();\n }\n }\n\n private checkSessionExpiry(): void {\n const elapsed = Date.now() - this.lastActivityTime;\n\n if (elapsed > this.sessionTimeout) {\n logger.info('Session expired during check, creating new session');\n this.sessionId = this.createNewSession();\n }\n }\n\n getSessionId(): string {\n return this.sessionId;\n }\n\n incrementEventCount(): void {\n this.eventCount++;\n this.lastActivityTime = Date.now();\n this.persistSession();\n }\n\n getSessionDuration(): number {\n return Date.now() - this.sessionStartTime;\n }\n\n getEventCount(): number {\n return this.eventCount;\n }\n\n getState(): SessionState {\n return {\n sessionId: this.sessionId,\n startTime: this.sessionStartTime,\n lastActivityTime: this.lastActivityTime,\n eventCount: this.eventCount,\n adClickIDs: this.adClickIDs,\n landingPage: this.landingPage,\n };\n }\n\n setAdClickIDs(adClickIDs: AdClickIDs, landingPage?: string): void {\n if (Object.keys(adClickIDs).length > 0) {\n this.adClickIDs = { ...this.adClickIDs, ...adClickIDs };\n if (landingPage) {\n this.landingPage = landingPage;\n }\n this.persistSession();\n logger.info('Ad click IDs stored in session:', this.adClickIDs);\n }\n }\n\n getAdClickIDs(): AdClickIDs {\n return this.adClickIDs;\n }\n\n getLandingPage(): string | undefined {\n return this.landingPage;\n }\n\n destroy(): void {\n if (this.checkInterval) {\n clearInterval(this.checkInterval);\n this.checkInterval = null;\n }\n }\n}\n","import { AegisEvent } from '../types/events';\nimport { Transport } from './transport';\nimport { Storage } from '../utils/storage';\nimport { logger } from '../utils/logger';\n\nexport interface QueueConfig {\n batchSize: number;\n batchInterval: number;\n enableOfflineMode: boolean;\n maxOfflineEvents: number;\n}\n\nexport class EventQueue {\n private buffer: AegisEvent[] = [];\n private config: QueueConfig;\n private transport: Transport;\n private storage: Storage;\n private flushInterval: number | null = null;\n private isFlushing: boolean = false;\n private offlineQueue: AegisEvent[] = [];\n private isOnline: boolean = navigator.onLine;\n\n constructor(config: QueueConfig, transport: Transport, storage: Storage) {\n this.config = config;\n this.transport = transport;\n this.storage = storage;\n\n if (config.enableOfflineMode) {\n this.loadOfflineQueue();\n this.setupOnlineListener();\n }\n\n this.startFlushTimer();\n this.setupUnloadHandlers();\n }\n\n private loadOfflineQueue(): void {\n const offlineData = this.storage.get('offline_queue');\n\n if (!offlineData) {\n return;\n }\n\n try {\n const events = JSON.parse(offlineData) as AegisEvent[];\n\n if (Array.isArray(events) && events.length > 0) {\n this.offlineQueue = events.slice(0, this.config.maxOfflineEvents);\n logger.info(`Loaded ${this.offlineQueue.length} offline events`);\n\n if (this.isOnline) {\n this.flushOfflineQueue();\n }\n }\n } catch (error) {\n logger.warn('Failed to load offline queue:', error);\n this.storage.remove('offline_queue');\n }\n }\n\n private saveOfflineQueue(): void {\n if (this.offlineQueue.length === 0) {\n this.storage.remove('offline_queue');\n return;\n }\n\n try {\n const data = JSON.stringify(this.offlineQueue);\n this.storage.set('offline_queue', data);\n logger.debug(`Saved ${this.offlineQueue.length} events to offline queue`);\n } catch (error) {\n logger.warn('Failed to save offline queue:', error);\n }\n }\n\n private setupOnlineListener(): void {\n window.addEventListener('online', () => {\n logger.info('Connection restored');\n this.isOnline = true;\n this.flushOfflineQueue();\n this.flush();\n });\n\n window.addEventListener('offline', () => {\n logger.warn('Connection lost, entering offline mode');\n this.isOnline = false;\n });\n }\n\n private async flushOfflineQueue(): Promise<void> {\n if (this.offlineQueue.length === 0) {\n return;\n }\n\n logger.info(`Flushing ${this.offlineQueue.length} offline events`);\n\n const events = [...this.offlineQueue];\n this.offlineQueue = [];\n this.storage.remove('offline_queue');\n\n const result = await this.transport.send(events);\n\n if (!result.success) {\n logger.warn('Failed to send offline events, re-queueing');\n this.offlineQueue = [...events, ...this.offlineQueue].slice(\n 0,\n this.config.maxOfflineEvents\n );\n this.saveOfflineQueue();\n } else {\n logger.info('Offline events sent successfully');\n }\n }\n\n push(event: AegisEvent): void {\n if (!this.isOnline && this.config.enableOfflineMode) {\n this.addToOfflineQueue(event);\n return;\n }\n\n this.buffer.push(event);\n logger.debug('Event queued:', event.type, event);\n\n if (this.buffer.length >= this.config.batchSize) {\n this.flush();\n }\n }\n\n private addToOfflineQueue(event: AegisEvent): void {\n if (this.offlineQueue.length >= this.config.maxOfflineEvents) {\n logger.warn('Offline queue full, dropping oldest event');\n this.offlineQueue.shift();\n }\n\n this.offlineQueue.push(event);\n this.saveOfflineQueue();\n logger.debug('Event added to offline queue');\n }\n\n async flush(): Promise<void> {\n if (this.isFlushing) {\n logger.debug('Flush already in progress, skipping');\n return;\n }\n\n if (this.buffer.length === 0) {\n return;\n }\n\n this.isFlushing = true;\n\n const events = [...this.buffer];\n this.buffer = [];\n\n logger.info(`Flushing ${events.length} events`);\n\n try {\n const result = await this.transport.send(events);\n\n if (!result.success) {\n logger.error('Failed to send events:', result.error);\n\n if (this.config.enableOfflineMode) {\n this.offlineQueue = [...this.offlineQueue, ...events].slice(\n 0,\n this.config.maxOfflineEvents\n );\n this.saveOfflineQueue();\n logger.info('Events saved to offline queue');\n } else {\n this.buffer.unshift(...events);\n logger.warn('Events re-queued for retry');\n }\n } else {\n logger.info('Events sent successfully');\n }\n } catch (error) {\n logger.error('Flush error:', error);\n\n if (this.config.enableOfflineMode) {\n this.offlineQueue = [...this.offlineQueue, ...events].slice(\n 0,\n this.config.maxOfflineEvents\n );\n this.saveOfflineQueue();\n }\n } finally {\n this.isFlushing = false;\n }\n }\n\n private startFlushTimer(): void {\n if (this.flushInterval) {\n clearInterval(this.flushInterval);\n }\n\n this.flushInterval = window.setInterval(() => {\n this.flush();\n }, this.config.batchInterval);\n\n logger.debug(\n `Flush timer started with interval: ${this.config.batchInterval}ms`\n );\n }\n\n private setupUnloadHandlers(): void {\n const flushBeforeUnload = () => {\n if (this.buffer.length > 0 || this.offlineQueue.length > 0) {\n this.persistBufferToOfflineQueue();\n this.flush();\n }\n };\n\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n flushBeforeUnload();\n }\n });\n\n window.addEventListener('beforeunload', flushBeforeUnload);\n\n window.addEventListener('pagehide', flushBeforeUnload);\n }\n\n private persistBufferToOfflineQueue(): void {\n if (this.buffer.length === 0) {\n return;\n }\n\n if (this.config.enableOfflineMode) {\n this.offlineQueue = [...this.offlineQueue, ...this.buffer].slice(\n 0,\n this.config.maxOfflineEvents\n );\n this.saveOfflineQueue();\n logger.debug('Buffer persisted to offline queue before unload');\n }\n }\n\n getQueueSize(): number {\n return this.buffer.length;\n }\n\n getOfflineQueueSize(): number {\n return this.offlineQueue.length;\n }\n\n clear(): void {\n this.buffer = [];\n this.offlineQueue = [];\n this.storage.remove('offline_queue');\n logger.info('Queue cleared');\n }\n\n destroy(): void {\n if (this.flushInterval) {\n clearInterval(this.flushInterval);\n this.flushInterval = null;\n }\n\n this.flush();\n }\n}\n","import { AegisEvent, BatchPayload, BatchResponse } from '../types/events';\nimport { CellEndpoint, CellRegion } from '../types/config';\nimport { logger } from '../utils/logger';\nimport { Storage } from '../utils/storage';\n\nexport interface TransportConfig {\n writeKey: string;\n apiHost: string | null;\n cellEndpoints: CellEndpoint[];\n preferredRegion: CellRegion | null;\n autoRegionDetection: boolean;\n requestTimeout: number;\n retryFailedRequests: boolean;\n maxRetries: number;\n retryBackoffMultiplier: number;\n}\n\nexport interface SendResult {\n success: boolean;\n response?: BatchResponse;\n error?: Error;\n endpoint?: string;\n}\n\nexport class Transport {\n private config: TransportConfig;\n private storage: Storage;\n private activeCell: CellEndpoint | null = null;\n private healthCheckInterval: number | null = null;\n private regionLatencyMap: Map<string, number> = new Map();\n\n constructor(config: TransportConfig, storage: Storage) {\n this.config = config;\n this.storage = storage;\n\n if (config.cellEndpoints.length > 0) {\n this.initializeCellularArchitecture();\n }\n }\n\n private async initializeCellularArchitecture(): Promise<void> {\n const cachedCell = this.loadCachedCell();\n\n if (cachedCell && this.isCellHealthy(cachedCell)) {\n this.activeCell = cachedCell;\n logger.info('Using cached cell:', cachedCell);\n } else {\n await this.selectOptimalCell();\n }\n\n this.startHealthChecks();\n }\n\n private loadCachedCell(): CellEndpoint | null {\n const cached = this.storage.get('active_cell');\n\n if (!cached) {\n return null;\n }\n\n try {\n return JSON.parse(cached) as CellEndpoint;\n } catch (error) {\n logger.warn('Failed to parse cached cell:', error);\n return null;\n }\n }\n\n private saveCachedCell(cell: CellEndpoint): void {\n this.storage.set('active_cell', JSON.stringify(cell), 7);\n }\n\n private isCellHealthy(cell: CellEndpoint): boolean {\n return (\n cell.healthy &&\n this.config.cellEndpoints.some(\n (c) => c.region === cell.region && c.url === cell.url\n )\n );\n }\n\n private async selectOptimalCell(): Promise<void> {\n logger.info('Selecting optimal cell...');\n\n if (this.config.preferredRegion) {\n const preferredCell = this.config.cellEndpoints.find(\n (cell) => cell.region === this.config.preferredRegion && cell.healthy\n );\n\n if (preferredCell) {\n this.activeCell = preferredCell;\n this.saveCachedCell(preferredCell);\n logger.info('Using preferred region cell:', preferredCell);\n return;\n }\n }\n\n if (this.config.autoRegionDetection) {\n await this.detectOptimalRegion();\n } else {\n this.selectCellByPriority();\n }\n }\n\n private async detectOptimalRegion(): Promise<void> {\n const healthyCells = this.config.cellEndpoints.filter((cell) => cell.healthy);\n\n if (healthyCells.length === 0) {\n logger.error('No healthy cells available');\n return;\n }\n\n const latencyPromises = healthyCells.map(async (cell) => {\n const latency = await this.measureLatency(cell);\n this.regionLatencyMap.set(cell.region, latency);\n return { cell, latency };\n });\n\n const results = await Promise.all(latencyPromises);\n results.sort((a, b) => a.latency - b.latency);\n\n const optimalCell = results[0].cell;\n this.activeCell = optimalCell;\n this.saveCachedCell(optimalCell);\n\n logger.info('Optimal cell selected:', {\n region: optimalCell.region,\n latency: results[0].latency,\n });\n }\n\n private async measureLatency(cell: CellEndpoint): Promise<number> {\n const startTime = performance.now();\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 2000);\n\n const response = await fetch(`${cell.url}/health`, {\n method: 'GET',\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return performance.now() - startTime;\n } else {\n return Infinity;\n }\n } catch (error) {\n logger.warn(`Health check failed for ${cell.region}:`, error);\n return Infinity;\n }\n }\n\n private selectCellByPriority(): void {\n const sortedCells = [...this.config.cellEndpoints]\n .filter((cell) => cell.healthy)\n .sort((a, b) => a.priority - b.priority);\n\n if (sortedCells.length > 0) {\n this.activeCell = sortedCells[0];\n this.saveCachedCell(sortedCells[0]);\n logger.info('Cell selected by priority:', sortedCells[0]);\n } else {\n logger.error('No healthy cells available');\n }\n }\n\n private startHealthChecks(): void {\n this.healthCheckInterval = window.setInterval(() => {\n this.performHealthChecks();\n }, 60000);\n }\n\n private async performHealthChecks(): Promise<void> {\n const healthPromises = this.config.cellEndpoints.map(async (cell) => {\n const isHealthy = await this.checkCellHealth(cell);\n cell.healthy = isHealthy;\n return { cell, isHealthy };\n });\n\n const results = await Promise.all(healthPromises);\n\n if (this.activeCell && !this.activeCell.healthy) {\n logger.warn('Active cell unhealthy, selecting new cell');\n await this.selectOptimalCell();\n }\n\n logger.debug('Health check results:', results);\n }\n\n private async checkCellHealth(cell: CellEndpoint): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 3000);\n\n const response = await fetch(`${cell.url}/health`, {\n method: 'GET',\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n return response.ok;\n } catch (error) {\n return false;\n }\n }\n\n async send(events: AegisEvent[]): Promise<SendResult> {\n if (events.length === 0) {\n return { success: true };\n }\n\n const endpoint = this.getActiveEndpoint();\n const payload = this.buildPayload(events);\n\n logger.debug('Sending batch:', { endpoint, eventCount: events.length });\n\n if (document.visibilityState === 'hidden' && typeof navigator.sendBeacon === 'function') {\n const result = this.sendViaBeacon(endpoint, payload);\n return Promise.resolve(result);\n } else {\n return this.sendViaFetch(endpoint, payload);\n }\n }\n\n private getActiveEndpoint(): string {\n if (this.activeCell) {\n return `${this.activeCell.url}/v1/batch`;\n }\n\n if (this.config.apiHost) {\n return `${this.config.apiHost}/v1/batch`;\n }\n\n throw new Error('No active endpoint available');\n }\n\n private buildPayload(events: AegisEvent[]): BatchPayload {\n return {\n batch: events,\n sentAt: new Date().toISOString(),\n writeKey: this.config.writeKey,\n context: this.activeCell\n ? {\n cell: {\n region: this.activeCell.region,\n endpoint: this.activeCell.url,\n },\n }\n : undefined,\n };\n }\n\n private sendViaBeacon(endpoint: string, payload: BatchPayload): SendResult | Promise<SendResult> {\n try {\n const blob = new Blob([JSON.stringify(payload)], {\n type: 'application/json',\n });\n\n const sent = navigator.sendBeacon(endpoint, blob);\n\n if (sent) {\n logger.debug('Batch sent via Beacon');\n return { success: true, endpoint };\n } else {\n logger.warn('Beacon send failed, falling back to fetch');\n return this.sendViaFetch(endpoint, payload);\n }\n } catch (error) {\n logger.error('Beacon send error:', error);\n return {\n success: false,\n error: error as Error,\n endpoint,\n };\n }\n }\n\n private async sendViaFetch(\n endpoint: string,\n payload: BatchPayload,\n attempt: number = 1\n ): Promise<SendResult> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n this.config.requestTimeout\n );\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.writeKey}`,\n },\n body: JSON.stringify(payload),\n keepalive: true,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n const result: BatchResponse = await response.json();\n logger.debug('Batch sent successfully:', result);\n return { success: true, response: result, endpoint };\n } else {\n const errorText = await response.text();\n const error = new Error(\n `HTTP ${response.status}: ${errorText || response.statusText}`\n );\n\n logger.error('Batch send failed:', error);\n\n if (this.shouldRetry(response.status, attempt)) {\n return this.retryRequest(endpoint, payload, attempt);\n }\n\n return { success: false, error, endpoint };\n }\n } catch (error) {\n logger.error('Fetch error:', error);\n\n if (this.shouldRetry(0, attempt)) {\n return this.retryRequest(endpoint, payload, attempt);\n }\n\n return {\n success: false,\n error: error as Error,\n endpoint,\n };\n }\n }\n\n private shouldRetry(statusCode: number, attempt: number): boolean {\n if (!this.config.retryFailedRequests) {\n return false;\n }\n\n if (attempt >= this.config.maxRetries) {\n return false;\n }\n\n if (statusCode === 0) {\n return true;\n }\n\n return statusCode >= 500 || statusCode === 429;\n }\n\n private async retryRequest(\n endpoint: string,\n payload: BatchPayload,\n attempt: number\n ): Promise<SendResult> {\n const delay =\n Math.pow(this.config.retryBackoffMultiplier, attempt) * 1000;\n\n logger.info(`Retrying request in ${delay}ms (attempt ${attempt + 1})`);\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n\n return this.sendViaFetch(endpoint, payload, attempt + 1);\n }\n\n getActiveCell(): CellEndpoint | null {\n return this.activeCell;\n }\n\n getRegionLatencies(): Map<string, number> {\n return new Map(this.regionLatencyMap);\n }\n\n destroy(): void {\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n this.healthCheckInterval = null;\n }\n }\n}\n","const STORAGE_PREFIX = 'aegis_';\n\nexport interface StorageOptions {\n cookieDomain?: string | null;\n secureCookie?: boolean;\n crossDomain?: boolean;\n}\n\nexport class Storage {\n private useLocalStorage: boolean;\n private options: StorageOptions;\n\n constructor(options: StorageOptions = {}) {\n this.options = options;\n this.useLocalStorage = this.isLocalStorageAvailable();\n }\n\n private isLocalStorageAvailable(): boolean {\n try {\n const test = '__aegis_test__';\n localStorage.setItem(test, test);\n localStorage.removeItem(test);\n return true;\n } catch {\n return false;\n }\n }\n\n set(key: string, value: string, expiryDays: number = 365): void {\n const fullKey = STORAGE_PREFIX + key;\n\n if (this.useLocalStorage) {\n try {\n const item = {\n value,\n expiry: Date.now() + expiryDays * 24 * 60 * 60 * 1000,\n };\n localStorage.setItem(fullKey, JSON.stringify(item));\n } catch (error) {\n console.warn('[Aegis Storage] localStorage.setItem failed:', error);\n }\n }\n\n this.setCookie(fullKey, value, expiryDays);\n }\n\n get(key: string): string | null {\n const fullKey = STORAGE_PREFIX + key;\n\n if (this.useLocalStorage) {\n try {\n const itemStr = localStorage.getItem(fullKey);\n if (itemStr) {\n const item = JSON.parse(itemStr);\n if (Date.now() < item.expiry) {\n return item.value;\n } else {\n localStorage.removeItem(fullKey);\n }\n }\n } catch (error) {\n console.warn('[Aegis Storage] localStorage.getItem failed:', error);\n }\n }\n\n return this.getCookie(fullKey);\n }\n\n remove(key: string): void {\n const fullKey = STORAGE_PREFIX + key;\n\n if (this.useLocalStorage) {\n try {\n localStorage.removeItem(fullKey);\n } catch (error) {\n console.warn('[Aegis Storage] localStorage.removeItem failed:', error);\n }\n }\n\n this.deleteCookie(fullKey);\n }\n\n clear(): void {\n if (this.useLocalStorage) {\n try {\n const keys = Object.keys(localStorage);\n keys.forEach((key) => {\n if (key.startsWith(STORAGE_PREFIX)) {\n localStorage.removeItem(key);\n }\n });\n } catch (error) {\n console.warn('[Aegis Storage] localStorage.clear failed:', error);\n }\n }\n\n const cookies = document.cookie.split(';');\n cookies.forEach((cookie) => {\n const key = cookie.split('=')[0].trim();\n if (key.startsWith(STORAGE_PREFIX)) {\n this.deleteCookie(key);\n }\n });\n }\n\n private setCookie(name: string, value: string, days: number): void {\n try {\n const date = new Date();\n date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\n const expires = `expires=${date.toUTCString()}`;\n \n let cookieStr = `${name}=${value};${expires};path=/`;\n \n if (this.options.secureCookie && window.location.protocol === 'https:') {\n cookieStr += ';Secure';\n }\n \n cookieStr += ';SameSite=Lax';\n \n if (this.options.cookieDomain) {\n cookieStr += `;domain=${this.options.cookieDomain}`;\n } else if (this.options.crossDomain) {\n const domain = this.getRootDomain();\n if (domain) {\n cookieStr += `;domain=${domain}`;\n }\n }\n \n document.cookie = cookieStr;\n } catch (error) {\n console.warn('[Aegis Storage] setCookie failed:', error);\n }\n }\n\n private getCookie(name: string): string | null {\n try {\n const nameEQ = name + '=';\n const ca = document.cookie.split(';');\n \n for (let i = 0; i < ca.length; i++) {\n let c = ca[i];\n while (c.charAt(0) === ' ') {\n c = c.substring(1, c.length);\n }\n if (c.indexOf(nameEQ) === 0) {\n return c.substring(nameEQ.length, c.length);\n }\n }\n } catch (error) {\n console.warn('[Aegis Storage] getCookie failed:', error);\n }\n \n return null;\n }\n\n private deleteCookie(name: string): void {\n try {\n let cookieStr = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/`;\n \n if (this.options.cookieDomain) {\n cookieStr += `;domain=${this.options.cookieDomain}`;\n } else if (this.options.crossDomain) {\n const domain = this.getRootDomain();\n if (domain) {\n cookieStr += `;domain=${domain}`;\n }\n }\n \n document.cookie = cookieStr;\n } catch (error) {\n console.warn('[Aegis Storage] deleteCookie failed:', error);\n }\n }\n\n private getRootDomain(): string | null {\n try {\n const hostname = window.location.hostname;\n \n if (/^(\\d{1,3}\\.){3}\\d{1,3}$/.test(hostname)) {\n return null;\n }\n \n if (hostname === 'localhost') {\n return null;\n }\n \n const parts = hostname.split('.');\n \n if (parts.length <= 2) {\n return `.${hostname}`;\n }\n \n return `.${parts.slice(-2).join('.')}`;\n } catch (error) {\n console.warn('[Aegis Storage] getRootDomain failed:', error);\n return null;\n }\n }\n}\n","import { EventContext } from '../types/events';\nimport { parseUTMParameters } from './url-parser';\nimport { AegisConfigInternal } from '../types/config';\nimport type { SessionManager } from '../core/session';\n\nexport function buildContext(config: AegisConfigInternal, session?: SessionManager): EventContext {\n const utm = config.capture_utm ? parseUTMParameters() : undefined;\n const device = detectDevice();\n const os = detectOS();\n const browser = detectBrowser();\n const network = detectNetworkInfo();\n\n const adClickIDs = session?.getAdClickIDs();\n const landingPage = session?.getLandingPage();\n\n return {\n library: {\n name: '@active-reach/web-sdk',\n version: '1.0.0',\n },\n page: {\n path: window.location.pathname,\n referrer: config.capture_referrer ? document.referrer : '',\n search: window.location.search,\n title: document.title,\n url: window.location.href,\n hash: window.location.hash,\n },\n userAgent: navigator.userAgent,\n locale: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n screen: {\n width: window.screen.width,\n height: window.screen.height,\n density: window.devicePixelRatio || 1,\n },\n viewport: {\n width: window.innerWidth,\n height: window.innerHeight,\n },\n ...(utm && Object.keys(utm).length > 0 && { campaign: utm }),\n ...(adClickIDs && Object.keys(adClickIDs).length > 0 && { adClickIDs }),\n ...(landingPage && { landingPage }),\n ...(network && { network }),\n ...(device && { device }),\n ...(os && { os }),\n ...(browser && { browser }),\n ...(config.active_cell && {\n cell: {\n region: config.active_cell.region,\n endpoint: config.active_cell.url,\n },\n }),\n };\n}\n\nfunction detectDevice(): EventContext['device'] {\n const ua = navigator.userAgent;\n\n if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {\n return { type: 'tablet' };\n }\n\n if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) {\n return { type: 'mobile' };\n }\n\n return { type: 'desktop' };\n}\n\nfunction detectOS(): EventContext['os'] {\n const ua = navigator.userAgent;\n\n if (/Windows NT 10/i.test(ua)) return { name: 'Windows', version: '10' };\n if (/Windows NT 6.3/i.test(ua)) return { name: 'Windows', version: '8.1' };\n if (/Windows NT 6.2/i.test(ua)) return { name: 'Windows', version: '8' };\n if (/Windows NT 6.1/i.test(ua)) return { name: 'Windows', version: '7' };\n if (/Windows/i.test(ua)) return { name: 'Windows', version: 'Unknown' };\n\n if (/Mac OS X (\\d+)[._](\\d+)/.test(ua)) {\n const match = ua.match(/Mac OS X (\\d+)[._](\\d+)/);\n return { name: 'macOS', version: `${match![1]}.${match![2]}` };\n }\n if (/Mac/i.test(ua)) return { name: 'macOS', version: 'Unknown' };\n\n if (/Android (\\d+\\.\\d+)/.test(ua)) {\n const match = ua.match(/Android (\\d+\\.\\d+)/);\n return { name: 'Android', version: match![1] };\n }\n if (/Android/i.test(ua)) return { name: 'Android', version: 'Unknown' };\n\n if (/iPhone OS (\\d+)_(\\d+)/.test(ua)) {\n const match = ua.match(/iPhone OS (\\d+)_(\\d+)/);\n return { name: 'iOS', version: `${match![1]}.${match![2]}` };\n }\n if (/iPad.*OS (\\d+)_(\\d+)/.test(ua)) {\n const match = ua.match(/iPad.*OS (\\d+)_(\\d+)/);\n return { name: 'iOS', version: `${match![1]}.${match![2]}` };\n }\n if (/iPhone|iPad/i.test(ua)) return { name: 'iOS', version: 'Unknown' };\n\n if (/Linux/i.test(ua)) return { name: 'Linux', version: 'Unknown' };\n\n return { name: 'Unknown', version: 'Unknown' };\n}\n\nfunction detectBrowser(): EventContext['browser'] {\n const ua = navigator.userAgent;\n\n if (/Edg\\/(\\d+\\.\\d+)/.test(ua)) {\n const match = ua.match(/Edg\\/(\\d+\\.\\d+)/);\n return { name: 'Edge', version: match![1] };\n }\n\n if (/Chrome\\/(\\d+\\.\\d+)/.test(ua) && !/Edg/.test(ua)) {\n const match = ua.match(/Chrome\\/(\\d+\\.\\d+)/);\n return { name: 'Chrome', version: match![1] };\n }\n\n if (/Firefox\\/(\\d+\\.\\d+)/.test(ua)) {\n const match = ua.match(/Firefox\\/(\\d+\\.\\d+)/);\n return { name: 'Firefox', version: match![1] };\n }\n\n if (/Safari\\/(\\d+\\.\\d+)/.test(ua) && !/Chrome/.test(ua)) {\n const match = ua.match(/Version\\/(\\d+\\.\\d+)/);\n return { name: 'Safari', version: match ? match[1] : 'Unknown' };\n }\n\n if (/MSIE (\\d+\\.\\d+)/.test(ua) || /Trident\\//.test(ua)) {\n const match = ua.match(/MSIE (\\d+\\.\\d+)/) || ua.match(/rv:(\\d+\\.\\d+)/);\n return { name: 'Internet Explorer', version: match ? match[1] : 'Unknown' };\n }\n\n return { name: 'Unknown', version: 'Unknown' };\n}\n\nfunction detectNetworkInfo(): EventContext['network'] | undefined {\n try {\n const connection =\n (navigator as any).connection ||\n (navigator as any).mozConnection ||\n (navigator as any).webkitConnection;\n\n if (connection) {\n return {\n effectiveType: connection.effectiveType,\n downlink: connection.downlink,\n rtt: connection.rtt,\n };\n }\n } catch (error) {\n console.warn('[Aegis Device] detectNetworkInfo failed:', error);\n }\n\n return undefined;\n}\n\nexport function isBot(): boolean {\n const ua = navigator.userAgent.toLowerCase();\n const botPatterns = [\n 'bot',\n 'crawl',\n 'spider',\n 'slurp',\n 'mediapartners',\n 'googlebot',\n 'bingbot',\n 'yahoo',\n 'duckduckbot',\n 'baiduspider',\n 'yandex',\n 'facebookexternalhit',\n 'linkedinbot',\n 'twitterbot',\n 'slackbot',\n 'telegrambot',\n 'whatsapp',\n 'pingdom',\n 'uptimerobot',\n ];\n\n return botPatterns.some((pattern) => ua.includes(pattern));\n}\n","export interface UTMParams {\n source?: string;\n medium?: string;\n campaign?: string;\n term?: string;\n content?: string;\n name?: string;\n}\n\nexport function parseUTMParameters(url?: string): UTMParams {\n try {\n const searchParams = url\n ? new URL(url).searchParams\n : new URLSearchParams(window.location.search);\n\n const utm: UTMParams = {};\n\n const utmKeys: Array<keyof UTMParams> = [\n 'source',\n 'medium',\n 'campaign',\n 'term',\n 'content',\n 'name',\n ];\n\n utmKeys.forEach((key) => {\n const value = searchParams.get(`utm_${key}`);\n if (value) {\n utm[key] = value;\n }\n });\n\n return utm;\n } catch (error) {\n console.warn('[Aegis URL Parser] parseUTMParameters failed:', error);\n return {};\n }\n}\n\nexport function parseQueryParameters(url?: string): Record<string, string> {\n try {\n const searchParams = url\n ? new URL(url).searchParams\n : new URLSearchParams(window.location.search);\n\n const params: Record<string, string> = {};\n\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n\n return params;\n } catch (error) {\n console.warn('[Aegis URL Parser] parseQueryParameters failed:', error);\n return {};\n }\n}\n\nexport function getCanonicalURL(): string {\n try {\n const canonical = document.querySelector('link[rel=\"canonical\"]');\n if (canonical && canonical.getAttribute('href')) {\n return canonical.getAttribute('href')!;\n }\n \n return window.location.href;\n } catch (error) {\n console.warn('[Aegis URL Parser] getCanonicalURL failed:', error);\n return window.location.href;\n }\n}\n\nexport function stripQueryParameters(url: string): string {\n try {\n const urlObj = new URL(url);\n return `${urlObj.protocol}//${urlObj.host}${urlObj.pathname}`;\n } catch (error) {\n console.warn('[Aegis URL Parser] stripQueryParameters failed:', error);\n return url;\n }\n}\n\nexport interface AdClickIDs {\n gclid?: string;\n fbclid?: string;\n msclkid?: string;\n ctwa_clid?: string;\n ttclid?: string;\n li_fat_id?: string;\n}\n\nexport function parseAdClickIDs(url?: string): AdClickIDs {\n try {\n const searchParams = url\n ? new URL(url).searchParams\n : new URLSearchParams(window.location.search);\n\n const adClickIDs: AdClickIDs = {};\n\n const clickIDKeys: Array<keyof AdClickIDs> = [\n 'gclid',\n 'fbclid',\n 'msclkid',\n 'ctwa_clid',\n 'ttclid',\n 'li_fat_id',\n ];\n\n clickIDKeys.forEach((key) => {\n const value = searchParams.get(key);\n if (value) {\n adClickIDs[key] = value;\n }\n });\n\n return adClickIDs;\n } catch (error) {\n console.warn('[Aegis URL Parser] parseAdClickIDs failed:', error);\n return {};\n }\n}\n\nexport function hasAdClickIDs(adClickIDs: AdClickIDs): boolean {\n return Object.keys(adClickIDs).length > 0;\n}\n","import { Plugin } from '../types/plugin';\nimport { logger } from '../utils/logger';\n\nexport class PluginRegistry {\n private plugins: Map<string, Plugin> = new Map();\n\n register(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n logger.warn(`Plugin \"${plugin.name}\" already registered, skipping`);\n return;\n }\n\n this.plugins.set(plugin.name, plugin);\n logger.info(`Plugin registered: ${plugin.name} v${plugin.version}`);\n }\n\n unregister(pluginName: string): void {\n const plugin = this.plugins.get(pluginName);\n\n if (!plugin) {\n logger.warn(`Plugin \"${pluginName}\" not found`);\n return;\n }\n\n if (plugin.destroy) {\n try {\n plugin.destroy();\n } catch (error) {\n logger.error(`Error destroying plugin \"${pluginName}\":`, error);\n }\n }\n\n this.plugins.delete(pluginName);\n logger.info(`Plugin unregistered: ${pluginName}`);\n }\n\n get(pluginName: string): Plugin | undefined {\n return this.plugins.get(pluginName);\n }\n\n getAll(): Plugin[] {\n return Array.from(this.plugins.values());\n }\n\n async executeHook<T = any>(\n hookName: keyof Plugin,\n ...args: any[]\n ): Promise<T | undefined> {\n for (const plugin of this.plugins.values()) {\n const hook = plugin[hookName];\n\n if (typeof hook === 'function') {\n try {\n const result = await (hook as Function).apply(plugin, args);\n\n if (result !== undefined) {\n return result as T;\n }\n } catch (error) {\n logger.error(\n `Error executing ${String(hookName)} in plugin \"${plugin.name}\":`,\n error\n );\n\n if (plugin.onError) {\n try {\n plugin.onError(error as Error, { hookName, args });\n } catch (onErrorError) {\n logger.error(\n `Error in onError handler for plugin \"${plugin.name}\":`,\n onErrorError\n );\n }\n }\n }\n }\n }\n\n return undefined;\n }\n\n async executeHookChain<T = any>(\n hookName: keyof Plugin,\n initialValue: T,\n ...additionalArgs: any[]\n ): Promise<T> {\n let value = initialValue;\n\n for (const plugin of this.plugins.values()) {\n const hook = plugin[hookName];\n\n if (typeof hook === 'function') {\n try {\n const result = await (hook as Function).apply(plugin, [\n value,\n ...additionalArgs,\n ]);\n\n if (result !== undefined && result !== null) {\n value = result;\n }\n } catch (error) {\n logger.error(\n `Error executing ${String(hookName)} in plugin \"${plugin.name}\":`,\n error\n );\n\n if (plugin.onError) {\n try {\n plugin.onError(error as Error, { hookName, value, additionalArgs });\n } catch (onErrorError) {\n logger.error(\n `Error in onError handler for plugin \"${plugin.name}\":`,\n onErrorError\n );\n }\n }\n }\n }\n }\n\n return value;\n }\n\n async executeHookParallel<T = any>(\n hookName: keyof Plugin,\n ...args: any[]\n ): Promise<T[]> {\n const promises: Promise<T>[] = [];\n\n for (const plugin of this.plugins.values()) {\n const hook = plugin[hookName];\n\n if (typeof hook === 'function') {\n const promise = (async () => {\n try {\n return await (hook as Function).apply(plugin, args);\n } catch (error) {\n logger.error(\n `Error executing ${String(hookName)} in plugin \"${plugin.name}\":`,\n error\n );\n\n if (plugin.onError) {\n try {\n plugin.onError(error as Error, { hookName, args });\n } catch (onErrorError) {\n logger.error(\n `Error in onError handler for plugin \"${plugin.name}\":`,\n onErrorError\n );\n }\n }\n\n return undefined;\n }\n })();\n\n promises.push(promise);\n }\n }\n\n const results = await Promise.all(promises);\n return results.filter((r) => r !== undefined) as T[];\n }\n\n clear(): void {\n for (const plugin of this.plugins.values()) {\n if (plugin.destroy) {\n try {\n plugin.destroy();\n } catch (error) {\n logger.error(`Error destroying plugin \"${plugin.name}\":`, error);\n }\n }\n }\n\n this.plugins.clear();\n logger.info('All plugins cleared');\n }\n}\n","import { Storage } from './storage';\nimport { logger } from './logger';\n\nexport type ConsentCategory =\n | 'analytics'\n | 'marketing'\n | 'functional'\n | 'necessary';\n\nexport interface ConsentPreferences {\n analytics: boolean;\n marketing: boolean;\n functional: boolean;\n necessary: boolean;\n}\n\nexport type ConsentStatus = 'granted' | 'denied' | 'pending';\n\nexport interface ConsentManagerConfig {\n defaultConsent?: Partial<ConsentPreferences>;\n waitForConsent?: boolean;\n consentStorageKey?: string;\n}\n\nexport class ConsentManager {\n private storage: Storage;\n private config: Required<ConsentManagerConfig>;\n private preferences: ConsentPreferences;\n private listeners: Array<(preferences: ConsentPreferences) => void> = [];\n\n constructor(storage: Storage, config: ConsentManagerConfig = {}) {\n this.storage = storage;\n this.config = {\n defaultConsent: config.defaultConsent || {},\n waitForConsent: config.waitForConsent ?? false,\n consentStorageKey: config.consentStorageKey || 'aegis_consent',\n };\n\n this.preferences = this.loadPreferences();\n }\n\n private loadPreferences(): ConsentPreferences {\n const stored = this.storage.get(this.config.consentStorageKey);\n\n if (stored) {\n try {\n const parsed = JSON.parse(stored);\n logger.info('Loaded consent preferences:', parsed);\n return this.mergeWithDefaults(parsed);\n } catch (error) {\n logger.warn('Failed to parse consent preferences:', error);\n }\n }\n\n return this.getDefaultPreferences();\n }\n\n private getDefaultPreferences(): ConsentPreferences {\n return {\n analytics: this.config.defaultConsent.analytics ?? false,\n marketing: this.config.defaultConsent.marketing ?? false,\n functional: this.config.defaultConsent.functional ?? true,\n necessary: true,\n };\n }\n\n private mergeWithDefaults(\n preferences: Partial<ConsentPreferences>\n ): ConsentPreferences {\n return {\n necessary: true,\n analytics: preferences.analytics ?? this.config.defaultConsent.analytics ?? false,\n marketing: preferences.marketing ?? this.config.defaultConsent.marketing ?? false,\n functional: preferences.functional ?? this.config.defaultConsent.functional ?? true,\n };\n }\n\n private savePreferences(): void {\n try {\n this.storage.set(\n this.config.consentStorageKey,\n JSON.stringify(this.preferences),\n 365\n );\n logger.info('Saved consent preferences:', this.preferences);\n } catch (error) {\n logger.error('Failed to save consent preferences:', error);\n }\n }\n\n setConsent(preferences: Partial<ConsentPreferences>): void {\n const updated = { ...this.preferences, ...preferences };\n updated.necessary = true;\n\n this.preferences = updated;\n this.savePreferences();\n this.notifyListeners();\n\n logger.info('Consent updated:', this.preferences);\n }\n\n grantAll(): void {\n this.setConsent({\n analytics: true,\n marketing: true,\n functional: true,\n necessary: true,\n });\n }\n\n denyAll(): void {\n this.setConsent({\n analytics: false,\n marketing: false,\n functional: false,\n necessary: true,\n });\n }\n\n hasConsent(category: ConsentCategory): boolean {\n return this.preferences[category];\n }\n\n getPreferences(): ConsentPreferences {\n return { ...this.preferences };\n }\n\n getStatus(category: ConsentCategory): ConsentStatus {\n if (this.hasConsent(category)) {\n return 'granted';\n }\n\n const stored = this.storage.get(this.config.consentStorageKey);\n if (!stored && this.config.waitForConsent) {\n return 'pending';\n }\n\n return 'denied';\n }\n\n isAnalyticsEnabled(): boolean {\n return this.hasConsent('analytics');\n }\n\n isMarketingEnabled(): boolean {\n return this.hasConsent('marketing');\n }\n\n onChange(callback: (preferences: ConsentPreferences) => void): () => void {\n this.listeners.push(callback);\n\n return () => {\n const index = this.listeners.indexOf(callback);\n if (index > -1) {\n this.listeners.splice(index, 1);\n }\n };\n }\n\n private notifyListeners(): void {\n this.listeners.forEach((listener) => {\n try {\n listener(this.getPreferences());\n } catch (error) {\n logger.error('Consent listener error:', error);\n }\n });\n }\n\n reset(): void {\n this.storage.remove(this.config.consentStorageKey);\n this.preferences = this.getDefaultPreferences();\n this.notifyListeners();\n logger.info('Consent preferences reset');\n }\n\n integrateOneTrust(): void {\n if (typeof window === 'undefined') return;\n\n const oneTrust = (window as any).OneTrust;\n if (!oneTrust) {\n logger.warn('OneTrust not detected');\n return;\n }\n\n const syncWithOneTrust = () => {\n const activeGroups = (window as any).OnetrustActiveGroups || '';\n\n this.setConsent({\n necessary: true,\n functional: activeGroups.includes('C0003'),\n analytics: activeGroups.includes('C0002'),\n marketing: activeGroups.includes('C0004'),\n });\n\n logger.info('Synced with OneTrust consent');\n };\n\n if ((window as any).OptanonWrapper) {\n const originalWrapper = (window as any).OptanonWrapper;\n (window as any).OptanonWrapper = function () {\n originalWrapper();\n syncWithOneTrust();\n };\n } else {\n (window as any).OptanonWrapper = syncWithOneTrust;\n }\n\n syncWithOneTrust();\n }\n\n integrateCookiebot(): void {\n if (typeof window === 'undefined') return;\n\n const cookiebot = (window as any).Cookiebot;\n if (!cookiebot) {\n logger.warn('Cookiebot not detected');\n return;\n }\n\n const syncWithCookiebot = () => {\n const consent = cookiebot.consent || {};\n\n this.setConsent({\n necessary: true,\n functional: consent.preferences || false,\n analytics: consent.statistics || false,\n marketing: consent.marketing || false,\n });\n\n logger.info('Synced with Cookiebot consent');\n };\n\n window.addEventListener('CookiebotOnAccept', syncWithCookiebot);\n window.addEventListener('CookiebotOnDecline', syncWithCookiebot);\n\n if (cookiebot.consent) {\n syncWithCookiebot();\n }\n }\n\n integrateGoogleConsentMode(): void {\n if (typeof window === 'undefined') return;\n\n const gtag = (window as any).gtag;\n if (!gtag) {\n logger.warn('Google Tag Manager not detected');\n return;\n }\n\n const updateGoogleConsent = () => {\n gtag('consent', 'update', {\n ad_storage: this.preferences.marketing ? 'granted' : 'denied',\n analytics_storage: this.preferences.analytics ? 'granted' : 'denied',\n ad_user_data: this.preferences.marketing ? 'granted' : 'denied',\n ad_personalization: this.preferences.marketing ? 'granted' : 'denied',\n functionality_storage: this.preferences.functional ? 'granted' : 'denied',\n personalization_storage: this.preferences.functional ? 'granted' : 'denied',\n security_storage: 'granted',\n });\n\n logger.info('Updated Google Consent Mode');\n };\n\n this.onChange(updateGoogleConsent);\n updateGoogleConsent();\n }\n}\n","/**\n * E-Commerce helper methods for the Aegis SDK.\n *\n * Provides standardized e-commerce event tracking that maps to the\n * Active Reach Intelligence data governance pipeline.\n *\n * Event names follow the canonical mapper:\n * product_viewed → engagement.product_view\n * product_list_viewed → engagement.product_list_view\n * cart_item_added → cart_item_added\n * cart_item_removed → cart_item_removed\n * cart_viewed → cart_viewed\n * checkout_started → checkout_started\n * checkout_step → checkout_step\n * order_completed → transaction.purchase\n * order_refunded → transaction.refund\n * coupon_applied → coupon_applied\n * coupon_removed → coupon_removed\n * search_performed → search_performed\n * wishlist_item_added → wishlist_item_added\n * promotion_viewed → promotion_viewed\n * promotion_clicked → promotion_clicked\n */\n\nimport type { Aegis } from '../core/analytics';\nimport type {\n EcommerceProduct,\n EcommerceCart,\n EcommerceCheckout,\n EcommerceOrder,\n EcommerceCoupon,\n EcommerceSearch,\n EcommerceProductList,\n EcommerceWishlist,\n EcommercePromotion,\n} from './types';\n\nfunction sumItems(products: EcommerceProduct[]): number {\n return products.reduce((sum, p) => sum + (p.quantity ?? 1), 0);\n}\n\n// Cart abandonment detection is SERVER-SIDE. The SDK fires the canonical\n// e-commerce events (`cart_item_added`, `cart_item_removed`, `cart_viewed`,\n// `transaction.purchase`); a Kafka consumer on cell-plane maintains cart\n// state in Redis (`cart_state:{org}:{contact}:{cart_id}`) and a Celery beat\n// task scans for carts with no activity for N minutes, emitting\n// `cart_abandoned` to BEHAVIORAL_EVENTS_TOPIC.\n//\n// We deliberately do NOT run a JS timer on the client — mobile browsers\n// throttle background timers to ~1Hz and they're unreliable for any\n// abandonment threshold beyond a few seconds. Industry alignment: WebEngage,\n// MoEngage, CleverTap, Bitespeed, Klaviyo all detect server-side.\n//\n// See: `apps/cell-plane/app/workers/cart_state_tracker.py`\n\nfunction mapProducts(products: EcommerceProduct[]) {\n return products.map((p) => ({\n product_id: p.product_id,\n sku: p.sku ?? p.product_id,\n name: p.name,\n price: p.price,\n quantity: p.quantity ?? 1,\n currency: p.currency,\n category: p.category,\n brand: p.brand,\n variant_id: p.variant_id,\n variant_label: p.variant_label,\n position: p.position,\n }));\n}\n\nexport class EcommerceTracker {\n constructor(private aegis: Aegis) {}\n\n // -- Product Discovery --\n\n productViewed(product: EcommerceProduct): void {\n this.aegis.track('product_viewed', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n currency: product.currency ?? 'INR',\n category: product.category,\n brand: product.brand,\n variant_id: product.variant_id,\n variant_label: product.variant_label,\n image_url: product.image_url,\n url: product.url,\n });\n }\n\n productListViewed(list: EcommerceProductList): void {\n this.aegis.track('product_list_viewed', {\n list_id: list.list_id,\n list_name: list.list_name,\n category: list.category,\n products: mapProducts(list.products),\n });\n }\n\n productClicked(product: EcommerceProduct, source?: { list_id?: string; position?: number; section?: string }): void {\n this.aegis.track('product_clicked', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n currency: product.currency ?? 'INR',\n category: product.category,\n brand: product.brand,\n variant_id: product.variant_id,\n list_id: source?.list_id,\n position: source?.position ?? product.position,\n section: source?.section,\n });\n }\n\n productImpressed(product: EcommerceProduct, source?: { list_id?: string; position?: number; section?: string }): void {\n this.aegis.track('product_impression', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n currency: product.currency ?? 'INR',\n category: product.category,\n list_id: source?.list_id,\n position: source?.position ?? product.position,\n section: source?.section,\n });\n }\n\n categoryFiltered(category: string, options?: { previous_category?: string; result_count?: number }): void {\n this.aegis.track('category_filtered', {\n category,\n previous_category: options?.previous_category,\n result_count: options?.result_count,\n });\n }\n\n searchPerformed(search: EcommerceSearch): void {\n this.aegis.track('search_performed', {\n query: search.query,\n results_count: search.results_count,\n filters: search.filters,\n });\n }\n\n // -- Cart --\n\n addToCart(product: EcommerceProduct): void {\n this.aegis.track('cart_item_added', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n quantity: product.quantity ?? 1,\n currency: product.currency ?? 'INR',\n category: product.category,\n brand: product.brand,\n variant_id: product.variant_id,\n variant_label: product.variant_label,\n });\n }\n\n removeFromCart(product: EcommerceProduct): void {\n this.aegis.track('cart_item_removed', {\n product_id: product.product_id,\n sku: product.sku ?? product.product_id,\n name: product.name,\n price: product.price,\n quantity: product.quantity ?? 1,\n currency: product.currency ?? 'INR',\n variant_id: product.variant_id,\n });\n }\n\n cartViewed(cart: EcommerceCart): void {\n this.aegis.track('cart_viewed', {\n cart_id: cart.cart_id,\n value: cart.value,\n currency: cart.currency ?? 'INR',\n num_items: sumItems(cart.products),\n products: mapProducts(cart.products),\n });\n }\n\n // -- Checkout --\n\n checkoutStarted(checkout: EcommerceCheckout): void {\n this.aegis.track('checkout_started', {\n checkout_id: checkout.checkout_id,\n value: checkout.value,\n currency: checkout.currency ?? 'INR',\n num_items: sumItems(checkout.products),\n coupon: checkout.coupon,\n shipping: checkout.shipping,\n tax: checkout.tax,\n products: mapProducts(checkout.products),\n });\n }\n\n checkoutStep(step: number, options?: Record<string, unknown>): void {\n this.aegis.track('checkout_step', {\n step,\n ...options,\n });\n }\n\n // -- Order --\n\n orderCompleted(order: EcommerceOrder): void {\n this.aegis.track('order_completed', {\n order_id: order.order_id,\n value: order.value,\n revenue: order.revenue ?? order.value,\n currency: order.currency ?? 'INR',\n num_items: sumItems(order.products),\n coupon: order.coupon,\n shipping: order.shipping,\n tax: order.tax,\n discount: order.discount,\n payment_method: order.payment_method,\n products: mapProducts(order.products),\n });\n }\n\n orderRefunded(orderId: string, value?: number, products?: EcommerceProduct[]): void {\n this.aegis.track('order_refunded', {\n order_id: orderId,\n value,\n products: products ? mapProducts(products) : undefined,\n });\n }\n\n // -- Coupons --\n\n couponApplied(coupon: EcommerceCoupon): void {\n this.aegis.track('coupon_applied', { ...coupon });\n }\n\n couponRemoved(coupon: EcommerceCoupon): void {\n this.aegis.track('coupon_removed', { ...coupon });\n }\n\n // -- Wishlist --\n\n wishlistItemAdded(wishlist: EcommerceWishlist): void {\n this.aegis.track('wishlist_item_added', {\n wishlist_id: wishlist.wishlist_id,\n wishlist_name: wishlist.wishlist_name,\n product_id: wishlist.product.product_id,\n sku: wishlist.product.sku ?? wishlist.product.product_id,\n name: wishlist.product.name,\n price: wishlist.product.price,\n variant_id: wishlist.product.variant_id,\n });\n }\n\n // -- Promotions --\n\n promotionViewed(promo: EcommercePromotion): void {\n this.aegis.track('promotion_viewed', { ...promo });\n }\n\n promotionClicked(promo: EcommercePromotion): void {\n this.aegis.track('promotion_clicked', { ...promo });\n }\n}\n\nexport type {\n EcommerceProduct,\n EcommerceCart,\n EcommerceCheckout,\n EcommerceOrder,\n EcommerceCoupon,\n EcommerceSearch,\n EcommerceProductList,\n EcommerceWishlist,\n EcommercePromotion,\n} from './types';\n","/**\n * Token bucket rate limiter for client-side event throttling.\n *\n * Limits per session: burst (default 100) + sustained (default 20/sec).\n * Drops events with a console warning once a burst sustains. Drops are\n * emitted as a single coalesced `aegis.client.rate_limited` meta-event\n * per second so we don't flood ingress with drop notifications.\n *\n * Defaults are deliberately generous — the goal is to prevent runaway\n * loops (a buggy app firing 10k events/sec) without affecting normal use.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface RateLimiterOptions {\n /** Max tokens (burst size). Default 100. */\n burstCapacity?: number;\n /** Sustained rate per second. Default 20. */\n refillPerSecond?: number;\n /** Window in ms over which dropped events are coalesced. Default 1000. */\n dropCoalesceWindowMs?: number;\n /** Optional callback fired with the count of dropped events per coalesce window. */\n onDropBatch?: (droppedCount: number, sampleEventName: string | null) => void;\n}\n\nexport class RateLimiter {\n private tokens: number;\n private readonly capacity: number;\n private readonly refillPerSecond: number;\n private lastRefillMs: number;\n\n private droppedThisWindow = 0;\n private firstDroppedName: string | null = null;\n private windowFlushTimer: ReturnType<typeof setTimeout> | null = null;\n private readonly windowMs: number;\n private readonly onDropBatch?: (droppedCount: number, sampleEventName: string | null) => void;\n\n constructor(options: RateLimiterOptions = {}) {\n this.capacity = Math.max(1, options.burstCapacity ?? 100);\n this.refillPerSecond = Math.max(1, options.refillPerSecond ?? 20);\n this.windowMs = options.dropCoalesceWindowMs ?? 1000;\n this.onDropBatch = options.onDropBatch;\n this.tokens = this.capacity;\n this.lastRefillMs = Date.now();\n }\n\n /**\n * Try to consume 1 token. Returns true if allowed, false if throttled.\n * Throttled events are coalesced into a single onDropBatch callback per window.\n */\n tryConsume(eventName: string): boolean {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n return true;\n }\n\n this.droppedThisWindow += 1;\n if (this.firstDroppedName === null) {\n this.firstDroppedName = eventName;\n logger.warn(\n `[Aegis] Rate limit reached — dropping event \"${eventName}\" and any further events for ${this.windowMs}ms. Burst=${this.capacity}, refill=${this.refillPerSecond}/s.`,\n );\n }\n\n if (!this.windowFlushTimer) {\n this.windowFlushTimer = setTimeout(() => this.flushWindow(), this.windowMs);\n }\n\n return false;\n }\n\n /** Diagnostics — current token count (rounded down). */\n getAvailableTokens(): number {\n this.refill();\n return Math.floor(this.tokens);\n }\n\n /** Cleanup. Idempotent. */\n destroy(): void {\n if (this.windowFlushTimer) {\n clearTimeout(this.windowFlushTimer);\n this.windowFlushTimer = null;\n }\n this.flushWindow();\n }\n\n // ---------------------------------------------------------------------\n\n private refill(): void {\n const now = Date.now();\n const elapsedSec = (now - this.lastRefillMs) / 1000;\n if (elapsedSec <= 0) return;\n\n const newTokens = elapsedSec * this.refillPerSecond;\n this.tokens = Math.min(this.capacity, this.tokens + newTokens);\n this.lastRefillMs = now;\n }\n\n private flushWindow(): void {\n if (this.windowFlushTimer) {\n clearTimeout(this.windowFlushTimer);\n this.windowFlushTimer = null;\n }\n if (this.droppedThisWindow > 0 && this.onDropBatch) {\n try {\n this.onDropBatch(this.droppedThisWindow, this.firstDroppedName);\n } catch (err) {\n logger.warn('[Aegis] RateLimiter.onDropBatch threw:', err);\n }\n }\n this.droppedThisWindow = 0;\n this.firstDroppedName = null;\n }\n}\n","/**\n * MurmurHash3 x86-32 — deterministic, byte-identical with Python `mmh3.hash`.\n *\n * We hand-roll rather than pull a dep because (a) our bundle-budget is\n * aggressive for storefront first-paint, and (b) this is the authoritative\n * cross-language hash for the event-governance bloom filter — any behavior\n * drift between Python and JS produces silent FP-rate spikes in prod.\n *\n * Contract:\n * • Input is a JS string. It is UTF-8 encoded via TextEncoder before hashing.\n * • Output is an unsigned 32-bit integer (0 .. 2^32-1).\n * • Matches `mmh3.hash(s.encode('utf-8'), seed=seed, signed=False)` in\n * Python exactly — verified by libs/shared-types/bloom-test-vectors.json\n * in CI.\n *\n * Reference: Austin Appleby, MurmurHash3 (public domain).\n * https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp\n *\n * Implementation notes:\n * • All arithmetic on 32-bit ints. JS does bitwise ops on 32-bit ints natively;\n * `Math.imul` gives us correct 32-bit multiplication without overflow.\n * • We use `>>> 0` to coerce to unsigned after every step that could produce\n * a negative or >32-bit value.\n * • UTF-8 encoding matters — a naive `charCodeAt` loop would mis-hash any\n * string with non-ASCII characters (e.g. emoji, accented chars) and the\n * Python side would disagree. We always encode via TextEncoder first.\n */\n\nconst C1 = 0xcc9e2d51;\nconst C2 = 0x1b873593;\n\n/**\n * Compute MurmurHash3 x86-32 of a UTF-8 encoded string.\n *\n * @param input The string to hash.\n * @param seed 32-bit unsigned seed.\n * @returns Unsigned 32-bit integer hash.\n */\nexport function murmurhash3_x86_32(input: string, seed: number = 0): number {\n // Encode to UTF-8 bytes — matches Python's `s.encode('utf-8')`.\n const bytes = new TextEncoder().encode(input);\n return murmurhash3_bytes(bytes, seed);\n}\n\n/**\n * Compute MurmurHash3 x86-32 over a byte buffer directly.\n *\n * Exposed for callers that already have UTF-8 bytes and want to skip the\n * encode step (e.g., internal bloom-hash paths).\n */\nexport function murmurhash3_bytes(bytes: Uint8Array, seed: number = 0): number {\n const len = bytes.length;\n const nBlocks = Math.floor(len / 4);\n\n let h1 = seed >>> 0;\n\n // Body — consume 4-byte blocks.\n for (let i = 0; i < nBlocks; i++) {\n const offset = i * 4;\n let k1 =\n bytes[offset] |\n (bytes[offset + 1] << 8) |\n (bytes[offset + 2] << 16) |\n (bytes[offset + 3] << 24);\n\n k1 = Math.imul(k1, C1);\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = Math.imul(k1, C2);\n\n h1 ^= k1;\n h1 = (h1 << 13) | (h1 >>> 19);\n h1 = (Math.imul(h1, 5) + 0xe6546b64) >>> 0;\n }\n\n // Tail — up to 3 trailing bytes.\n const tailStart = nBlocks * 4;\n let k1 = 0;\n const tailLen = len - tailStart;\n if (tailLen === 3) k1 ^= bytes[tailStart + 2] << 16;\n if (tailLen >= 2) k1 ^= bytes[tailStart + 1] << 8;\n if (tailLen >= 1) {\n k1 ^= bytes[tailStart];\n k1 = Math.imul(k1, C1);\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = Math.imul(k1, C2);\n h1 ^= k1;\n }\n\n // Finalization — avalanche (fmix32).\n h1 ^= len;\n h1 ^= h1 >>> 16;\n h1 = Math.imul(h1, 0x85ebca6b);\n h1 ^= h1 >>> 13;\n h1 = Math.imul(h1, 0xc2b2ae35);\n h1 ^= h1 >>> 16;\n\n return h1 >>> 0;\n}\n","/**\n * Bloom filter — wire-compatible with the Python builder in\n * apps/control-plane/app/services/event_governance_bloom.py\n *\n * This SDK-side variant is QUERY-ONLY. The filter is built server-side\n * from the org's registered event-name set, base64-encoded, and shipped\n * to the browser on `/v1/sdk/bootstrap`. The SDK reads it once, uses it\n * to gate `track()` calls, and discards it on the next bootstrap.\n *\n * Wire format:\n * • `m` bits of storage, represented as m/8 bytes, base64-encoded.\n * • Bit `i` is at byte `i >> 3`, bitmask `1 << (i & 7)` — LSB-first.\n * • `m` MUST be a power of two — allows `idx & (m-1)` modulo.\n * • `k` hash functions synthesized via Kirsch-Mitzenmacher from two\n * MurmurHash3 x86-32 hashes with seeds (seedA, seedB):\n * h_i(x) = (h1(x) + i * h2(x)) mod m\n * • Input strings are UTF-8 encoded (handled inside murmurhash3_x86_32).\n */\n\nimport { murmurhash3_x86_32 } from './murmur3';\n\n/** Decode a base64 string to a Uint8Array. Accepts web (atob) and node (Buffer). */\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof atob !== 'undefined') {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n }\n // Node.js fallback — used by tests and SSR integrations.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const B = (globalThis as any).Buffer;\n if (B && typeof B.from === 'function') {\n const buf: Uint8Array = B.from(b64, 'base64');\n // Copy into a plain Uint8Array so callers don't observe Buffer semantics.\n return new Uint8Array(buf);\n }\n throw new Error('No base64 decoder available (neither atob nor Buffer)');\n}\n\nexport interface BloomFilterParams {\n /** Bits in the filter (must be power of 2). */\n m: number;\n /** Number of hash functions (Kirsch-Mitzenmacher synthesized). */\n k: number;\n /** Seed for the first MurmurHash3 call. */\n seedA: number;\n /** Seed for the second MurmurHash3 call. */\n seedB: number;\n}\n\nexport class BloomFilter {\n private readonly buf: Uint8Array;\n private readonly mask: number;\n\n constructor(buf: Uint8Array, private readonly params: BloomFilterParams) {\n if ((params.m & (params.m - 1)) !== 0) {\n throw new Error(`Bloom filter m must be a power of 2, got ${params.m}`);\n }\n if (buf.length !== params.m >> 3) {\n throw new Error(\n `Bloom filter buffer size mismatch: expected ${params.m >> 3} bytes, got ${buf.length}`\n );\n }\n this.buf = buf;\n this.mask = params.m - 1;\n }\n\n /** Build from the wire format (base64 bytes + explicit params). */\n static fromBase64(bloomB64: string, params: BloomFilterParams): BloomFilter {\n const bytes = base64ToBytes(bloomB64);\n return new BloomFilter(bytes, params);\n }\n\n /**\n * Returns true if `name` is probably in the set — possibly with the\n * filter's configured false-positive rate. FALSE is always authoritative.\n *\n * FP here means: SDK thinks a name is already registered when it isn't.\n * That costs one wasted server round-trip (gateway does the exact check\n * and catches it) — strictly safer than a false-negative, which could\n * leak a novel name past the SDK.\n */\n has(name: string): boolean {\n const h1 = murmurhash3_x86_32(name, this.params.seedA);\n const h2 = murmurhash3_x86_32(name, this.params.seedB);\n\n for (let i = 0; i < this.params.k; i++) {\n // >>> 0 at each step to keep arithmetic in unsigned 32-bit land;\n // we can't just take & mask at the end because h1 + i*h2 could\n // overflow past 2^32 when i*h2 is large.\n const combined = (h1 + Math.imul(i, h2)) >>> 0;\n const idx = combined & this.mask;\n const bit = this.buf[idx >> 3] & (1 << (idx & 7));\n if (bit === 0) return false;\n }\n return true;\n }\n}\n","/**\n * NameGovernor — client-side event-name cap enforcement.\n *\n * The governor consumes an `EventGovernanceHint` from the bootstrap response\n * and decides whether to let a `track()` call proceed to the network or drop\n * it locally.\n *\n * Why this exists:\n * Without it, a page that calls `track('new_btn_' + Date.now())` in a\n * render loop would (a) pass the local rate-limiter if within burst, (b)\n * force the gateway to ask control-plane for a verdict on every unique\n * name, and (c) amplify the CP `/event-governance/check` load quadratically\n * in the number of tabs firing the same bug. The bloom filter gives the\n * SDK enough information to drop novel names locally once the org hits\n * its cap, collapsing the amplification to zero.\n *\n * Design constraints:\n * • FAIL-OPEN — missing hint (Enterprise org, Redis outage) lets every\n * name through. The gateway is still the authoritative cap.\n * • FALSE-POSITIVE-SAFE — if the bloom says \"known\" for a name that isn't\n * actually registered, we send to gateway and the gateway's exact check\n * catches it. FPs cost one round trip, not a cap bypass.\n * • LOCAL-MEMO — a novel name that has already charged `remainingNewNames`\n * in this tab must NOT charge again on subsequent calls within the same\n * hint TTL. Without this, `track('new_btn_click')` fired 50 times would\n * drain 50 from the counter and block every OTHER legitimate novel name.\n * See `localNovelNames`.\n *\n * See docs/architecture/RFC_2026_04_SDK_GOVERNANCE_HINTS.md §3.3.\n */\n\nimport { BloomFilter } from './bloom-filter';\n\n/** Shape of the hint delivered by `/v1/sdk/bootstrap`. */\nexport interface EventGovernanceHint {\n bloom_algo: string;\n seed_a: number;\n seed_b: number;\n k: number;\n m: number;\n bloom_b64: string;\n remaining_new_names: number | null;\n /**\n * When true, the server is in its 7-day soft-cap grace window: it accepts\n * novel event names past the cap. SDK must NOT drop locally in this mode —\n * doing so would enforce harder than the server. See\n * apps/control-plane/app/schemas/event_governance_hint.py for the canonical\n * contract.\n */\n grace_active?: boolean;\n ttl_seconds: number;\n}\n\nexport interface DropReport {\n /** Map of event_name → count of local drops since last drain. */\n events: Record<string, number>;\n /** Total events dropped across all names (sum of values). */\n total: number;\n /** When the report window started (ms since epoch). */\n since: number;\n}\n\n/** Matches the `bloom_algo` tag shipped by the current control-plane build. */\nconst SUPPORTED_ALGO = 'mmh3_x86_32_km';\n\n/**\n * Best-effort console.warn — coalesced so a runaway render loop doesn't\n * flood the dev console. We only warn on the FIRST distinct dropped name;\n * subsequent names silently increment the telemetry counter.\n */\nfunction warnOncePerSession(message: string): void {\n if (typeof console === 'undefined' || typeof console.warn !== 'function') return;\n console.warn(message);\n}\n\nexport class NameGovernor {\n private bloom: BloomFilter | null = null;\n private remainingNewNames: number = Infinity;\n private graceActive: boolean = false;\n\n /**\n * Names this SDK instance has seen AS NOVEL and already charged against\n * `remainingNewNames`. Reset on every `ingestHint()` so we don't leak\n * accounting across hint refreshes.\n */\n private localNovelNames: Set<string> = new Set();\n\n /** Coalesced telemetry — flushed to the transport via drainDropReport(). */\n private droppedSinceLastReport: Map<string, number> = new Map();\n private reportWindowStart: number = Date.now();\n private hasWarnedThisSession = false;\n\n /**\n * Ingest a freshly-bootstrapped hint. Call on every successful bootstrap.\n * Passing `null` disables governance (fail-open).\n */\n ingestHint(hint: EventGovernanceHint | null): void {\n if (!hint || hint.bloom_algo !== SUPPORTED_ALGO) {\n // Unknown algo — a newer CP ships a version this SDK can't decode.\n // Silently disable governance; gateway remains authoritative.\n this.bloom = null;\n this.remainingNewNames = Infinity;\n this.graceActive = false;\n this.localNovelNames.clear();\n return;\n }\n\n try {\n this.bloom = BloomFilter.fromBase64(hint.bloom_b64, {\n m: hint.m,\n k: hint.k,\n seedA: hint.seed_a,\n seedB: hint.seed_b,\n });\n } catch {\n // Malformed hint — fail-open. Logged by the caller.\n this.bloom = null;\n }\n\n this.remainingNewNames = hint.remaining_new_names ?? Infinity;\n this.graceActive = hint.grace_active === true;\n this.localNovelNames.clear();\n }\n\n /**\n * Decide whether a `track()` call should proceed.\n *\n * Returns true = send to network (rate-limiter still runs after).\n * Returns false = drop locally; caller should return early.\n */\n shouldSend(eventName: string): boolean {\n // No hint = unlimited plan or fail-open. Send everything.\n if (!this.bloom) return true;\n\n // 7-day soft-cap grace window is active — server accepts novel names\n // past the cap, so SDK must not enforce harder. Fail-open to gateway.\n if (this.graceActive) return true;\n\n // Known name — send.\n if (this.bloom.has(eventName)) return true;\n\n // Already charged in this session — send (gateway has it cached too).\n if (this.localNovelNames.has(eventName)) return true;\n\n // Novel name, within headroom — charge once, send.\n if (this.remainingNewNames > 0) {\n this.localNovelNames.add(eventName);\n this.remainingNewNames -= 1;\n return true;\n }\n\n // Novel name, over the cap — drop locally, record for telemetry.\n const prev = this.droppedSinceLastReport.get(eventName) ?? 0;\n this.droppedSinceLastReport.set(eventName, prev + 1);\n\n // Only warn once per session, only on the first distinct dropped name —\n // a runaway loop will fill droppedSinceLastReport silently.\n if (!this.hasWarnedThisSession) {\n this.hasWarnedThisSession = true;\n warnOncePerSession(\n `[aegis] Event-name cap reached — \"${eventName}\" dropped locally. ` +\n `Upgrade your plan or remove dynamically-generated event names.`\n );\n }\n return false;\n }\n\n /**\n * Snapshot + reset the dropped-names counter. Called by the telemetry\n * beacon on batch flush so the gateway gets visibility into client-side\n * drops for ops dashboards.\n */\n drainDropReport(): DropReport | null {\n if (this.droppedSinceLastReport.size === 0) return null;\n\n const events: Record<string, number> = {};\n let total = 0;\n for (const [name, count] of this.droppedSinceLastReport) {\n events[name] = count;\n total += count;\n }\n\n const since = this.reportWindowStart;\n this.droppedSinceLastReport.clear();\n this.reportWindowStart = Date.now();\n\n return { events, total, since };\n }\n\n // Test-only accessors — not part of public API but easier than reflection.\n /** @internal */\n _debugState(): {\n hasBloom: boolean;\n remaining: number;\n localNovel: number;\n graceActive: boolean;\n } {\n return {\n hasBloom: this.bloom !== null,\n remaining: this.remainingNewNames,\n localNovel: this.localNovelNames.size,\n graceActive: this.graceActive,\n };\n }\n}\n","import {\n AegisConfig,\n AegisConfigInternal,\n DEFAULT_CONFIG,\n CellEndpoint,\n} from '../types/config';\nimport {\n TrackEvent,\n IdentifyEvent,\n PageEvent,\n GroupEvent,\n AliasEvent,\n AegisEvent,\n} from '../types/events';\nimport { Plugin } from '../types/plugin';\nimport { Identity } from '../utils/identity';\nimport { SessionManager } from './session';\nimport { EventQueue } from './queue';\nimport { Transport } from './transport';\nimport { Storage } from '../utils/storage';\nimport { buildContext, isBot } from '../utils/device';\nimport { generateMessageId } from '../utils/uuid';\nimport { logger } from '../utils/logger';\nimport { PluginRegistry } from '../plugins/registry';\nimport { ConsentManager, ConsentPreferences, ConsentCategory } from '../utils/consent';\nimport { parseAdClickIDs, hasAdClickIDs } from '../utils/url-parser';\nimport { EcommerceTracker } from '../ecommerce';\nimport { RateLimiter } from './rate-limiter';\nimport { NameGovernor, EventGovernanceHint } from '../governance';\n\nexport class Aegis {\n private config: AegisConfigInternal | null = null;\n private storage!: Storage;\n private identity!: Identity;\n private session: SessionManager | null = null;\n private queue: EventQueue | null = null;\n private transport: Transport | null = null;\n private plugins: PluginRegistry = new PluginRegistry();\n private initPromise: Promise<void> | null = null;\n private consent: ConsentManager | null = null;\n private _ecommerce: EcommerceTracker | null = null;\n private rateLimiter: RateLimiter | null = null;\n private nameGovernor: NameGovernor = new NameGovernor();\n private _lastPageUrl: string | null = null;\n private _popstateHandler: (() => void) | null = null;\n private _originalPushState: typeof history.pushState | null = null;\n private _originalReplaceState: typeof history.replaceState | null = null;\n\n async init(\n writeKey: string,\n config?: Partial<AegisConfig>\n ): Promise<void> {\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = this._init(writeKey, config);\n return this.initPromise;\n }\n\n private async _init(\n writeKey: string,\n config?: Partial<AegisConfig>\n ): Promise<void> {\n if (this.config?.initialized) {\n logger.warn('SDK already initialized');\n return;\n }\n\n if (this.shouldRespectDNT(config)) {\n logger.info('Do Not Track is enabled, SDK disabled');\n return;\n }\n\n if (isBot()) {\n logger.info('Bot detected, SDK disabled');\n return;\n }\n\n this.config = this.buildConfig(writeKey, config);\n\n if (this.config.debug) {\n logger.enable();\n }\n\n logger.info('Initializing Aegis SDK...', this.config);\n\n this.storage = new Storage({\n cookieDomain: this.config.cookie_domain,\n secureCookie: this.config.secure_cookie,\n crossDomain: this.config.cross_domain_tracking,\n });\n\n this.identity = new Identity(this.storage);\n\n this.consent = new ConsentManager(this.storage, {\n defaultConsent: this.config.default_consent,\n waitForConsent: this.config.wait_for_consent,\n });\n\n if (this.config.integrate_onetrust) {\n this.consent.integrateOneTrust();\n }\n\n if (this.config.integrate_cookiebot) {\n this.consent.integrateCookiebot();\n }\n\n if (this.config.integrate_google_consent_mode) {\n this.consent.integrateGoogleConsentMode();\n }\n\n this.session = new SessionManager(\n this.storage,\n this.config.session_timeout\n );\n\n this.captureAdClickIDsOnInit();\n\n this.transport = new Transport(\n {\n writeKey: this.config.write_key,\n apiHost: this.config.api_host,\n cellEndpoints: this.config.cell_endpoints,\n preferredRegion: this.config.preferred_region,\n autoRegionDetection: this.config.auto_region_detection,\n requestTimeout: this.config.request_timeout,\n retryFailedRequests: this.config.retry_failed_requests,\n maxRetries: this.config.max_retries,\n retryBackoffMultiplier: this.config.retry_backoff_multiplier,\n },\n this.storage\n );\n\n this.config.active_cell = this.transport.getActiveCell();\n\n this.queue = new EventQueue(\n {\n batchSize: this.config.batch_size,\n batchInterval: this.config.batch_interval,\n enableOfflineMode: this.config.enable_offline_mode,\n maxOfflineEvents: this.config.max_offline_events,\n },\n this.transport,\n this.storage\n );\n\n this.rateLimiter = new RateLimiter({\n burstCapacity: this.config.rate_limit_burst,\n refillPerSecond: this.config.rate_limit_per_second,\n onDropBatch: (count, sampleName) => this.emitRateLimitMeta(count, sampleName),\n });\n\n await this.initializePlugins();\n\n if (this.config.auto_page_view) {\n this.page();\n this.startSPATracking();\n }\n\n logger.info('Aegis SDK initialized successfully');\n }\n\n /**\n * SPA navigation tracking — monkey-patches pushState/replaceState and\n * listens for popstate to fire page() on every client-side route change.\n */\n private startSPATracking(): void {\n this._lastPageUrl = window.location.href;\n\n const onRouteChange = () => {\n // Debounce: only fire if URL actually changed\n const currentUrl = window.location.href;\n if (currentUrl === this._lastPageUrl) return;\n this._lastPageUrl = currentUrl;\n\n // Small delay to let the framework update document.title\n setTimeout(() => {\n this.page();\n }, 50);\n };\n\n // Listen for browser back/forward\n this._popstateHandler = onRouteChange;\n window.addEventListener('popstate', this._popstateHandler);\n\n // Monkey-patch pushState and replaceState\n this._originalPushState = history.pushState.bind(history);\n this._originalReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n this._originalPushState!(...args);\n onRouteChange();\n };\n\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n this._originalReplaceState!(...args);\n onRouteChange();\n };\n }\n\n private stopSPATracking(): void {\n if (this._popstateHandler) {\n window.removeEventListener('popstate', this._popstateHandler);\n this._popstateHandler = null;\n }\n\n if (this._originalPushState) {\n history.pushState = this._originalPushState;\n this._originalPushState = null;\n }\n\n if (this._originalReplaceState) {\n history.replaceState = this._originalReplaceState;\n this._originalReplaceState = null;\n }\n }\n\n private buildConfig(\n writeKey: string,\n config?: Partial<AegisConfig>\n ): AegisConfigInternal {\n return {\n ...DEFAULT_CONFIG,\n ...config,\n write_key: writeKey,\n initialized: true,\n } as AegisConfigInternal;\n }\n\n private shouldRespectDNT(config?: Partial<AegisConfig>): boolean {\n const respectDNT = config?.respect_dnt !== false;\n if (!respectDNT) return false;\n\n const dnt =\n navigator.doNotTrack ||\n (window as any).doNotTrack ||\n (navigator as any).msDoNotTrack;\n\n return dnt === '1' || dnt === 'yes';\n }\n\n private captureAdClickIDsOnInit(): void {\n if (!this.session) return;\n\n const adClickIDs = parseAdClickIDs();\n\n if (hasAdClickIDs(adClickIDs)) {\n this.session.setAdClickIDs(adClickIDs, window.location.href);\n logger.info('Ad click IDs captured on page load:', adClickIDs);\n }\n }\n\n private async initializePlugins(): Promise<void> {\n if (!this.config) return;\n\n for (const pluginName of this.config.plugins) {\n logger.debug(`Initializing plugin: ${pluginName}`);\n }\n\n await this.plugins.executeHook('init', this.config);\n }\n\n use(plugin: Plugin): void {\n this.plugins.register(plugin);\n\n if (this.config?.initialized && plugin.init) {\n Promise.resolve(plugin.init(this.config)).catch((error: any) => {\n logger.error(`Failed to initialize plugin \"${plugin.name}\":`, error);\n });\n }\n }\n\n track(eventName: string, properties?: Record<string, any>): void {\n if (!this.assertInitialized()) return;\n\n const event: TrackEvent = {\n type: 'track',\n event: eventName,\n properties: properties || {},\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session!.getSessionId(),\n workspace_id: this.config!.workspace_id || undefined,\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n identify(userId: string, traits?: Record<string, any>): void {\n if (!this.assertInitialized()) return;\n\n this.identity.setUserId(userId, traits);\n\n const event: IdentifyEvent = {\n type: 'identify',\n traits: traits || {},\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: userId,\n sessionId: this.session!.getSessionId(),\n workspace_id: this.config!.workspace_id || undefined,\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n page(name?: string, properties?: Record<string, any>): void {\n if (!this.assertInitialized()) return;\n\n const event: PageEvent = {\n type: 'page',\n name: name || document.title,\n properties: properties || {},\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session!.getSessionId(),\n workspace_id: this.config!.workspace_id || undefined,\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n group(groupId: string, traits?: Record<string, any>): void {\n if (!this.assertInitialized()) return;\n\n const event: GroupEvent = {\n type: 'group',\n groupId,\n traits: traits || {},\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session!.getSessionId(),\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n alias(newUserId: string): void {\n if (!this.assertInitialized()) return;\n\n const { previousId } = this.identity.alias(newUserId);\n\n const event: AliasEvent = {\n type: 'alias',\n previousId,\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: newUserId,\n sessionId: this.session!.getSessionId(),\n context: buildContext(this.config!, this.session!),\n };\n\n this.captureEvent(event);\n }\n\n private async captureEvent(event: AegisEvent): Promise<void> {\n if (this.config?.enable_consent_mode && this.consent) {\n if (event.type === 'track' || event.type === 'page') {\n if (!this.consent.hasConsent('analytics')) {\n logger.debug('Event blocked: analytics consent not granted');\n return;\n }\n }\n }\n\n // Event-name governance — drops novel names once the org's unique-event\n // cap is exhausted. Meta events (aegis.client.*) bypass the governor so\n // the telemetry channel stays open even under a cap-exhaustion storm.\n // See governance/name-governor.ts.\n if (event.type === 'track') {\n const trackEvent = event as TrackEvent;\n const isMetaEvent =\n typeof trackEvent.event === 'string' &&\n trackEvent.event.startsWith('aegis.client.');\n if (!isMetaEvent && !this.nameGovernor.shouldSend(trackEvent.event)) {\n return;\n }\n }\n\n if (this.rateLimiter) {\n const eventLabel =\n event.type === 'track' && (event as TrackEvent).event\n ? (event as TrackEvent).event\n : event.type;\n // Meta-events bypass the rate limiter to avoid recursion / lost telemetry.\n const isMetaEvent =\n event.type === 'track' &&\n typeof (event as TrackEvent).event === 'string' &&\n (event as TrackEvent).event.startsWith('aegis.client.');\n if (!isMetaEvent && !this.rateLimiter.tryConsume(eventLabel)) {\n return;\n }\n }\n\n // Auto-inject campaign attribution from UTM context into event properties\n // so downstream consumers (event-ingress, ClickHouse) receive campaign_id\n // without requiring manual mapping by the integrator.\n const ctx = (event as any).context;\n const props = (event as any).properties;\n if (ctx?.campaign && props && !props.campaign_id) {\n const utm = ctx.campaign;\n if (utm.campaign) props.campaign_id = utm.campaign;\n if (utm.source) props.campaign_source = utm.source;\n if (utm.medium) props.campaign_medium = utm.medium;\n if (utm.content) props.campaign_content = utm.content;\n if (utm.term) props.campaign_term = utm.term;\n }\n if (ctx?.adClickIDs && props) {\n const clicks = ctx.adClickIDs;\n const clickId = clicks.gclid || clicks.fbclid || clicks.ctwa_clid || clicks.msclkid || clicks.ttclid;\n if (clickId && !props.campaign_click_id) props.campaign_click_id = clickId;\n }\n\n logger.debug('Capturing event:', event);\n\n const transformedEvent = await this.plugins.executeHookChain(\n 'beforeEventCapture',\n event\n );\n\n if (!transformedEvent) {\n logger.debug('Event cancelled by plugin');\n return;\n }\n\n this.queue!.push(transformedEvent);\n this.session!.incrementEventCount();\n\n await this.plugins.executeHook('afterEventCapture', transformedEvent);\n }\n\n /**\n * Emit a coalesced meta-event reporting client-side rate-limit drops.\n * Bypasses the limiter (see captureEvent guard).\n */\n private emitRateLimitMeta(count: number, sampleEventName: string | null): void {\n if (!this.config?.initialized || !this.session || !this.identity) return;\n const event: TrackEvent = {\n type: 'track',\n event: 'aegis.client.rate_limited',\n properties: {\n dropped_count: count,\n sample_event_name: sampleEventName,\n burst_capacity: this.config.rate_limit_burst,\n refill_per_second: this.config.rate_limit_per_second,\n },\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session.getSessionId(),\n context: buildContext(this.config, this.session),\n };\n this.queue?.push(event);\n }\n\n reset(): void {\n if (!this.assertInitialized()) return;\n\n this.identity.reset();\n logger.info('User identity reset');\n }\n\n /**\n * Ingest the event-governance hint returned from `/v1/sdk/bootstrap`.\n *\n * Callers (Shopify pixel, snippet, react integration) run `bootstrap()`\n * themselves and pass the resulting `eventGovernance` field here so the\n * SDK can self-throttle novel event names before they hit the gateway.\n *\n * Passing null/undefined disables governance (Enterprise plan / outage\n * fail-open). Safe to call before `init()` — the hint is stored and\n * applied as soon as init completes.\n */\n ingestGovernanceHint(hint: EventGovernanceHint | null | undefined): void {\n this.nameGovernor.ingestHint(hint ?? null);\n logger.debug('Governance hint ingested', hint ? {\n k: hint.k,\n m: hint.m,\n remaining: hint.remaining_new_names,\n } : 'disabled');\n }\n\n /**\n * Drain the client-side drop counter and emit a meta-event. Called\n * periodically by the queue flush path so ops dashboards see novel-name\n * amplification patterns in near-real-time.\n */\n private emitGovernanceDropMeta(): void {\n if (!this.config?.initialized || !this.session || !this.identity) return;\n const report = this.nameGovernor.drainDropReport();\n if (!report) return;\n\n const event: TrackEvent = {\n type: 'track',\n event: 'aegis.client.name_governor_dropped',\n properties: {\n dropped_count: report.total,\n distinct_names: Object.keys(report.events).length,\n // Cap the payload — a runaway loop could produce thousands of names;\n // we ship the top 10 for diagnostics and the total for counting.\n sample_names: Object.entries(report.events)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([name, count]) => ({ name, count })),\n window_start: report.since,\n window_end: Date.now(),\n },\n messageId: generateMessageId(),\n timestamp: new Date().toISOString(),\n anonymousId: this.identity.getAnonymousId(),\n userId: this.identity.getUserId() || undefined,\n sessionId: this.session.getSessionId(),\n context: buildContext(this.config, this.session),\n };\n this.queue?.push(event);\n }\n\n async flush(): Promise<void> {\n if (!this.assertInitialized()) return;\n\n // Emit any coalesced governance-drop telemetry BEFORE flushing so the\n // meta event rides in the same batch as the rest.\n this.emitGovernanceDropMeta();\n await this.queue!.flush();\n }\n\n getAnonymousId(): string | null {\n if (!this.identity) return null;\n return this.identity.getAnonymousId();\n }\n\n getUserId(): string | null {\n if (!this.identity) return null;\n return this.identity.getUserId();\n }\n\n getSessionId(): string | null {\n if (!this.session) return null;\n return this.session.getSessionId();\n }\n\n debug(enable: boolean = true): void {\n if (enable) {\n logger.enable();\n } else {\n logger.disable();\n }\n\n if (this.config) {\n this.config.debug = enable;\n }\n }\n\n setCell(cellEndpoint: CellEndpoint): void {\n if (!this.config) {\n logger.warn('SDK not initialized');\n return;\n }\n\n const existingCell = this.config.cell_endpoints.find(\n (c) => c.region === cellEndpoint.region\n );\n\n if (existingCell) {\n Object.assign(existingCell, cellEndpoint);\n } else {\n this.config.cell_endpoints.push(cellEndpoint);\n }\n\n logger.info('Cell endpoint configured:', cellEndpoint);\n }\n\n getCellInfo() {\n if (!this.transport) return null;\n\n return {\n activeCell: this.transport.getActiveCell(),\n latencies: this.transport.getRegionLatencies(),\n };\n }\n\n setConsent(preferences: Partial<ConsentPreferences>): void {\n if (!this.consent) {\n logger.warn('Consent manager not initialized');\n return;\n }\n\n this.consent.setConsent(preferences);\n logger.info('Consent preferences updated');\n }\n\n grantConsent(category?: ConsentCategory): void {\n if (!this.consent) {\n logger.warn('Consent manager not initialized');\n return;\n }\n\n if (category) {\n this.consent.setConsent({ [category]: true });\n } else {\n this.consent.grantAll();\n }\n }\n\n denyConsent(category?: ConsentCategory): void {\n if (!this.consent) {\n logger.warn('Consent manager not initialized');\n return;\n }\n\n if (category) {\n this.consent.setConsent({ [category]: false });\n } else {\n this.consent.denyAll();\n }\n }\n\n hasConsent(category: ConsentCategory): boolean {\n if (!this.consent) {\n return true;\n }\n\n return this.consent.hasConsent(category);\n }\n\n getConsentPreferences(): ConsentPreferences | null {\n if (!this.consent) {\n return null;\n }\n\n return this.consent.getPreferences();\n }\n\n onConsentChange(callback: (preferences: ConsentPreferences) => void): () => void {\n if (!this.consent) {\n logger.warn('Consent manager not initialized');\n return () => {};\n }\n\n return this.consent.onChange(callback);\n }\n\n private assertInitialized(): boolean {\n if (!this.config?.initialized) {\n logger.warn('SDK not initialized. Call aegis.init() first.');\n return false;\n }\n return true;\n }\n\n get ecommerce(): EcommerceTracker {\n if (!this._ecommerce) {\n this._ecommerce = new EcommerceTracker(this);\n }\n return this._ecommerce;\n }\n\n destroy(): void {\n this.stopSPATracking();\n\n if (this.queue) {\n this.queue.destroy();\n }\n\n if (this.session) {\n this.session.destroy();\n }\n\n if (this.transport) {\n this.transport.destroy();\n }\n\n if (this.rateLimiter) {\n this.rateLimiter.destroy();\n this.rateLimiter = null;\n }\n\n this.plugins.clear();\n\n logger.info('SDK destroyed');\n }\n}\n","/**\n * CarouselCards renderer — a swipeable / autoplaying sequence of product\n * cards. Used for post-purchase upsells, cross-sell, and \"recently viewed\"\n * surfaces. The entire card list is pre-bundled — no network call on\n * trigger; slide advance is pure client state.\n *\n * Data shape (interactive_config, populated at campaign create time and\n * validated server-side):\n * cards: Array<{ image_url?, title, body?, cta_text?, cta_url? }>\n * autoplay_ms?: number // 0 = manual advance only\n * loop?: boolean // wrap to card 0 on last-next\n */\n\nimport type { RenderContext } from './types';\n\ntype Card = {\n image_url?: string;\n title?: string;\n body?: string;\n cta_text?: string;\n cta_url?: string;\n};\n\nconst MAX_CARDS_RENDERED = 10;\n\nexport function renderCarouselCards(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const rawCards = Array.isArray(ic.cards) ? (ic.cards as Card[]) : [];\n const cards = rawCards.slice(0, MAX_CARDS_RENDERED);\n\n if (cards.length === 0) {\n log('carousel_cards rendered with zero cards — skipping', 'warn');\n return;\n }\n\n const autoplay = Number(ic.autoplay_ms) || 0;\n const loop = ic.loop !== false; // default true\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#ffffff');\n const fg = sanitizeColor((campaign.text_color as string) || '#0f172a');\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-carousel-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = `\n position: fixed; left: 0; right: 0; bottom: 0;\n z-index: 99999; padding: 12px 12px 20px;\n background: rgba(0,0,0,0.12); backdrop-filter: blur(8px);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n `;\n\n const card = document.createElement('div');\n card.style.cssText = `\n background: ${bg}; color: ${fg}; border-radius: 16px;\n box-shadow: 0 8px 20px rgba(0,0,0,0.08); padding: 16px;\n max-width: 520px; margin: 0 auto; position: relative;\n `;\n\n const header = document.createElement('div');\n header.style.cssText = 'display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 12px;';\n\n const headerText = document.createElement('div');\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 700; font-size: 15px; margin-bottom: 2px;';\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.75;';\n headerText.appendChild(title);\n headerText.appendChild(body);\n header.appendChild(headerText);\n\n const closeBtn = document.createElement('button');\n closeBtn.textContent = '✕';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 16px; cursor: pointer; opacity: 0.6; padding: 2px 6px;\n `;\n closeBtn.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n });\n header.appendChild(closeBtn);\n card.appendChild(header);\n\n const track = document.createElement('div');\n track.style.cssText = `\n display: flex; gap: 10px; overflow-x: auto; scroll-snap-type: x mandatory;\n scrollbar-width: none; -ms-overflow-style: none; padding-bottom: 4px;\n `;\n (track.style as unknown as { msOverflowStyle?: string }).msOverflowStyle = 'none';\n track.addEventListener('wheel', (e) => {\n if (Math.abs(e.deltaX) < Math.abs(e.deltaY)) return;\n track.scrollLeft += e.deltaX;\n });\n\n cards.forEach((c, i) => {\n const tile = document.createElement('div');\n tile.setAttribute('data-card-index', String(i));\n tile.style.cssText = `\n flex: 0 0 auto; width: 140px; scroll-snap-align: start;\n background: ${fg}0a; border-radius: 12px; padding: 10px;\n display: flex; flex-direction: column; gap: 6px;\n cursor: ${c.cta_url ? 'pointer' : 'default'};\n `;\n if (c.image_url) {\n const img = document.createElement('img');\n const safe = sanitizeUrl(c.image_url);\n if (safe) {\n img.src = safe;\n img.alt = '';\n img.loading = 'lazy';\n img.style.cssText = 'width: 100%; height: 96px; border-radius: 8px; object-fit: cover;';\n tile.appendChild(img);\n }\n }\n if (c.title) {\n const t = document.createElement('div');\n t.textContent = c.title;\n t.style.cssText = 'font-weight: 600; font-size: 13px; line-height: 1.3;';\n tile.appendChild(t);\n }\n if (c.body) {\n const b = document.createElement('div');\n b.textContent = c.body;\n b.style.cssText = 'font-size: 11.5px; opacity: 0.72; line-height: 1.3;';\n tile.appendChild(b);\n }\n if (c.cta_text && c.cta_url) {\n const cta = document.createElement('button');\n cta.textContent = c.cta_text;\n cta.style.cssText = `\n margin-top: auto; background: ${fg}; color: ${bg};\n border: none; padding: 6px 10px; border-radius: 999px;\n font-size: 12px; font-weight: 600; cursor: pointer;\n `;\n const goto = (e: Event) => {\n e.stopPropagation();\n trackEvent(campaign.id, 'clicked');\n const safe = sanitizeUrl(c.cta_url!);\n if (safe) window.location.href = safe;\n };\n cta.addEventListener('click', goto);\n tile.appendChild(cta);\n tile.addEventListener('click', goto);\n }\n track.appendChild(tile);\n });\n card.appendChild(track);\n\n // Dots + autoplay\n const dots = document.createElement('div');\n dots.style.cssText = 'display: flex; justify-content: center; gap: 6px; margin-top: 10px;';\n const dotEls: HTMLSpanElement[] = [];\n cards.forEach(() => {\n const dot = document.createElement('span');\n dot.style.cssText = `\n width: 6px; height: 6px; border-radius: 999px; background: ${fg};\n opacity: 0.25; transition: opacity 0.2s;\n `;\n dotEls.push(dot);\n dots.appendChild(dot);\n });\n card.appendChild(dots);\n\n const setActive = (idx: number) => {\n dotEls.forEach((d, i) => (d.style.opacity = i === idx ? '0.9' : '0.25'));\n };\n setActive(0);\n\n let activeIdx = 0;\n const tiles = track.querySelectorAll<HTMLDivElement>('[data-card-index]');\n const goto = (idx: number) => {\n activeIdx = ((idx % cards.length) + cards.length) % cards.length;\n const el = tiles[activeIdx];\n if (el) {\n el.scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' });\n setActive(activeIdx);\n }\n };\n\n let autoplayTimer: ReturnType<typeof setInterval> | null = null;\n if (autoplay > 0 && cards.length > 1) {\n autoplayTimer = setInterval(() => {\n const next = activeIdx + 1;\n if (next >= cards.length && !loop) {\n if (autoplayTimer) clearInterval(autoplayTimer);\n return;\n }\n goto(next);\n }, autoplay);\n }\n\n overlay.addEventListener('remove', () => {\n if (autoplayTimer) clearInterval(autoplayTimer);\n });\n\n // Observe scroll to keep dots in sync when the user swipes.\n track.addEventListener('scroll', () => {\n const approx = Math.round(track.scrollLeft / 150);\n if (approx !== activeIdx && approx >= 0 && approx < cards.length) {\n activeIdx = approx;\n setActive(activeIdx);\n }\n });\n\n overlay.appendChild(card);\n document.body.appendChild(overlay);\n}\n","/**\n * StickyBar renderer — a pinned notification strip at the top or bottom\n * of the viewport. Used for free-shipping hints, flash-sale banners,\n * cart-reminder strips. Dismissible, optionally auto-hiding.\n *\n * interactive_config:\n * sticky_position: 'top' | 'bottom' (required)\n * sticky_bg_color?: string\n * sticky_dismissible?: boolean default true\n * sticky_auto_hide_ms?: number 0 = never\n */\n\nimport type { RenderContext } from './types';\n\n// Persist per-campaign dismissal across reloads so we don't re-show a\n// bar the user already closed. Scoped per campaign ID; storage key\n// survives navigation but is cleared when the user explicitly clears site data.\nconst DISMISS_STORAGE_PREFIX = 'aegis_sticky_dismissed:';\n\nexport function renderStickyBar(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const position = ic.sticky_position === 'top' ? 'top' : 'bottom';\n const dismissible = ic.sticky_dismissible !== false;\n const autoHide = Number(ic.sticky_auto_hide_ms) || 0;\n\n // Already dismissed this session? Skip silently — the prefetch bundle\n // keeps re-offering it, but the user's explicit close stands until TTL.\n try {\n if (\n typeof localStorage !== 'undefined' &&\n localStorage.getItem(DISMISS_STORAGE_PREFIX + campaign.id)\n ) {\n log(`sticky_bar ${campaign.id} suppressed — user dismissed earlier`);\n return;\n }\n } catch {\n // localStorage blocked — fall through and render\n }\n\n addAnimationStyles();\n\n const bg = sanitizeColor(\n (ic.sticky_bg_color as string) || (campaign.background_color as string) || '#4169e1',\n );\n const fg = sanitizeColor((campaign.text_color as string) || '#ffffff');\n\n const bar = document.createElement('div');\n bar.className = 'aegis-in-app-sticky-bar';\n bar.setAttribute('data-campaign-id', campaign.id);\n\n const positionCss =\n position === 'top'\n ? 'top: 0; left: 0; right: 0; animation: aegisSlideDown 0.3s ease-out;'\n : 'bottom: 0; left: 0; right: 0; animation: aegisSlideInFromBottom 0.3s ease-out;';\n\n bar.style.cssText = `\n position: fixed; ${positionCss}\n background: ${bg}; color: ${fg};\n padding: 10px 14px; z-index: 999998;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n display: flex; align-items: center; gap: 12px; justify-content: center;\n box-shadow: 0 ${position === 'top' ? '2px' : '-2px'} 8px rgba(0,0,0,0.08);\n `;\n\n const label = document.createElement('div');\n label.style.cssText = 'flex: 0 1 auto; font-size: 13px; font-weight: 500; text-align: center;';\n const strong = document.createElement('strong');\n strong.textContent = campaign.title;\n strong.style.cssText = 'margin-right: 6px; font-weight: 700;';\n label.appendChild(strong);\n label.appendChild(document.createTextNode(campaign.body));\n bar.appendChild(label);\n\n if (campaign.action_url && campaign.button_text) {\n const cta = document.createElement('button');\n cta.textContent = campaign.button_text;\n cta.style.cssText = `\n background: ${fg}; color: ${bg};\n border: none; padding: 6px 14px; border-radius: 999px;\n font-size: 12px; font-weight: 700; cursor: pointer; white-space: nowrap;\n `;\n cta.addEventListener('click', () => {\n trackEvent(campaign.id, 'clicked');\n const safe = sanitizeUrl(campaign.action_url!);\n if (safe) window.location.href = safe;\n });\n bar.appendChild(cta);\n }\n\n let autoHideTimer: ReturnType<typeof setTimeout> | null = null;\n const remove = (persist: boolean) => {\n if (autoHideTimer) clearTimeout(autoHideTimer);\n if (persist) {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(DISMISS_STORAGE_PREFIX + campaign.id, '1');\n }\n } catch {\n // swallow — localStorage may be disabled\n }\n }\n bar.remove();\n };\n\n if (dismissible) {\n const close = document.createElement('button');\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Dismiss');\n close.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 16px; cursor: pointer; padding: 0 4px; opacity: 0.75;\n `;\n close.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n remove(true);\n });\n bar.appendChild(close);\n }\n\n if (autoHide > 0) {\n autoHideTimer = setTimeout(() => remove(false), autoHide);\n }\n\n document.body.appendChild(bar);\n}\n","/**\n * ProgressBar renderer — a persistent bar that shows the user's progress\n * toward a reward threshold (free shipping, loyalty tier, referral bonus).\n *\n * Two sources of the current value:\n * 'client' — cheap: read from window.Shopify / WooCommerce / Magento\n * cart globals. Untrusted; fine for visual-only hints.\n * 'sse' — trusted: cell-plane pushes current_value via SSE to the\n * already-shipped realtime server. For cart-gated rewards\n * (must agree with server-side checkout guard), prefer SSE.\n *\n * For Phase 1 we implement CLIENT mode end-to-end. SSE mode reads\n * `window.__aegisProgressSSE[campaign.id]` if populated by a parent app\n * — higher-level integration (the SSE bridge) can push values there.\n *\n * interactive_config:\n * progress_goal_type: 'cart_total' | 'items_in_cart' | 'loyalty_points' | 'referrals'\n * progress_threshold: number\n * progress_reward_text?: string\n * progress_source?: 'client' | 'sse' default 'client'\n */\n\nimport type { RenderContext } from './types';\n\ntype GoalType = 'cart_total' | 'items_in_cart' | 'loyalty_points' | 'referrals';\n\nexport function renderProgressBar(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const goalType = (ic.progress_goal_type as GoalType) || 'cart_total';\n const threshold = Number(ic.progress_threshold);\n if (!(threshold > 0)) {\n log('progress_bar requires a positive progress_threshold — skipping', 'warn');\n return;\n }\n const rewardText =\n (ic.progress_reward_text as string) || (campaign.body as string) || 'Unlocked!';\n const source = ic.progress_source === 'sse' ? 'sse' : 'client';\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#f8fafc');\n const fill = sanitizeColor((campaign.text_color as string) || '#4169e1');\n const fg = '#0f172a';\n\n const bar = document.createElement('div');\n bar.className = 'aegis-in-app-progress-bar';\n bar.setAttribute('data-campaign-id', campaign.id);\n bar.style.cssText = `\n position: fixed; left: 12px; right: 12px; bottom: 12px;\n max-width: 540px; margin: 0 auto;\n background: ${bg}; color: ${fg}; border-radius: 12px;\n padding: 10px 14px; z-index: 999997;\n box-shadow: 0 8px 20px rgba(0,0,0,0.08);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n `;\n\n const label = document.createElement('div');\n label.style.cssText = 'display: flex; justify-content: space-between; font-size: 13px; font-weight: 600; margin-bottom: 6px;';\n\n const leading = document.createElement('span');\n leading.textContent = campaign.title;\n label.appendChild(leading);\n\n const numeric = document.createElement('span');\n numeric.style.cssText = 'opacity: 0.7; font-weight: 500;';\n label.appendChild(numeric);\n bar.appendChild(label);\n\n const shell = document.createElement('div');\n shell.style.cssText = `\n height: 8px; border-radius: 999px; background: ${fill}22;\n overflow: hidden;\n `;\n const fillEl = document.createElement('div');\n fillEl.style.cssText = `\n height: 100%; border-radius: 999px; background: ${fill};\n width: 0%; transition: width 0.4s cubic-bezier(.4,0,.2,1);\n `;\n shell.appendChild(fillEl);\n bar.appendChild(shell);\n\n const footnote = document.createElement('div');\n footnote.style.cssText = 'font-size: 11.5px; opacity: 0.65; margin-top: 6px;';\n bar.appendChild(footnote);\n\n const readCurrentValue = (): number => {\n if (source === 'sse') {\n const hook = (window as unknown as {\n __aegisProgressSSE?: Record<string, number>;\n }).__aegisProgressSSE;\n return (hook && typeof hook[campaign.id] === 'number' ? hook[campaign.id] : 0) as number;\n }\n // client mode — read the platform cart globals the widget manager\n // already normalises (Shopify/Woo/Magento). We peek at the same\n // locations without pulling in AegisWidgetManager's 2k-line module.\n try {\n if (goalType === 'cart_total' || goalType === 'items_in_cart') {\n const win = window as unknown as {\n Shopify?: { checkout?: { total_price?: string | number } };\n aegis_cart?: { cart_total?: number; cart_items?: unknown[] };\n localStorage?: Storage;\n };\n if (win.Shopify?.checkout) {\n const v = parseFloat(String(win.Shopify.checkout.total_price || 0));\n return goalType === 'cart_total' ? v : 0;\n }\n if (win.aegis_cart) {\n if (goalType === 'items_in_cart') {\n return Array.isArray(win.aegis_cart.cart_items) ? win.aegis_cart.cart_items.length : 0;\n }\n return Number(win.aegis_cart.cart_total || 0);\n }\n // Magento cache fallback\n try {\n const cacheStr = window.localStorage?.getItem('mage-cache-storage');\n if (cacheStr) {\n const cache = JSON.parse(cacheStr) as { cart?: { subtotalAmount?: number; items?: unknown[] } };\n const cart = cache.cart;\n if (cart) {\n return goalType === 'cart_total'\n ? Number(cart.subtotalAmount || 0)\n : Array.isArray(cart.items)\n ? cart.items.length\n : 0;\n }\n }\n } catch {\n /* noop */\n }\n }\n // loyalty_points / referrals are expected to flow via SSE/push; in\n // client mode we cannot trust a local counter.\n return 0;\n } catch {\n return 0;\n }\n };\n\n let lastFiredUnlock = false;\n const update = () => {\n const cur = readCurrentValue();\n const pct = Math.max(0, Math.min(100, (cur / threshold) * 100));\n fillEl.style.width = `${pct}%`;\n numeric.textContent = `${cur.toFixed(0)} / ${threshold.toFixed(0)}`;\n if (pct >= 100) {\n footnote.textContent = rewardText;\n if (!lastFiredUnlock) {\n lastFiredUnlock = true;\n trackEvent(campaign.id, 'clicked'); // \"unlocked\" recorded as click\n }\n } else {\n const remaining = Math.max(0, threshold - cur);\n footnote.textContent = `Add ${remaining.toFixed(0)} more to unlock: ${rewardText}`;\n }\n };\n\n update();\n\n // Client-mode cart state changes fire events on the storefront globals\n // (Shopify emits `cart:updated`, Woo emits its own). Poll fallback at\n // 1s — negligible overhead because every tick is synchronous.\n const pollTimer = setInterval(update, 1000);\n const cleanup = () => clearInterval(pollTimer);\n window.addEventListener('beforeunload', cleanup, { once: true });\n bar.addEventListener('remove', cleanup);\n\n document.body.appendChild(bar);\n}\n","/**\n * CoachmarkTour renderer — a guided, multi-step walkthrough anchored to\n * DOM elements via CSS selectors. One tooltip appears at a time with\n * next/back navigation; completion + skip are persisted per contact via\n * localStorage under the `resume_key`, so an abandoned tour resumes on\n * the next visit instead of restarting or re-bothering the user.\n *\n * interactive_config:\n * steps: Array<{\n * anchor_web?: string, // CSS selector for THIS platform\n * anchor_android?: string, // ignored on web\n * anchor_ios?: string, // ignored on web\n * title: string,\n * body: string,\n * placement?: 'top' | 'bottom' | 'left' | 'right',\n * cta_text?: string,\n * }>\n * resume_key: string,\n * allow_skip?: boolean,\n * show_progress_dots?: boolean,\n */\n\nimport type { RenderContext } from './types';\n\ntype Step = {\n anchor_web?: string;\n anchor_android?: string;\n anchor_ios?: string;\n title: string;\n body: string;\n placement?: 'top' | 'bottom' | 'left' | 'right';\n cta_text?: string;\n};\n\nconst RESUME_PREFIX = 'aegis_coachmark_progress:';\n\nfunction readResumeIdx(resumeKey: string): number {\n try {\n if (typeof localStorage === 'undefined') return 0;\n const raw = localStorage.getItem(RESUME_PREFIX + resumeKey);\n const n = raw ? parseInt(raw, 10) : 0;\n return Number.isFinite(n) && n >= 0 ? n : 0;\n } catch {\n return 0;\n }\n}\n\nfunction writeResumeIdx(resumeKey: string, idx: number): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(RESUME_PREFIX + resumeKey, String(idx));\n }\n } catch {\n /* noop */\n }\n}\n\nfunction clearResume(resumeKey: string): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem(RESUME_PREFIX + resumeKey);\n }\n } catch {\n /* noop */\n }\n}\n\nexport function renderCoachmarkTour(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const resumeKey = ic.resume_key as string | undefined;\n if (!resumeKey) {\n log('coachmark_tour requires interactive_config.resume_key — skipping', 'warn');\n return;\n }\n\n const steps = Array.isArray(ic.steps) ? (ic.steps as Step[]) : [];\n if (steps.length === 0) {\n log('coachmark_tour has no steps — skipping', 'warn');\n return;\n }\n\n const allowSkip = ic.allow_skip !== false;\n const showDots = ic.show_progress_dots !== false;\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#0f172a');\n const fg = sanitizeColor((campaign.text_color as string) || '#ffffff');\n\n // Resume or start at 0.\n let current = readResumeIdx(resumeKey);\n if (current >= steps.length) {\n log(`coachmark_tour ${resumeKey} already complete — not re-showing`);\n return;\n }\n\n // Track the single overall impression once per mount.\n trackEvent(campaign.id, 'impression');\n\n let pointerEl: HTMLElement | null = null;\n let tipEl: HTMLElement | null = null;\n let highlightEl: HTMLElement | null = null;\n\n const cleanupOne = () => {\n pointerEl?.remove();\n tipEl?.remove();\n highlightEl?.remove();\n pointerEl = null;\n tipEl = null;\n highlightEl = null;\n };\n\n const finish = (opts: { skipped: boolean }) => {\n cleanupOne();\n if (opts.skipped) {\n trackEvent(campaign.id, 'dismissed');\n } else {\n trackEvent(campaign.id, 'clicked'); // completion\n }\n // Mark tour as complete so we never restart it for this contact.\n writeResumeIdx(resumeKey, steps.length);\n };\n\n const showStep = (idx: number) => {\n cleanupOne();\n const step = steps[idx];\n if (!step) {\n finish({ skipped: false });\n return;\n }\n writeResumeIdx(resumeKey, idx);\n\n const selector = step.anchor_web;\n let anchor: Element | null = null;\n if (selector) {\n try {\n anchor = document.querySelector(selector);\n } catch {\n anchor = null;\n }\n }\n if (!anchor) {\n log(`coachmark step ${idx} — selector '${selector}' not found; advancing`, 'warn');\n showStep(idx + 1);\n return;\n }\n\n const rect = anchor.getBoundingClientRect();\n // Slight highlight around the anchor so the user's eye snaps to it.\n highlightEl = document.createElement('div');\n highlightEl.style.cssText = `\n position: fixed;\n top: ${rect.top - 6}px; left: ${rect.left - 6}px;\n width: ${rect.width + 12}px; height: ${rect.height + 12}px;\n border-radius: 10px; z-index: 999998;\n box-shadow: 0 0 0 2px ${fg}, 0 0 0 9999px rgba(0,0,0,0.4);\n pointer-events: none;\n transition: all 0.2s ease;\n `;\n document.body.appendChild(highlightEl);\n\n const placement = step.placement || 'bottom';\n tipEl = document.createElement('div');\n tipEl.setAttribute('data-campaign-id', campaign.id);\n tipEl.style.cssText = `\n position: fixed; z-index: 999999;\n background: ${bg}; color: ${fg};\n padding: 12px 14px; border-radius: 12px;\n max-width: 260px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.25);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisFadeIn 0.2s ease;\n `;\n\n const titleEl = document.createElement('div');\n titleEl.textContent = step.title;\n titleEl.style.cssText = 'font-weight: 700; font-size: 13px; margin-bottom: 4px;';\n tipEl.appendChild(titleEl);\n\n const bodyEl = document.createElement('div');\n bodyEl.textContent = step.body;\n bodyEl.style.cssText = 'font-size: 12.5px; line-height: 1.4; opacity: 0.9;';\n tipEl.appendChild(bodyEl);\n\n const controls = document.createElement('div');\n controls.style.cssText = 'display: flex; align-items: center; justify-content: space-between; margin-top: 10px; gap: 8px;';\n\n // Dots\n if (showDots) {\n const dots = document.createElement('div');\n dots.style.cssText = 'display: flex; gap: 4px;';\n steps.forEach((_, i) => {\n const d = document.createElement('span');\n d.style.cssText = `\n width: 5px; height: 5px; border-radius: 999px;\n background: ${fg}; opacity: ${i === idx ? '0.95' : '0.3'};\n `;\n dots.appendChild(d);\n });\n controls.appendChild(dots);\n } else {\n controls.appendChild(document.createElement('span'));\n }\n\n const buttons = document.createElement('div');\n buttons.style.cssText = 'display: flex; gap: 6px;';\n\n if (allowSkip && idx < steps.length - 1) {\n const skip = document.createElement('button');\n skip.textContent = 'Skip';\n skip.style.cssText = `\n background: transparent; color: inherit; opacity: 0.7;\n border: none; font-size: 12px; cursor: pointer; padding: 6px 8px;\n `;\n skip.addEventListener('click', () => finish({ skipped: true }));\n buttons.appendChild(skip);\n }\n\n const next = document.createElement('button');\n const isLast = idx === steps.length - 1;\n next.textContent = step.cta_text || (isLast ? 'Done' : 'Next');\n next.style.cssText = `\n background: ${fg}; color: ${bg};\n border: none; padding: 6px 12px; border-radius: 999px;\n font-size: 12px; font-weight: 700; cursor: pointer;\n `;\n next.addEventListener('click', () => {\n if (isLast) {\n finish({ skipped: false });\n } else {\n showStep(idx + 1);\n }\n });\n buttons.appendChild(next);\n\n controls.appendChild(buttons);\n tipEl.appendChild(controls);\n document.body.appendChild(tipEl);\n\n // Position after insertion so we know the tip's own dimensions.\n const tipRect = tipEl.getBoundingClientRect();\n const margin = 12;\n let top = rect.bottom + margin;\n let left = rect.left;\n if (placement === 'top') {\n top = rect.top - tipRect.height - margin;\n } else if (placement === 'left') {\n top = rect.top;\n left = rect.left - tipRect.width - margin;\n } else if (placement === 'right') {\n top = rect.top;\n left = rect.right + margin;\n }\n // Clamp to viewport.\n top = Math.max(8, Math.min(window.innerHeight - tipRect.height - 8, top));\n left = Math.max(8, Math.min(window.innerWidth - tipRect.width - 8, left));\n tipEl.style.top = `${top}px`;\n tipEl.style.left = `${left}px`;\n };\n\n showStep(current);\n\n // If the host page unloads mid-tour, leave the current index persisted so\n // the next session resumes from there. Nothing else to do — writeResumeIdx\n // was called in showStep.\n // Expose a cancel hook so app code can reset the tour from Dev Tools etc.\n (window as unknown as { aegisResetTour?: (key: string) => void }).aegisResetTour = (key: string) => clearResume(key);\n}\n","/**\n * AegisInAppManager - Web SDK In-App Messaging Module\n *\n * HTTP polling architecture with client-side evaluation.\n *\n * Security:\n * - XSS Protection: Uses DOM APIs (createElement, textContent) instead of innerHTML\n * - URL Validation: Prevents javascript: protocol injection\n * - CSP Compatible: No inline styles in HTML strings\n *\n * Architecture (RFC 2026-04-16):\n * - Polls /v1/in-app/active on initialize + on identity change\n * - Caches campaigns locally in memory\n * - Evaluates trigger rules client-side\n * - Tracks events (impression, click, dismiss) asynchronously\n *\n * NOTE: Persistent SSE for downstream delivery is disabled by default\n * (enableSSE=false). Tenant dashboards that need realtime (inbox, chat,\n * live page) open SSE directly via Next.js API routes — not via this SDK.\n * End-user storefronts use polling + Web Push for background delivery.\n */\n\nimport type { RenderContext } from './renderers';\nimport {\n renderCarouselCards,\n renderCoachmarkTour,\n renderProductRecommendation,\n renderProgressBar,\n renderStickyBar,\n} from './renderers';\nimport { Storage } from '../utils/storage';\n\n// Read the SDK's persisted anonymous_id from localStorage/cookie if available.\n// Returns undefined when called server-side (no document/window) or when no\n// id has been minted yet — caller falls through to leaving userId unset.\nfunction readAnonIdFromStorage(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n try {\n const storage = new Storage();\n return storage.get('anon_id') ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface InAppCampaign {\n id: string;\n type:\n | 'modal'\n | 'banner'\n | 'tooltip'\n | 'full_screen'\n | 'half_interstitial'\n | 'alert'\n | 'pip'\n // Preload-first display types (2026-04-22 §5.4 of the expansion plan)\n | 'carousel_cards'\n | 'sticky_bar'\n | 'progress_bar'\n | 'coachmark_tour'\n | 'product_recommendation';\n sub_type?: string;\n title: string;\n body: string;\n image_url?: string;\n video_url?: string;\n action_url?: string;\n button_text?: string;\n background_color?: string;\n text_color?: string;\n priority: number;\n expires_at?: string;\n frequency?: {\n max_impressions?: number;\n max_impressions_per_day?: number;\n cooldown_seconds?: number;\n // Conversion-aware suppression — added by Micro-Intent Engine P0a (2026-04-30).\n // Mirrors cell-plane FrequencyCap. When the host app calls\n // `notifyConversion(goalName)`, every armed campaign whose\n // `suppress_after_conversion_seconds` is set gets silenced for that\n // many seconds (session-scoped via sessionStorage). Prevents the\n // \"showing 10% off to a buyer who just paid full price\" failure mode.\n suppress_after_conversion_seconds?: number;\n suppress_after_dismiss_seconds?: number;\n scope?: 'session' | 'user' | 'user_sku';\n };\n interactive_config?: Record<string, unknown>;\n client_trigger?: {\n type: string;\n config?: Record<string, unknown>;\n };\n assigned_variant_id?: string;\n}\n\nexport interface AegisInAppConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n // Resolved by POST /v1/sdk/bootstrap — required in production. Campaigns\n // with a non-empty `target_properties` list are filtered against this on\n // the server, so passing the wrong id (or omitting it) narrows visible\n // campaigns to the property-agnostic ones only.\n propertyId?: string;\n debugMode?: boolean;\n enableSSE?: boolean;\n /**\n * Callback invoked when the manager receives an in-app campaign with\n * a gamification sub_type (spin_wheel / scratch_card). The facade\n * (AegisMessageRuntime) wires this to the widget-renderer path so\n * interactive campaigns render correctly. When this is undefined,\n * gamification campaigns are logged and skipped.\n */\n onInteractiveCampaign?: (campaign: InAppCampaign) => void;\n}\n\nexport class AegisInAppManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private propertyId?: string;\n private debugMode: boolean;\n private enableSSE: boolean;\n private onInteractiveCampaign?: (campaign: InAppCampaign) => void;\n\n private campaigns: InAppCampaign[] = [];\n private displayedCampaigns = new Set<string>();\n // Conversion-aware suppression — campaign_id -> epoch_ms when suppression expires.\n // Populated by `notifyConversion()` and rehydrated from sessionStorage in\n // `refreshCampaigns()` so a navigation between pages preserves silence.\n private suppressedUntil = new Map<string, number>();\n private eventSource?: EventSource;\n private isInitialized = false;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n // sessionStorage key prefix — one entry per goal so we can introspect what\n // converted and when. Format: { ts: epoch_ms }.\n private static readonly CONVERSION_STORAGE_PREFIX = 'aegis_conv_';\n \n constructor(config: AegisInAppConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n // Fall back to the SDK's persisted anonymous_id (set on first /v1/sdk/bootstrap\n // and reused across the main analytics SDK) so anonymous storefront users\n // get journey-driven in-app messages keyed to the same identity used in\n // /v1/batch payloads. Without this, polling defaults to \"anonymous\" on the\n // server and bucket-misses every per-contact priority queue.\n this.userId = config.userId ?? readAnonIdFromStorage();\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.propertyId = config.propertyId;\n this.debugMode = config.debugMode || false;\n // SSE is disabled by default. Kept as opt-in capability for future tenant\n // dashboards that embed the Aegis SDK and need realtime updates. End-user\n // storefronts must NOT enable this — persistent-per-tab SSE doesn't scale.\n this.enableSSE = config.enableSSE === true;\n this.onInteractiveCampaign = config.onInteractiveCampaign;\n }\n \n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisInApp already initialized');\n return;\n }\n\n // Mark user as returning for subsequent visits\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('aegis_returning_user', '1');\n }\n\n await this.refreshCampaigns();\n\n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n \n this.isInitialized = true;\n this.log('AegisInApp initialized successfully');\n }\n \n updateUserId(userId: string): void {\n this.userId = userId;\n this.refreshCampaigns();\n }\n \n updateContactId(contactId: string): void {\n this.contactId = contactId;\n this.disconnectSSE();\n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n this.refreshCampaigns();\n }\n\n /**\n * Conversion-aware suppression. Call this when the host app observes a\n * goal event (purchase, order_placed, checkout_completed, or any custom\n * goal the workspace has configured per-campaign).\n *\n * For every armed campaign whose `frequency.suppress_after_conversion_seconds`\n * is set, this:\n * 1. Persists the conversion in sessionStorage (so subsequent page\n * loads in the same tab retain silence).\n * 2. Computes an expiry epoch_ms and stores it in `suppressedUntil`.\n * 3. The two campaign-evaluation paths (`tryDisplayNextCampaign`\n * and `onClientEvent`) skip campaigns whose `suppressedUntil`\n * has not yet passed.\n *\n * Scope: only `session` is implemented in P0a. `user` and `user_sku`\n * scopes degrade to session-only with a debug log; the schema accepts\n * them so future expansion is non-breaking.\n *\n * Safe to call repeatedly for the same goal — each call refreshes the\n * sessionStorage timestamp and re-applies suppression to any campaigns\n * loaded since the last call.\n */\n notifyConversion(goalName: string): void {\n if (!goalName) {\n this.log('notifyConversion called with empty goalName; ignored', 'warn');\n return;\n }\n const ts = Date.now();\n if (typeof sessionStorage !== 'undefined') {\n try {\n sessionStorage.setItem(\n `${AegisInAppManager.CONVERSION_STORAGE_PREFIX}${goalName}`,\n JSON.stringify({ ts }),\n );\n } catch {\n // sessionStorage may be disabled (Safari private mode, blocked\n // third-party context). Suppression still applies for the\n // current page lifetime via the in-memory map.\n }\n }\n this.applySuppressionFromCampaigns(ts);\n this.log(`notifyConversion: ${goalName} — suppressing ${this.suppressedUntil.size} armed campaigns`);\n }\n\n /**\n * Compute and store `suppressedUntil` entries for every armed campaign\n * whose `frequency.suppress_after_conversion_seconds` is set. Called by\n * `notifyConversion()` and `refreshCampaigns()` (the latter rehydrates\n * suppression for newly-loaded campaigns when a prior conversion event\n * exists in sessionStorage).\n *\n * `convertedAt` is the epoch_ms of the conversion; pass `Date.now()`\n * when called from `notifyConversion`, or the `ts` recovered from\n * sessionStorage when rehydrating.\n */\n private applySuppressionFromCampaigns(convertedAt: number): void {\n for (const c of this.campaigns) {\n const seconds = c.frequency?.suppress_after_conversion_seconds;\n if (typeof seconds !== 'number' || seconds <= 0) continue;\n const scope = c.frequency?.scope ?? 'session';\n if (scope !== 'session') {\n // P0a only implements session scope. Schema accepts user / user_sku\n // so future work doesn't break wire compatibility, but for now we\n // degrade to session and log.\n this.log(\n `applySuppressionFromCampaigns: scope=${scope} not implemented; degrading to session for campaign ${c.id}`,\n 'warn',\n );\n }\n const expiresAt = convertedAt + seconds * 1000;\n // Take the max so a later/longer suppression wins over an earlier one.\n const existing = this.suppressedUntil.get(c.id);\n if (existing === undefined || existing < expiresAt) {\n this.suppressedUntil.set(c.id, expiresAt);\n }\n }\n }\n\n /**\n * Recover any prior conversion timestamps from sessionStorage and apply\n * suppression to currently-loaded campaigns. Called from\n * `refreshCampaigns()` after `this.campaigns` is populated. This is the\n * mechanism that prevents a converted buyer from seeing a discount popup\n * on the next page load within the same session.\n */\n private rehydrateSuppressionFromStorage(): void {\n if (typeof sessionStorage === 'undefined') return;\n let earliestTs: number | null = null;\n try {\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i);\n if (!key || !key.startsWith(AegisInAppManager.CONVERSION_STORAGE_PREFIX)) continue;\n const raw = sessionStorage.getItem(key);\n if (!raw) continue;\n const parsed = JSON.parse(raw) as { ts?: number };\n if (typeof parsed.ts === 'number') {\n earliestTs = earliestTs === null ? parsed.ts : Math.min(earliestTs, parsed.ts);\n }\n }\n } catch {\n // Malformed entries are silently skipped — suppression simply\n // doesn't apply for them.\n return;\n }\n if (earliestTs !== null) {\n this.applySuppressionFromCampaigns(earliestTs);\n }\n }\n\n /**\n * Returns true if the campaign is currently suppressed (Date.now() is\n * before the stored expiry). Used by both display paths.\n */\n private isSuppressed(campaignId: string): boolean {\n const expiresAt = this.suppressedUntil.get(campaignId);\n if (expiresAt === undefined) return false;\n if (Date.now() >= expiresAt) {\n this.suppressedUntil.delete(campaignId);\n return false;\n }\n return true;\n }\n \n private connectSSE(): void {\n if (this.eventSource) {\n this.disconnectSSE();\n }\n \n if (!this.organizationId) {\n this.log('Cannot connect SSE without organization ID', 'warn');\n return;\n }\n \n const url = new URL('/v1/stream/realtime', this.apiHost);\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Organization-ID': this.organizationId,\n };\n \n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n \n const queryParams = new URLSearchParams();\n Object.entries(headers).forEach(([key, value]) => {\n queryParams.append(key, value);\n });\n \n this.eventSource = new EventSource(`${url}?${queryParams.toString()}`);\n \n this.eventSource.addEventListener('open', () => {\n this.log('SSE connection established');\n this.reconnectAttempts = 0;\n });\n \n this.eventSource.addEventListener('in_app_campaign_updated', (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data);\n this.log(`Received in-app campaign update: ${data.campaign_id}`);\n this.refreshCampaigns();\n } catch (error) {\n this.log(`Error parsing SSE event: ${error}`, 'error');\n }\n });\n \n this.eventSource.addEventListener('heartbeat', (event: MessageEvent) => {\n this.log('SSE heartbeat received');\n });\n \n this.eventSource.addEventListener('error', (error) => {\n this.log('SSE connection error', 'error');\n \n if (this.eventSource?.readyState === EventSource.CLOSED) {\n this.attemptReconnect();\n }\n });\n }\n \n private disconnectSSE(): void {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = undefined;\n this.log('SSE connection closed');\n }\n }\n \n private attemptReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n this.log('Max reconnect attempts reached, giving up', 'warn');\n return;\n }\n \n this.reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);\n \n this.log(`Reconnecting SSE in ${delay}ms (attempt ${this.reconnectAttempts})`);\n \n setTimeout(() => {\n if (this.isInitialized && this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n }, delay);\n }\n \n private async refreshCampaigns(): Promise<void> {\n try {\n // Build URL with client context for server-side targeting (Critical Fix B)\n const context = new URLSearchParams({\n device_type: this.detectDeviceType(),\n page_url: typeof window !== 'undefined' ? window.location.pathname : '/',\n });\n\n // Geo is resolved server-side from IP — no need to send\n context.set('is_new_user', this.isNewUser() ? 'true' : 'false');\n\n const url = `${this.apiHost}/v1/in-app/active?${context.toString()}`;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n\n if (this.userId) {\n headers['X-User-ID'] = this.userId;\n }\n\n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n\n if (this.organizationId) {\n headers['X-Organization-ID'] = this.organizationId;\n }\n\n if (this.propertyId) {\n headers['X-Property-Id'] = this.propertyId;\n }\n\n // Send cached A/B assignments so server can skip re-evaluation (Critical Fix C)\n const abAssignments = this.getABAssignments();\n if (Object.keys(abAssignments).length > 0) {\n headers['X-AB-Assignments'] = btoa(JSON.stringify(abAssignments));\n }\n\n const response = await fetch(url, {\n method: 'GET',\n headers,\n credentials: 'include',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch campaigns: ${response.status}`);\n }\n\n const payload = await response.json();\n // Server returns an array; defensively handle error bodies (HTML\n // from misconfigured gateways, {} from maintenance endpoints, etc.)\n // so a bad response doesn't turn `updateContactId` into a thrower.\n this.campaigns = Array.isArray(payload) ? payload : [];\n\n // Process A/B assignments from server response (Critical Fix C)\n this.processABAssignments(this.campaigns);\n\n // Rehydrate conversion suppression from sessionStorage so a buyer\n // who converted on a prior page load in the same tab does not see\n // a discount popup on this load. Must run after this.campaigns is\n // populated and BEFORE tryDisplayNextCampaign so the first display\n // attempt honors suppression.\n this.rehydrateSuppressionFromStorage();\n\n this.log(`Fetched ${this.campaigns.length} campaigns`);\n\n this.tryDisplayNextCampaign();\n\n } catch (error) {\n this.log(`Error refreshing campaigns: ${error}`, 'error');\n }\n }\n\n // --- Client Context Helpers (Critical Fix B) ---\n\n private detectDeviceType(): 'mobile' | 'desktop' | 'tablet' {\n if (typeof navigator === 'undefined') return 'desktop';\n const ua = navigator.userAgent;\n if (/Mobi|Android/i.test(ua)) return 'mobile';\n if (/iPad|Tablet/i.test(ua)) return 'tablet';\n return 'desktop';\n }\n\n private isNewUser(): boolean {\n if (typeof localStorage === 'undefined') return true;\n return !localStorage.getItem('aegis_returning_user');\n }\n\n // --- A/B Assignment Persistence (Critical Fix C) ---\n\n private getABAssignments(): Record<string, string> {\n if (typeof localStorage === 'undefined') return {};\n try {\n return JSON.parse(localStorage.getItem('aegis_ab_assignments') || '{}');\n } catch {\n return {};\n }\n }\n\n private processABAssignments(campaigns: InAppCampaign[]): void {\n if (typeof localStorage === 'undefined') return;\n const stored = this.getABAssignments();\n for (const campaign of campaigns) {\n if (campaign.assigned_variant_id) {\n stored[campaign.id] = campaign.assigned_variant_id;\n }\n }\n localStorage.setItem('aegis_ab_assignments', JSON.stringify(stored));\n }\n\n private getVariantId(campaignId: string): string | undefined {\n const assignments = this.getABAssignments();\n return assignments[campaignId] ?? undefined;\n }\n \n private tryDisplayNextCampaign(): void {\n // Only auto-display campaigns that DO NOT have a client_trigger.\n // Trigger-gated campaigns wait for the host app to call\n // `onClientEvent()` or for TriggerEngine to fire the matching\n // behavioural event. This preserves the preload-first contract —\n // the campaign is armed but the render is gated.\n // Conversion-aware suppression: campaigns silenced by a prior\n // notifyConversion() call (or rehydrated from sessionStorage) are\n // skipped until their suppression window expires.\n const campaign = this.campaigns.find((c) =>\n !this.displayedCampaigns.has(c.id) && !c.client_trigger && !this.isSuppressed(c.id),\n );\n\n if (campaign) {\n this.displayCampaign(campaign);\n }\n }\n\n /**\n * Evaluate the currently armed campaigns against a client-side event\n * and render any that match their `client_trigger`.\n *\n * Called by the host app (e.g., the EcommerceTracker on product_viewed),\n * or by future TriggerEngine bridges. Safe to call repeatedly for the\n * same event — dedup happens via `displayedCampaigns`.\n *\n * Supported trigger types (align with the cell-plane server-side\n * `display_rules.trigger_type`):\n * - `custom_event` : fire when eventName matches config.event\n * - `product_match` : fire on `product_viewed` when eventData.product_id\n * matches config.product_id (string or string[])\n * - `delay` : client-side setTimeout — evaluated at armeng\n * time (kicked off from `displayCampaign`), not here.\n */\n onClientEvent(eventName: string, eventData: Record<string, unknown> = {}): void {\n for (const c of this.campaigns) {\n if (this.displayedCampaigns.has(c.id)) continue;\n if (!c.client_trigger) continue;\n // Conversion-aware suppression: trigger-gated campaigns silenced by\n // a prior notifyConversion() call are skipped until expiry.\n if (this.isSuppressed(c.id)) continue;\n if (this.matchesClientTrigger(c.client_trigger, eventName, eventData)) {\n this.displayCampaign(c);\n }\n }\n }\n\n private matchesClientTrigger(\n trigger: { type: string; config?: Record<string, unknown> },\n eventName: string,\n eventData: Record<string, unknown>,\n ): boolean {\n const cfg = trigger.config || {};\n switch (trigger.type) {\n case 'custom_event':\n return typeof cfg.event === 'string' && cfg.event === eventName;\n case 'product_match': {\n if (eventName !== 'product_viewed' && eventName !== 'product_view') {\n return false;\n }\n const wantedRaw = cfg.product_id;\n const wanted: string[] = Array.isArray(wantedRaw)\n ? (wantedRaw as string[])\n : typeof wantedRaw === 'string'\n ? [wantedRaw]\n : [];\n if (wanted.length === 0) return false;\n const actual = String(\n eventData.product_id ??\n eventData.productId ??\n (eventData.product as Record<string, unknown> | undefined)?.id ??\n '',\n );\n return wanted.includes(actual);\n }\n default:\n // Unknown or server-evaluated — do not auto-fire from the client.\n return false;\n }\n }\n \n private displayCampaign(campaign: InAppCampaign): void {\n this.displayedCampaigns.add(campaign.id);\n\n // Sub-type routing: interactive types are handled by dedicated renderers\n const interactiveSubTypes = new Set([\n 'spin_wheel', 'scratch_card', 'nps_survey', 'quiz',\n 'countdown_offer', 'star_rating', 'quick_poll',\n ]);\n\n if (campaign.sub_type && interactiveSubTypes.has(campaign.sub_type)) {\n this.renderInteractive(campaign);\n this.trackEvent(campaign.id, 'impression');\n return;\n }\n\n switch (campaign.type) {\n case 'modal':\n this.renderModal(campaign);\n break;\n case 'banner':\n this.renderBanner(campaign);\n break;\n case 'full_screen':\n this.renderFullScreen(campaign);\n break;\n case 'half_interstitial':\n this.renderHalfInterstitial(campaign);\n break;\n case 'alert':\n this.renderAlert(campaign);\n break;\n case 'pip':\n this.renderPIP(campaign);\n break;\n case 'tooltip':\n this.renderTooltip(campaign);\n break;\n // Preload-first display types (2026-04-22). These renderers own their\n // own impression tracking so we don't double-count alongside the\n // trailing `this.trackEvent(... 'impression')` below — return early.\n case 'carousel_cards':\n renderCarouselCards(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n return;\n case 'sticky_bar':\n renderStickyBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n return;\n case 'progress_bar':\n renderProgressBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n return;\n case 'coachmark_tour':\n // coachmark_tour fires its own impression/dismiss/click events\n // from within its state machine — don't double-report here.\n renderCoachmarkTour(this.buildRenderContext(campaign));\n return;\n case 'product_recommendation':\n renderProductRecommendation(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n return;\n }\n\n this.trackEvent(campaign.id, 'impression');\n }\n\n /**\n * Build the shared context passed into the preload-first renderers.\n * Matches the interface in `./renderers/types.ts`. Kept as a private\n * method (rather than inlined at each call-site) so future renderer\n * additions stay consistent and easy to audit.\n */\n private buildRenderContext(campaign: InAppCampaign): RenderContext {\n return {\n campaign,\n trackEvent: (id, evt) => {\n void this.trackEvent(id, evt);\n },\n sanitizeUrl: (url: string) => this.sanitizeUrl(url),\n sanitizeColor: (color: string) => this.sanitizeColor(color),\n log: (msg: string, level?: 'log' | 'warn' | 'error') => this.log(msg, level),\n addAnimationStyles: () => this.addAnimationStyles(),\n };\n }\n\n /**\n * Renders interactive sub-type campaigns (spin wheel, NPS, quiz, etc.)\n * using DOM-safe rendering. These sub-types use the campaign's\n * interactive_config payload for type-specific behavior.\n */\n private renderInteractive(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const bg = this.sanitizeColor(campaign.background_color || '#4169e1');\n const text = this.sanitizeColor(campaign.text_color || '#ffffff');\n\n switch (campaign.sub_type) {\n case 'nps_survey':\n this.renderNPSSurvey(campaign, ic, bg, text);\n break;\n case 'countdown_offer':\n this.renderCountdownOffer(campaign, ic, bg, text);\n break;\n case 'star_rating':\n this.renderStarRating(campaign, ic, bg, text);\n break;\n case 'quick_poll':\n this.renderQuickPoll(campaign, ic, bg, text);\n break;\n case 'quiz':\n this.renderQuiz(campaign, ic, bg, text);\n break;\n case 'spin_wheel':\n case 'scratch_card':\n if (this.onInteractiveCampaign) {\n this.onInteractiveCampaign(campaign);\n } else {\n this.log(\n `${campaign.sub_type} campaign received but no onInteractiveCampaign handler wired — install via AegisMessageRuntime`,\n 'warn',\n );\n }\n break;\n default:\n this.log(`Unknown interactive sub_type: ${campaign.sub_type}`, 'warn');\n this.renderModal(campaign);\n }\n }\n\n // --- Interactive Renderers ---\n\n private renderNPSSurvey(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-nps-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 360px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const question = document.createElement('div');\n question.style.cssText = 'font-size: 16px; font-weight: 700; margin-bottom: 16px;';\n question.textContent = (ic.nps_question as string) || 'How likely are you to recommend us?';\n body.appendChild(question);\n\n const scale = document.createElement('div');\n scale.style.cssText = 'display: flex; gap: 4px; justify-content: center; flex-wrap: wrap; margin-bottom: 12px;';\n for (let i = 0; i <= 10; i++) {\n const btn = document.createElement('span');\n btn.style.cssText = `\n width: 28px; height: 28px; border-radius: 6px; display: flex;\n align-items: center; justify-content: center; font-size: 11px;\n font-weight: 600; cursor: pointer; background: ${text}33; color: ${text};\n transition: transform 0.1s;\n `;\n btn.textContent = String(i);\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n });\n scale.appendChild(btn);\n }\n body.appendChild(scale);\n\n const labels = document.createElement('div');\n labels.style.cssText = 'display: flex; justify-content: space-between; font-size: 11px; opacity: 0.6; margin-bottom: 16px;';\n const notLikely = document.createElement('span');\n notLikely.textContent = 'Not likely';\n const veryLikely = document.createElement('span');\n veryLikely.textContent = 'Very likely';\n labels.appendChild(notLikely);\n labels.appendChild(veryLikely);\n body.appendChild(labels);\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderCountdownOffer(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-countdown-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 20px; font-weight: 700; margin-bottom: 8px;';\n title.textContent = campaign.title || 'Flash Sale';\n body.appendChild(title);\n\n const label = document.createElement('div');\n label.style.cssText = 'font-size: 13px; opacity: 0.8; margin-bottom: 12px;';\n label.textContent = (ic.countdown_label as string) || 'Sale ends in:';\n body.appendChild(label);\n\n // Countdown digits\n const digits = document.createElement('div');\n digits.style.cssText = 'display: flex; gap: 8px; justify-content: center; margin-bottom: 16px;';\n const digitStyle = `padding: 8px 12px; border-radius: 8px; font-size: 24px; font-weight: 700; font-family: monospace; background: ${text}22;`;\n for (const val of ['00', ':', '00', ':', '00']) {\n const el = document.createElement('span');\n if (val === ':') {\n el.style.cssText = 'font-size: 24px; font-weight: 700; align-self: center;';\n } else {\n el.style.cssText = digitStyle;\n }\n el.textContent = val;\n digits.appendChild(el);\n }\n body.appendChild(digits);\n\n // Start countdown from target or 2h default\n const targetStr = ic.countdown_target as string | undefined;\n if (targetStr) {\n const target = new Date(targetStr).getTime();\n const update = () => {\n const diff = Math.max(0, target - Date.now());\n const h = String(Math.floor(diff / 3600000)).padStart(2, '0');\n const m = String(Math.floor((diff % 3600000) / 60000)).padStart(2, '0');\n const s = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0');\n const spans = digits.querySelectorAll('span');\n if (spans.length >= 5) {\n spans[0].textContent = h;\n spans[2].textContent = m;\n spans[4].textContent = s;\n }\n if (diff > 0) requestAnimationFrame(update);\n };\n update();\n }\n\n if (campaign.body) {\n const desc = document.createElement('div');\n desc.style.cssText = 'font-size: 14px; opacity: 0.85; margin-bottom: 16px;';\n desc.textContent = campaign.body;\n body.appendChild(desc);\n }\n\n if (campaign.button_text) {\n const btn = this.createCTAButton(campaign, bg, text);\n body.appendChild(btn);\n }\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderStarRating(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-rating-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 18px; font-weight: 700; margin-bottom: 16px;';\n title.textContent = campaign.title || 'Rate your experience';\n body.appendChild(title);\n\n const stars = document.createElement('div');\n stars.style.cssText = 'display: flex; gap: 8px; justify-content: center; margin-bottom: 16px;';\n const maxStars = (ic.rating_scale as number) || 5;\n for (let i = 1; i <= maxStars; i++) {\n const star = document.createElement('span');\n star.style.cssText = 'font-size: 32px; cursor: pointer; transition: transform 0.1s;';\n star.textContent = '\\u2606'; // ☆\n star.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n });\n star.addEventListener('mouseenter', () => { star.style.transform = 'scale(1.2)'; });\n star.addEventListener('mouseleave', () => { star.style.transform = 'scale(1)'; });\n stars.appendChild(star);\n }\n body.appendChild(stars);\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderQuickPoll(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-poll-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 16px; font-weight: 700; margin-bottom: 16px;';\n title.textContent = campaign.title || 'Quick question';\n body.appendChild(title);\n\n const options = (ic.poll_options as string[]) || [];\n const optionsList = document.createElement('div');\n optionsList.style.cssText = 'display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px;';\n for (const opt of options) {\n const optBtn = document.createElement('button');\n optBtn.style.cssText = `\n padding: 10px 16px; border-radius: 10px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 14px; cursor: pointer;\n text-align: left; transition: background 0.15s;\n `;\n optBtn.textContent = opt;\n optBtn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n });\n optionsList.appendChild(optBtn);\n }\n body.appendChild(optionsList);\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderQuiz(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-quiz-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 360px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 18px; font-weight: 700; margin-bottom: 8px;';\n title.textContent = campaign.title || 'Quiz';\n body.appendChild(title);\n\n const questions = (ic.questions as Array<{ question: string; options: string[] }>) || [];\n let currentQ = 0;\n\n const renderQuestion = () => {\n // Clear previous content except title\n while (body.childNodes.length > 1) {\n body.removeChild(body.lastChild!);\n }\n\n if (currentQ >= questions.length) {\n const result = document.createElement('div');\n result.style.cssText = 'font-size: 16px; margin: 16px 0;';\n result.textContent = (ic.thank_you_message as string) || 'Thanks for completing the quiz!';\n body.appendChild(result);\n this.trackEvent(campaign.id, 'clicked');\n this.addCloseButton(body, overlay, campaign.id);\n return;\n }\n\n const q = questions[currentQ];\n const progress = document.createElement('div');\n progress.style.cssText = 'font-size: 12px; opacity: 0.6; margin-bottom: 12px;';\n progress.textContent = `Question ${currentQ + 1} of ${questions.length}`;\n body.appendChild(progress);\n\n const questionText = document.createElement('div');\n questionText.style.cssText = 'font-size: 14px; font-weight: 600; margin-bottom: 16px;';\n questionText.textContent = q.question;\n body.appendChild(questionText);\n\n const optionsDiv = document.createElement('div');\n optionsDiv.style.cssText = 'display: flex; flex-direction: column; gap: 8px;';\n for (const opt of q.options) {\n const optBtn = document.createElement('button');\n optBtn.style.cssText = `\n padding: 10px 16px; border-radius: 10px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 14px; cursor: pointer;\n text-align: left; transition: background 0.15s;\n `;\n optBtn.textContent = opt;\n optBtn.addEventListener('click', () => {\n currentQ++;\n renderQuestion();\n });\n optionsDiv.appendChild(optBtn);\n }\n body.appendChild(optionsDiv);\n this.addCloseButton(body, overlay, campaign.id);\n };\n\n renderQuestion();\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n // --- Shared Rendering Helpers ---\n\n private createOverlay(className: string): HTMLElement {\n const overlay = document.createElement('div');\n overlay.className = className;\n overlay.style.cssText = `\n position: fixed; top: 0; left: 0; right: 0; bottom: 0;\n background: rgba(0,0,0,0.5); display: flex; align-items: center;\n justify-content: center; z-index: 99999; animation: aegisFadeIn 0.3s ease;\n `;\n return overlay;\n }\n\n private createCTAButton(campaign: InAppCampaign, bg: string, text: string): HTMLElement {\n const btn = document.createElement('button');\n btn.style.cssText = `\n display: inline-block; padding: 10px 28px; border-radius: 999px;\n font-size: 14px; font-weight: 600; cursor: pointer; border: none;\n background: ${text}; color: ${bg}; transition: transform 0.15s;\n `;\n btn.textContent = campaign.button_text || 'OK';\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safeUrl = this.sanitizeUrl(campaign.action_url);\n if (safeUrl) window.open(safeUrl, '_blank');\n }\n });\n return btn;\n }\n\n private addCloseButton(container: HTMLElement, overlay: HTMLElement, campaignId: string): void {\n const close = document.createElement('div');\n close.style.cssText = 'margin-top: 12px; font-size: 12px; opacity: 0.6; cursor: pointer;';\n close.textContent = 'Close';\n close.addEventListener('click', () => {\n this.trackEvent(campaignId, 'dismissed');\n this.removeModal(overlay);\n });\n container.appendChild(close);\n }\n \n /**\n * Navigate to a campaign CTA URL.\n *\n * Dispatches a cancellable `aegis:campaign-click` CustomEvent so host\n * apps (e.g., the storefront SPA) can intercept and route in-place via\n * their client-side router, avoiding a full page reload that re-runs\n * SSR + re-renders the location picker / banner / cart drawer state.\n *\n * The host calls `event.preventDefault()` to suppress the hard nav and\n * handle the URL itself. If no listener calls preventDefault, the SDK\n * falls through to `window.location.href` so plain HTML pages without a\n * SPA still get the user to the destination.\n *\n * Industry parallel: CleverTap dispatches `clevertap-deeplink-click`,\n * MoEngage dispatches `MoE_inappRedirect`. The pattern lets the same\n * SDK serve both vanilla websites (full nav fallback) and SPAs\n * (in-place state change) without per-host configuration.\n */\n private navigateToCampaignAction(campaign: InAppCampaign, safeUrl: string): void {\n if (typeof window === 'undefined') return;\n const event = new CustomEvent('aegis:campaign-click', {\n detail: {\n campaign_id: campaign.id,\n campaign_type: campaign.type,\n action_url: safeUrl,\n },\n cancelable: true,\n });\n const proceeded = window.dispatchEvent(event);\n if (proceeded && !event.defaultPrevented) {\n window.location.href = safeUrl;\n }\n }\n\n private renderBanner(campaign: InAppCampaign): void {\n const banner = document.createElement('div');\n banner.className = 'aegis-in-app-banner';\n banner.setAttribute('data-campaign-id', campaign.id);\n \n banner.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n background: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.text_color || '#ffffff')};\n padding: 16px;\n z-index: 999999;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideDown 0.3s ease-out;\n `;\n \n const contentContainer = document.createElement('div');\n contentContainer.style.cssText = 'flex: 1; display: flex; align-items: center; gap: 12px;';\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 40px; height: 40px; border-radius: 4px; object-fit: cover;';\n contentContainer.appendChild(img);\n }\n }\n \n const textContainer = document.createElement('div');\n textContainer.style.cssText = 'flex: 1;';\n \n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 600; font-size: 14px; margin-bottom: 4px;';\n textContainer.appendChild(title);\n \n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.9;';\n textContainer.appendChild(body);\n \n contentContainer.appendChild(textContainer);\n \n const actionsContainer = document.createElement('div');\n actionsContainer.style.cssText = 'display: flex; align-items: center; gap: 12px; margin-left: 16px;';\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: white;\n color: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-weight: 600;\n cursor: pointer;\n font-size: 13px;\n white-space: nowrap;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeBanner(banner);\n });\n \n actionsContainer.appendChild(ctaButton);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n background: transparent;\n border: none;\n color: inherit;\n font-size: 20px;\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0.7;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeBanner(banner);\n });\n \n actionsContainer.appendChild(closeButton);\n \n banner.appendChild(contentContainer);\n banner.appendChild(actionsContainer);\n \n this.addAnimationStyles();\n document.body.appendChild(banner);\n }\n \n private renderModal(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-modal-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-in-app-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 8px;\n max-width: 500px;\n width: 90%;\n max-height: 80vh;\n overflow: auto;\n box-shadow: 0 10px 40px rgba(0,0,0,0.2);\n animation: aegisScaleIn 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 200px; object-fit: cover; border-radius: 8px 8px 0 0;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 24px;';\n \n const title = document.createElement('h2');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n content.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0 0 20px 0; font-size: 15px; line-height: 1.5; color: #4a4a4a;';\n content.appendChild(body);\n \n const actions = document.createElement('div');\n actions.style.cssText = 'display: flex; gap: 12px; justify-content: flex-end;';\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.text_color || '#ffffff')};\n border: none;\n padding: 10px 24px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n \n actions.appendChild(ctaButton);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: transparent;\n border: 1px solid #d0d0d0;\n color: #4a4a4a;\n padding: 10px 24px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n actions.appendChild(closeButton);\n \n content.appendChild(actions);\n modal.appendChild(content);\n overlay.appendChild(modal);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderFullScreen(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-fullscreen-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: ${this.sanitizeColor(campaign.background_color || '#ffffff')};\n color: ${this.sanitizeColor(campaign.text_color || '#1a1a1a')};\n z-index: 1000001;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n animation: aegisFadeIn 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n overflow-y: auto;\n `;\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'max-width: 100%; max-height: 40vh; object-fit: contain; margin-bottom: 32px;';\n overlay.appendChild(img);\n }\n }\n \n const contentContainer = document.createElement('div');\n contentContainer.style.cssText = 'max-width: 600px; text-align: center;';\n \n const title = document.createElement('h1');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 32px; font-weight: 700;';\n contentContainer.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0 0 32px 0; font-size: 18px; line-height: 1.6; opacity: 0.9;';\n contentContainer.appendChild(body);\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(campaign.text_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.background_color || '#ffffff')};\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 18px;\n cursor: pointer;\n margin-bottom: 16px;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n \n contentContainer.appendChild(ctaButton);\n }\n \n overlay.appendChild(contentContainer);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 20px;\n right: 20px;\n background: transparent;\n border: none;\n color: inherit;\n font-size: 32px;\n cursor: pointer;\n padding: 0;\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0.6;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n overlay.appendChild(closeButton);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderHalfInterstitial(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-half-interstitial-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000000;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-in-app-half-interstitial';\n modal.style.cssText = `\n background: white;\n border-radius: 16px 16px 0 0;\n width: 100%;\n max-width: 600px;\n max-height: 60vh;\n overflow: auto;\n box-shadow: 0 -4px 20px rgba(0,0,0,0.2);\n animation: aegisSlideUp 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 200px; object-fit: cover;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 32px 24px;';\n \n const title = document.createElement('h2');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; line-height: 1.5; color: #4a4a4a;';\n content.appendChild(body);\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.text_color || '#ffffff')};\n border: none;\n padding: 14px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n \n content.appendChild(ctaButton);\n }\n \n modal.appendChild(content);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: rgba(255,255,255,0.9);\n border: none;\n color: #333;\n font-size: 24px;\n cursor: pointer;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderAlert(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-alert-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.6);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.2s ease-out;\n `;\n \n const alert = document.createElement('div');\n alert.className = 'aegis-in-app-alert';\n alert.style.cssText = `\n background: white;\n border-radius: 12px;\n max-width: 320px;\n width: 85%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n animation: aegisScaleIn 0.2s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n overflow: hidden;\n `;\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 24px 20px; text-align: center;';\n \n const title = document.createElement('h3');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 8px 0; font-size: 18px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0; font-size: 14px; line-height: 1.4; color: #666;';\n content.appendChild(body);\n \n alert.appendChild(content);\n \n const buttonContainer = document.createElement('div');\n buttonContainer.style.cssText = 'display: flex; border-top: 1px solid #e0e0e0;';\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n flex: 1;\n background: transparent;\n border: none;\n border-right: 1px solid #e0e0e0;\n color: #1a73e8;\n padding: 14px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n \n buttonContainer.appendChild(ctaButton);\n }\n \n const cancelButton = document.createElement('button');\n cancelButton.textContent = 'Cancel';\n cancelButton.style.cssText = `\n flex: 1;\n background: transparent;\n border: none;\n color: #666;\n padding: 14px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n `;\n \n cancelButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n buttonContainer.appendChild(cancelButton);\n \n alert.appendChild(buttonContainer);\n overlay.appendChild(alert);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderPIP(campaign: InAppCampaign): void {\n const pip = document.createElement('div');\n pip.className = 'aegis-in-app-pip';\n pip.setAttribute('data-campaign-id', campaign.id);\n \n pip.style.cssText = `\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 320px;\n background: black;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 8px 24px rgba(0,0,0,0.3);\n z-index: 999999;\n animation: aegisSlideUp 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (campaign.video_url) {\n const video = document.createElement('video');\n const safeUrl = this.sanitizeUrl(campaign.video_url);\n if (safeUrl) {\n video.src = safeUrl;\n video.controls = true;\n video.autoplay = true;\n video.muted = true;\n video.style.cssText = 'width: 100%; display: block;';\n pip.appendChild(video);\n }\n } else if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; display: block;';\n pip.appendChild(img);\n }\n }\n \n const overlay = document.createElement('div');\n overlay.style.cssText = `\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: linear-gradient(to top, rgba(0,0,0,0.9), transparent);\n padding: 40px 16px 16px;\n color: white;\n `;\n \n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-size: 14px; font-weight: 600; margin-bottom: 4px;';\n overlay.appendChild(title);\n \n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 12px; opacity: 0.9;';\n overlay.appendChild(body);\n \n pip.appendChild(overlay);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 8px;\n right: 8px;\n background: rgba(0,0,0,0.6);\n border: none;\n color: white;\n font-size: 18px;\n cursor: pointer;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n pip.style.animation = 'aegisSlideDown 0.3s ease-out';\n setTimeout(() => {\n if (pip.parentNode) {\n pip.parentNode.removeChild(pip);\n }\n }, 300);\n });\n \n pip.appendChild(closeButton);\n \n if (campaign.action_url) {\n pip.style.cursor = 'pointer';\n pip.addEventListener('click', (e) => {\n if (e.target !== closeButton) {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n window.open(safeUrl, '_blank');\n }\n }\n });\n }\n \n this.addAnimationStyles();\n document.body.appendChild(pip);\n }\n \n private removeBanner(banner: HTMLElement): void {\n banner.style.animation = 'aegisSlideUp 0.3s ease-out';\n setTimeout(() => {\n if (banner.parentNode) {\n banner.parentNode.removeChild(banner);\n }\n }, 300);\n }\n \n private removeModal(overlay: HTMLElement): void {\n overlay.style.animation = 'aegisFadeOut 0.3s ease-out';\n setTimeout(() => {\n if (overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n }, 300);\n }\n \n private renderTooltip(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const anchorSelector = (ic.tooltip_anchor_selector as string) || '[data-aegis-tooltip]';\n const preferredPosition = (ic.tooltip_position as string) || 'bottom'; // top | bottom | left | right\n\n const anchor = document.querySelector(anchorSelector);\n if (!anchor) {\n this.log(`Tooltip anchor not found: ${anchorSelector}`, 'warn');\n return;\n }\n\n const bg = this.sanitizeColor(campaign.background_color || '#1a1a1a');\n const textColor = this.sanitizeColor(campaign.text_color || '#ffffff');\n\n // Tooltip container (positioned absolute to body)\n const tooltip = document.createElement('div');\n tooltip.className = 'aegis-in-app-tooltip';\n tooltip.setAttribute('data-campaign-id', campaign.id);\n tooltip.style.cssText = `\n position: absolute; z-index: 1000001; max-width: 280px; width: max-content;\n background: ${bg}; color: ${textColor}; border-radius: 10px; padding: 14px 16px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.18); font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.2s ease-out; pointer-events: auto;\n `;\n\n // Arrow\n const arrow = document.createElement('div');\n arrow.className = 'aegis-tooltip-arrow';\n arrow.style.cssText = `\n position: absolute; width: 10px; height: 10px; background: ${bg};\n transform: rotate(45deg);\n `;\n\n // Close button\n const closeBtn = document.createElement('button');\n closeBtn.textContent = '\\u00d7';\n closeBtn.style.cssText = `\n position: absolute; top: 6px; right: 8px; background: none; border: none;\n color: ${textColor}; opacity: 0.6; font-size: 16px; cursor: pointer; padding: 0; line-height: 1;\n `;\n\n const dismiss = () => {\n tooltip.style.animation = 'aegisFadeOut 0.2s ease-out';\n setTimeout(() => { tooltip.parentNode?.removeChild(tooltip); }, 200);\n this.trackEvent(campaign.id, 'dismissed');\n };\n\n closeBtn.addEventListener('click', (e) => { e.stopPropagation(); dismiss(); });\n\n // Title\n if (campaign.title) {\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-size: 13px; font-weight: 700; margin-bottom: 4px; padding-right: 16px;';\n tooltip.appendChild(title);\n }\n\n // Body\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 12px; line-height: 1.4; opacity: 0.9;';\n tooltip.appendChild(body);\n\n // CTA button\n if (campaign.button_text && campaign.action_url) {\n const cta = document.createElement('a');\n cta.textContent = campaign.button_text;\n cta.href = campaign.action_url;\n cta.style.cssText = `\n display: inline-block; margin-top: 8px; font-size: 12px; font-weight: 600;\n color: ${textColor}; text-decoration: underline; cursor: pointer;\n `;\n cta.addEventListener('click', () => { this.trackEvent(campaign.id, 'clicked'); });\n tooltip.appendChild(cta);\n }\n\n tooltip.appendChild(closeBtn);\n tooltip.appendChild(arrow);\n document.body.appendChild(tooltip);\n\n // Position relative to anchor\n const anchorRect = anchor.getBoundingClientRect();\n const tooltipRect = tooltip.getBoundingClientRect();\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n const gap = 10;\n\n let top = 0;\n let left = 0;\n let arrowTop = '';\n let arrowLeft = '';\n let arrowBottom = '';\n let arrowRight = '';\n\n switch (preferredPosition) {\n case 'top':\n top = anchorRect.top + scrollY - tooltipRect.height - gap;\n left = anchorRect.left + scrollX + (anchorRect.width - tooltipRect.width) / 2;\n arrowBottom = '-5px';\n arrowLeft = `${tooltipRect.width / 2 - 5}px`;\n break;\n case 'left':\n top = anchorRect.top + scrollY + (anchorRect.height - tooltipRect.height) / 2;\n left = anchorRect.left + scrollX - tooltipRect.width - gap;\n arrowRight = '-5px';\n arrowTop = `${tooltipRect.height / 2 - 5}px`;\n break;\n case 'right':\n top = anchorRect.top + scrollY + (anchorRect.height - tooltipRect.height) / 2;\n left = anchorRect.right + scrollX + gap;\n arrowLeft = '-5px';\n arrowTop = `${tooltipRect.height / 2 - 5}px`;\n break;\n default: // bottom\n top = anchorRect.bottom + scrollY + gap;\n left = anchorRect.left + scrollX + (anchorRect.width - tooltipRect.width) / 2;\n arrowTop = '-5px';\n arrowLeft = `${tooltipRect.width / 2 - 5}px`;\n break;\n }\n\n // Clamp to viewport\n left = Math.max(8, Math.min(left, window.innerWidth + scrollX - tooltipRect.width - 8));\n top = Math.max(8, top);\n\n tooltip.style.top = `${top}px`;\n tooltip.style.left = `${left}px`;\n arrow.style.top = arrowTop || '';\n arrow.style.left = arrowLeft || '';\n arrow.style.bottom = arrowBottom || '';\n arrow.style.right = arrowRight || '';\n\n // Dismiss on outside click\n const outsideClickHandler = (e: MouseEvent) => {\n if (!tooltip.contains(e.target as Node) && !anchor.contains(e.target as Node)) {\n document.removeEventListener('click', outsideClickHandler);\n dismiss();\n }\n };\n setTimeout(() => document.addEventListener('click', outsideClickHandler), 100);\n }\n\n private addAnimationStyles(): void {\n if (document.getElementById('aegis-in-app-styles')) {\n return;\n }\n \n const style = document.createElement('style');\n style.id = 'aegis-in-app-styles';\n style.textContent = `\n @keyframes aegisSlideDown {\n from { transform: translateY(-100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes aegisSlideUp {\n from { transform: translateY(0); opacity: 1; }\n to { transform: translateY(-100%); opacity: 0; }\n }\n \n @keyframes aegisFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes aegisFadeOut {\n from { opacity: 1; }\n to { opacity: 0; }\n }\n \n @keyframes aegisScaleIn {\n from { transform: scale(0.9); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n }\n\n /* Bottom-anchored slide IN (opposite of aegisSlideUp which slides OUT).\n Used by the preload-first renderers: sticky_bar (bottom),\n progress_bar, carousel_cards, product_recommendation. */\n @keyframes aegisSlideInFromBottom {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n `;\n \n document.head.appendChild(style);\n }\n \n private sanitizeUrl(url: string): string | null {\n try {\n const parsedUrl = new URL(url, window.location.origin);\n \n if (parsedUrl.protocol === 'javascript:' || parsedUrl.protocol === 'data:') {\n this.log(`Blocked unsafe URL: ${url}`, 'error');\n return null;\n }\n \n return parsedUrl.href;\n } catch (error) {\n this.log(`Invalid URL: ${url}`, 'error');\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n if (/^#[0-9A-Fa-f]{3,6}$/.test(color)) {\n return color;\n }\n \n if (/^rgb\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*\\)$/.test(color)) {\n return color;\n }\n \n if (/^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*[\\d.]+\\s*\\)$/.test(color)) {\n return color;\n }\n \n const namedColors = ['white', 'black', 'red', 'green', 'blue', 'yellow', 'orange', 'purple', 'pink', 'gray', 'transparent'];\n if (namedColors.includes(color.toLowerCase())) {\n return color;\n }\n \n return '#000000';\n }\n \n /**\n * Track in-app event via the standard Event Ingress pipeline.\n *\n * Events flow: SDK → Event Ingress → Kafka → Governance Consumer\n * → Event Engine → ClickHouse (in_app_events + events_with_ttl)\n *\n * The event_type uses the canonical prefix `in_app.` so the event\n * switchboard maps it to the correct canonical form:\n * in_app.impression → engagement.view\n * in_app.clicked → engagement.click\n * in_app.dismissed → engagement.dismiss\n */\n private async trackEvent(campaignId: string, eventType: 'impression' | 'clicked' | 'dismissed'): Promise<void> {\n try {\n // Use the public SDK scheme (/v1/in_app/events) — the gateway has an\n // explicit handler that auths via X-Aegis-Write-Key and forwards to\n // event-switchboard. Direct POST to /api/v1/events bypasses the SDK\n // auth model and hits the JWT preHandler → 401.\n // See docs/architecture/API_ROUTING.md §5.\n const url = `${this.apiHost}/v1/in_app/events`;\n const externalEventId = `inapp_${campaignId}_${eventType}_${Date.now()}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey,\n };\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n\n const body = {\n campaign_id: campaignId,\n event_type: eventType,\n user_id: this.userId,\n contact_id: this.contactId,\n anonymous_id: this.userId,\n platform: 'web',\n metadata: {\n property_id: this.propertyId,\n variant_id: this.getVariantId(campaignId) ?? undefined,\n },\n idempotency_key: externalEventId,\n };\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n credentials: 'include',\n }).catch(error => {\n this.log(`Error tracking event: ${error}`, 'error');\n });\n\n this.log(`Tracked ${eventType} event for campaign ${campaignId}`);\n } catch (error) {\n this.log(`Error tracking event: ${error}`, 'error');\n }\n }\n \n private log(message: string, level: 'log' | 'warn' | 'error' = 'log'): void {\n if (this.debugMode) {\n console[level](`[AegisInApp] ${message}`);\n }\n }\n \n destroy(options?: { clearABState?: boolean }): void {\n this.disconnectSSE();\n\n if (typeof document !== 'undefined') {\n document.querySelectorAll(\n '.aegis-in-app-banner, .aegis-in-app-modal-overlay, .aegis-in-app-fullscreen-overlay, ' +\n '.aegis-in-app-half-interstitial-overlay, .aegis-in-app-alert-overlay, .aegis-in-app-pip, ' +\n '.aegis-in-app-nps-overlay, .aegis-in-app-countdown-overlay, .aegis-in-app-rating-overlay, ' +\n '.aegis-in-app-poll-overlay, .aegis-in-app-quiz-overlay'\n ).forEach(el => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n });\n\n const styles = document.getElementById('aegis-in-app-styles');\n if (styles && styles.parentNode) {\n styles.parentNode.removeChild(styles);\n }\n }\n\n // Optionally clear A/B assignment state\n if (options?.clearABState && typeof localStorage !== 'undefined') {\n localStorage.removeItem('aegis_ab_assignments');\n }\n\n this.isInitialized = false;\n this.log('AegisInApp destroyed');\n }\n}\n","/**\n * ProductRecommendation renderer — personalized product grid/row rendered\n * from `interactive_config.cards[]` that the cell-plane populated at\n * bundle-assembly time. The SDK never calls a product-API at render\n * time — the preload contract is that the recommended products are\n * already in the bundle.\n *\n * The layout is narrower than the generic carousel because product recs\n * should feel like a first-class product grid, not a marketing slider.\n * Three layouts: grid (2-col / 3-col responsive), row (horizontal-scroll),\n * carousel (same as carousel_cards but different framing copy).\n *\n * interactive_config:\n * rec_source?: 'viewed' | 'abandoned' | 'cross_sell' | 'trending' | 'personalized'\n * (metadata only — the actual product list is in `cards[]`)\n * rec_count?: number (display hint; rendering is driven by cards.length)\n * rec_layout?: 'grid' | 'row' | 'carousel' default 'grid'\n * rec_cta_text?: string default 'Shop now'\n * cards: Array<{ image_url?, title?, body?, cta_url?, metadata? }>\n */\n\nimport type { RenderContext } from './types';\n\ntype Card = {\n image_url?: string;\n title?: string;\n body?: string;\n cta_text?: string;\n cta_url?: string;\n metadata?: Record<string, unknown>;\n};\n\nconst MAX_PRODUCTS = 24;\n\nexport function renderProductRecommendation(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const rawCards = Array.isArray(ic.cards) ? (ic.cards as Card[]) : [];\n const cards = rawCards.slice(0, MAX_PRODUCTS);\n if (cards.length === 0) {\n log('product_recommendation rendered with zero products — skipping', 'warn');\n return;\n }\n\n const layout = (ic.rec_layout as string) || 'grid';\n const ctaDefault = (ic.rec_cta_text as string) || 'Shop now';\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#ffffff');\n const fg = sanitizeColor((campaign.text_color as string) || '#0f172a');\n const accent = sanitizeColor('#4169e1');\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-product-rec';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = `\n position: fixed; inset: 0;\n background: rgba(15,23,42,0.55); backdrop-filter: blur(4px);\n display: flex; align-items: flex-end; justify-content: center;\n z-index: 99999; animation: aegisFadeIn 0.25s ease;\n `;\n\n const sheet = document.createElement('div');\n sheet.style.cssText = `\n background: ${bg}; color: ${fg};\n max-width: 560px; width: 100%; max-height: 80vh; overflow-y: auto;\n border-radius: 20px 20px 0 0;\n padding: 18px 16px 22px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n box-shadow: 0 -12px 30px rgba(0,0,0,0.12);\n `;\n\n // Drag handle (decorative, for mobile context)\n const handle = document.createElement('div');\n handle.style.cssText = `\n width: 36px; height: 4px; border-radius: 999px; background: ${fg}1f;\n margin: 0 auto 12px;\n `;\n sheet.appendChild(handle);\n\n const header = document.createElement('div');\n header.style.cssText = 'display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;';\n\n const headerText = document.createElement('div');\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 700; font-size: 16px; margin-bottom: 2px;';\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.7; line-height: 1.4;';\n headerText.appendChild(title);\n headerText.appendChild(body);\n header.appendChild(headerText);\n\n const close = document.createElement('button');\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Close');\n close.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 18px; cursor: pointer; padding: 4px 8px; opacity: 0.7;\n `;\n close.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n });\n header.appendChild(close);\n sheet.appendChild(header);\n\n const grid = document.createElement('div');\n if (layout === 'row' || layout === 'carousel') {\n grid.style.cssText = `\n display: flex; gap: 10px; overflow-x: auto;\n scroll-snap-type: x mandatory; padding: 14px 0 4px;\n `;\n } else {\n grid.style.cssText = `\n display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;\n padding-top: 14px;\n `;\n }\n\n cards.forEach((c) => {\n const tile = document.createElement('div');\n const isRow = layout === 'row' || layout === 'carousel';\n tile.style.cssText = `\n background: ${fg}08; border-radius: 12px;\n padding: 10px; display: flex; flex-direction: column; gap: 6px;\n cursor: ${c.cta_url ? 'pointer' : 'default'};\n ${isRow ? 'flex: 0 0 150px; scroll-snap-align: start;' : ''}\n transition: transform 0.15s ease;\n `;\n\n if (c.image_url) {\n const img = document.createElement('img');\n const safe = sanitizeUrl(c.image_url);\n if (safe) {\n img.src = safe;\n img.alt = '';\n img.loading = 'lazy';\n img.style.cssText = 'width: 100%; aspect-ratio: 1 / 1; border-radius: 8px; object-fit: cover;';\n tile.appendChild(img);\n }\n }\n\n if (c.title) {\n const t = document.createElement('div');\n t.textContent = c.title;\n t.style.cssText = 'font-weight: 600; font-size: 13px; line-height: 1.3;';\n tile.appendChild(t);\n }\n\n // Price lives in metadata.price per the dashboard schema; we show it\n // prominently if present.\n const price = c.metadata && typeof c.metadata === 'object' ? (c.metadata as Record<string, unknown>).price : undefined;\n if (price !== undefined) {\n const p = document.createElement('div');\n p.textContent = String(price);\n p.style.cssText = `color: ${accent}; font-weight: 700; font-size: 13px;`;\n tile.appendChild(p);\n } else if (c.body) {\n const b = document.createElement('div');\n b.textContent = c.body;\n b.style.cssText = 'font-size: 11.5px; opacity: 0.72; line-height: 1.3;';\n tile.appendChild(b);\n }\n\n const cta = document.createElement('button');\n cta.textContent = c.cta_text || ctaDefault;\n cta.style.cssText = `\n margin-top: auto;\n background: ${accent}; color: #fff;\n border: none; padding: 7px 10px; border-radius: 999px;\n font-size: 12px; font-weight: 600; cursor: pointer;\n `;\n const go = (e: Event) => {\n e.stopPropagation();\n trackEvent(campaign.id, 'clicked');\n if (c.cta_url) {\n const safe = sanitizeUrl(c.cta_url);\n if (safe) window.location.href = safe;\n }\n };\n cta.addEventListener('click', go);\n tile.appendChild(cta);\n if (c.cta_url) tile.addEventListener('click', go);\n\n grid.appendChild(tile);\n });\n\n sheet.appendChild(grid);\n overlay.appendChild(sheet);\n\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n }\n });\n\n document.body.appendChild(overlay);\n}\n","/**\n * AegisWidgetManager - Web SDK Widget Module\n * \n * Smart Pull architecture for persistent web widgets.\n * \n * Features:\n * - Gamification (spin wheel, scratch card) with server-side prize generation\n * - Chat bubbles (WhatsApp, support)\n * - Social proof toasts (real-time purchase notifications)\n * - Feedback forms (NPS, surveys)\n * \n * Security:\n * - XSS Protection: Uses DOM APIs instead of innerHTML\n * - Server-side prize generation prevents client manipulation\n * - URL validation prevents javascript: protocol injection\n * \n * Architecture:\n * - Fetches widget configs from /v1/widgets/config on page load\n * - Integrates with TriggerEngine for behavioral triggers\n * - Tracks widget events (show, click, dismiss, submit)\n * - Server-side prize generation for gamification\n */\n\nimport { TriggerEngine } from '../triggers/TriggerEngine';\nimport { Storage } from '../utils/storage';\n\n// Read the SDK's persisted anonymous_id from localStorage/cookie if available.\n// Returns undefined when called server-side or when no id has been minted yet.\n// See AegisInAppManager for the same pattern + canonical contract in\n// docs/architecture/API_ROUTING.md §3.\nfunction readAnonIdFromStorage(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n try {\n const storage = new Storage();\n return storage.get('anon_id') ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface WidgetConfig {\n widget_id: string;\n widget_type: 'chat_bubble' | 'spin_wheel' | 'scratch_card' | 'toast' | 'feedback_form' | 'exit_intent_popup';\n name: string;\n config: Record<string, any>;\n position?: string;\n priority: number;\n trigger_rules?: {\n type: 'exit_intent' | 'scroll_depth' | 'time_on_page' | 'immediate';\n config?: Record<string, any>;\n };\n}\n\nexport interface GamificationPrize {\n prize_label: string;\n prize_value?: string;\n coupon_code?: string;\n play_id: string;\n}\n\nexport interface AegisWidgetConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n debugMode?: boolean;\n triggerEngine?: TriggerEngine;\n /** If true, WidgetManager takes ownership of the TriggerEngine and\n * will call `triggerEngine.stop()` on destroy(). Leave false when\n * the caller shares the engine across managers (e.g. the facade). */\n ownsTriggerEngine?: boolean;\n enablePrefetch?: boolean;\n cssCustomization?: WidgetCSSCustomization;\n onEvent?: (eventType: string, data: any) => void;\n /** Source platform passed as X-Source-Platform header so the API\n * can filter campaigns whose display_rules.sources restricts them\n * to specific integrations (e.g. 'shopify', 'woocommerce'). */\n sourcePlatform?: 'web' | 'shopify' | 'woocommerce' | 'mobile_sdk';\n}\n\nexport interface WidgetCSSCustomization {\n exitIntent?: {\n backgroundColor?: string;\n textColor?: string;\n accentColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n overlayOpacity?: number;\n };\n spinWheel?: {\n backgroundColor?: string;\n textColor?: string;\n accentColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n wheelColors?: string[];\n buttonColor?: string;\n };\n chatBubble?: {\n backgroundColor?: string;\n textColor?: string;\n position?: 'bottom_right' | 'bottom_left' | 'top_right' | 'top_left';\n size?: 'small' | 'medium' | 'large';\n };\n}\n\nexport interface PrefetchWidgetConfig {\n exit_intent?: {\n enabled: boolean;\n type: 'cart_recovery' | 'lead_gen';\n tier?: string;\n title?: string;\n message?: string;\n discount_code?: string;\n discount_percentage?: number;\n cta_text?: string;\n cta_url?: string;\n background_color?: string;\n text_color?: string;\n accent_color?: string;\n show_cart_items?: boolean;\n show_timer?: boolean;\n timer_minutes?: number;\n priority: number;\n mobile_triggers?: {\n scroll_velocity?: boolean;\n scroll_threshold?: number;\n scroll_min_position?: number;\n scroll_cooldown?: number;\n idle_timer?: boolean;\n idle_seconds?: number;\n visibility_change?: boolean;\n back_button?: boolean;\n };\n };\n spin_wheel?: {\n enabled: boolean;\n type: 'lead_gen' | 'cart_recovery';\n title?: string;\n prizes?: any[];\n priority: number;\n };\n}\n\nexport interface CartData {\n cart_id: string;\n cart_total: number;\n cart_currency: string;\n cart_items: Array<{\n product_id: string;\n product_name?: string;\n quantity: number;\n price?: number;\n }>;\n}\n\nexport class AegisWidgetManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private debugMode: boolean;\n private triggerEngine?: TriggerEngine;\n private enablePrefetch: boolean;\n private cssCustomization: WidgetCSSCustomization;\n private onEvent?: (eventType: string, data: any) => void;\n private sourcePlatform?: string;\n\n private widgets: WidgetConfig[] = [];\n private renderedWidgets = new Set<string>();\n private isInitialized = false;\n private isDestroyed = false;\n private ownsTriggerEngine: boolean;\n\n private prefetchWidgetConfigs: PrefetchWidgetConfig = {};\n private cartData?: CartData;\n \n constructor(config: AegisWidgetConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n // Fall back to the SDK's persisted anonymous_id when callers don't pass\n // userId explicitly. Without this, /v1/widgets/config requests omit\n // X-User-ID and the cell-plane buckets the call into \"anonymous\", which\n // misses any user-targeted widget configs. Mirror in AegisInAppManager.\n this.userId = config.userId ?? readAnonIdFromStorage();\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.debugMode = config.debugMode || false;\n this.triggerEngine = config.triggerEngine;\n this.ownsTriggerEngine = config.ownsTriggerEngine === true;\n this.enablePrefetch = config.enablePrefetch !== false;\n this.cssCustomization = config.cssCustomization || {};\n this.onEvent = config.onEvent;\n this.sourcePlatform = config.sourcePlatform;\n }\n \n updateCSSCustomization(customization: WidgetCSSCustomization): void {\n this.cssCustomization = { ...this.cssCustomization, ...customization };\n this.log('CSS customization updated');\n }\n\n /**\n * Swap the identity that outgoing widget requests are attributed to.\n * Safe to call at any time; if prefetch is enabled and the manager\n * has already initialised, this will re-fetch the per-contact widget\n * configs so subsequent renders target the new identity. Does NOT\n * re-render already-visible widgets — a full teardown requires destroy().\n */\n async updateContactId(contactId: string | undefined): Promise<void> {\n if (this.contactId === contactId) return;\n this.contactId = contactId;\n this.log(`Contact ID updated → ${contactId ?? '(cleared)'}`);\n if (this.isInitialized && !this.isDestroyed && this.enablePrefetch && contactId) {\n await this.fetchPrefetchConfigs();\n this.preloadWidgetAssets();\n }\n }\n\n /**\n * Render an in-app campaign whose sub_type routes it to the\n * gamification-widget code path (spin_wheel / scratch_card).\n * InAppCampaign is adapted to the minimal WidgetConfig shape that\n * the internal renderers already understand — no rewrite needed.\n *\n * AegisMessageRuntime wires this method as AegisInAppManager's\n * `onInteractiveCampaign` callback so impressions from the inbox\n * prefetch bundle actually land on screen.\n */\n renderInteractiveCampaign(campaign: {\n id: string;\n title: string;\n sub_type?: string;\n priority?: number;\n interactive_config?: Record<string, unknown>;\n }): void {\n if (this.isDestroyed) return;\n if (typeof document === 'undefined') return;\n const subType = campaign.sub_type;\n if (subType !== 'spin_wheel' && subType !== 'scratch_card') {\n this.log(`renderInteractiveCampaign: unsupported sub_type \"${subType}\"`, true);\n return;\n }\n const widget: WidgetConfig = {\n widget_id: campaign.id,\n widget_type: subType,\n name: campaign.title,\n config: (campaign.interactive_config ?? {}) as Record<string, any>,\n priority: campaign.priority ?? 0,\n };\n if (this.renderedWidgets.has(widget.widget_id)) return;\n this.renderedWidgets.add(widget.widget_id);\n if (subType === 'spin_wheel') {\n this.renderSpinWheel(widget);\n } else {\n this.renderScratchCard(widget);\n }\n }\n\n /**\n * Tear down everything the manager installed: trigger listeners (if\n * we own the TriggerEngine), injected style sheets, and any rendered\n * widget roots. Further render attempts from in-flight triggers are\n * short-circuited by the `isDestroyed` flag.\n */\n destroy(): void {\n if (this.isDestroyed) return;\n this.isDestroyed = true;\n\n if (this.triggerEngine && this.ownsTriggerEngine) {\n this.triggerEngine.stop();\n }\n\n if (typeof document !== 'undefined') {\n const animationStyle = document.getElementById('aegis-widget-animations');\n animationStyle?.remove();\n document.querySelectorAll('[data-aegis-widget-root]').forEach((node) => {\n node.remove();\n });\n }\n\n this.renderedWidgets.clear();\n this.widgets = [];\n this.isInitialized = false;\n this.log('AegisWidgets destroyed');\n }\n \n private emitEvent(eventType: string, data: any): void {\n if (this.onEvent) {\n try {\n this.onEvent(eventType, data);\n } catch (error) {\n this.log(`Error in event callback: ${error}`, true);\n }\n }\n }\n \n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisWidgets already initialized');\n return;\n }\n \n if (this.enablePrefetch && this.contactId) {\n await this.fetchPrefetchConfigs();\n this.preloadWidgetAssets();\n }\n \n await this.fetchWidgets();\n \n this.renderImmediateWidgets();\n \n this.setupTriggerListeners();\n \n this.setupExitIntentWithPrefetch();\n \n this.isInitialized = true;\n this.log('AegisWidgets initialized successfully');\n }\n \n setCartData(cartData: CartData): void {\n this.cartData = cartData;\n this.log(`Cart data updated: ${cartData.cart_items.length} items, total: ${cartData.cart_currency} ${cartData.cart_total}`);\n }\n \n private detectPlatformCart(): CartData | null {\n const shopifyCart = this.normalizeShopifyCart();\n if (shopifyCart) {\n this.log('Detected Shopify cart via browser globals');\n return shopifyCart;\n }\n \n const wooCart = this.normalizeWooCart();\n if (wooCart) {\n this.log('Detected WooCommerce cart via injected data');\n return wooCart;\n }\n \n const magentoCart = this.normalizeMagentoCart();\n if (magentoCart) {\n this.log('Detected Magento cart via localStorage');\n return magentoCart;\n }\n \n if (this.cartData) {\n this.log('Using manually set cart data');\n return this.cartData;\n }\n \n return null;\n }\n \n private normalizeShopifyCart(): CartData | null {\n try {\n if (typeof window === 'undefined') return null;\n \n const win = window as any;\n \n if (win.Shopify?.checkout) {\n const checkout = win.Shopify.checkout;\n return {\n cart_id: checkout.token || `shopify_${Date.now()}`,\n cart_total: parseFloat(checkout.total_price) || 0,\n cart_currency: checkout.currency || 'USD',\n cart_items: (checkout.line_items || []).map((item: any) => ({\n product_id: String(item.product_id || item.id),\n product_name: item.title || item.product_title,\n quantity: item.quantity || 1,\n price: parseFloat(item.price) || 0\n }))\n };\n }\n \n const cartJsonEl = document.getElementById('cart-json');\n if (cartJsonEl?.textContent) {\n const cart = JSON.parse(cartJsonEl.textContent);\n return {\n cart_id: cart.token || `shopify_${Date.now()}`,\n cart_total: (cart.total_price || 0) / 100,\n cart_currency: cart.currency || 'USD',\n cart_items: (cart.items || []).map((item: any) => ({\n product_id: String(item.product_id || item.id),\n product_name: item.product_title || item.title,\n quantity: item.quantity || 1,\n price: (item.price || 0) / 100\n }))\n };\n }\n \n return null;\n } catch (error) {\n this.log(`Error detecting Shopify cart: ${error}`, true);\n return null;\n }\n }\n \n private normalizeWooCart(): CartData | null {\n try {\n if (typeof window === 'undefined') return null;\n \n const win = window as any;\n \n if (win.aegis_cart) {\n const cart = win.aegis_cart;\n return {\n cart_id: cart.cart_id || `woo_${Date.now()}`,\n cart_total: parseFloat(cart.cart_total) || 0,\n cart_currency: cart.cart_currency || 'USD',\n cart_items: (cart.cart_items || []).map((item: any) => ({\n product_id: String(item.product_id),\n product_name: item.product_name,\n quantity: item.quantity || 1,\n price: parseFloat(item.price) || 0\n }))\n };\n }\n \n return null;\n } catch (error) {\n this.log(`Error detecting WooCommerce cart: ${error}`, true);\n return null;\n }\n }\n \n private normalizeMagentoCart(): CartData | null {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return null;\n \n const mageCacheStr = localStorage.getItem('mage-cache-storage');\n if (!mageCacheStr) return null;\n \n const mageCache = JSON.parse(mageCacheStr);\n if (!mageCache?.cart) return null;\n \n const cart = mageCache.cart;\n \n return {\n cart_id: cart.quote_id || cart.id || `magento_${Date.now()}`,\n cart_total: parseFloat(cart.subtotalAmount || cart.subtotal || 0),\n cart_currency: cart.currencyCode || 'USD',\n cart_items: (cart.items || []).map((item: any) => ({\n product_id: String(item.item_id || item.product_id),\n product_name: item.product_name || item.name,\n quantity: item.qty || 1,\n price: parseFloat(item.product_price_value || item.price || 0)\n }))\n };\n } catch (error) {\n this.log(`Error detecting Magento cart: ${error}`, true);\n return null;\n }\n }\n \n private preloadWidgetAssets(): void {\n try {\n const exitIntentConfig = this.prefetchWidgetConfigs.exit_intent;\n if (exitIntentConfig?.enabled) {\n const imageUrl = (exitIntentConfig as any).image_url;\n if (imageUrl) {\n const img = new Image();\n img.src = imageUrl;\n this.log(`Preloading exit intent image: ${imageUrl}`);\n }\n }\n \n const spinWheelConfig = this.prefetchWidgetConfigs.spin_wheel;\n if (spinWheelConfig?.enabled) {\n const imageUrl = (spinWheelConfig as any).image_url;\n if (imageUrl) {\n const img = new Image();\n img.src = imageUrl;\n this.log(`Preloading spin wheel image: ${imageUrl}`);\n }\n }\n } catch (error) {\n this.log(`Error preloading widget assets: ${error}`, true);\n }\n }\n \n private async fetchPrefetchConfigs(): Promise<void> {\n try {\n const startTime = performance.now();\n const url = `${this.apiHost}/v1/widgets/config/prefetch`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n };\n \n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, { headers, credentials: 'include' });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch prefetch configs: ${response.status}`);\n }\n \n this.prefetchWidgetConfigs = await response.json();\n \n const elapsed = performance.now() - startTime;\n this.log(`Fetched prefetch widget configs in ${elapsed.toFixed(2)}ms`);\n \n } catch (error) {\n this.log(`Error fetching prefetch configs: ${error}`, true);\n }\n }\n \n private async fetchWidgets(): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/widgets/config`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Platform': 'web',\n 'X-Device-Type': this.getDeviceType()\n };\n\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.sourcePlatform) headers['X-Source-Platform'] = this.sourcePlatform;\n \n const response = await fetch(url, { headers, credentials: 'include' });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch widgets: ${response.status}`);\n }\n \n this.widgets = await response.json();\n \n this.log(`Fetched ${this.widgets.length} widgets`);\n \n } catch (error) {\n this.log(`Error fetching widgets: ${error}`, true);\n }\n }\n \n private renderImmediateWidgets(): void {\n const immediateWidgets = this.widgets.filter(w => \n !w.trigger_rules || w.trigger_rules.type === 'immediate'\n );\n \n immediateWidgets.forEach(widget => this.renderWidget(widget));\n }\n \n private setupTriggerListeners(): void {\n if (!this.triggerEngine) {\n this.log('TriggerEngine not provided, skipping trigger-based widgets');\n return;\n }\n \n this.widgets.forEach(widget => {\n if (!widget.trigger_rules) return;\n \n const { type, config } = widget.trigger_rules;\n \n switch (type) {\n case 'exit_intent':\n this.triggerEngine!.registerExitIntent();\n this.triggerEngine!.on('exit_intent', () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n \n case 'scroll_depth':\n const depthPercent = (config as any)?.depth_percent || 50;\n this.triggerEngine!.registerScrollDepth(depthPercent);\n this.triggerEngine!.on(`scroll_depth_${depthPercent}`, () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n \n case 'time_on_page':\n const seconds = (config as any)?.seconds || 30;\n this.triggerEngine!.registerTimeOnPage(seconds);\n this.triggerEngine!.on(`time_on_page_${seconds}`, () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n }\n });\n }\n \n private setupExitIntentWithPrefetch(): void {\n if (!this.enablePrefetch || !this.triggerEngine) {\n return;\n }\n \n const spinWheelConfig = this.prefetchWidgetConfigs.spin_wheel;\n const exitIntentConfig = this.prefetchWidgetConfigs.exit_intent;\n \n if (spinWheelConfig && spinWheelConfig.enabled) {\n const isMobile = this.isMobileDevice();\n const mobileConfig = exitIntentConfig?.mobile_triggers || {};\n \n const handleSpinWheelIntent = () => {\n const widgetId = `prefetch_spin_wheel_${Date.now()}`;\n \n if (this.renderedWidgets.has(widgetId)) {\n return;\n }\n \n this.renderedWidgets.add(widgetId);\n \n const detectedCart = this.detectPlatformCart();\n \n if (spinWheelConfig.type === 'cart_recovery' && detectedCart) {\n this.cartData = detectedCart;\n this.renderSpinWheelWidget(widgetId, spinWheelConfig);\n this.sendCartAbandonmentBeacon();\n } else if (spinWheelConfig.type === 'lead_gen') {\n this.renderSpinWheelWidget(widgetId, spinWheelConfig);\n }\n };\n \n if (isMobile) {\n const scrollVelocityEnabled = mobileConfig.scroll_velocity !== false;\n if (scrollVelocityEnabled) {\n this.triggerEngine.registerScrollVelocity({\n threshold: mobileConfig.scroll_threshold || 0.5,\n minScrollPosition: mobileConfig.scroll_min_position || 100,\n cooldown: mobileConfig.scroll_cooldown || 5000\n });\n this.triggerEngine.on('mobile_exit_intent', handleSpinWheelIntent);\n this.log('Registered mobile scroll velocity trigger for spin wheel');\n }\n \n const idleTimerEnabled = mobileConfig.idle_timer !== false;\n if (idleTimerEnabled) {\n const idleSeconds = mobileConfig.idle_seconds || 15;\n this.triggerEngine.registerInactivity(idleSeconds);\n this.triggerEngine.on(`inactivity_${idleSeconds}`, handleSpinWheelIntent);\n this.log(`Registered mobile idle timer trigger for spin wheel: ${idleSeconds}s`);\n }\n \n const visibilityChangeEnabled = mobileConfig.visibility_change !== false;\n if (visibilityChangeEnabled) {\n const detectedCart = this.detectPlatformCart();\n if (detectedCart && detectedCart.cart_items && detectedCart.cart_items.length > 0) {\n this.triggerEngine.registerVisibilityChange();\n this.triggerEngine.on('visibility_hidden', handleSpinWheelIntent);\n this.log('Registered mobile visibility change trigger for spin wheel (cart detected)');\n }\n }\n \n const backButtonEnabled = mobileConfig.back_button === true;\n if (backButtonEnabled) {\n this.triggerEngine.registerBackButton();\n this.triggerEngine.on('back_button', handleSpinWheelIntent);\n this.log('Registered mobile back button trigger for spin wheel');\n }\n \n this.log(`Setup mobile spin wheel: type=${spinWheelConfig.type}, priority=${spinWheelConfig.priority}`);\n } else {\n this.triggerEngine.registerExitIntent();\n this.triggerEngine.on('exit_intent', handleSpinWheelIntent);\n this.log(`Setup desktop spin wheel exit intent: type=${spinWheelConfig.type}, priority=${spinWheelConfig.priority}`);\n }\n \n return;\n }\n \n if (!exitIntentConfig || !exitIntentConfig.enabled) {\n this.log('No exit intent config found in prefetch');\n return;\n }\n \n const isMobile = this.isMobileDevice();\n const mobileConfig = exitIntentConfig.mobile_triggers || {};\n \n const handleExitIntent = () => {\n const widgetId = `prefetch_exit_intent_${Date.now()}`;\n \n if (this.renderedWidgets.has(widgetId)) {\n return;\n }\n \n this.renderedWidgets.add(widgetId);\n \n const detectedCart = this.detectPlatformCart();\n \n if (exitIntentConfig.type === 'cart_recovery' && detectedCart) {\n this.cartData = detectedCart;\n this.renderCartRecoveryPopup(widgetId, exitIntentConfig);\n this.sendCartAbandonmentBeacon();\n } else if (exitIntentConfig.type === 'lead_gen') {\n this.renderLeadGenPopup(widgetId, exitIntentConfig);\n } else {\n this.log('Unknown exit intent type or missing cart data');\n }\n };\n \n if (isMobile) {\n const scrollVelocityEnabled = mobileConfig.scroll_velocity !== false;\n if (scrollVelocityEnabled) {\n this.triggerEngine.registerScrollVelocity({\n threshold: mobileConfig.scroll_threshold || 0.5,\n minScrollPosition: mobileConfig.scroll_min_position || 100,\n cooldown: mobileConfig.scroll_cooldown || 5000\n });\n this.triggerEngine.on('mobile_exit_intent', handleExitIntent);\n this.log('Registered mobile scroll velocity trigger');\n }\n \n const idleTimerEnabled = mobileConfig.idle_timer !== false;\n if (idleTimerEnabled) {\n const idleSeconds = mobileConfig.idle_seconds || 15;\n this.triggerEngine.registerInactivity(idleSeconds);\n this.triggerEngine.on(`inactivity_${idleSeconds}`, handleExitIntent);\n this.log(`Registered mobile idle timer trigger: ${idleSeconds}s`);\n }\n \n const visibilityChangeEnabled = mobileConfig.visibility_change !== false;\n if (visibilityChangeEnabled) {\n const detectedCart = this.detectPlatformCart();\n if (detectedCart && detectedCart.cart_items && detectedCart.cart_items.length > 0) {\n this.triggerEngine.registerVisibilityChange();\n this.triggerEngine.on('visibility_hidden', handleExitIntent);\n this.log('Registered mobile visibility change trigger (cart detected)');\n } else {\n this.log('Skipped visibility change trigger (no cart items)');\n }\n }\n \n const backButtonEnabled = mobileConfig.back_button === true;\n if (backButtonEnabled) {\n this.triggerEngine.registerBackButton();\n this.triggerEngine.on('back_button', handleExitIntent);\n this.log('Registered mobile back button trigger (aggressive mode)');\n }\n \n this.log(`Setup mobile exit intent: type=${exitIntentConfig.type}, priority=${exitIntentConfig.priority}`);\n } else {\n this.triggerEngine.registerExitIntent();\n this.triggerEngine.on('exit_intent', handleExitIntent);\n this.log(`Setup desktop exit intent: type=${exitIntentConfig.type}, priority=${exitIntentConfig.priority}`);\n }\n }\n \n private sendCartAbandonmentBeacon(): void {\n if (!this.cartData) {\n this.log('No cart data available for beacon', true);\n return;\n }\n \n const beaconData = {\n organization_id: this.organizationId || 'default',\n contact_id: this.contactId,\n cart_id: this.cartData.cart_id,\n cart_total: this.cartData.cart_total,\n cart_currency: this.cartData.cart_currency,\n cart_items: this.cartData.cart_items,\n user_email: this.userId,\n abandoned_at: new Date().toISOString(),\n page_url: window.location.href,\n referrer: document.referrer\n };\n \n const beaconUrl = `${this.apiHost}/v1/widgets/beacon/cart-abandoned`;\n \n if (navigator.sendBeacon) {\n const blob = new Blob([JSON.stringify(beaconData)], { type: 'application/json' });\n const sent = navigator.sendBeacon(beaconUrl, blob);\n \n if (sent) {\n this.log('Cart abandonment beacon sent successfully');\n } else {\n this.log('Failed to send cart abandonment beacon', true);\n }\n } else {\n fetch(beaconUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey\n },\n body: JSON.stringify(beaconData),\n keepalive: true,\n credentials: 'include',\n }).catch(err => {\n this.log(`Error sending cart abandonment via fetch: ${err}`, true);\n });\n }\n }\n \n private renderWidget(widget: WidgetConfig): void {\n if (this.isDestroyed) return;\n if (this.renderedWidgets.has(widget.widget_id)) {\n return;\n }\n\n this.renderedWidgets.add(widget.widget_id);\n \n switch (widget.widget_type) {\n case 'chat_bubble':\n this.renderChatBubble(widget);\n break;\n case 'spin_wheel':\n this.renderSpinWheel(widget);\n break;\n case 'scratch_card':\n this.renderScratchCard(widget);\n break;\n case 'toast':\n this.renderToast(widget);\n break;\n case 'feedback_form':\n this.renderFeedbackForm(widget);\n break;\n case 'exit_intent_popup':\n this.renderExitIntentPopup(widget);\n break;\n default:\n this.log(`Unknown widget type: ${widget.widget_type}`, true);\n }\n \n this.trackEvent(widget.widget_id, 'show');\n }\n \n private renderChatBubble(widget: WidgetConfig): void {\n const { text, icon_url, link_url, background_color, text_color } = widget.config;\n const position = widget.position || 'bottom_right';\n \n const bubble = document.createElement('div');\n bubble.className = 'aegis-chat-bubble';\n bubble.setAttribute('data-widget-id', widget.widget_id);\n \n const positionStyles: Record<string, string> = {\n bottom_right: 'bottom: 20px; right: 20px;',\n bottom_left: 'bottom: 20px; left: 20px;',\n top_right: 'top: 20px; right: 20px;',\n top_left: 'top: 20px; left: 20px;'\n };\n \n bubble.style.cssText = `\n position: fixed;\n ${positionStyles[position] || positionStyles.bottom_right}\n background: ${this.sanitizeColor(background_color || '#25D366')};\n color: ${this.sanitizeColor(text_color || '#ffffff')};\n padding: 16px 24px;\n border-radius: 50px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n cursor: pointer;\n z-index: 999999;\n display: flex;\n align-items: center;\n gap: 12px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n font-weight: 600;\n font-size: 14px;\n animation: aegisBubbleIn 0.3s ease-out;\n `;\n \n if (icon_url) {\n const icon = document.createElement('img');\n const safeUrl = this.sanitizeUrl(icon_url);\n if (safeUrl) {\n icon.src = safeUrl;\n icon.alt = '';\n icon.style.cssText = 'width: 24px; height: 24px;';\n bubble.appendChild(icon);\n }\n }\n \n const textEl = document.createElement('span');\n textEl.textContent = text || 'Chat with us';\n bubble.appendChild(textEl);\n \n bubble.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'click');\n const safeUrl = this.sanitizeUrl(link_url);\n if (safeUrl) {\n window.open(safeUrl, '_blank');\n }\n });\n \n this.addAnimationStyles();\n bubble.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(bubble);\n }\n \n private renderSpinWheel(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-gamification-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-spin-wheel-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'Spin to Win!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Try your luck and win exclusive prizes!';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n modal.appendChild(description);\n \n // Draw an SVG wheel that honours the tenant's configured segments.\n // Each segment's `color` + `label` is painted as a pie slice; falls\n // back to a 4-color placeholder if no segments are provided.\n const segments: Array<{ label: string; color?: string }> = Array.isArray(\n (widget.config as any).segments,\n )\n ? (widget.config as any).segments\n : [\n { label: 'Prize 1', color: '#ff6b6b' },\n { label: 'Prize 2', color: '#feca57' },\n { label: 'Prize 3', color: '#48dbfb' },\n { label: 'Prize 4', color: '#ff6348' },\n ];\n\n const SVG_NS = 'http://www.w3.org/2000/svg';\n const wheel = document.createElementNS(SVG_NS, 'svg');\n wheel.setAttribute('viewBox', '-160 -160 320 320');\n wheel.setAttribute('width', '300');\n wheel.setAttribute('height', '300');\n wheel.style.cssText = 'margin: 0 auto 24px; display: block;';\n\n const n = segments.length;\n const anglePer = (2 * Math.PI) / n;\n const radius = 140;\n for (let i = 0; i < n; i++) {\n const start = i * anglePer - Math.PI / 2;\n const end = start + anglePer;\n const x1 = Math.cos(start) * radius;\n const y1 = Math.sin(start) * radius;\n const x2 = Math.cos(end) * radius;\n const y2 = Math.sin(end) * radius;\n const largeArc = anglePer > Math.PI ? 1 : 0;\n const path = document.createElementNS(SVG_NS, 'path');\n path.setAttribute(\n 'd',\n `M 0 0 L ${x1.toFixed(2)} ${y1.toFixed(2)} A ${radius} ${radius} 0 ${largeArc} 1 ${x2.toFixed(2)} ${y2.toFixed(2)} Z`,\n );\n path.setAttribute('fill', this.sanitizeColor(segments[i].color || '#cccccc'));\n path.setAttribute('stroke', '#ffffff');\n path.setAttribute('stroke-width', '2');\n wheel.appendChild(path);\n\n const labelAngle = start + anglePer / 2;\n const lx = Math.cos(labelAngle) * radius * 0.65;\n const ly = Math.sin(labelAngle) * radius * 0.65;\n const text = document.createElementNS(SVG_NS, 'text');\n text.setAttribute('x', lx.toFixed(2));\n text.setAttribute('y', ly.toFixed(2));\n text.setAttribute('fill', '#ffffff');\n text.setAttribute('font-size', '13');\n text.setAttribute('font-weight', '600');\n text.setAttribute('text-anchor', 'middle');\n text.setAttribute('dominant-baseline', 'middle');\n text.textContent = segments[i].label || `#${i + 1}`;\n wheel.appendChild(text);\n }\n modal.appendChild(wheel);\n \n const spinButton = document.createElement('button');\n spinButton.textContent = 'SPIN NOW!';\n spinButton.style.cssText = `\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n margin-bottom: 16px;\n `;\n \n spinButton.addEventListener('click', async () => {\n spinButton.disabled = true;\n spinButton.textContent = 'SPINNING...';\n \n try {\n const prize = await this.generatePrize(widget.config.config_id);\n\n wheel.style.animation = 'aegisSpin 2s ease-out';\n\n setTimeout(() => {\n this.showPrizeResult(modal, prize);\n }, 2000);\n \n } catch (error) {\n this.log(`Error generating prize: ${error}`, true);\n spinButton.disabled = false;\n spinButton.textContent = 'TRY AGAIN';\n }\n });\n \n modal.appendChild(spinButton);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderSpinWheelWidget(widgetId: string, config: NonNullable<PrefetchWidgetConfig['spin_wheel']>): void {\n if (this.isDestroyed) return;\n const cart = this.detectPlatformCart();\n \n if (config.type === 'cart_recovery' && !cart) {\n this.log('Spin wheel requires cart, but none detected');\n return;\n }\n \n if (cart) {\n this.cartData = cart;\n }\n \n const customization = this.cssCustomization.spinWheel || {};\n const accentColor = customization.accentColor || (config as any).accent_color || '#FF6B6B';\n const backgroundColor = customization.backgroundColor || (config as any).background_color || '#FFFFFF';\n const textColor = customization.textColor || (config as any).text_color || '#333333';\n const buttonColor = customization.buttonColor || (config as any).button_color || accentColor;\n const wheelColors = customization.wheelColors || ['#FF6B6B', '#4ECDC4', '#FFE66D', '#95E1D3'];\n \n const overlay = document.createElement('div');\n overlay.className = 'aegis-spin-wheel-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.7);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 999999;\n animation: aegisFadeIn 0.3s ease;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-spin-wheel-modal';\n modal.style.cssText = `\n background: ${this.sanitizeColor(backgroundColor)};\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n position: relative;\n animation: aegisScaleIn 0.4s ease;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n const closeBtn = document.createElement('button');\n closeBtn.innerHTML = '✕';\n closeBtn.className = 'aegis-spin-wheel-close';\n closeBtn.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #999;\n `;\n closeBtn.onclick = () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'spin_wheel' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n };\n modal.appendChild(closeBtn);\n \n const title = document.createElement('h2');\n title.textContent = this.interpolateCartVariables((config as any).title || 'Spin to Win!');\n title.style.cssText = `\n margin: 0 0 16px 0;\n font-size: 28px;\n font-weight: bold;\n text-align: center;\n color: ${this.sanitizeColor(textColor)};\n `;\n modal.appendChild(title);\n \n if (cart) {\n const subtitle = document.createElement('p');\n subtitle.textContent = `Complete your ${cart.cart_currency} ${cart.cart_total.toFixed(2)} order and save!`;\n subtitle.style.cssText = `\n margin: 0 0 24px 0;\n font-size: 16px;\n text-align: center;\n color: #666;\n `;\n modal.appendChild(subtitle);\n }\n \n const wheelContainer = document.createElement('div');\n wheelContainer.className = 'aegis-wheel-container';\n wheelContainer.style.cssText = `\n width: 300px;\n height: 300px;\n margin: 0 auto 24px auto;\n background: conic-gradient(\n from 0deg,\n ${wheelColors[0]} 0deg 90deg,\n ${wheelColors[1]} 90deg 180deg,\n ${wheelColors[2]} 180deg 270deg,\n ${wheelColors[3]} 270deg 360deg\n );\n border-radius: 50%;\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n \n const form = document.createElement('form');\n form.className = 'aegis-spin-form';\n form.style.cssText = 'display: block;';\n \n const phoneInput = document.createElement('input');\n phoneInput.type = 'tel';\n phoneInput.placeholder = 'Enter your phone number';\n phoneInput.required = true;\n phoneInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(phoneInput);\n \n const emailInput = document.createElement('input');\n emailInput.type = 'email';\n emailInput.placeholder = 'Enter your email (optional)';\n emailInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(emailInput);\n \n const nameInput = document.createElement('input');\n nameInput.type = 'text';\n nameInput.placeholder = 'Enter your name (optional)';\n nameInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(nameInput);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Spin the Wheel!';\n submitButton.style.cssText = `\n width: 100%;\n padding: 14px;\n background: ${this.sanitizeColor(buttonColor)};\n color: white;\n border: none;\n border-radius: 8px;\n font-size: 16px;\n font-weight: 700;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n const errorMessage = document.createElement('div');\n errorMessage.className = 'aegis-spin-error';\n errorMessage.style.cssText = `\n color: #d32f2f;\n font-size: 14px;\n margin-top: 12px;\n text-align: center;\n display: none;\n `;\n form.appendChild(errorMessage);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n const phone = phoneInput.value.trim();\n const email = emailInput.value.trim();\n const name = nameInput.value.trim();\n \n if (!this.validatePhone(phone)) {\n errorMessage.textContent = 'Please enter a valid phone number (e.g., +1234567890)';\n errorMessage.style.display = 'block';\n return;\n }\n \n if (email && !this.validateEmail(email)) {\n errorMessage.textContent = 'Please enter a valid email address';\n errorMessage.style.display = 'block';\n return;\n }\n \n errorMessage.style.display = 'none';\n submitButton.disabled = true;\n submitButton.textContent = 'Spinning...';\n \n wheelContainer.style.animation = 'aegisSpin 2s ease-out';\n \n setTimeout(async () => {\n try {\n const prize = await this.submitSpinWheel({\n phone,\n email,\n name,\n cart,\n widgetId\n });\n \n this.showSpinWheelPrize(modal, prize);\n this.trackEvent(widgetId, 'submit', {\n type: 'spin_wheel',\n prize_label: prize.prize_label,\n has_email: !!email\n });\n \n } catch (error) {\n this.log(`Error submitting spin wheel: ${error}`, true);\n errorMessage.textContent = 'Failed to submit. Please try again.';\n errorMessage.style.display = 'block';\n submitButton.disabled = false;\n submitButton.textContent = 'Spin the Wheel!';\n wheelContainer.style.animation = '';\n }\n }, 2000);\n });\n \n modal.appendChild(wheelContainer);\n modal.appendChild(form);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'spin_wheel' });\n }\n \n private validatePhone(phone: string): boolean {\n const e164Regex = /^\\+?[1-9]\\d{1,14}$/;\n return e164Regex.test(phone.replace(/[\\s()-]/g, ''));\n }\n \n private validateEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n }\n \n private async submitSpinWheel(data: {\n phone: string;\n email: string;\n name: string;\n cart: CartData | null;\n widgetId: string;\n }): Promise<GamificationPrize> {\n const url = `${this.apiHost}/v1/widgets/spin-wheel/submit`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const geoRegion = this.detectGeoRegion();\n const deviceType = this.getDeviceType();\n const utmParams = this.getUTMParams();\n \n const body: any = {\n phone: data.phone.replace(/[\\s()-]/g, ''),\n email: data.email || undefined,\n name: data.name || undefined,\n cart_id: data.cart?.cart_id || `web_${Date.now()}`,\n cart_token: data.cart?.cart_id,\n cart_total: data.cart?.cart_total || 0,\n cart_currency: data.cart?.cart_currency || 'USD',\n cart_items: data.cart?.cart_items || [],\n cart_url: window.location.href,\n platform: 'web',\n geo_region: geoRegion,\n device_type: deviceType,\n session_id: this.getSessionId() || undefined,\n anonymous_id: this.getAnonymousId() || undefined,\n utm_source: utmParams.utm_source,\n utm_medium: utmParams.utm_medium,\n utm_campaign: utmParams.utm_campaign\n };\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n credentials: 'include',\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to submit spin wheel: ${response.status} - ${errorText}`);\n }\n \n return await response.json();\n }\n \n private showSpinWheelPrize(modal: HTMLElement, prize: GamificationPrize): void {\n modal.innerHTML = '';\n \n const resultContainer = document.createElement('div');\n resultContainer.style.cssText = 'text-align: center; padding: 40px 20px;';\n \n const emoji = document.createElement('div');\n emoji.textContent = '🎉';\n emoji.style.cssText = 'font-size: 60px; margin-bottom: 20px;';\n resultContainer.appendChild(emoji);\n \n const title = document.createElement('h2');\n title.textContent = 'Congratulations!';\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 28px; font-weight: 700; color: #1a73e8;';\n resultContainer.appendChild(title);\n \n const prizeLabel = document.createElement('p');\n prizeLabel.textContent = prize.prize_label;\n prizeLabel.style.cssText = 'margin: 0 0 20px 0; font-size: 20px; font-weight: 600; color: #333;';\n resultContainer.appendChild(prizeLabel);\n \n if (prize.coupon_code) {\n const couponContainer = document.createElement('div');\n couponContainer.style.cssText = `\n background: #f5f5f5;\n padding: 16px;\n border-radius: 8px;\n margin-bottom: 20px;\n border: 2px dashed #1a73e8;\n `;\n \n const couponLabel = document.createElement('div');\n couponLabel.textContent = 'Your coupon code:';\n couponLabel.style.cssText = 'font-size: 12px; color: #666; margin-bottom: 8px;';\n couponContainer.appendChild(couponLabel);\n \n const couponCode = document.createElement('div');\n couponCode.textContent = prize.coupon_code;\n couponCode.style.cssText = 'font-size: 24px; font-weight: 700; color: #1a73e8; letter-spacing: 2px;';\n couponContainer.appendChild(couponCode);\n \n resultContainer.appendChild(couponContainer);\n }\n \n const message = document.createElement('p');\n message.textContent = 'Check your WhatsApp/SMS for your discount code and cart link!';\n message.style.cssText = 'margin: 0 0 20px 0; font-size: 14px; color: #666;';\n resultContainer.appendChild(message);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n \n closeButton.addEventListener('click', () => {\n const overlay = modal.parentElement;\n if (overlay && document.body.contains(overlay)) {\n document.body.removeChild(overlay);\n }\n });\n \n resultContainer.appendChild(closeButton);\n modal.appendChild(resultContainer);\n }\n \n private detectGeoRegion(): string {\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n \n if (timezone.includes('America')) return 'north_america';\n if (timezone.includes('Europe')) return 'europe';\n if (timezone.includes('Asia/Kolkata') || timezone.includes('Asia/Calcutta')) return 'india';\n if (timezone.includes('Asia/Singapore') || timezone.includes('Asia/Bangkok') || timezone.includes('Asia/Jakarta')) return 'southeast_asia';\n if (timezone.includes('Asia/Dubai') || timezone.includes('Asia/Riyadh')) return 'middle_east';\n if (timezone.includes('America') && (timezone.includes('Sao_Paulo') || timezone.includes('Buenos_Aires'))) return 'latin_america';\n if (timezone.includes('Australia') || timezone.includes('Pacific/Auckland')) return 'oceania';\n \n return 'north_america';\n }\n \n private getUTMParams(): { utm_source?: string; utm_medium?: string; utm_campaign?: string } {\n const params = new URLSearchParams(window.location.search);\n return {\n utm_source: params.get('utm_source') || undefined,\n utm_medium: params.get('utm_medium') || undefined,\n utm_campaign: params.get('utm_campaign') || undefined\n };\n }\n \n private getSessionId(): string | null {\n return sessionStorage.getItem('aegis_session_id');\n }\n \n private getAnonymousId(): string | null {\n return localStorage.getItem('aegis_anonymous_id');\n }\n \n private renderScratchCard(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-gamification-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-scratch-card-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'Scratch & Win!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Scratch to reveal your prize!';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n modal.appendChild(description);\n \n const canvas = document.createElement('canvas');\n canvas.width = 300;\n canvas.height = 200;\n canvas.style.cssText = `\n border-radius: 8px;\n cursor: pointer;\n margin: 0 auto 24px;\n display: block;\n box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n `;\n modal.appendChild(canvas);\n \n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.fillStyle = '#c0c0c0';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.fillStyle = '#888';\n ctx.font = '20px Arial';\n ctx.textAlign = 'center';\n ctx.fillText('Scratch here!', canvas.width / 2, canvas.height / 2);\n \n let isScratching = false;\n \n const scratch = (x: number, y: number) => {\n ctx.globalCompositeOperation = 'destination-out';\n ctx.beginPath();\n ctx.arc(x, y, 20, 0, Math.PI * 2);\n ctx.fill();\n };\n \n canvas.addEventListener('mousedown', () => { isScratching = true; });\n canvas.addEventListener('mouseup', () => { isScratching = false; });\n canvas.addEventListener('mousemove', (e) => {\n if (isScratching) {\n const rect = canvas.getBoundingClientRect();\n scratch(e.clientX - rect.left, e.clientY - rect.top);\n }\n });\n }\n \n const scratchButton = document.createElement('button');\n scratchButton.textContent = 'REVEAL PRIZE';\n scratchButton.style.cssText = `\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n color: white;\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n `;\n \n scratchButton.addEventListener('click', async () => {\n scratchButton.disabled = true;\n scratchButton.textContent = 'REVEALING...';\n \n try {\n const prize = await this.generatePrize(widget.config.config_id);\n this.showPrizeResult(modal, prize);\n } catch (error) {\n this.log(`Error generating prize: ${error}`, true);\n scratchButton.disabled = false;\n scratchButton.textContent = 'TRY AGAIN';\n }\n });\n \n modal.appendChild(scratchButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderToast(widget: WidgetConfig): void {\n const { message, icon, duration } = widget.config;\n const position = widget.position || 'bottom_left';\n \n const toast = document.createElement('div');\n toast.className = 'aegis-toast';\n toast.setAttribute('data-widget-id', widget.widget_id);\n \n const positionStyles: Record<string, string> = {\n bottom_left: 'bottom: 20px; left: 20px;',\n bottom_right: 'bottom: 20px; right: 20px;',\n top_left: 'top: 20px; left: 20px;',\n top_right: 'top: 20px; right: 20px;'\n };\n \n toast.style.cssText = `\n position: fixed;\n ${positionStyles[position] || positionStyles.bottom_left}\n background: white;\n padding: 16px 20px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n z-index: 999998;\n display: flex;\n align-items: center;\n gap: 12px;\n max-width: 350px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisToastIn 0.3s ease-out;\n `;\n \n if (icon) {\n const iconEl = document.createElement('div');\n iconEl.textContent = icon;\n iconEl.style.cssText = 'font-size: 20px;';\n toast.appendChild(iconEl);\n }\n \n const messageEl = document.createElement('div');\n messageEl.textContent = message || 'Someone just made a purchase!';\n messageEl.style.cssText = 'flex: 1; font-size: 13px; color: #333;';\n toast.appendChild(messageEl);\n \n this.addAnimationStyles();\n toast.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(toast);\n \n setTimeout(() => {\n toast.style.animation = 'aegisToastOut 0.3s ease-out';\n setTimeout(() => {\n if (document.body.contains(toast)) {\n document.body.removeChild(toast);\n }\n this.renderedWidgets.delete(widget.widget_id);\n }, 300);\n }, duration || 5000);\n }\n \n private renderFeedbackForm(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-feedback-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 400px;\n background: white;\n box-shadow: -4px 0 20px rgba(0,0,0,0.15);\n z-index: 1000000;\n padding: 32px;\n overflow-y: auto;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInRight 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'We value your feedback!';\n title.style.cssText = 'margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n overlay.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Help us improve your experience.';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n overlay.appendChild(description);\n \n const form = document.createElement('form');\n \n const label = document.createElement('label');\n label.textContent = 'How likely are you to recommend us? (0-10)';\n label.style.cssText = 'display: block; font-size: 14px; font-weight: 600; margin-bottom: 8px; color: #333;';\n form.appendChild(label);\n \n const input = document.createElement('input');\n input.type = 'number';\n input.min = '0';\n input.max = '10';\n input.style.cssText = `\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n margin-bottom: 16px;\n `;\n form.appendChild(input);\n \n const textareaLabel = document.createElement('label');\n textareaLabel.textContent = 'Tell us more (optional)';\n textareaLabel.style.cssText = 'display: block; font-size: 14px; font-weight: 600; margin-bottom: 8px; color: #333;';\n form.appendChild(textareaLabel);\n \n const textarea = document.createElement('textarea');\n textarea.rows = 4;\n textarea.style.cssText = `\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n resize: vertical;\n margin-bottom: 16px;\n font-family: inherit;\n `;\n form.appendChild(textarea);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Submit Feedback';\n submitButton.style.cssText = `\n width: 100%;\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px;\n border-radius: 6px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n \n try {\n await this.submitFeedback(widget.widget_id, {\n score: parseInt(input.value),\n comment: textarea.value\n });\n \n overlay.innerHTML = '<div style=\"text-align: center; padding: 60px 20px;\"><h3 style=\"margin: 0 0 12px 0; color: #1a73e8;\">Thank you!</h3><p style=\"margin: 0; color: #666;\">Your feedback helps us improve.</p></div>';\n \n setTimeout(() => {\n document.body.removeChild(overlay);\n }, 2000);\n \n } catch (error) {\n this.log(`Error submitting feedback: ${error}`, true);\n submitButton.disabled = false;\n submitButton.textContent = 'Submit Feedback';\n }\n });\n \n overlay.appendChild(form);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n overlay.appendChild(closeButton);\n \n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderExitIntentPopup(widget: WidgetConfig): void {\n const { title, description, cta_text, cta_url, image_url } = widget.config;\n \n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-exit-popup-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n max-width: 600px;\n width: 90%;\n overflow: hidden;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 250px; object-fit: cover;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 32px;';\n \n const titleEl = document.createElement('h2');\n titleEl.textContent = title || 'Wait! Don\\'t leave yet!';\n titleEl.style.cssText = 'margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(titleEl);\n \n const descEl = document.createElement('p');\n descEl.textContent = description || 'Get 10% off your first order!';\n descEl.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; color: #666; line-height: 1.5;';\n content.appendChild(descEl);\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n content.appendChild(ctaButton);\n }\n \n modal.appendChild(content);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: white;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #666;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private async generatePrize(configId: string): Promise<GamificationPrize> {\n const url = `${this.apiHost}/v1/widgets/gamification/generate-prize`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({ config_id: configId }),\n credentials: 'include',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to generate prize: ${response.status}`);\n }\n \n return await response.json();\n }\n \n private showPrizeResult(modal: HTMLElement, prize: GamificationPrize): void {\n modal.innerHTML = '';\n \n const resultContainer = document.createElement('div');\n resultContainer.style.cssText = 'text-align: center; padding: 40px 20px;';\n \n const emoji = document.createElement('div');\n emoji.textContent = '🎉';\n emoji.style.cssText = 'font-size: 60px; margin-bottom: 20px;';\n resultContainer.appendChild(emoji);\n \n const title = document.createElement('h2');\n title.textContent = 'Congratulations!';\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 28px; font-weight: 700; color: #1a73e8;';\n resultContainer.appendChild(title);\n \n const prizeLabel = document.createElement('p');\n prizeLabel.textContent = prize.prize_label;\n prizeLabel.style.cssText = 'margin: 0 0 20px 0; font-size: 20px; font-weight: 600; color: #333;';\n resultContainer.appendChild(prizeLabel);\n \n if (prize.coupon_code) {\n const couponContainer = document.createElement('div');\n couponContainer.style.cssText = `\n background: #f5f5f5;\n padding: 16px;\n border-radius: 8px;\n margin-bottom: 20px;\n border: 2px dashed #1a73e8;\n `;\n \n const couponLabel = document.createElement('div');\n couponLabel.textContent = 'Your coupon code:';\n couponLabel.style.cssText = 'font-size: 12px; color: #666; margin-bottom: 8px;';\n couponContainer.appendChild(couponLabel);\n \n const couponCode = document.createElement('div');\n couponCode.textContent = prize.coupon_code;\n couponCode.style.cssText = 'font-size: 24px; font-weight: 700; color: #1a73e8; letter-spacing: 2px;';\n couponContainer.appendChild(couponCode);\n \n resultContainer.appendChild(couponContainer);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n \n closeButton.addEventListener('click', () => {\n const overlay = modal.parentElement;\n if (overlay && document.body.contains(overlay)) {\n document.body.removeChild(overlay);\n }\n });\n \n resultContainer.appendChild(closeButton);\n modal.appendChild(resultContainer);\n }\n \n private async submitFeedback(widgetId: string, data: Record<string, any>): Promise<void> {\n const url = `${this.apiHost}/v1/widgets/track-event`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n widget_id: widgetId,\n event_type: 'submit',\n event_data: data\n }),\n credentials: 'include',\n });\n \n if (!response.ok) {\n throw new Error(`Failed to submit feedback: ${response.status}`);\n }\n }\n \n private async trackEvent(widgetId: string, eventType: string, metadata?: Record<string, any>): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/widgets/track-event`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n widget_id: widgetId,\n event_type: eventType,\n event_data: metadata || {}\n }),\n credentials: 'include',\n });\n\n } catch (error) {\n this.log(`Error tracking widget event: ${error}`, true);\n }\n }\n \n private sanitizeUrl(url?: string): string | null {\n if (!url) return null;\n \n try {\n const parsed = new URL(url, window.location.href);\n if (parsed.protocol === 'javascript:' || parsed.protocol === 'data:') {\n this.log(`Blocked dangerous URL: ${url}`, true);\n return null;\n }\n return parsed.href;\n } catch {\n this.log(`Invalid URL: ${url}`, true);\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n if (/^#[0-9A-F]{3,8}$/i.test(color)) {\n return color;\n }\n \n if (/^rgb\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*\\)$/i.test(color)) {\n return color;\n }\n \n if (/^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*[\\d.]+\\s*\\)$/i.test(color)) {\n return color;\n }\n \n return '#1a73e8';\n }\n \n private getDeviceType(): string {\n const ua = navigator.userAgent;\n if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {\n return 'tablet';\n }\n if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) {\n return 'mobile';\n }\n return 'desktop';\n }\n \n private isMobileDevice(): boolean {\n const deviceType = this.getDeviceType();\n return deviceType === 'mobile' || deviceType === 'tablet';\n }\n \n private addAnimationStyles(): void {\n if (document.getElementById('aegis-widget-animations')) {\n return;\n }\n \n const style = document.createElement('style');\n style.id = 'aegis-widget-animations';\n style.textContent = `\n @keyframes aegisFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes aegisScaleIn {\n from { transform: scale(0.8); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n }\n \n @keyframes aegisBubbleIn {\n from { transform: translateY(20px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes aegisToastIn {\n from { transform: translateX(-100%); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n }\n \n @keyframes aegisToastOut {\n from { transform: translateX(0); opacity: 1; }\n to { transform: translateX(-100%); opacity: 0; }\n }\n \n @keyframes aegisSlideInRight {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n \n @keyframes aegisSpin {\n from { transform: rotate(0deg); }\n to { transform: rotate(1440deg); }\n }\n `;\n document.head.appendChild(style);\n }\n \n private renderCartRecoveryPopup(widgetId: string, config: NonNullable<PrefetchWidgetConfig['exit_intent']>): void {\n if (this.isDestroyed) return;\n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n overlay.setAttribute('data-aegis-widget-root', '');\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-cart-recovery-modal';\n modal.style.cssText = `\n background: ${this.sanitizeColor(config.background_color || '#FFFFFF')};\n color: ${this.sanitizeColor(config.text_color || '#333333')};\n border-radius: 16px;\n max-width: 600px;\n width: 90%;\n padding: 40px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n position: relative;\n `;\n \n const title = document.createElement('h2');\n const titleText = this.interpolateCartVariables(config.title || 'Complete Your Order');\n title.textContent = titleText;\n title.style.cssText = `margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: ${this.sanitizeColor(config.accent_color || '#FF6B00')};`;\n modal.appendChild(title);\n \n const message = document.createElement('p');\n const messageText = this.interpolateCartVariables(config.message || 'Your cart is waiting for you!');\n message.textContent = messageText;\n message.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; line-height: 1.5;';\n modal.appendChild(message);\n \n if (config.show_cart_items && this.cartData) {\n const cartItems = document.createElement('div');\n cartItems.style.cssText = 'margin: 0 0 24px 0; padding: 16px; background: rgba(0,0,0,0.05); border-radius: 8px;';\n \n const cartTitle = document.createElement('div');\n cartTitle.textContent = `${this.cartData.cart_items.length} items in your cart`;\n cartTitle.style.cssText = 'font-weight: 600; margin-bottom: 12px;';\n cartItems.appendChild(cartTitle);\n \n this.cartData.cart_items.slice(0, 3).forEach(item => {\n const itemDiv = document.createElement('div');\n itemDiv.textContent = `${item.quantity}× ${item.product_name || item.product_id}`;\n itemDiv.style.cssText = 'font-size: 14px; margin-bottom: 4px;';\n cartItems.appendChild(itemDiv);\n });\n \n modal.appendChild(cartItems);\n }\n \n if (config.discount_code) {\n const discountBox = document.createElement('div');\n discountBox.style.cssText = `\n margin: 0 0 24px 0;\n padding: 16px;\n background: ${this.sanitizeColor(config.accent_color || '#FF6B00')};\n color: white;\n border-radius: 8px;\n text-align: center;\n font-weight: 700;\n font-size: 18px;\n `;\n discountBox.textContent = `Use code: ${config.discount_code} for ${config.discount_percentage || 10}% off!`;\n modal.appendChild(discountBox);\n }\n \n if (config.show_timer && config.timer_minutes) {\n const timer = document.createElement('div');\n timer.style.cssText = 'margin: 0 0 24px 0; text-align: center; font-size: 14px; color: #999;';\n timer.textContent = `⏰ Offer expires in ${config.timer_minutes} minutes`;\n modal.appendChild(timer);\n }\n \n const ctaButton = document.createElement('button');\n ctaButton.textContent = config.cta_text || 'Complete Checkout';\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(config.accent_color || '#FF6B00')};\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'click', { type: 'cart_recovery' });\n const checkoutUrl = this.sanitizeUrl(config.cta_url || '/checkout');\n if (checkoutUrl) {\n window.location.href = checkoutUrl;\n }\n });\n \n modal.appendChild(ctaButton);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'cart_recovery' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n });\n \n modal.appendChild(closeButton);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'cart_recovery', tier: config.tier });\n }\n \n private renderLeadGenPopup(widgetId: string, config: NonNullable<PrefetchWidgetConfig['exit_intent']>): void {\n if (this.isDestroyed) return;\n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n overlay.setAttribute('data-aegis-widget-root', '');\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-leadgen-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n max-width: 500px;\n width: 90%;\n padding: 40px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n position: relative;\n `;\n \n const title = document.createElement('h2');\n title.textContent = config.title || 'Get 10% Off Your First Order!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const message = document.createElement('p');\n message.textContent = config.message || 'Subscribe to our newsletter and get an exclusive discount code.';\n message.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; color: #666;';\n modal.appendChild(message);\n \n const form = document.createElement('form');\n \n const emailInput = document.createElement('input');\n emailInput.type = 'email';\n emailInput.placeholder = 'Enter your email';\n emailInput.required = true;\n emailInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 16px;\n box-sizing: border-box;\n `;\n form.appendChild(emailInput);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Get My Discount';\n submitButton.style.cssText = `\n width: 100%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n \n try {\n await this.trackEvent(widgetId, 'submit', { \n type: 'lead_gen',\n email: emailInput.value \n });\n \n modal.innerHTML = `\n <div style=\"text-align: center; padding: 20px;\">\n <div style=\"font-size: 48px; margin-bottom: 16px;\">✅</div>\n <h3 style=\"margin: 0 0 12px 0; color: #1a73e8;\">Thank You!</h3>\n <p style=\"margin: 0; color: #666;\">Check your email for your discount code!</p>\n </div>\n `;\n \n setTimeout(() => {\n document.body.removeChild(overlay);\n }, 2500);\n \n } catch (error) {\n this.log(`Error submitting lead gen form: ${error}`, true);\n submitButton.disabled = false;\n submitButton.textContent = 'Get My Discount';\n }\n });\n \n modal.appendChild(form);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'lead_gen' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n });\n \n modal.appendChild(closeButton);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'lead_gen' });\n }\n \n private interpolateCartVariables(template: string): string {\n if (!this.cartData) return template;\n \n return template\n .replace(/\\{\\{cart_total\\}\\}/g, `${this.cartData.cart_currency} ${this.cartData.cart_total.toFixed(2)}`)\n .replace(/\\{\\{cart_currency\\}\\}/g, this.cartData.cart_currency)\n .replace(/\\{\\{cart_items_count\\}\\}/g, this.cartData.cart_items.length.toString());\n }\n \n private log(message: string, isError: boolean = false): void {\n if (this.debugMode || isError) {\n const method = isError ? 'error' : 'log';\n console[method](`[AegisWidgets] ${message}`);\n }\n }\n}\n","/**\n * TriggerEngine - Client-Side Trigger Evaluation\n * \n * Evaluates behavioral triggers that require real-time client state:\n * - Scroll depth (e.g., user scrolled >= 50%)\n * - Time on page (e.g., >= 30 seconds on current page)\n * - Exit intent (mouse leaving viewport toward browser controls)\n * - Inactivity (no user interaction for X seconds)\n * - Scroll velocity (mobile exit intent - fast upward scroll)\n * - Visibility change (tab/app switching)\n * - Back button (history navigation)\n * \n * Architecture:\n * - Server evaluates historical triggers (event counts, segments)\n * - Client evaluates behavioral triggers (scroll, time, exit intent)\n * - Zero latency - no server round trip needed\n * \n * Usage:\n * const trigger = new TriggerEngine();\n * trigger.on('scroll_depth_50', (data) => {\n * console.log('User scrolled to 50%', data);\n * });\n * trigger.start();\n */\n\nexport interface TriggerRule {\n type: 'scroll_depth' | 'time_on_page' | 'exit_intent' | 'inactivity' | 'scroll_velocity' | 'visibility_change' | 'back_button';\n config: ScrollDepthConfig | TimeOnPageConfig | ExitIntentConfig | InactivityConfig | ScrollVelocityConfig | VisibilityChangeConfig | BackButtonConfig;\n}\n\nexport interface ScrollDepthConfig {\n depth_percent: number;\n}\n\nexport interface TimeOnPageConfig {\n seconds: number;\n}\n\nexport interface ExitIntentConfig {\n enabled: boolean;\n}\n\nexport interface InactivityConfig {\n idle_seconds: number;\n}\n\nexport interface ScrollVelocityConfig {\n threshold: number;\n minScrollPosition: number;\n cooldown: number;\n}\n\nexport interface VisibilityChangeConfig {\n enabled: boolean;\n}\n\nexport interface BackButtonConfig {\n enabled: boolean;\n}\n\nexport interface TriggerEvent {\n type: string;\n data: Record<string, any>;\n timestamp: number;\n}\n\ntype TriggerCallback = (event: TriggerEvent) => void;\n\nexport class TriggerEngine {\n private listeners: Map<string, Set<TriggerCallback>> = new Map();\n private isStarted = false;\n \n private scrollDepthTargets = new Set<number>();\n private scrollDepthReached = new Set<number>();\n \n private timeOnPageTargets = new Map<number, number>();\n private pageLoadTime?: number;\n \n private exitIntentEnabled = false;\n private exitIntentFired = false;\n \n private inactivityTargets = new Map<number, number>();\n private lastActivityTime = Date.now();\n private inactivityCheckInterval?: number;\n \n private scrollVelocityEnabled = false;\n private scrollVelocityFired = false;\n private scrollVelocityConfig: ScrollVelocityConfig = {\n threshold: 0.5,\n minScrollPosition: 100,\n cooldown: 5000\n };\n private lastScrollY = 0;\n private lastScrollTime = Date.now();\n private scrollVelocityCooldownTimer?: number;\n \n private visibilityChangeEnabled = false;\n \n private backButtonEnabled = false;\n private backButtonFired = false;\n \n constructor() {}\n \n on(eventType: string, callback: TriggerCallback): void {\n if (!this.listeners.has(eventType)) {\n this.listeners.set(eventType, new Set());\n }\n this.listeners.get(eventType)!.add(callback);\n }\n \n off(eventType: string, callback: TriggerCallback): void {\n const callbacks = this.listeners.get(eventType);\n if (callbacks) {\n callbacks.delete(callback);\n }\n }\n \n registerScrollDepth(depthPercent: number): void {\n this.scrollDepthTargets.add(depthPercent);\n }\n \n registerTimeOnPage(seconds: number): void {\n if (!this.timeOnPageTargets.has(seconds)) {\n const timerId = window.setTimeout(() => {\n this.emit(`time_on_page_${seconds}`, {\n seconds,\n page_url: window.location.href\n });\n this.timeOnPageTargets.delete(seconds);\n }, seconds * 1000);\n \n this.timeOnPageTargets.set(seconds, timerId);\n }\n }\n \n registerExitIntent(): void {\n this.exitIntentEnabled = true;\n }\n \n registerInactivity(idleSeconds: number): void {\n if (!this.inactivityTargets.has(idleSeconds)) {\n const timerId = window.setTimeout(() => {\n const idleTime = (Date.now() - this.lastActivityTime) / 1000;\n \n if (idleTime >= idleSeconds) {\n this.emit(`inactivity_${idleSeconds}`, {\n idle_seconds: idleSeconds,\n actual_idle_time: idleTime\n });\n }\n \n this.inactivityTargets.delete(idleSeconds);\n }, idleSeconds * 1000);\n \n this.inactivityTargets.set(idleSeconds, timerId);\n }\n }\n \n registerScrollVelocity(config?: Partial<ScrollVelocityConfig>): void {\n this.scrollVelocityEnabled = true;\n \n if (config) {\n this.scrollVelocityConfig = {\n threshold: config.threshold ?? this.scrollVelocityConfig.threshold,\n minScrollPosition: config.minScrollPosition ?? this.scrollVelocityConfig.minScrollPosition,\n cooldown: config.cooldown ?? this.scrollVelocityConfig.cooldown\n };\n }\n }\n \n registerVisibilityChange(): void {\n this.visibilityChangeEnabled = true;\n }\n \n registerBackButton(): void {\n this.backButtonEnabled = true;\n }\n \n start(): void {\n if (this.isStarted) {\n return;\n }\n \n this.pageLoadTime = Date.now();\n this.lastActivityTime = Date.now();\n this.lastScrollY = window.scrollY || 0;\n this.lastScrollTime = Date.now();\n \n if (this.scrollDepthTargets.size > 0) {\n this.attachScrollListener();\n }\n \n if (this.exitIntentEnabled) {\n this.attachExitIntentListener();\n }\n \n if (this.scrollVelocityEnabled) {\n this.attachScrollVelocityListener();\n }\n \n if (this.visibilityChangeEnabled) {\n this.attachVisibilityChangeListener();\n }\n \n if (this.backButtonEnabled) {\n this.attachBackButtonListener();\n }\n \n this.attachActivityListeners();\n \n this.startInactivityCheck();\n \n this.isStarted = true;\n }\n \n stop(): void {\n if (!this.isStarted) {\n return;\n }\n \n this.removeScrollListener();\n this.removeExitIntentListener();\n this.removeScrollVelocityListener();\n this.removeVisibilityChangeListener();\n this.removeBackButtonListener();\n this.removeActivityListeners();\n \n this.timeOnPageTargets.forEach(timerId => clearTimeout(timerId));\n this.timeOnPageTargets.clear();\n \n this.inactivityTargets.forEach(timerId => clearTimeout(timerId));\n this.inactivityTargets.clear();\n \n if (this.inactivityCheckInterval) {\n clearInterval(this.inactivityCheckInterval);\n this.inactivityCheckInterval = undefined;\n }\n \n if (this.scrollVelocityCooldownTimer) {\n clearTimeout(this.scrollVelocityCooldownTimer);\n this.scrollVelocityCooldownTimer = undefined;\n }\n \n this.isStarted = false;\n }\n \n reset(): void {\n this.scrollDepthReached.clear();\n this.exitIntentFired = false;\n this.scrollVelocityFired = false;\n this.backButtonFired = false;\n this.pageLoadTime = Date.now();\n this.lastActivityTime = Date.now();\n this.lastScrollY = window.scrollY || 0;\n this.lastScrollTime = Date.now();\n \n if (this.scrollVelocityCooldownTimer) {\n clearTimeout(this.scrollVelocityCooldownTimer);\n this.scrollVelocityCooldownTimer = undefined;\n }\n }\n \n private attachScrollListener(): void {\n window.addEventListener('scroll', this.handleScroll, { passive: true });\n this.handleScroll();\n }\n \n private removeScrollListener(): void {\n window.removeEventListener('scroll', this.handleScroll);\n }\n \n private handleScroll = (): void => {\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;\n const scrollPercent = scrollHeight > 0 ? (scrollTop / scrollHeight) * 100 : 0;\n \n for (const targetDepth of this.scrollDepthTargets) {\n if (scrollPercent >= targetDepth && !this.scrollDepthReached.has(targetDepth)) {\n this.scrollDepthReached.add(targetDepth);\n \n this.emit(`scroll_depth_${targetDepth}`, {\n depth_percent: targetDepth,\n actual_percent: scrollPercent,\n scroll_top: scrollTop,\n scroll_height: scrollHeight\n });\n }\n }\n };\n \n private attachExitIntentListener(): void {\n document.addEventListener('mouseleave', this.handleExitIntent);\n }\n \n private removeExitIntentListener(): void {\n document.removeEventListener('mouseleave', this.handleExitIntent);\n }\n \n private handleExitIntent = (event: MouseEvent): void => {\n if (this.exitIntentFired) {\n return;\n }\n \n if (event.clientY < 10) {\n this.exitIntentFired = true;\n \n this.emit('exit_intent', {\n client_y: event.clientY,\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n }\n };\n \n private attachScrollVelocityListener(): void {\n window.addEventListener('scroll', this.handleScrollVelocity, { passive: true });\n }\n \n private removeScrollVelocityListener(): void {\n window.removeEventListener('scroll', this.handleScrollVelocity);\n }\n \n private handleScrollVelocity = (): void => {\n if (this.scrollVelocityFired) {\n return;\n }\n \n const currentY = window.scrollY || document.documentElement.scrollTop;\n const currentTime = Date.now();\n const timeDiff = currentTime - this.lastScrollTime;\n \n if (timeDiff > 100) {\n const distance = this.lastScrollY - currentY;\n const velocity = Math.abs(distance / timeDiff);\n \n if (\n distance > 0 &&\n velocity > this.scrollVelocityConfig.threshold &&\n currentY > this.scrollVelocityConfig.minScrollPosition\n ) {\n this.scrollVelocityFired = true;\n \n this.emit('mobile_exit_intent', {\n scroll_velocity: velocity,\n scroll_distance: distance,\n current_position: currentY,\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n \n this.scrollVelocityCooldownTimer = window.setTimeout(() => {\n this.scrollVelocityFired = false;\n }, this.scrollVelocityConfig.cooldown);\n }\n \n this.lastScrollY = currentY;\n this.lastScrollTime = currentTime;\n }\n };\n \n private attachVisibilityChangeListener(): void {\n document.addEventListener('visibilitychange', this.handleVisibilityChange);\n }\n \n private removeVisibilityChangeListener(): void {\n document.removeEventListener('visibilitychange', this.handleVisibilityChange);\n }\n \n private handleVisibilityChange = (): void => {\n if (document.hidden) {\n this.emit('visibility_hidden', {\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n } else {\n this.emit('visibility_visible', {\n page_url: window.location.href\n });\n }\n };\n \n private attachBackButtonListener(): void {\n if (typeof window !== 'undefined' && window.history) {\n window.history.pushState(null, '', window.location.href);\n window.addEventListener('popstate', this.handleBackButton);\n }\n }\n \n private removeBackButtonListener(): void {\n window.removeEventListener('popstate', this.handleBackButton);\n }\n \n private handleBackButton = (): void => {\n if (this.backButtonFired) {\n return;\n }\n \n this.backButtonFired = true;\n \n window.history.pushState(null, '', window.location.href);\n \n this.emit('back_button', {\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n };\n \n private attachActivityListeners(): void {\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n events.forEach(event => {\n document.addEventListener(event, this.handleActivity, { passive: true });\n });\n }\n \n private removeActivityListeners(): void {\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n events.forEach(event => {\n document.removeEventListener(event, this.handleActivity);\n });\n }\n \n private handleActivity = (): void => {\n this.lastActivityTime = Date.now();\n };\n \n private startInactivityCheck(): void {\n this.inactivityCheckInterval = window.setInterval(() => {\n const idleTime = (Date.now() - this.lastActivityTime) / 1000;\n \n for (const [idleSeconds] of this.inactivityTargets) {\n if (idleTime >= idleSeconds) {\n this.emit(`inactivity_${idleSeconds}`, {\n idle_seconds: idleSeconds,\n actual_idle_time: idleTime\n });\n \n const timerId = this.inactivityTargets.get(idleSeconds);\n if (timerId) {\n clearTimeout(timerId);\n this.inactivityTargets.delete(idleSeconds);\n }\n }\n }\n }, 1000);\n }\n \n private emit(eventType: string, data: Record<string, any>): void {\n const event: TriggerEvent = {\n type: eventType,\n data,\n timestamp: Date.now()\n };\n \n const callbacks = this.listeners.get(eventType);\n if (callbacks) {\n callbacks.forEach(callback => {\n try {\n callback(event);\n } catch (error) {\n console.error(`Error in trigger callback for ${eventType}:`, error);\n }\n });\n }\n \n const wildcardCallbacks = this.listeners.get('*');\n if (wildcardCallbacks) {\n wildcardCallbacks.forEach(callback => {\n try {\n callback(event);\n } catch (error) {\n console.error(`Error in wildcard trigger callback:`, error);\n }\n });\n }\n }\n}\n","/**\n * SDK Bootstrap\n *\n * Strict origin-assertion handshake against the control-plane. Called once\n * at SDK init — resolves writeKey → propertyId, asserts origin, and returns\n * the VAPID public key + first-party cookie id the SDK needs for the rest\n * of the session.\n *\n * A failed bootstrap (401/403) aborts SDK init — the SDK refuses to emit\n * events or request push permission against an origin it cannot prove it\n * owns.\n *\n * See docs/architecture/SUBSCRIPTION_PROPERTY_ARCHITECTURE.md §5.\n */\n\nconst COOKIE_NAME = 'aegis_fpc';\nconst COOKIE_MAX_AGE_DAYS = 365 * 2;\n\nexport interface BootstrapRequest {\n writeKey: string;\n currentOrigin?: string;\n firstPartyCookieId?: string;\n attestationToken?: string;\n userAgent?: string;\n}\n\nimport type { EventGovernanceHint } from '../governance';\n\nexport interface BootstrapResult {\n propertyId: string;\n organizationId: string;\n workspaceId: string;\n propertyType: 'shopify_store' | 'hosted_commerce' | 'custom_website' | 'mobile_app';\n vapidPublicKey: string | null;\n allowedOrigins: string[];\n pushEnabled: boolean;\n inAppEnabled: boolean;\n transportMode: string;\n firstPartyCookieId: string;\n /**\n * Event-governance hint for SDK-side unique-event-name cap enforcement.\n * Null = Enterprise plan / CP outage / org has no cap. Safe to pass\n * directly to `aegis.ingestGovernanceHint()`.\n */\n eventGovernance: EventGovernanceHint | null;\n}\n\nexport class BootstrapError extends Error {\n constructor(public readonly status: number, message: string) {\n super(message);\n this.name = 'BootstrapError';\n }\n}\n\n/**\n * Read the first-party cookie id from document.cookie. Returns null if\n * unset — caller should pass undefined so the server issues a fresh one.\n */\nexport function readFirstPartyCookie(): string | null {\n if (typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${COOKIE_NAME}=([^;]+)`));\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n/**\n * Persist the first-party cookie id returned by the server. Stored as a\n * first-party cookie (readable by JS — it's not a secret, it's a device\n * id) so that the same browser hitting a second origin on the same\n * registrable domain gets the same cookie back.\n */\nexport function writeFirstPartyCookie(cookieId: string): void {\n if (typeof document === 'undefined') return;\n const expires = new Date();\n expires.setDate(expires.getDate() + COOKIE_MAX_AGE_DAYS);\n // Derive the registrable-domain boundary where possible so the cookie is\n // shared across subdomains (e.g., shop.sweettruths.com + www.sweettruths.com).\n // We conservatively use the current host without a leading dot —\n // browsers scope the cookie to that host. For cross-registrable-domain\n // siblings (Shopify myshopify.com + actii.me), each domain gets its own\n // cookie, which is the expected per-origin behavior.\n document.cookie =\n `${COOKIE_NAME}=${encodeURIComponent(cookieId)};` +\n `expires=${expires.toUTCString()};` +\n `path=/;SameSite=Lax`;\n // Also mirror into localStorage so the SDK can read it synchronously at\n // init time even in environments where document.cookie is delayed.\n try {\n window.localStorage.setItem(COOKIE_NAME, cookieId);\n } catch {\n // private mode / storage disabled — cookie alone is sufficient\n }\n}\n\n/**\n * Perform the bootstrap handshake.\n *\n * @throws BootstrapError on 4xx — the SDK should stop init and surface the\n * error to the console. 5xx are retried once.\n */\nexport async function bootstrap(\n apiHost: string,\n req: BootstrapRequest\n): Promise<BootstrapResult> {\n const body: Record<string, unknown> = { writeKey: req.writeKey };\n if (req.currentOrigin) body.currentOrigin = req.currentOrigin;\n if (req.firstPartyCookieId) body.firstPartyCookieId = req.firstPartyCookieId;\n if (req.attestationToken) body.attestationToken = req.attestationToken;\n if (req.userAgent) body.userAgent = req.userAgent;\n\n const url = `${apiHost.replace(/\\/$/, '')}/v1/sdk/bootstrap`;\n\n const doFetch = async (): Promise<Response> =>\n fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n credentials: 'omit',\n });\n\n let resp = await doFetch();\n if (resp.status >= 500) {\n await new Promise((r) => setTimeout(r, 750));\n resp = await doFetch();\n }\n\n if (resp.status === 401) {\n throw new BootstrapError(401, 'writeKey not recognized or revoked');\n }\n if (resp.status === 403) {\n throw new BootstrapError(403, 'Origin validation failed — this writeKey is bound to a different property');\n }\n if (!resp.ok) {\n throw new BootstrapError(resp.status, `Bootstrap failed: HTTP ${resp.status}`);\n }\n\n const json = (await resp.json()) as BootstrapResult;\n writeFirstPartyCookie(json.firstPartyCookieId);\n return json;\n}\n\n/**\n * Derive a deterministic device fingerprint from the first-party cookie id\n * and a few stable UA parts. This is the value sent on every push-subscribe\n * call — its stability lets the backend UPSERT on (property_id, fingerprint)\n * across re-subscribes and VAPID rotations.\n */\nexport async function deriveDeviceFingerprint(firstPartyCookieId: string): Promise<string> {\n const ua = typeof navigator !== 'undefined' ? navigator.userAgent : '';\n const platform = typeof navigator !== 'undefined' ? (navigator.platform || '') : '';\n const language = typeof navigator !== 'undefined' ? (navigator.language || '') : '';\n const input = `${firstPartyCookieId}|${ua}|${platform}|${language}`;\n\n // Prefer subtle.crypto — available in all push-capable browsers.\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n const bytes = new TextEncoder().encode(input);\n const hash = await crypto.subtle.digest('SHA-256', bytes);\n const hex = Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return hex;\n }\n\n // Last-resort fallback — basic 32-bit FNV hash (non-cryptographic but\n // stable). Push-capable browsers always have subtle.crypto so this path\n // is practically unreachable; included only for completeness.\n let h = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return `fnv-${h.toString(16)}`;\n}\n","import { Aegis } from './core/analytics';\nimport { AegisMessageRuntime } from './runtime';\nimport { AegisPlacementManager } from './placements/AegisPlacementManager';\nimport { TriggerEngine } from './triggers';\nimport { bootstrap } from './core/bootstrap';\n\ndeclare global {\n interface Window {\n aegis: any;\n Aegis: typeof Aegis;\n AegisMessageRuntime: typeof AegisMessageRuntime;\n AegisPlacementManager: typeof AegisPlacementManager;\n TriggerEngine: typeof TriggerEngine;\n /**\n * `/v1/sdk/bootstrap` handshake. Exposed for integrations that embed the\n * CDN bundle and need to retrieve `eventGovernance`, `vapidPublicKey`, etc.\n * Added in SDK 1.4.0 alongside SDK-side event-governance.\n */\n aegisBootstrap: typeof bootstrap;\n }\n}\n\nconst globalName = 'aegis';\nconst existingQueue: any = window[globalName] || [];\n\nconst instance = new Aegis();\n\nif (Array.isArray(existingQueue)) {\n const loadOptions = (existingQueue as any)._loadOptions;\n\n existingQueue.forEach((item: any) => {\n if (!Array.isArray(item)) {\n return;\n }\n\n const [method, ...args] = item;\n\n if (typeof instance[method as keyof Aegis] === 'function') {\n try {\n (instance[method as keyof Aegis] as Function).apply(instance, args);\n } catch (error) {\n console.error(`[Aegis SDK] Error executing queued method \"${method}\":`, error);\n }\n } else {\n console.warn(`[Aegis SDK] Unknown method \"${method}\"`);\n }\n });\n\n if (loadOptions?.key) {\n instance.init(loadOptions.key, loadOptions.options).catch((error) => {\n console.error('[Aegis SDK] Initialization failed:', error);\n });\n }\n}\n\nwindow[globalName] = instance;\nwindow.Aegis = Aegis;\nwindow.AegisMessageRuntime = AegisMessageRuntime;\nwindow.AegisPlacementManager = AegisPlacementManager;\nwindow.TriggerEngine = TriggerEngine;\nwindow.aegisBootstrap = bootstrap;\n\nexport default instance;\n","/**\n * AegisMessageRuntime — unified facade for in-app messaging.\n *\n * The sole public entry point for all 20 in-app types (announce +\n * collect + assist buckets) plus the legacy gamification surface\n * (chat_bubble / toast / exit_intent_popup configured via\n * /v1/widgets/config). Under the hood it composes an\n * `AegisInAppManager` + `AegisWidgetManager`; callers never touch them\n * directly.\n *\n * Public API:\n * new AegisMessageRuntime({ writeKey, apiHost, ... })\n * await runtime.initialize()\n * await runtime.updateContactId(id)\n * runtime.onClientEvent(eventName, data)\n * runtime.destroy()\n *\n * Internal wiring: spin_wheel + scratch_card campaigns land in the\n * inbox prefetch bundle but need DOM renderers that live in\n * WidgetManager. The facade passes an `onInteractiveCampaign` callback\n * into the InAppManager constructor; the callback forwards to\n * `widgets.renderInteractiveCampaign(campaign)` — no CustomEvent bus,\n * no listeners, no registration-order bugs.\n */\n\nimport { AegisInAppManager, type AegisInAppConfig, type InAppCampaign } from '../inapp';\nimport { AegisWidgetManager, type AegisWidgetConfig } from '../widgets';\nimport { TriggerEngine } from '../triggers/TriggerEngine';\n\nexport interface AegisMessageRuntimeConfig extends AegisInAppConfig {\n /** If set, a `TriggerEngine` from the SDK is wired to the WidgetManager\n * for its exit-intent / scroll-velocity / inactivity handlers. Leave\n * undefined to have the runtime construct one internally. */\n triggerEngine?: AegisWidgetConfig['triggerEngine'];\n /** WidgetManager prefetch toggle. Defaults to true — matches the\n * existing behaviour where spin_wheel / scratch_card prefetch their\n * configs from `/v1/widgets/config/prefetch`. */\n enableWidgetPrefetch?: boolean;\n /** Source platform for gamification attribution (shopify / woocommerce\n * / magento / mobile_sdk / web). Passed through to WidgetManager. */\n sourcePlatform?: AegisWidgetConfig['sourcePlatform'];\n}\n\n/**\n * One runtime, all in-app types. Consumers should prefer this over\n * importing AegisInAppManager / AegisWidgetManager directly. Those two\n * classes remain exported for a deprecation window — see `./deprecated.ts`.\n */\nexport class AegisMessageRuntime {\n readonly inApp: AegisInAppManager;\n readonly widgets: AegisWidgetManager;\n private initialized = false;\n private ownedTriggerEngine: TriggerEngine | null = null;\n\n constructor(config: AegisMessageRuntimeConfig) {\n const triggerEngine = config.triggerEngine ?? new TriggerEngine();\n const ownsTriggerEngine = !config.triggerEngine;\n if (ownsTriggerEngine) this.ownedTriggerEngine = triggerEngine;\n\n this.widgets = new AegisWidgetManager({\n writeKey: config.writeKey,\n apiHost: config.apiHost,\n userId: config.userId,\n contactId: config.contactId,\n organizationId: config.organizationId,\n debugMode: config.debugMode,\n triggerEngine,\n ownsTriggerEngine,\n enablePrefetch: config.enableWidgetPrefetch !== false,\n sourcePlatform: config.sourcePlatform,\n });\n\n this.inApp = new AegisInAppManager({\n writeKey: config.writeKey,\n apiHost: config.apiHost,\n userId: config.userId,\n contactId: config.contactId,\n organizationId: config.organizationId,\n propertyId: config.propertyId,\n debugMode: config.debugMode,\n enableSSE: config.enableSSE,\n // Route gamification sub_types straight to the widget renderer —\n // replaces the old CustomEvent('aegis:render-widget') bridge which\n // had no listener and silently dropped impressions.\n onInteractiveCampaign: (campaign) => {\n this.widgets.renderInteractiveCampaign(campaign);\n },\n });\n }\n\n /**\n * Boots both managers in parallel. Safe to call multiple times — the\n * second + subsequent calls are no-ops.\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n this.initialized = true;\n await Promise.all([\n this.inApp.initialize(),\n this.widgets.initialize(),\n ]);\n }\n\n /**\n * Both managers carry contactId. Updates both so the server-side\n * targeting pipeline sees the identity for campaign eligibility AND\n * the widget prefetch includes per-contact segment configs. The\n * widgets call is async (may re-fetch prefetch configs) but we don't\n * wait — callers that care about the fetched state await on the\n * returned promise.\n */\n async updateContactId(contactId: string): Promise<void> {\n this.inApp.updateContactId?.(contactId);\n await this.widgets.updateContactId(contactId);\n }\n\n /**\n * Forward a client-side event (product_viewed, cart_idle_90s, etc.)\n * to the in-app manager's client-trigger evaluator. The WidgetManager\n * has its own TriggerEngine wiring (exit-intent, scroll-velocity) so\n * we don't forward there — events it cares about arrive through that\n * channel already.\n */\n onClientEvent(eventName: string, eventData: Record<string, unknown> = {}): void {\n this.inApp.onClientEvent?.(eventName, eventData);\n }\n\n /**\n * Conversion-aware suppression — call when the host app observes a\n * goal event (purchase / order_completed / checkout_completed / custom).\n *\n * Forwards to AegisInAppManager.notifyConversion() which:\n * - Persists the conversion in sessionStorage so subsequent page loads\n * in the same tab keep armed campaigns silenced.\n * - For every armed campaign whose\n * `frequency.suppress_after_conversion_seconds` is set, computes an\n * expiry epoch_ms and silences it until then.\n *\n * Storefronts integrate via the React provider's useCommerceEvents\n * helper which calls this after `ecom.orderCompleted(...)`. Direct SDK\n * users call it themselves.\n *\n * Added by Micro-Intent Engine P0a Task 6 (2026-04-30).\n */\n notifyConversion(goalName: string): void {\n this.inApp.notifyConversion?.(goalName);\n }\n\n /**\n * Tear down both managers. Used by React component unmounts + during\n * identity switches where we want a full reset. If the facade created\n * its own TriggerEngine, WidgetManager.destroy() will stop it;\n * caller-supplied engines are left alone.\n */\n destroy(): void {\n this.inApp.destroy?.();\n this.widgets.destroy();\n this.ownedTriggerEngine = null;\n this.initialized = false;\n }\n\n /**\n * Current armed campaigns visible to the InAppManager. Accessible for\n * the Prefetch Inspector and for debugging. WidgetManager's prefetched\n * spin_wheel / scratch_card configs are NOT in this list — they live\n * in `this.widgets` and have their own lifecycle.\n */\n getCampaigns(): InAppCampaign[] {\n // AegisInAppManager keeps `campaigns` as a private field. Expose it\n // via bracket access; the field is stable as of SDK 1.5.0. Once\n // Phase 7c unifies render paths this becomes a first-class getter.\n return ((this.inApp as unknown as { campaigns?: InAppCampaign[] }).campaigns) ?? [];\n }\n}\n","/**\n * AegisPlacementManager - Web SDK Placement Module\n * \n * Real-time SSE architecture for inline content placements.\n * \n * Security:\n * - XSS Protection: Uses DOMPurify (when available) with allowlisted tags/attrs; safe text-only fallback\n * - URL Validation: Prevents javascript: protocol injection\n * - CSP Compatible: No inline styles in HTML strings\n * \n * Architecture:\n * - Connects to SSE endpoint for real-time placement updates\n * - Initial fetch on load, then SSE for updates\n * - Caches placement content locally in memory\n * - Renders content into pre-defined UI slots (inline, not overlay)\n * - Tracks events (impression, click, conversion) asynchronously\n * \n * Key Differences from In-App Messages:\n * - INLINE content (part of layout), not overlays\n * - Content rendered immediately on slot registration\n * - No trigger rules (shown when slot loads)\n * - Supports banner, card, carousel, video, HTML content types\n */\n\nexport interface PlacementContent {\n placement_id: string;\n variant_id: string;\n content_type: 'banner' | 'card' | 'carousel' | 'video' | 'html' | 'dynamic_injection';\n content: Record<string, any>;\n css_selector?: string;\n injection_mode?: 'replace' | 'append' | 'prepend';\n}\n\nexport interface PlacementSlot {\n placementId: string;\n containerId: string;\n fallbackContent?: string;\n onRender?: (content: PlacementContent) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface AegisPlacementConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n debugMode?: boolean;\n enableSSE?: boolean;\n}\n\nexport class AegisPlacementManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private debugMode: boolean;\n private enableSSE: boolean;\n \n private placements: Map<string, PlacementContent> = new Map();\n private slots: Map<string, PlacementSlot> = new Map();\n private renderedSlots = new Set<string>();\n private eventSource?: EventSource;\n private isInitialized = false;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n \n constructor(config: AegisPlacementConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n this.userId = config.userId;\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.debugMode = config.debugMode || false;\n this.enableSSE = config.enableSSE !== false;\n }\n \n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisPlacements already initialized');\n return;\n }\n \n await this.refreshPlacements();\n \n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n \n this.isInitialized = true;\n this.log('AegisPlacements initialized successfully');\n }\n \n register(placementId: string, options: Omit<PlacementSlot, 'placementId'>): void {\n const slot: PlacementSlot = {\n placementId,\n ...options\n };\n \n this.slots.set(placementId, slot);\n this.log(`Registered placement slot: ${placementId}`);\n \n const existingContent = this.placements.get(placementId);\n if (existingContent) {\n this.renderSlot(slot, existingContent);\n } else if (options.fallbackContent) {\n this.renderFallback(slot);\n }\n }\n \n unregister(placementId: string): void {\n this.slots.delete(placementId);\n this.renderedSlots.delete(placementId);\n this.log(`Unregistered placement slot: ${placementId}`);\n }\n \n async refreshPlacements(): Promise<void> {\n try {\n const placementIds = Array.from(this.slots.keys());\n \n if (placementIds.length === 0) {\n this.log('No registered slots, skipping refresh');\n return;\n }\n \n const url = `${this.apiHost}/v1/placements/content?placement_ids=${placementIds.join(',')}`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Type': this.getDeviceType(),\n 'X-Platform': 'web'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, { headers });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch placements: ${response.status}`);\n }\n \n const data = await response.json();\n \n this.placements.clear();\n \n for (const placement of data.placements || []) {\n this.placements.set(placement.placement_id, placement);\n }\n \n this.renderAllSlots();\n \n this.log(`Refreshed ${this.placements.size} placements`);\n \n } catch (error) {\n this.log(`Error refreshing placements: ${error}`, true);\n }\n }\n \n private renderAllSlots(): void {\n for (const [placementId, slot] of this.slots.entries()) {\n const content = this.placements.get(placementId);\n \n if (content) {\n this.renderSlot(slot, content);\n } else if (slot.fallbackContent) {\n this.renderFallback(slot);\n }\n }\n }\n \n private renderSlot(slot: PlacementSlot, content: PlacementContent): void {\n try {\n if (content.content_type === 'dynamic_injection') {\n this.renderDynamicInjection(content);\n } else {\n const container = document.getElementById(slot.containerId);\n \n if (!container) {\n this.log(`Container not found: ${slot.containerId}`, true);\n return;\n }\n \n container.innerHTML = '';\n \n switch (content.content_type) {\n case 'banner':\n this.renderBanner(container, content);\n break;\n case 'card':\n this.renderCard(container, content);\n break;\n case 'carousel':\n this.renderCarousel(container, content);\n break;\n case 'video':\n this.renderVideo(container, content);\n break;\n case 'html':\n this.renderHTML(container, content);\n break;\n default:\n this.log(`Unknown content type: ${content.content_type}`, true);\n return;\n }\n }\n \n if (!this.renderedSlots.has(slot.placementId)) {\n this.trackEvent(content.placement_id, content.variant_id, 'impression');\n this.renderedSlots.add(slot.placementId);\n }\n \n if (slot.onRender) {\n slot.onRender(content);\n }\n \n this.log(`Rendered placement: ${content.placement_id} (${content.content_type})`);\n \n } catch (error) {\n this.log(`Error rendering placement: ${error}`, true);\n \n if (slot.onError) {\n slot.onError(error as Error);\n }\n }\n }\n \n private renderBanner(container: HTMLElement, content: PlacementContent): void {\n const { title, body, image_url, cta_text, cta_url, background_color, text_color } = content.content;\n \n const banner = document.createElement('div');\n banner.className = 'aegis-placement-banner';\n banner.style.cssText = `\n background: ${this.sanitizeColor(background_color || '#1a73e8')};\n color: ${this.sanitizeColor(text_color || '#ffffff')};\n padding: 24px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n gap: 16px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 80px; height: 80px; border-radius: 8px; object-fit: cover;';\n banner.appendChild(img);\n }\n }\n \n const textContainer = document.createElement('div');\n textContainer.style.cssText = 'flex: 1;';\n \n if (title) {\n const titleEl = document.createElement('div');\n titleEl.textContent = title;\n titleEl.style.cssText = 'font-size: 18px; font-weight: 600; margin-bottom: 8px;';\n textContainer.appendChild(titleEl);\n }\n \n if (body) {\n const bodyEl = document.createElement('div');\n bodyEl.textContent = body;\n bodyEl.style.cssText = 'font-size: 14px; opacity: 0.9;';\n textContainer.appendChild(bodyEl);\n }\n \n banner.appendChild(textContainer);\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: white;\n color: ${this.sanitizeColor(background_color || '#1a73e8')};\n border: none;\n padding: 12px 24px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n white-space: nowrap;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n banner.appendChild(ctaButton);\n }\n \n container.appendChild(banner);\n }\n \n private renderCard(container: HTMLElement, content: PlacementContent): void {\n const { title, body, image_url, cta_text, cta_url } = content.content;\n \n const card = document.createElement('div');\n card.className = 'aegis-placement-card';\n card.style.cssText = `\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = title || '';\n img.style.cssText = 'width: 100%; height: 200px; object-fit: cover;';\n card.appendChild(img);\n }\n }\n \n const cardBody = document.createElement('div');\n cardBody.style.cssText = 'padding: 20px;';\n \n if (title) {\n const titleEl = document.createElement('h3');\n titleEl.textContent = title;\n titleEl.style.cssText = 'margin: 0 0 12px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n cardBody.appendChild(titleEl);\n }\n \n if (body) {\n const bodyEl = document.createElement('p');\n bodyEl.textContent = body;\n bodyEl.style.cssText = 'margin: 0 0 16px 0; font-size: 14px; color: #666; line-height: 1.5;';\n cardBody.appendChild(bodyEl);\n }\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 10px 20px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n cardBody.appendChild(ctaButton);\n }\n \n card.appendChild(cardBody);\n container.appendChild(card);\n }\n \n private renderCarousel(container: HTMLElement, content: PlacementContent): void {\n const { items } = content.content;\n \n if (!Array.isArray(items) || items.length === 0) {\n this.log('Carousel items empty or invalid', true);\n return;\n }\n \n const carousel = document.createElement('div');\n carousel.className = 'aegis-placement-carousel';\n carousel.style.cssText = `\n display: flex;\n gap: 16px;\n overflow-x: auto;\n padding: 8px 0;\n scroll-behavior: smooth;\n -webkit-overflow-scrolling: touch;\n `;\n \n for (const item of items) {\n const carouselItem = document.createElement('div');\n carouselItem.style.cssText = `\n flex: 0 0 250px;\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n overflow: hidden;\n cursor: pointer;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (item.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(item.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = item.title || '';\n img.style.cssText = 'width: 100%; height: 150px; object-fit: cover;';\n carouselItem.appendChild(img);\n }\n }\n \n const itemContent = document.createElement('div');\n itemContent.style.cssText = 'padding: 12px;';\n \n if (item.title) {\n const title = document.createElement('div');\n title.textContent = item.title;\n title.style.cssText = 'font-size: 14px; font-weight: 600; margin-bottom: 4px; color: #1a1a1a;';\n itemContent.appendChild(title);\n }\n \n if (item.price) {\n const price = document.createElement('div');\n price.textContent = item.price;\n price.style.cssText = 'font-size: 16px; font-weight: 700; color: #1a73e8;';\n itemContent.appendChild(price);\n }\n \n carouselItem.appendChild(itemContent);\n \n if (item.url) {\n carouselItem.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click', { item_index: items.indexOf(item) });\n const safeUrl = this.sanitizeUrl(item.url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n }\n \n carousel.appendChild(carouselItem);\n }\n \n container.appendChild(carousel);\n }\n \n private renderVideo(container: HTMLElement, content: PlacementContent): void {\n const { video_url, poster_url, autoplay, muted } = content.content;\n \n if (!video_url) {\n this.log('Video URL missing', true);\n return;\n }\n \n const safeVideoUrl = this.sanitizeUrl(video_url);\n if (!safeVideoUrl) {\n this.log('Invalid video URL', true);\n return;\n }\n \n const video = document.createElement('video');\n video.src = safeVideoUrl;\n video.controls = true;\n video.autoplay = autoplay || false;\n video.muted = muted || false;\n video.style.cssText = 'width: 100%; border-radius: 8px;';\n \n if (poster_url) {\n const safePosterUrl = this.sanitizeUrl(poster_url);\n if (safePosterUrl) {\n video.poster = safePosterUrl;\n }\n }\n \n video.addEventListener('play', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click', { action: 'video_play' });\n });\n \n container.appendChild(video);\n }\n \n private renderHTML(container: HTMLElement, content: PlacementContent): void {\n const { html } = content.content;\n \n if (!html) {\n this.log('HTML content missing', true);\n return;\n }\n \n const wrapper = document.createElement('div');\n wrapper.className = 'aegis-placement-html';\n wrapper.innerHTML = this.sanitizeHTML(html);\n \n const links = wrapper.querySelectorAll('a');\n links.forEach((link) => {\n link.addEventListener('click', (e) => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n });\n });\n \n container.appendChild(wrapper);\n }\n \n private renderDynamicInjection(content: PlacementContent): void {\n const { html } = content.content;\n const cssSelector = content.css_selector;\n const injectionMode = content.injection_mode || 'replace';\n \n if (!cssSelector) {\n this.log('CSS selector missing for dynamic injection', true);\n return;\n }\n \n if (!html) {\n this.log('HTML content missing for dynamic injection', true);\n return;\n }\n \n let targetElement: HTMLElement | null = null;\n \n try {\n targetElement = document.querySelector(cssSelector);\n } catch (error) {\n this.log(`Invalid CSS selector: ${cssSelector}`, true);\n return;\n }\n \n if (!targetElement) {\n this.log(`Target element not found for selector: ${cssSelector}`, true);\n return;\n }\n \n const wrapper = document.createElement('div');\n wrapper.className = 'aegis-dynamic-injection';\n wrapper.setAttribute('data-placement-id', content.placement_id);\n wrapper.setAttribute('data-variant-id', content.variant_id);\n wrapper.innerHTML = this.sanitizeHTML(html);\n \n const links = wrapper.querySelectorAll('a');\n links.forEach((link) => {\n link.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n });\n });\n \n switch (injectionMode) {\n case 'replace':\n targetElement.innerHTML = '';\n targetElement.appendChild(wrapper);\n this.log(`Replaced content in ${cssSelector}`, false);\n break;\n \n case 'append':\n targetElement.appendChild(wrapper);\n this.log(`Appended content to ${cssSelector}`, false);\n break;\n \n case 'prepend':\n targetElement.insertBefore(wrapper, targetElement.firstChild);\n this.log(`Prepended content to ${cssSelector}`, false);\n break;\n \n default:\n this.log(`Unknown injection mode: ${injectionMode}`, true);\n return;\n }\n \n this.log(`Dynamically injected content for ${content.placement_id} into ${cssSelector} (${injectionMode})`);\n }\n \n private renderFallback(slot: PlacementSlot): void {\n if (!slot.fallbackContent) return;\n \n const container = document.getElementById(slot.containerId);\n if (!container) return;\n \n container.innerHTML = slot.fallbackContent;\n this.log(`Rendered fallback content for: ${slot.placementId}`);\n }\n \n private async trackEvent(\n placementId: string,\n variantId: string,\n eventType: 'impression' | 'click' | 'conversion',\n metadata: Record<string, any> = {}\n ): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/placements/track`;\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Type': this.getDeviceType(),\n 'X-Platform': 'web'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const body = {\n placement_id: placementId,\n variant_id: variantId,\n event_type: eventType,\n metadata: {\n device_type: this.getDeviceType(),\n platform: 'web',\n ...metadata\n }\n };\n \n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body)\n }).catch(err => this.log(`Track event failed: ${err}`, true));\n \n this.log(`Tracked ${eventType}: ${placementId}`);\n \n } catch (error) {\n this.log(`Error tracking event: ${error}`, true);\n }\n }\n \n private connectSSE(): void {\n if (this.eventSource) {\n this.disconnectSSE();\n }\n \n if (!this.organizationId) {\n this.log('Cannot connect SSE without organization ID', true);\n return;\n }\n \n const url = new URL('/v1/stream/realtime', this.apiHost);\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Organization-ID': this.organizationId,\n };\n \n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n \n const queryParams = new URLSearchParams();\n Object.entries(headers).forEach(([key, value]) => {\n queryParams.append(key, value);\n });\n \n this.eventSource = new EventSource(`${url}?${queryParams.toString()}`);\n \n this.eventSource.addEventListener('open', () => {\n this.log('SSE connection established');\n this.reconnectAttempts = 0;\n });\n \n this.eventSource.addEventListener('placement_content_updated', (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data);\n this.log(`Received placement content update: ${data.placement_id}`);\n this.refreshPlacements();\n } catch (error) {\n this.log(`Error parsing SSE event: ${error}`, true);\n }\n });\n \n this.eventSource.addEventListener('heartbeat', (event: MessageEvent) => {\n this.log('SSE heartbeat received');\n });\n \n this.eventSource.addEventListener('error', (error) => {\n this.log('SSE connection error', true);\n \n if (this.eventSource?.readyState === EventSource.CLOSED) {\n this.attemptReconnect();\n }\n });\n }\n \n private disconnectSSE(): void {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = undefined;\n this.log('SSE connection closed');\n }\n }\n \n private attemptReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n this.log('Max reconnect attempts reached, giving up', true);\n return;\n }\n \n this.reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);\n \n this.log(`Reconnecting SSE in ${delay}ms (attempt ${this.reconnectAttempts})`);\n \n setTimeout(() => {\n if (this.isInitialized && this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n }, delay);\n }\n \n private getDeviceType(): string {\n const width = window.innerWidth;\n if (width < 768) return 'mobile_web';\n if (width < 1024) return 'tablet_web';\n return 'desktop_web';\n }\n \n private sanitizeUrl(url: string): string | null {\n try {\n const parsed = new URL(url, window.location.href);\n \n if (parsed.protocol === 'javascript:' || parsed.protocol === 'data:') {\n this.log(`Blocked unsafe URL protocol: ${parsed.protocol}`, true);\n return null;\n }\n \n return parsed.href;\n } catch {\n this.log(`Invalid URL: ${url}`, true);\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n const hexPattern = /^#[0-9A-Fa-f]{3,6}$/;\n const rgbPattern = /^rgba?\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*(,\\s*[\\d.]+\\s*)?\\)$/;\n const namedColors = ['white', 'black', 'red', 'blue', 'green', 'yellow', 'transparent'];\n \n if (hexPattern.test(color) || rgbPattern.test(color) || namedColors.includes(color.toLowerCase())) {\n return color;\n }\n \n this.log(`Invalid color: ${color}`, true);\n return '#000000';\n }\n \n private sanitizeHTML(html: string): string {\n // Use DOMPurify if available (recommended for production)\n const purify = (window as unknown as Record<string, unknown>).DOMPurify as\n | { sanitize: (dirty: string, cfg?: Record<string, unknown>) => string }\n | undefined;\n\n if (purify?.sanitize) {\n return purify.sanitize(html, {\n ALLOWED_TAGS: [\n 'a', 'b', 'br', 'div', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'i', 'img', 'li', 'ol', 'p', 'span', 'strong', 'u', 'ul', 'table',\n 'thead', 'tbody', 'tr', 'th', 'td', 'blockquote', 'hr', 'figure',\n 'figcaption', 'picture', 'source', 'video', 'section', 'article',\n ],\n ALLOWED_ATTR: [\n 'href', 'target', 'rel', 'src', 'alt', 'width', 'height', 'class',\n 'id', 'style', 'title', 'loading', 'srcset', 'sizes', 'type',\n 'media', 'controls', 'poster',\n ],\n ALLOW_DATA_ATTR: false,\n });\n }\n\n // Built-in fallback: strip all tags via DOM parsing, then re-allow safe subset\n this.log(\n 'DOMPurify not found — falling back to built-in sanitizer. ' +\n 'For full HTML placement support, add <script src=\"https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.4/purify.min.js\"></script>',\n false\n );\n const tempDiv = document.createElement('div');\n tempDiv.textContent = html;\n return tempDiv.innerHTML;\n }\n \n private log(message: string, isError = false): void {\n if (this.debugMode || isError) {\n console[isError ? 'error' : 'log'](`[AegisPlacements] ${message}`);\n }\n }\n \n destroy(): void {\n this.disconnectSSE();\n this.slots.clear();\n this.placements.clear();\n this.renderedSlots.clear();\n this.isInitialized = false;\n this.log('AegisPlacements destroyed');\n }\n}\n"],"names":["DEFAULT_CONFIG","workspace_id","batch_size","batch_interval","capture_utm","capture_referrer","auto_page_view","session_timeout","debug","respect_dnt","cross_domain_tracking","secure_cookie","enable_offline_mode","max_offline_events","retry_failed_requests","max_retries","retry_backoff_multiplier","request_timeout","rate_limit_burst","rate_limit_per_second","auto_region_detection","wait_for_consent","enable_consent_mode","integrate_onetrust","integrate_cookiebot","integrate_google_consent_mode","default_consent","analytics","marketing","functional","initialized","api_host","cell_endpoints","preferred_region","cookie_domain","plugins","active_cell","generateUUID","crypto","randomUUID","replace","c","r","Math","random","toString","generateMessageId","Date","now","slice","logger","constructor","this","enabled","prefix","enable","disable","isEnabled","message","args","info","console","warn","error","Identity","storage","userId","traits","anonymousId","getOrCreateAnonymousId","loadUserIdentity","id","get","set","storedUserId","storedTraits","JSON","parse","getAnonymousId","setUserId","setTraits","getUserId","stringify","getTraits","reset","remove","alias","newUserId","previousId","getState","SessionManager","sessionTimeoutMinutes","eventCount","checkInterval","activityThrottle","lastActivityUpdate","adClickIDs","sessionTimeout","lastActivityTime","sessionStartTime","session","loadSession","sessionId","startTime","landingPage","createNewSession","startActivityTracking","startExpiryCheck","sessionData","newSessionId","persistSession","activityHandler","onActivity","forEach","event","window","addEventListener","passive","document","visibilityState","setInterval","checkSessionExpiry","getSessionId","incrementEventCount","getSessionDuration","getEventCount","setAdClickIDs","Object","keys","length","getAdClickIDs","getLandingPage","destroy","clearInterval","EventQueue","config","transport","buffer","flushInterval","isFlushing","offlineQueue","isOnline","navigator","onLine","enableOfflineMode","loadOfflineQueue","setupOnlineListener","startFlushTimer","setupUnloadHandlers","offlineData","events","Array","isArray","maxOfflineEvents","flushOfflineQueue","saveOfflineQueue","data","flush","send","success","push","type","batchSize","addToOfflineQueue","shift","result","unshift","batchInterval","flushBeforeUnload","persistBufferToOfflineQueue","getQueueSize","getOfflineQueueSize","clear","Transport","activeCell","healthCheckInterval","regionLatencyMap","Map","cellEndpoints","initializeCellularArchitecture","cachedCell","loadCachedCell","isCellHealthy","selectOptimalCell","startHealthChecks","cached","saveCachedCell","cell","healthy","some","region","url","preferredRegion","preferredCell","find","autoRegionDetection","detectOptimalRegion","selectCellByPriority","healthyCells","filter","latencyPromises","map","async","latency","measureLatency","results","Promise","all","sort","a","b","optimalCell","performance","controller","AbortController","timeoutId","setTimeout","abort","response","fetch","method","signal","clearTimeout","ok","Infinity","sortedCells","priority","performHealthChecks","healthPromises","isHealthy","checkCellHealth","endpoint","getActiveEndpoint","payload","buildPayload","sendBeacon","sendViaBeacon","resolve","sendViaFetch","apiHost","Error","batch","sentAt","toISOString","writeKey","context","blob","Blob","attempt","requestTimeout","headers","Authorization","body","keepalive","json","errorText","text","status","statusText","shouldRetry","retryRequest","statusCode","retryFailedRequests","maxRetries","delay","pow","retryBackoffMultiplier","getActiveCell","getRegionLatencies","STORAGE_PREFIX","Storage","options","useLocalStorage","isLocalStorageAvailable","test","localStorage","setItem","removeItem","key","value","expiryDays","fullKey","item","expiry","setCookie","itemStr","getItem","getCookie","deleteCookie","startsWith","cookie","split","trim","name","days","date","setTime","getTime","cookieStr","toUTCString","secureCookie","location","protocol","cookieDomain","crossDomain","domain","getRootDomain","nameEQ","ca","i","charAt","substring","indexOf","hostname","parts","join","buildContext","utm","searchParams","URL","URLSearchParams","search","parseUTMParameters","device","ua","userAgent","detectDevice","os","version","match","detectOS","browser","detectBrowser","network","connection","mozConnection","webkitConnection","effectiveType","downlink","rtt","detectNetworkInfo","library","page","path","pathname","referrer","title","href","hash","locale","language","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","screen","width","height","density","devicePixelRatio","viewport","innerWidth","innerHeight","campaign","PluginRegistry","register","plugin","has","unregister","pluginName","delete","getAll","from","values","executeHook","hookName","hook","apply","String","onError","onErrorError","executeHookChain","initialValue","additionalArgs","executeHookParallel","promises","promise","ConsentManager","listeners","defaultConsent","waitForConsent","consentStorageKey","preferences","loadPreferences","stored","parsed","mergeWithDefaults","getDefaultPreferences","necessary","savePreferences","setConsent","updated","notifyListeners","grantAll","denyAll","hasConsent","category","getPreferences","getStatus","isAnalyticsEnabled","isMarketingEnabled","onChange","callback","index","splice","listener","integrateOneTrust","OneTrust","syncWithOneTrust","activeGroups","OnetrustActiveGroups","includes","OptanonWrapper","originalWrapper","integrateCookiebot","cookiebot","Cookiebot","syncWithCookiebot","consent","statistics","integrateGoogleConsentMode","gtag","updateGoogleConsent","ad_storage","analytics_storage","ad_user_data","ad_personalization","functionality_storage","personalization_storage","security_storage","sumItems","products","reduce","sum","p","quantity","mapProducts","product_id","sku","price","currency","brand","variant_id","variant_label","position","EcommerceTracker","aegis","productViewed","product","track","image_url","productListViewed","list","list_id","list_name","productClicked","source","section","productImpressed","categoryFiltered","previous_category","result_count","searchPerformed","query","results_count","filters","addToCart","removeFromCart","cartViewed","cart","cart_id","num_items","checkoutStarted","checkout","checkout_id","coupon","shipping","tax","checkoutStep","step","orderCompleted","order","order_id","revenue","discount","payment_method","orderRefunded","orderId","couponApplied","couponRemoved","wishlistItemAdded","wishlist","wishlist_id","wishlist_name","promotionViewed","promo","promotionClicked","RateLimiter","droppedThisWindow","firstDroppedName","windowFlushTimer","capacity","max","burstCapacity","refillPerSecond","windowMs","dropCoalesceWindowMs","onDropBatch","tokens","lastRefillMs","tryConsume","eventName","refill","flushWindow","getAvailableTokens","floor","elapsedSec","newTokens","min","err","C1","C2","murmurhash3_x86_32","input","seed","bytes","len","nBlocks","h1","offset","k1","imul","tailStart","tailLen","murmurhash3_bytes","TextEncoder","encode","BloomFilter","buf","params","m","mask","fromBase64","bloomB64","b64","atob","bin","out","Uint8Array","charCodeAt","B","globalThis","Buffer","base64ToBytes","seedA","h2","seedB","k","idx","NameGovernor","bloom","remainingNewNames","graceActive","localNovelNames","Set","droppedSinceLastReport","reportWindowStart","hasWarnedThisSession","ingestHint","hint","bloom_algo","bloom_b64","seed_a","seed_b","remaining_new_names","grace_active","shouldSend","add","prev","drainDropReport","size","total","count","since","_debugState","hasBloom","remaining","localNovel","Aegis","queue","initPromise","_ecommerce","rateLimiter","nameGovernor","_lastPageUrl","_popstateHandler","_originalPushState","_originalReplaceState","init","_init","_a","shouldRespectDNT","toLowerCase","pattern","isBot","buildConfig","identity","captureAdClickIDsOnInit","write_key","sampleName","emitRateLimitMeta","initializePlugins","startSPATracking","onRouteChange","currentUrl","history","pushState","bind","replaceState","stopSPATracking","removeEventListener","dnt","doNotTrack","msDoNotTrack","parseAdClickIDs","hasAdClickIDs","use","catch","properties","assertInitialized","messageId","timestamp","captureEvent","identify","group","groupId","trackEvent","eventLabel","ctx","props","campaign_id","campaign_source","medium","campaign_medium","content","campaign_content","term","campaign_term","clicks","clickId","gclid","fbclid","ctwa_clid","msclkid","ttclid","campaign_click_id","transformedEvent","sampleEventName","dropped_count","sample_event_name","burst_capacity","refill_per_second","_b","ingestGovernanceHint","emitGovernanceDropMeta","report","distinct_names","sample_names","entries","window_start","window_end","setCell","cellEndpoint","existingCell","assign","getCellInfo","latencies","grantConsent","denyConsent","getConsentPreferences","onConsentChange","ecommerce","renderCarouselCards","sanitizeUrl","sanitizeColor","log","addAnimationStyles","ic","interactive_config","cards","autoplay","Number","autoplay_ms","loop","bg","background_color","fg","text_color","overlay","createElement","className","setAttribute","style","cssText","card","header","headerText","textContent","appendChild","closeBtn","msOverflowStyle","e","abs","deltaX","deltaY","scrollLeft","tile","cta_url","img","safe","src","alt","loading","t","cta_text","cta","goto","stopPropagation","dots","dotEls","dot","setActive","d","opacity","activeIdx","tiles","querySelectorAll","autoplayTimer","next","el","scrollIntoView","behavior","inline","block","approx","round","DISMISS_STORAGE_PREFIX","renderProgressBar","goalType","progress_goal_type","threshold","progress_threshold","rewardText","progress_reward_text","progress_source","fill","bar","label","leading","numeric","shell","fillEl","footnote","lastFiredUnlock","update","cur","__aegisProgressSSE","win","Shopify","v","parseFloat","total_price","aegis_cart","cart_items","cart_total","cacheStr","subtotalAmount","items","readCurrentValue","pct","toFixed","pollTimer","cleanup","once","RESUME_PREFIX","writeResumeIdx","resumeKey","renderCoachmarkTour","resume_key","steps","allowSkip","allow_skip","showDots","show_progress_dots","current","raw","n","parseInt","isFinite","readResumeIdx","pointerEl","tipEl","highlightEl","cleanupOne","finish","opts","skipped","showStep","selector","anchor_web","anchor","querySelector","rect","getBoundingClientRect","top","left","placement","titleEl","bodyEl","controls","_","buttons","skip","isLast","tipRect","bottom","right","aegisResetTour","clearResume","_AegisInAppManager","campaigns","displayedCampaigns","suppressedUntil","isInitialized","reconnectAttempts","maxReconnectAttempts","readAnonIdFromStorage","contactId","organizationId","propertyId","debugMode","enableSSE","onInteractiveCampaign","initialize","refreshCampaigns","connectSSE","updateUserId","updateContactId","disconnectSSE","notifyConversion","goalName","ts","sessionStorage","CONVERSION_STORAGE_PREFIX","applySuppressionFromCampaigns","convertedAt","seconds","frequency","suppress_after_conversion_seconds","scope","expiresAt","existing","rehydrateSuppressionFromStorage","earliestTs","isSuppressed","campaignId","eventSource","queryParams","append","EventSource","readyState","CLOSED","attemptReconnect","close","device_type","detectDeviceType","page_url","isNewUser","abAssignments","getABAssignments","btoa","credentials","processABAssignments","tryDisplayNextCampaign","assigned_variant_id","getVariantId","client_trigger","displayCampaign","onClientEvent","eventData","matchesClientTrigger","trigger","cfg","wantedRaw","wanted","actual","productId","interactiveSubTypes","sub_type","renderInteractive","renderModal","renderBanner","renderFullScreen","renderHalfInterstitial","renderAlert","renderPIP","renderTooltip","buildRenderContext","sticky_position","dismissible","sticky_dismissible","autoHide","sticky_auto_hide_ms","sticky_bg_color","positionCss","strong","createTextNode","action_url","button_text","autoHideTimer","persist","renderStickyBar","layout","rec_layout","ctaDefault","rec_cta_text","accent","sheet","handle","grid","isRow","metadata","go","target","renderProductRecommendation","evt","color","msg","level","renderNPSSurvey","renderCountdownOffer","renderStarRating","renderQuickPoll","renderQuiz","createOverlay","modal","question","nps_question","scale","btn","labels","notLikely","veryLikely","addCloseButton","countdown_label","digits","digitStyle","val","targetStr","countdown_target","diff","h","padStart","s","spans","requestAnimationFrame","desc","createCTAButton","stars","maxStars","rating_scale","star","transform","poll_options","optionsList","opt","optBtn","questions","currentQ","renderQuestion","childNodes","removeChild","lastChild","thank_you_message","q","progress","questionText","optionsDiv","safeUrl","open","container","removeModal","navigateToCampaignAction","CustomEvent","detail","campaign_type","cancelable","dispatchEvent","defaultPrevented","banner","contentContainer","textContainer","actionsContainer","ctaButton","removeBanner","closeButton","actions","alert","buttonContainer","cancelButton","pip","video_url","video","muted","animation","parentNode","cursor","anchorSelector","tooltip_anchor_selector","preferredPosition","tooltip_position","textColor","tooltip","arrow","dismiss","anchorRect","tooltipRect","scrollX","scrollY","arrowTop","arrowLeft","arrowBottom","arrowRight","outsideClickHandler","contains","getElementById","head","parsedUrl","origin","eventType","externalEventId","event_type","user_id","contact_id","anonymous_id","platform","property_id","idempotency_key","styles","clearABState","AegisInAppManager","AegisWidgetManager","widgets","renderedWidgets","isDestroyed","prefetchWidgetConfigs","triggerEngine","ownsTriggerEngine","enablePrefetch","cssCustomization","onEvent","sourcePlatform","updateCSSCustomization","customization","fetchPrefetchConfigs","preloadWidgetAssets","renderInteractiveCampaign","subType","widget","widget_id","widget_type","renderSpinWheel","renderScratchCard","stop","animationStyle","node","emitEvent","fetchWidgets","renderImmediateWidgets","setupTriggerListeners","setupExitIntentWithPrefetch","setCartData","cartData","cart_currency","detectPlatformCart","shopifyCart","normalizeShopifyCart","wooCart","normalizeWooCart","magentoCart","normalizeMagentoCart","token","line_items","product_name","product_title","cartJsonEl","mageCacheStr","mageCache","quote_id","subtotal","currencyCode","item_id","qty","product_price_value","exitIntentConfig","exit_intent","imageUrl","Image","spinWheelConfig","spin_wheel","elapsed","getDeviceType","w","trigger_rules","renderWidget","registerExitIntent","on","depthPercent","depth_percent","registerScrollDepth","registerTimeOnPage","isMobile","isMobileDevice","mobileConfig","mobile_triggers","handleSpinWheelIntent","widgetId","detectedCart","renderSpinWheelWidget","sendCartAbandonmentBeacon","scroll_velocity","registerScrollVelocity","scroll_threshold","minScrollPosition","scroll_min_position","cooldown","scroll_cooldown","idle_timer","idleSeconds","idle_seconds","registerInactivity","visibility_change","registerVisibilityChange","back_button","registerBackButton","handleExitIntent","renderCartRecoveryPopup","renderLeadGenPopup","beaconData","organization_id","user_email","abandoned_at","beaconUrl","renderChatBubble","renderToast","renderFeedbackForm","renderExitIntentPopup","icon_url","link_url","bubble","positionStyles","bottom_right","bottom_left","top_right","top_left","icon","textEl","description","segments","SVG_NS","wheel","createElementNS","anglePer","PI","radius","start","end","x1","cos","y1","sin","x2","y2","largeArc","labelAngle","lx","ly","spinButton","disabled","prize","generatePrize","config_id","showPrizeResult","spinWheel","accentColor","accent_color","backgroundColor","buttonColor","button_color","wheelColors","innerHTML","onclick","interpolateCartVariables","subtitle","wheelContainer","form","phoneInput","placeholder","required","emailInput","nameInput","submitButton","errorMessage","preventDefault","phone","email","validatePhone","validateEmail","display","submitSpinWheel","showSpinWheelPrize","prize_label","has_email","geoRegion","detectGeoRegion","deviceType","utmParams","getUTMParams","cart_token","_c","_d","_e","cart_url","geo_region","session_id","utm_source","utm_medium","utm_campaign","resultContainer","emoji","prizeLabel","coupon_code","couponContainer","couponLabel","couponCode","parentElement","canvas","getContext","fillStyle","fillRect","font","textAlign","fillText","isScratching","scratch","x","y","globalCompositeOperation","beginPath","arc","clientX","clientY","scratchButton","duration","toast","iconEl","messageEl","textareaLabel","textarea","rows","submitFeedback","score","comment","descEl","configId","event_data","titleText","messageText","show_cart_items","cartItems","cartTitle","itemDiv","discount_code","discountBox","discount_percentage","show_timer","timer_minutes","timer","checkoutUrl","tier","template","isError","TriggerEngine","isStarted","scrollDepthTargets","scrollDepthReached","timeOnPageTargets","exitIntentEnabled","exitIntentFired","inactivityTargets","scrollVelocityEnabled","scrollVelocityFired","scrollVelocityConfig","lastScrollY","lastScrollTime","visibilityChangeEnabled","backButtonEnabled","backButtonFired","handleScroll","scrollTop","pageYOffset","documentElement","scrollHeight","scrollPercent","targetDepth","emit","actual_percent","scroll_top","scroll_height","client_y","time_on_page","pageLoadTime","handleScrollVelocity","currentY","currentTime","timeDiff","distance","velocity","scroll_distance","current_position","scrollVelocityCooldownTimer","handleVisibilityChange","hidden","handleBackButton","handleActivity","off","callbacks","timerId","idleTime","actual_idle_time","attachScrollListener","attachExitIntentListener","attachScrollVelocityListener","attachVisibilityChangeListener","attachBackButtonListener","attachActivityListeners","startInactivityCheck","removeScrollListener","removeExitIntentListener","removeScrollVelocityListener","removeVisibilityChangeListener","removeBackButtonListener","removeActivityListeners","inactivityCheckInterval","wildcardCallbacks","COOKIE_NAME","BootstrapError","super","globalName","existingQueue","instance","loadOptions","_loadOptions","AegisMessageRuntime","ownedTriggerEngine","enableWidgetPrefetch","inApp","call","getCampaigns","AegisPlacementManager","placements","slots","renderedSlots","refreshPlacements","placementId","slot","existingContent","renderSlot","fallbackContent","renderFallback","placementIds","placement_id","renderAllSlots","content_type","renderDynamicInjection","containerId","renderCard","renderCarousel","renderVideo","renderHTML","onRender","cardBody","carousel","carouselItem","itemContent","item_index","poster_url","safeVideoUrl","safePosterUrl","poster","action","html","wrapper","sanitizeHTML","link","cssSelector","css_selector","injectionMode","injection_mode","targetElement","insertBefore","firstChild","variantId","purify","DOMPurify","sanitize","ALLOWED_TAGS","ALLOWED_ATTR","ALLOW_DATA_ATTR","tempDiv","aegisBootstrap","req","currentOrigin","firstPartyCookieId","attestationToken","doFetch","resp","cookieId","expires","setDate","getDate","encodeURIComponent","writeFirstPartyCookie"],"mappings":"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"}
|