@active-reach/web-sdk 1.14.1 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils/debounce.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/renderers/product-recommendation.ts","../src/inapp/AegisInAppManager.ts","../src/inapp/renderPreview.ts","../src/placements/AegisPlacementManager.ts","../src/triggers/TriggerEngine.ts","../src/core/sdk-config-poller.ts","../src/core/prefetch-bundle-client.ts","../src/inbox/AegisInbox.ts","../src/widgets/AegisWidgetManager.ts","../src/runtime/AegisMessageRuntime.ts","../src/core/bootstrap.ts","../src/index.ts"],"sourcesContent":["export function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n return function debounced(...args: Parameters<T>): void {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n\n timeoutId = setTimeout(() => {\n func(...args);\n timeoutId = null;\n }, wait);\n };\n}\n\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n limit: number\n): (...args: Parameters<T>) => void {\n let inThrottle = false;\n\n return function throttled(...args: Parameters<T>): void {\n if (!inThrottle) {\n func(...args);\n inThrottle = true;\n setTimeout(() => {\n inThrottle = false;\n }, limit);\n }\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 * 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 * 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 // F2 — campaign-delivery surface selection. When the array contains\n // 'embedded_card' AND the page has a `[data-aegis-slot=\"<widget_category>\"]`\n // anchor, the SDK renders this campaign INTO the slot (in addition to or\n // instead of an overlay; see `renderIntoSlots`). Defaults to\n // `['in_app_overlay']` server-side so legacy campaigns keep auto-overlay\n // behavior unchanged.\n delivery_modes?: Array<'in_app_overlay' | 'embedded_card' | 'standalone_page'>;\n // F3 — wide grouping discriminator used as the slot lookup key. A campaign\n // with `widget_category='feedback'` will fill the first\n // `[data-aegis-slot=\"feedback\"]` element on the page (if `embedded_card` is\n // among its delivery_modes).\n widget_category?: 'feedback' | 'loyalty' | 'promo' | 'commerce' | 'support' | 'custom';\n // F2 — page-key for `standalone_page` delivery mode. Read by the Next.js\n // route handler in `apps/cashier-portal/src/app/s/[slug]/[workspace]/[page_key]`.\n // Matches the existing storefront vocabulary (`rewards`/`members`)\n // in apps/cashier-portal/src/app/s/[slug]/{rewards,members}/page.tsx.\n page_key?: 'bill' | 'rewards' | 'feedback' | 'reviews' | 'members';\n}\n\n/**\n * Payload for `campaign-click` lifecycle event. CANCELLABLE — return `false`\n * (or call `evt.preventDefault()`) from the handler to suppress the SDK's\n * default `window.location.href` navigation, e.g. to route via a SPA router.\n */\nexport interface CampaignClickEvent {\n campaign: InAppCampaign;\n /** Sanitized destination URL — already passed through `sanitizeUrl()`. */\n action_url: string;\n /** Best-effort button identifier — populated when the click came from a\n * named button in a multi-button campaign (modals, alerts). `cta` for the\n * primary CTA on single-button campaigns. */\n button_id?: string;\n /** Mutate via `evt.preventDefault()` to signal the SDK to skip its\n * default hard-navigation. Identical semantics to DOM CustomEvent. */\n preventDefault: () => void;\n defaultPrevented: boolean;\n}\n\n/** Payload for `campaign-dismiss` lifecycle event. */\nexport interface CampaignDismissEvent {\n campaign: InAppCampaign;\n /** Source of dismissal — close button, swipe, ESC key, programmatic. */\n source: 'close_button' | 'overlay' | 'esc' | 'auto_timeout' | 'programmatic';\n}\n\n/** Payload for `error` lifecycle event. Aggregates non-fatal SDK errors so\n * host apps can wire them into Sentry / Datadog RUM / similar. */\nexport interface AegisErrorEvent {\n message: string;\n error: unknown;\n /** Optional structured context — `{ event: 'campaign-click' }` for handler\n * throws, `{ campaign_id, stage }` for render path failures, etc. */\n context: Record<string, unknown>;\n}\n\n/**\n * Map of lifecycle event name → handler signature. Used by the typed\n * `on(event, handler)` overload below so TS correctly narrows the payload\n * type per event without a discriminated union at the call site.\n */\nexport interface InAppLifecycleEventMap {\n 'campaigns-loaded': (campaigns: InAppCampaign[]) => void;\n 'campaign-will-show': (campaign: InAppCampaign) => void | false;\n 'campaign-shown': (campaign: InAppCampaign) => void;\n 'campaign-click': (evt: CampaignClickEvent) => void | false;\n 'campaign-dismiss': (evt: CampaignDismissEvent) => void;\n 'error': (evt: AegisErrorEvent) => void;\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 * Workspace cascade reader. Set this from the host SDK as\n * `getWorkspaceId: () => aegis.getEffectiveWorkspaceId()` so in-app\n * impressions/clicks/dismisses carry the same workspace context the\n * main analytics SDK sees (URL path slug, ?ws=, setWorkspace runtime).\n * Without it, in-app engagement events arrive at event-ingress with\n * no workspace_id stamped → cross-outlet attribution silently falls\n * back to the org's primary workspace.\n */\n getWorkspaceId?: () => string | undefined;\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 private getWorkspaceId?: () => string | undefined;\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 // ── Lifecycle event bus (1.8.0) ────────────────────────────────────────\n // Typed callback registry — host apps register handlers via the public\n // `on*` methods below. Each handler is stored once; calling the\n // returned unsubscribe fn removes it. Multiple subscribers per event are\n // supported. Callbacks that return `false` (or call `evt.preventDefault()`\n // on cancellable events) signal the SDK to skip its default behaviour.\n //\n // Industry parity: matches CleverTap `notificationCallback`, WebEngage\n // `onCallback`, MoEngage `onSelfHandledClick`, Iterable url-delegate, etc.\n // The DOM CustomEvent path (window.dispatchEvent('aegis:campaign-click'))\n // is preserved for backward compat + advanced multi-subscriber + pre-init\n // patterns where typed methods aren't reachable yet.\n private hooks = new Map<string, Set<(...args: unknown[]) => void | false | undefined>>();\n // `aegis.inApp.ready` resolves when the first refreshCampaigns completes\n // — matches CleverTap `onLoad`, WebEngage `onReady`. Lets host apps await\n // a known-good state before reading `campaigns` or registering handlers\n // that need armed campaigns visible.\n private readyResolve!: () => void;\n readonly ready: Promise<void> = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n\n private emit<T>(eventName: string, payload: T): boolean {\n const handlers = this.hooks.get(eventName);\n if (!handlers || handlers.size === 0) return true;\n let proceed = true;\n for (const handler of handlers) {\n try {\n const result = (handler as (p: T) => void | false | undefined)(payload);\n if (result === false) proceed = false;\n } catch (err) {\n // Don't let a misbehaving host handler crash the SDK render path.\n // Surface via onError but keep going for the remaining handlers.\n this.emitError(err, { event: eventName });\n }\n }\n return proceed;\n }\n\n private emitError(err: unknown, context?: Record<string, unknown>): void {\n const handlers = this.hooks.get('error');\n if (!handlers || handlers.size === 0) {\n // No subscriber — log to console so errors aren't completely silent.\n this.log(`Active Reach SDK error: ${err instanceof Error ? err.message : String(err)}`, 'error');\n return;\n }\n for (const handler of handlers) {\n try {\n (handler as (e: AegisErrorEvent) => void)({\n message: err instanceof Error ? err.message : String(err),\n error: err,\n context: context ?? {},\n });\n } catch {\n // ignore — we already tried to surface\n }\n }\n }\n\n private register<T>(\n eventName: string,\n handler: (payload: T) => void | false | undefined,\n ): () => void {\n if (!this.hooks.has(eventName)) this.hooks.set(eventName, new Set());\n this.hooks.get(eventName)!.add(handler as (...args: unknown[]) => void | false | undefined);\n return () => {\n this.hooks.get(eventName)?.delete(handler as (...args: unknown[]) => void | false | undefined);\n };\n }\n\n /**\n * Subscribe to in-app message lifecycle events. Returns an unsubscribe\n * function — call to remove the handler (matches React `useEffect` cleanup\n * convention).\n *\n * Supported events: `campaigns-loaded`, `campaign-will-show` (cancellable),\n * `campaign-shown`, `campaign-click` (cancellable), `campaign-dismiss`,\n * `error`. Cancellable events: handler returns `false` to suppress the\n * SDK's default behaviour (e.g., prevent the hard navigation on click,\n * skip rendering on will-show).\n */\n on<E extends keyof InAppLifecycleEventMap>(\n event: E,\n handler: InAppLifecycleEventMap[E],\n ): () => void {\n return this.register(event, handler as never);\n }\n\n /** Sugar: subscribe to `campaigns-loaded`. Fires after every successful\n * `/v1/in-app/active` poll with the full active-campaign list. */\n onCampaignsLoaded(\n handler: (campaigns: InAppCampaign[]) => void,\n ): () => void {\n return this.register('campaigns-loaded', handler);\n }\n\n /** Sugar: subscribe to `campaign-will-show`. CANCELLABLE — return `false`\n * to suppress rendering this campaign (host-side suppression rules,\n * route-aware blocking, etc.). */\n onCampaignWillShow(\n handler: (campaign: InAppCampaign) => void | false,\n ): () => void {\n return this.register('campaign-will-show', handler);\n }\n\n /** Sugar: subscribe to `campaign-shown`. Fires after the SDK has painted\n * the campaign to the DOM (post-impression). */\n onCampaignShown(\n handler: (campaign: InAppCampaign) => void,\n ): () => void {\n return this.register('campaign-shown', handler);\n }\n\n /** Sugar: subscribe to `campaign-click`. CANCELLABLE — return `false` (or\n * call `evt.preventDefault()`) to suppress the SDK's default\n * `window.location.href` navigation, e.g. to route via a SPA router. */\n onCampaignClick(\n handler: (evt: CampaignClickEvent) => void | false,\n ): () => void {\n return this.register('campaign-click', handler);\n }\n\n /** Sugar: subscribe to `campaign-dismiss`. Fires when user closes/swipes\n * away the campaign before clicking through. */\n onCampaignDismiss(\n handler: (evt: CampaignDismissEvent) => void,\n ): () => void {\n return this.register('campaign-dismiss', handler);\n }\n\n /** Sugar: subscribe to `error`. Aggregates non-fatal SDK errors — fetch\n * failures, render exceptions, host-handler throws. Wire this into your\n * error monitoring (Sentry, Datadog RUM, etc.). */\n onError(\n handler: (evt: AegisErrorEvent) => void,\n ): () => void {\n return this.register('error', handler);\n }\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 Active Reach 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 this.getWorkspaceId = config.getWorkspaceId;\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', () => {\n this.log('SSE heartbeat received');\n });\n\n this.eventSource.addEventListener('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 // Lifecycle: `campaigns-loaded` — fires after every successful refresh\n // with the full active-campaign list. Host apps subscribe to drive\n // route-aware allowlists, sticky inboxes, badge counts, etc.\n this.emit('campaigns-loaded', this.campaigns);\n\n // Resolve `aegis.inApp.ready` after the FIRST successful poll so host\n // apps can `await aegis.inApp.ready` before reading `campaigns` or\n // making decisions that depend on a known-good initial state. Idempotent\n // — calling resolve() twice is a no-op for an already-settled promise.\n this.readyResolve();\n\n this.tryDisplayNextCampaign();\n\n // F2/F3 / U8 — fill any `[data-aegis-slot]` anchors with matching\n // `embedded_card`-mode campaigns. Independent of the overlay path:\n // a campaign with delivery_modes=[overlay,card] renders both ways\n // (overlay if conditions match + card if the page has a slot).\n // No-op when no slots are on the page.\n this.renderIntoSlots();\n\n // PR-B U7 — also fill any `[data-aegis-token-data]` anchors with\n // a server-injected campaign payload. Used by the standalone-page\n // route at `/s/[slug]/[workspace]/[page_key]?t=<token>`: the page\n // handler verifies the token server-side (via F16 internal),\n // embeds the resolved campaign data inline, and the SDK uses the\n // SAME renderer dispatch as the slot path. No separate widget\n // code, no public token-resolve endpoint.\n this.renderTokenAnchors();\n\n } catch (error) {\n this.emitError(error, { stage: 'refresh-campaigns' });\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 // --- F2/F3 / U8: embedded-card slot rendering ---------------------------\n //\n // Tracks slot DOM elements we've already filled so a second\n // refresh-cycle (SSE update, polling tick) doesn't re-render the same\n // campaign on top of itself. WeakSet so DOM removals get GC'd.\n private filledSlots = new WeakSet<Element>();\n\n /**\n * Scan the page for `[data-aegis-slot]` anchors and render any\n * campaign whose `widget_category` matches the slot key AND whose\n * `delivery_modes` includes `'embedded_card'`.\n *\n * Runs after every refresh-campaigns success — the WeakSet guard\n * keeps it idempotent across re-fetches. The slot key is the campaign's\n * `widget_category` (the wide grouping discriminator from F3), so a\n * `<div data-aegis-slot=\"feedback\">` will accept the first active\n * campaign with `widget_category='feedback'` + embedded_card mode.\n */\n private renderIntoSlots(): void {\n if (typeof document === 'undefined') return;\n const slots = document.querySelectorAll('[data-aegis-slot]');\n if (slots.length === 0) return;\n\n // First-active-per-category wins. Caller-side ordering of\n // `this.campaigns` is priority-sorted by the cell-plane endpoint.\n const eligibleByCategory = new Map<string, InAppCampaign>();\n for (const c of this.campaigns) {\n const modes = c.delivery_modes;\n const category = c.widget_category;\n if (!modes || !modes.includes('embedded_card')) continue;\n if (!category) continue;\n if (!eligibleByCategory.has(category)) {\n eligibleByCategory.set(category, c);\n }\n }\n if (eligibleByCategory.size === 0) return;\n\n slots.forEach((slot) => {\n if (this.filledSlots.has(slot)) return;\n const key = slot.getAttribute('data-aegis-slot');\n if (!key) return;\n const campaign = eligibleByCategory.get(key);\n if (!campaign) return;\n this.renderCampaignIntoSlot(campaign, slot as HTMLElement);\n this.filledSlots.add(slot);\n });\n }\n\n /**\n * U7 — render server-injected token-bound campaigns.\n *\n * The standalone-page route at `apps/cashier-portal/src/app/s/[slug]/\n * [workspace]/[page_key]/page.tsx` (and the `/c/[token]` Aegis-hosted\n * fallback) verify the URL token server-side via the F16 internal\n * endpoint, then embed the resolved campaign payload as JSON inside\n * a `<div data-aegis-token-data=\"...\">` anchor. This SDK method\n * scans for those anchors, parses the payload, and dispatches to\n * the SAME `renderCampaignIntoSlot` used by the [data-aegis-slot]\n * path — so widget rendering code is single-sourced.\n *\n * Why server-injected (not client-fetched): keeps INTERNAL_API_SECRET\n * server-side, avoids an extra browser round-trip for verify, gives\n * Next.js SSR-friendly initial HTML for SEO/no-JS users (rendered\n * via the page handler's React tree alongside the SDK anchor).\n *\n * Idempotency: filledSlots is the same WeakSet used by\n * renderIntoSlots — re-running on SSE/poll refresh is a no-op for\n * already-filled anchors.\n */\n private renderTokenAnchors(): void {\n if (typeof document === 'undefined') return;\n const anchors = document.querySelectorAll('[data-aegis-token-data]');\n if (anchors.length === 0) return;\n\n anchors.forEach((anchor) => {\n if (this.filledSlots.has(anchor)) return;\n const raw = anchor.getAttribute('data-aegis-token-data');\n if (!raw) return;\n\n let payload:\n | { campaign?: InAppCampaign; submit_url?: string }\n | null = null;\n try {\n payload = JSON.parse(raw);\n } catch (e) {\n this.log(\n `data-aegis-token-data: invalid JSON, skipping anchor (${e})`,\n 'warn',\n );\n this.filledSlots.add(anchor); // don't retry on next refresh\n return;\n }\n if (!payload || !payload.campaign || !payload.campaign.id) {\n this.log(\n 'data-aegis-token-data: missing `campaign` in payload, skipping',\n 'warn',\n );\n this.filledSlots.add(anchor);\n return;\n }\n\n // U7 step 3 — pass the submit_url through to the renderer so\n // click handlers can POST the structured response (rating value,\n // NPS score, etc.) and atomically consume the token.\n this.renderCampaignIntoSlot(\n payload.campaign,\n anchor as HTMLElement,\n { submitUrl: payload.submit_url },\n );\n this.filledSlots.add(anchor);\n });\n }\n\n /**\n * Slot-mode counterpart to `displayCampaign`. Reuses the existing\n * lifecycle hooks (`campaign-will-show`, `displayedCampaigns`,\n * `campaign-shown`, impression tracking) so analytics + frequency\n * caps work the same way as overlay renders.\n *\n * Only the sub_types that make UX sense embedded are handled; the\n * rest (modal, full_screen, half_interstitial, alert, pip) silently\n * skip — those types only make sense as fullscreen overlays.\n */\n private renderCampaignIntoSlot(\n campaign: InAppCampaign,\n target: HTMLElement,\n options?: { submitUrl?: string },\n ): void {\n const proceed = this.emit('campaign-will-show', campaign);\n if (!proceed) {\n this.log(\n `slot campaign ${campaign.id} suppressed by campaign-will-show handler`,\n );\n return;\n }\n\n this.displayedCampaigns.add(campaign.id);\n this.addAnimationStyles();\n\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 const submitUrl = options?.submitUrl;\n\n let rendered = false;\n switch (campaign.sub_type) {\n case 'star_rating':\n rendered = this.renderStarRatingSlot(\n campaign, ic, bg, text, target, submitUrl,\n );\n break;\n case 'nps_survey':\n rendered = this.renderNPSSurveySlot(\n campaign, ic, bg, text, target, submitUrl,\n );\n break;\n // Future sub_types (quick_poll, countdown_offer, quiz, sticky_bar,\n // progress_bar, carousel_cards, product_recommendation) get added\n // here as merchants need them embedded. Until then, fall through\n // to the warn below — campaigns will still render as overlays via\n // the parallel `tryDisplayNextCampaign` path.\n default:\n this.log(\n `slot mode not yet supported for sub_type: ${campaign.sub_type ?? campaign.type}`,\n 'warn',\n );\n // Roll back the displayed marker so the overlay path can still\n // run — slot fallback shouldn't burn the campaign.\n this.displayedCampaigns.delete(campaign.id);\n return;\n }\n\n if (!rendered) return;\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n }\n\n /**\n * Slot-mode wrappers. They build a small card container (no overlay\n * positioning, no close button) and append the SHARED body element\n * the overlay path also uses. Body construction lives in the\n * `_buildXxxBody` helpers below so visual output stays identical\n * between overlay and slot modes — adding a renderer feature in\n * one place updates both.\n */\n private renderStarRatingSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n submitUrl?: string,\n ): boolean {\n const card = this._wrapInSlotCard(\n 'aegis-in-app-rating-card', campaign.id, bg, text,\n );\n card.appendChild(\n this._buildStarRatingBody(campaign, ic, text, 'slot', submitUrl),\n );\n target.appendChild(card);\n return true;\n }\n\n private renderNPSSurveySlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n submitUrl?: string,\n ): boolean {\n const card = this._wrapInSlotCard(\n 'aegis-in-app-nps-card', campaign.id, bg, text,\n );\n card.appendChild(\n this._buildNPSSurveyBody(campaign, ic, text, 'slot', submitUrl),\n );\n target.appendChild(card);\n return true;\n }\n\n /**\n * Token-bound submission helper. POSTs the structured response to\n * the per-token submit URL the page handler embedded. Best-effort\n * — failure is logged but doesn't throw (the customer already\n * clicked; we can't undo their interaction).\n */\n private _submitTokenResponse(\n submitUrl: string,\n payload: Record<string, unknown>,\n ): void {\n if (!submitUrl) return;\n // Fire-and-forget; we don't gate the UI on the response.\n fetch(submitUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ response: payload }),\n keepalive: true,\n }).catch((err) => {\n this.log(`token submit failed: ${err}`, 'warn');\n });\n }\n\n // --- Shared body builders (used by both overlay + slot paths) ----------\n //\n // Sizing: `'overlay'` matches the legacy fullscreen-modal scale (24px\n // padding, 18px title, 32px stars). `'slot'` is the embedded card\n // scale (20px padding, 16px title, 28px stars) — proportional, doesn't\n // dwarf merchant page chrome. Adding a new variant means a new tuple\n // here, not a new renderer.\n\n private _wrapInSlotCard(\n className: string,\n campaignId: string,\n bg: string,\n text: string,\n ): HTMLElement {\n const card = document.createElement('div');\n card.className = className;\n card.setAttribute('data-campaign-id', campaignId);\n card.style.cssText = `\n width: 100%; border-radius: 12px; overflow: hidden;\n background: ${bg}; color: ${text};\n box-shadow: 0 4px 12px rgba(0,0,0,0.06);\n `;\n return card;\n }\n\n private _buildStarRatingBody(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n text: string,\n variant: 'overlay' | 'slot',\n submitUrl?: string,\n ): HTMLElement {\n const isOverlay = variant === 'overlay';\n const padding = isOverlay ? '24px' : '20px';\n const titleSize = isOverlay ? '18px' : '16px';\n const titleWeight = isOverlay ? '700' : '600';\n const titleMargin = isOverlay ? '16px' : '12px';\n const starSize = isOverlay ? '32px' : '28px';\n const starsMarginBottom = isOverlay ? '16px' : '0';\n const hoverScale = isOverlay ? '1.2' : '1.15';\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${padding}; text-align: center;`;\n\n const title = document.createElement('div');\n title.style.cssText =\n `font-size: ${titleSize}; font-weight: ${titleWeight}; margin-bottom: ${titleMargin};`;\n title.textContent = campaign.title || 'Rate your experience';\n body.appendChild(title);\n\n const stars = document.createElement('div');\n stars.style.cssText =\n `display: flex; gap: 8px; justify-content: center;` +\n (starsMarginBottom !== '0' ? ` margin-bottom: ${starsMarginBottom};` : '');\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 =\n `font-size: ${starSize}; cursor: pointer; transition: transform 0.1s; user-select: none;` +\n (text ? ` color: ${text};` : '');\n star.textContent = '☆'; // ☆\n const value = i;\n star.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, {\n sub_type: 'star_rating', value,\n });\n }\n });\n star.addEventListener('mouseenter', () => {\n star.style.transform = `scale(${hoverScale})`;\n });\n star.addEventListener('mouseleave', () => {\n star.style.transform = 'scale(1)';\n });\n stars.appendChild(star);\n }\n body.appendChild(stars);\n return body;\n }\n\n private _buildNPSSurveyBody(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n text: string,\n variant: 'overlay' | 'slot',\n submitUrl?: string,\n ): HTMLElement {\n const isOverlay = variant === 'overlay';\n const padding = isOverlay ? '24px' : '20px';\n const titleAlign = isOverlay ? 'center' : 'center';\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${padding};` +\n (isOverlay ? ' text-align: center;' : '');\n\n const title = document.createElement('div');\n title.style.cssText =\n `font-size: 16px; font-weight: ${isOverlay ? '700' : '600'}; ` +\n `margin-bottom: ${isOverlay ? '16px' : '12px'}; text-align: ${titleAlign};`;\n title.textContent =\n (ic.nps_question as string) || campaign.title ||\n 'How likely are you to recommend us?';\n body.appendChild(title);\n\n if (isOverlay) {\n // Overlay variant uses the round-pip scale + Not/Very labels\n // below — keeps the legacy modal look pixel-identical.\n const scale = document.createElement('div');\n scale.style.cssText =\n '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 const value = i;\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, {\n sub_type: 'nps_survey', value,\n });\n }\n });\n scale.appendChild(btn);\n }\n body.appendChild(scale);\n\n const labels = document.createElement('div');\n labels.style.cssText =\n '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 return body;\n }\n\n // Slot variant: 11-column grid of bordered buttons — fits inline\n // card width without scrolling. No Not/Very labels (slot is small\n // enough that the customer sees both ends without prompting).\n const grid = document.createElement('div');\n grid.style.cssText =\n 'display: grid; grid-template-columns: repeat(11, 1fr); gap: 4px;';\n for (let n = 0; n <= 10; n++) {\n const btn = document.createElement('button');\n btn.style.cssText = `\n padding: 8px 0; border-radius: 6px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 13px; font-weight: 600;\n cursor: pointer; transition: background 0.15s;\n `;\n btn.textContent = String(n);\n const value = n;\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, {\n sub_type: 'nps_survey', value,\n });\n }\n });\n grid.appendChild(btn);\n }\n body.appendChild(grid);\n return body;\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 // Lifecycle: `campaign-will-show` — CANCELLABLE. Host returns `false` to\n // suppress render (e.g. route-aware blocking, host-side frequency caps,\n // self-handled mode). When suppressed we DO NOT mark the campaign as\n // displayed so a subsequent `tryDisplayNextCampaign` (after the host\n // unblocks) can re-evaluate it.\n const proceed = this.emit('campaign-will-show', campaign);\n if (!proceed) {\n this.log(`campaign ${campaign.id} suppressed by campaign-will-show handler`);\n return;\n }\n\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 this.emit('campaign-shown', campaign);\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 this.emit('campaign-shown', campaign);\n return;\n case 'sticky_bar':\n renderStickyBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'progress_bar':\n renderProgressBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\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 this.emit('campaign-shown', campaign);\n return;\n case 'product_recommendation':\n renderProductRecommendation(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n }\n\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\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 = this._buildNPSSurveyBody(campaign, ic, text, 'overlay');\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 = this._buildStarRatingBody(campaign, ic, text, 'overlay');\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(\n campaign: InAppCampaign,\n safeUrl: string,\n buttonId: string = 'cta',\n ): void {\n if (typeof window === 'undefined') return;\n\n // Typed lifecycle hook (1.8.0). Mirror the DOM `preventDefault` contract\n // — a handler returning `false` OR mutating `defaultPrevented` via the\n // helper suppresses the SDK's hard-nav. Built first so handlers attached\n // via the typed API see the click before the DOM event fires.\n let typedDefaultPrevented = false;\n const typedEvent: CampaignClickEvent = {\n campaign,\n action_url: safeUrl,\n button_id: buttonId,\n preventDefault: () => {\n typedDefaultPrevented = true;\n typedEvent.defaultPrevented = true;\n },\n defaultPrevented: false,\n };\n const typedProceed = this.emit('campaign-click', typedEvent);\n\n // DOM CustomEvent path — preserved for backward compat (1.7.x consumers\n // already listen for `aegis:campaign-click`) and for advanced patterns\n // (multi-frame embeds, host-app code that runs before the SDK is\n // instantiated, debugging via DevTools event listener panel).\n const domEvent = new CustomEvent('aegis:campaign-click', {\n detail: {\n campaign_id: campaign.id,\n campaign_type: campaign.type,\n action_url: safeUrl,\n button_id: buttonId,\n },\n cancelable: true,\n });\n const domProceed = window.dispatchEvent(domEvent);\n\n // Either path can suppress the hard-nav. We OR the prevent signals so\n // host apps don't have to remember to handle both — registering on\n // either API is enough.\n const suppressed =\n !typedProceed ||\n typedDefaultPrevented ||\n !domProceed ||\n domEvent.defaultPrevented;\n\n if (!suppressed) {\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 // Lifecycle: `campaign-dismiss` — fire from this single chokepoint so\n // every renderer (8 sites today + future ones) emits consistently.\n // Source granularity (close_button / overlay / esc / auto_timeout) can\n // be refined in a future minor by passing source through to trackEvent;\n // for 1.8.0 we surface the event itself since that's the high-value\n // signal host apps need (inbox state updates, dismiss analytics).\n if (eventType === 'dismissed') {\n const campaign = this.campaigns.find((c) => c.id === campaignId);\n if (campaign) {\n this.emit('campaign-dismiss', {\n campaign,\n source: 'close_button',\n });\n }\n }\n\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 // Plumb the same workspace cascade the main analytics SDK uses\n // (config → ?ws= → URL path slug → setWorkspace runtime → session\n // storage). Without this, in-app engagement events arrive at\n // event-ingress unscoped and fall back to the org's primary\n // workspace — see PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n const workspaceId = this.getWorkspaceId?.();\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 workspace_id: workspaceId,\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 // F2/F3 / U8 — slot-rendered card classes\n '.aegis-in-app-rating-card, .aegis-in-app-nps-card'\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 * renderPreview — Static Preview Renderer for Dashboard iframe (Critical Fix A)\n *\n * Used exclusively by the sandboxed iframe preview route\n * (`/api/preview/in-app/route.tsx`). Renders a single campaign into the\n * current document body using the same rendering logic as the production SDK.\n *\n * Data flow:\n * editor-sidebar.tsx → onChange → formState → postMessage({type:'preview_update', config})\n * → iframe receives message → calls renderPreview(config)\n *\n * This ensures 100% fidelity between the dashboard editor preview and\n * production rendering — both use the same SDK code.\n */\n\nimport type { InAppCampaign } from './AegisInAppManager';\nimport { AegisInAppManager } from './AegisInAppManager';\n\n/**\n * Renders a single in-app campaign into the current document for preview.\n *\n * Creates a temporary AegisInAppManager with preview-only config (no tracking,\n * no SSE, no network requests). Calls the same rendering pipeline as production.\n */\nexport function renderPreview(config: InAppCampaign & { interactive_config?: Record<string, unknown> }): void {\n // Clear previous preview\n document.querySelectorAll(\n '[class^=\"aegis-in-app-\"]'\n ).forEach((el) => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n });\n\n if (!config) return;\n\n // Create a lightweight preview-only manager\n const manager = new AegisInAppManager({\n writeKey: 'preview-mode',\n apiHost: '',\n debugMode: false,\n enableSSE: false,\n });\n\n // Override trackEvent to be a no-op in preview mode\n // Access private via any cast — preview only, not production code\n const m = manager as unknown as {\n displayCampaign: (campaign: InAppCampaign) => void;\n trackEvent: (campaignId: string, eventType: string) => Promise<void>;\n addAnimationStyles: () => void;\n };\n\n // No-op tracking for preview\n m.trackEvent = async () => {};\n\n // Ensure animation styles are injected\n m.addAnimationStyles();\n\n // Render the campaign\n m.displayCampaign(config);\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 * Workspace cascade reader. Host SDK sets this to\n * `() => aegis.getEffectiveWorkspaceId()` so placement\n * impression/click/conversion events arrive at the gateway with the\n * same workspace context the main analytics SDK uses. See\n * PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n */\n getWorkspaceId?: () => string | undefined;\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 private getWorkspaceId?: () => string | undefined;\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 this.getWorkspaceId = config.getWorkspaceId;\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', () => {\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 // Plumb the same workspace cascade the main analytics SDK uses\n // (config → ?ws= → URL path slug → setWorkspace runtime → session\n // storage). Without this, placement events arrive at event-ingress\n // unscoped and silently attribute to the org's primary workspace.\n const workspaceId = this.getWorkspaceId?.();\n\n const body = {\n placement_id: placementId,\n variant_id: variantId,\n event_type: eventType,\n workspace_id: workspaceId,\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', () => {\n this.log('SSE heartbeat received');\n });\n\n this.eventSource.addEventListener('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","/**\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\n/**\n * Rage-click detection (Micro-Intent Engine P2 Task 1).\n *\n * Per-intent ring buffer: when ≥ `threshold` clicks land on the same\n * intent inside `windowMs`, the engine emits `rage_click` with the\n * intent name + current count + window. Frustration signal used by the\n * Stuck-at-Checkout pattern (e.g., rage-clicking the coupon input four\n * times in 800ms).\n *\n * Defaults match the plan:\n * threshold = 3 clicks\n * windowMs = 1000 ms\n *\n * TriggerEngine does NOT attach its own pointerdown listener — the\n * SelectorBinder (P1 Task 5) owns the global, delegated listener and\n * dispatches per-intent click events. The IntentSnapshotCollector\n * (P2 Task 5) wires `SelectorBinder.onIntent` to\n * `TriggerEngine.noteClick(intent)` so TriggerEngine sees a clean\n * intent-stamped stream instead of raw DOM events.\n */\nexport interface RageClickConfig {\n threshold: number;\n windowMs: number;\n}\n\n/** Payload emitted on the `rage_click` event. */\nexport interface RageClickData {\n intent: string;\n count: number;\n window_ms: number;\n}\n\n/**\n * Hover-dwell tracking (Micro-Intent Engine P2 Task 2).\n *\n * Tracks per-intent hover duration in milliseconds. `getHoverMs(intent)`\n * returns:\n * - if currently hovering the intent: ms since hover_start (live)\n * - else: ms duration of the most recent hover on that intent (sticky)\n * - if never hovered: 0\n *\n * The sticky behaviour is deliberate. The canonical use case\n * (MICRO_INTENT_ENGINE.md Story 1):\n * \"Priya hovers price for 1.8s, considers, moves cursor away.\n * Exit_intent fires. Rule checks price_hover_ms >= 1500 → true.\"\n * The rule evaluator queries `price_hover_ms` AFTER the hover ends. If\n * we reset to 0 on hover_end, the rule never matches the very pattern\n * the engine exists to detect.\n *\n * Threshold-based emission: when a hover crosses one of the registered\n * dwell targets (e.g. 1500ms), a `<intent>_hover_dwell_<ms>` event\n * fires. Useful for journeys that want event-style hooks; the\n * snapshot-style `getHoverMs` is the primary surface for the\n * compound-rule evaluator.\n */\nexport interface HoverDwellConfig {\n /** Dwell thresholds (ms) per intent. The engine fires\n * `<intent>_hover_dwell_<ms>` when an active hover crosses each\n * threshold. Defaults: price→[1500], cta→[1500]. */\n thresholdsByIntent?: Partial<Record<string, ReadonlyArray<number>>>;\n}\n\n/**\n * Mouse velocity toward the viewport top (Micro-Intent Engine P2 Task 3).\n *\n * Detects the early phase of exit-intent: the mouse moving rapidly\n * upward before it actually crosses out of the viewport. The signal is\n * a continuous px/ms value (positive = moving up), updated as samples\n * arrive. When velocity crosses `threshold`, a `mouse_velocity_to_top`\n * event fires (once per session-window cooldown to avoid spamming on a\n * single gesture).\n *\n * Sampling: callers feed positions via `noteMousePosition(x, y, ts)`.\n * The engine keeps a sliding `windowMs` ring buffer of samples and\n * computes velocity as the average dy / dt over samples in the window.\n * Per the plan: sampled at 100ms, 400ms window. That bound is\n * configurable.\n *\n * Why \"to top\" specifically: exit-intent fires only when y crosses 0;\n * we want the warning BEFORE that. A typical exit-intent gesture has\n * upward velocity well above any normal browsing motion.\n */\nexport interface MouseVelocityConfig {\n /** Threshold in px/ms (positive = moving up). Default 1.5 px/ms,\n * ≈ moving 600px in 400ms, which only happens during a deliberate\n * upward sweep. */\n threshold: number;\n /** Rolling-window length over which to compute velocity. */\n windowMs: number;\n /** Cooldown after a fire before the signal can fire again. */\n cooldownMs: number;\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 // Rage-click state (P2 Task 1). Buffer indexed by intent name (price /\n // cta / coupon / checkout). Per-intent so rage-clicking the coupon\n // input doesn't get conflated with rapid CTA presses.\n private rageClickEnabled = false;\n private rageClickConfig: RageClickConfig = { threshold: 3, windowMs: 1000 };\n private rageClickBuffer = new Map<string, number[]>();\n /** Tracks whether a rage_click event has already fired for an intent\n * in the current burst. Reset when the buffer empties below threshold.\n * Prevents the same burst from firing the event N-2 times as each\n * click after threshold pushes the count higher. */\n private rageClickFiredInBurst = new Set<string>();\n\n // Hover-dwell state (P2 Task 2). Tracks live + sticky-last dwell per\n // intent. `hoverStartAt` undefined means no active hover.\n private hoverEnabled = false;\n private hoverStartAt = new Map<string, number>();\n private hoverLastMs = new Map<string, number>();\n private hoverThresholds = new Map<string, ReadonlyArray<number>>([\n ['price', [1500]],\n ['cta', [1500]],\n ]);\n /** Track which (intent, threshold) pairs have already fired in the\n * current hover so a single long hover doesn't double-fire as time\n * marches on. Reset on hover_start. */\n private hoverThresholdsFired = new Map<string, Set<number>>();\n /** Pending threshold timers, keyed by intent. Cleared on hover_end. */\n private hoverThresholdTimers = new Map<string, number[]>();\n\n // Mouse-velocity-to-top state (P2 Task 3).\n private mouseVelEnabled = false;\n private mouseVelConfig: MouseVelocityConfig = {\n threshold: 1.5,\n windowMs: 400,\n cooldownMs: 5000,\n };\n /** Ring buffer of (x, y, ts) samples within the rolling window. */\n private mouseSamples: Array<{ x: number; y: number; ts: number }> = [];\n /** Last computed velocity-to-top in px/ms (positive = moving up). */\n private mouseVelLast = 0;\n /** Epoch ms when the velocity event last fired — gates cooldown. */\n private mouseVelLastFiredAt = 0;\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 /**\n * Enable rage-click detection (P2 Task 1).\n *\n * After calling this, feed click events via `noteClick(intent)`.\n * SelectorBinder (P1 Task 5) is the upstream source; the wiring lives\n * in IntentSnapshotCollector (P2 Task 5). Calling `noteClick` without\n * a prior `registerRageClick()` is a no-op so legacy callers don't\n * accidentally enable the feature.\n */\n registerRageClick(config?: Partial<RageClickConfig>): void {\n this.rageClickEnabled = true;\n if (config) {\n this.rageClickConfig = {\n threshold: config.threshold ?? this.rageClickConfig.threshold,\n windowMs: config.windowMs ?? this.rageClickConfig.windowMs,\n };\n }\n }\n\n /**\n * Feed a click event for rage-click detection. Returns the current\n * count within-window for the intent — useful for the snapshot\n * collector (P2 Task 5) which updates IntentRuleEvaluator with\n * `rage_click_count` continuously, not just at the burst threshold.\n *\n * Idempotent w.r.t. `registerRageClick` — when not enabled, this\n * returns 0 without buffering.\n */\n noteClick(intent: string, timestamp: number = Date.now()): number {\n if (!this.rageClickEnabled) return 0;\n const buf = this.rageClickBuffer.get(intent) ?? [];\n const cutoff = timestamp - this.rageClickConfig.windowMs;\n // Drop expired timestamps (clicks older than the window).\n // The buffer is append-only and timestamps are non-decreasing in\n // practice (Date.now is monotonic per device, modulo system-clock\n // adjustments), so an in-place trim from the head is correct.\n let trimStart = 0;\n while (trimStart < buf.length && buf[trimStart] < cutoff) trimStart++;\n const recent = trimStart === 0 ? buf : buf.slice(trimStart);\n recent.push(timestamp);\n this.rageClickBuffer.set(intent, recent);\n\n // Burst reset: when the recent count drops below threshold (because\n // older clicks aged out), the burst is over — re-arm the per-intent\n // fire-once latch so a fresh burst can fire again.\n if (recent.length < this.rageClickConfig.threshold) {\n this.rageClickFiredInBurst.delete(intent);\n }\n\n if (\n recent.length >= this.rageClickConfig.threshold &&\n !this.rageClickFiredInBurst.has(intent)\n ) {\n this.rageClickFiredInBurst.add(intent);\n this.emit('rage_click', {\n intent,\n count: recent.length,\n window_ms: this.rageClickConfig.windowMs,\n });\n }\n\n return recent.length;\n }\n\n /** Snapshot the current rage_click count for an intent. The\n * IntentSnapshotCollector (P2 Task 5) calls this when building the\n * `rage_click_count` signal value for the IntentRuleEvaluator. */\n getRageClickCount(intent: string): number {\n if (!this.rageClickEnabled) return 0;\n const buf = this.rageClickBuffer.get(intent);\n if (!buf) return 0;\n const cutoff = Date.now() - this.rageClickConfig.windowMs;\n // Lazy prune on read so the count reflects only currently-valid\n // clicks. Cheap because buffers are tiny (cap at threshold + 1 in\n // practice — older entries get dropped on every note).\n let live = 0;\n for (const ts of buf) {\n if (ts >= cutoff) live++;\n }\n return live;\n }\n\n /**\n * Enable hover-dwell tracking (P2 Task 2). After registration, feed\n * hover events via `noteHoverStart(intent, ts)` / `noteHoverEnd`.\n * SelectorBinder (P1 Task 5) is the upstream source; wiring lands in\n * P2 Task 5.\n */\n registerHoverDwell(config?: HoverDwellConfig): void {\n this.hoverEnabled = true;\n if (config?.thresholdsByIntent) {\n for (const [intent, thresholds] of Object.entries(config.thresholdsByIntent)) {\n if (thresholds) this.hoverThresholds.set(intent, thresholds);\n }\n }\n }\n\n /** Record the start of a hover on the named intent. Schedules\n * per-threshold timers that emit `<intent>_hover_dwell_<ms>` when\n * the active hover passes each registered threshold. */\n noteHoverStart(intent: string, timestamp: number = Date.now()): void {\n if (!this.hoverEnabled) return;\n // If a prior hover is still pending (no hover_end fired — possible\n // when the DOM node was unmounted mid-hover), close it out first to\n // keep `hoverLastMs` consistent.\n if (this.hoverStartAt.has(intent)) {\n this.noteHoverEnd(intent, timestamp);\n }\n this.hoverStartAt.set(intent, timestamp);\n this.hoverThresholdsFired.set(intent, new Set());\n\n // Schedule threshold timers. Uses the global setTimeout (works in\n // both browser and node, and vitest's fake-timers stub the global).\n // registerHoverDwell with no thresholds for an intent => no events,\n // only the snapshot value.\n const thresholds = this.hoverThresholds.get(intent);\n if (thresholds) {\n const timers: number[] = [];\n for (const ms of thresholds) {\n const timerId = setTimeout(() => {\n // Only fire if still hovering this intent — the event must\n // not fire after hover_end.\n if (!this.hoverStartAt.has(intent)) return;\n const firedSet = this.hoverThresholdsFired.get(intent);\n if (firedSet?.has(ms)) return;\n firedSet?.add(ms);\n this.emit(`${intent}_hover_dwell_${ms}`, {\n intent,\n threshold_ms: ms,\n actual_ms: Date.now() - timestamp,\n });\n }, ms) as unknown as number;\n timers.push(timerId);\n }\n this.hoverThresholdTimers.set(intent, timers);\n }\n }\n\n /** Record the end of a hover on the named intent. Updates the sticky\n * `lastHoverMs` so `getHoverMs` keeps returning the last-known\n * duration until the next hover_start. */\n noteHoverEnd(intent: string, timestamp: number = Date.now()): void {\n if (!this.hoverEnabled) return;\n const startAt = this.hoverStartAt.get(intent);\n if (startAt === undefined) return;\n const dwell = Math.max(0, timestamp - startAt);\n this.hoverLastMs.set(intent, dwell);\n this.hoverStartAt.delete(intent);\n // Clear pending threshold timers for this intent.\n const pending = this.hoverThresholdTimers.get(intent);\n if (pending) {\n for (const id of pending) clearTimeout(id);\n this.hoverThresholdTimers.delete(intent);\n }\n this.hoverThresholdsFired.delete(intent);\n }\n\n /**\n * Enable mouse-velocity-to-top tracking (P2 Task 3). After\n * registration, feed positions via `noteMousePosition(x, y, ts?)`.\n * IntentSnapshotCollector (P2 Task 5) wires window 'mousemove' to\n * this method, with throttling to ~100ms per the plan.\n */\n registerMouseVelocityToTop(config?: Partial<MouseVelocityConfig>): void {\n this.mouseVelEnabled = true;\n if (config) {\n this.mouseVelConfig = {\n threshold: config.threshold ?? this.mouseVelConfig.threshold,\n windowMs: config.windowMs ?? this.mouseVelConfig.windowMs,\n cooldownMs: config.cooldownMs ?? this.mouseVelConfig.cooldownMs,\n };\n }\n }\n\n /** Feed a mouse-position sample. Recomputes the rolling-window\n * velocity-to-top and fires `mouse_velocity_to_top` when the value\n * crosses the configured threshold (subject to cooldown). */\n noteMousePosition(x: number, y: number, timestamp: number = Date.now()): number {\n if (!this.mouseVelEnabled) return 0;\n const cutoff = timestamp - this.mouseVelConfig.windowMs;\n // Trim expired samples from the head; keep the buffer small.\n let trimStart = 0;\n while (trimStart < this.mouseSamples.length && this.mouseSamples[trimStart].ts < cutoff) {\n trimStart++;\n }\n if (trimStart > 0) this.mouseSamples = this.mouseSamples.slice(trimStart);\n this.mouseSamples.push({ x, y, ts: timestamp });\n\n // Velocity-to-top = -(dy / dt) over the oldest-to-newest pair in\n // the window. Positive value = moving up. With 2+ samples this is\n // the instantaneous slope across the window; with 1 sample we\n // return 0 (cannot compute velocity from a single point).\n if (this.mouseSamples.length < 2) {\n this.mouseVelLast = 0;\n return 0;\n }\n const oldest = this.mouseSamples[0];\n const newest = this.mouseSamples[this.mouseSamples.length - 1];\n const dt = newest.ts - oldest.ts;\n if (dt <= 0) {\n this.mouseVelLast = 0;\n return 0;\n }\n const velocity = -(newest.y - oldest.y) / dt; // px/ms; up = +\n this.mouseVelLast = velocity;\n\n // Threshold + cooldown firing. Initial state allows the first fire\n // — only subsequent fires within cooldownMs of the prior are gated.\n const cooldownOk =\n this.mouseVelLastFiredAt === 0 ||\n timestamp - this.mouseVelLastFiredAt >= this.mouseVelConfig.cooldownMs;\n if (velocity >= this.mouseVelConfig.threshold && cooldownOk) {\n this.mouseVelLastFiredAt = timestamp;\n this.emit('mouse_velocity_to_top', {\n velocity,\n threshold: this.mouseVelConfig.threshold,\n window_ms: this.mouseVelConfig.windowMs,\n samples: this.mouseSamples.length,\n });\n }\n return velocity;\n }\n\n /** Snapshot the current velocity-to-top in px/ms (positive = up).\n * Returns 0 when not enabled or insufficient samples. */\n getMouseVelocityToTop(): number {\n return this.mouseVelEnabled ? this.mouseVelLast : 0;\n }\n\n /**\n * Snapshot the hover dwell for an intent.\n * - Currently hovering: returns `Date.now() - hover_start_at`.\n * - Hovered before, not currently: returns the most recent hover's\n * duration (sticky — the rule evaluator queries this AFTER\n * mouseleave to see \"did Priya hover the price ≥ 1.5s?\").\n * - Never hovered: returns 0.\n */\n getHoverMs(intent: string): number {\n if (!this.hoverEnabled) return 0;\n const startAt = this.hoverStartAt.get(intent);\n if (startAt !== undefined) {\n return Math.max(0, Date.now() - startAt);\n }\n return this.hoverLastMs.get(intent) ?? 0;\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 Config Poller\n *\n * Fetches non-sensitive SDK configuration from GET /v1/sdk/config\n * with ETag/If-None-Match support for 304 responses.\n *\n * Polls every 5 minutes by default. Config changes are applied\n * to push/in-app managers without re-initialization.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface SdkConfig {\n version: string;\n push: {\n enabled: boolean;\n vapid_public_key: string | null;\n platforms: string[];\n };\n in_app: {\n enabled: boolean;\n };\n consent: {\n channels_requiring_opt_in: string[];\n };\n}\n\nexport interface SdkConfigPollerOptions {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n pollIntervalMs?: number;\n}\n\nexport type ConfigChangeCallback = (config: SdkConfig) => void;\n\nexport class SdkConfigPoller {\n private options: Required<Omit<SdkConfigPollerOptions, 'organizationId'>> & { organizationId?: string };\n private currentETag: string | null = null;\n private currentConfig: SdkConfig | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private listeners: ConfigChangeCallback[] = [];\n\n constructor(options: SdkConfigPollerOptions) {\n this.options = {\n pollIntervalMs: 300_000, // 5 minutes\n ...options,\n };\n }\n\n /**\n * Fetch config once (on init) and start polling.\n */\n async start(): Promise<SdkConfig | null> {\n const config = await this.fetchConfig();\n\n this.pollTimer = setInterval(() => {\n this.fetchConfig().catch((err) => {\n logger.warn('SDK config poll failed:', err);\n });\n }, this.options.pollIntervalMs);\n\n return config;\n }\n\n /**\n * Stop polling.\n */\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n /**\n * Register a callback for config changes.\n */\n onChange(callback: ConfigChangeCallback): () => void {\n this.listeners.push(callback);\n return () => {\n const idx = this.listeners.indexOf(callback);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n /**\n * Get current cached config.\n */\n getConfig(): SdkConfig | null {\n return this.currentConfig;\n }\n\n /**\n * Fetch config with ETag/304 support.\n */\n private async fetchConfig(): Promise<SdkConfig | null> {\n try {\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.options.writeKey,\n 'Accept': 'application/json',\n };\n\n if (this.options.organizationId) {\n headers['X-Organization-ID'] = this.options.organizationId;\n }\n\n if (this.currentETag) {\n headers['If-None-Match'] = this.currentETag;\n }\n\n const response = await fetch(`${this.options.apiHost}/v1/sdk/config`, {\n method: 'GET',\n headers,\n });\n\n // 304 Not Modified — config unchanged\n if (response.status === 304) {\n return this.currentConfig;\n }\n\n if (!response.ok) {\n logger.warn(`SDK config fetch failed: HTTP ${response.status}`);\n return this.currentConfig;\n }\n\n const config: SdkConfig = await response.json();\n const newETag = response.headers.get('ETag');\n\n if (newETag) {\n this.currentETag = newETag;\n }\n\n // Detect changes\n const changed = !this.currentConfig ||\n JSON.stringify(this.currentConfig) !== JSON.stringify(config);\n\n this.currentConfig = config;\n\n if (changed) {\n for (const listener of this.listeners) {\n try {\n listener(config);\n } catch (err) {\n logger.warn('SDK config change listener error:', err);\n }\n }\n }\n\n return config;\n } catch (err) {\n logger.warn('SDK config fetch error:', err);\n return this.currentConfig;\n }\n }\n}\n","/**\n * PrefetchBundleClient — unified init-time resolver for in-app state.\n *\n * Fetches /v1/sdk/prefetch-bundle at SDK init and on a 5-minute ETag\n * refresh cadence. The bundle payload carries:\n * • `campaigns[]` — eligible, property-scoped, A/B-assigned campaigns\n * armed for this contact. EVERY in-app type is in\n * here (modal, banner, spin_wheel, carousel_cards,\n * sticky_bar, progress_bar, coachmark_tour, etc.).\n * • `inbox` — first page + unread count for the notification\n * drawer; lets AegisInbox hydrate without a second\n * round-trip.\n * • `etag` — content-hashed, stable when state is unchanged;\n * 304 responses cost ~50ms and consume no body.\n * • `invalidation_topic` — SSE channel name the cell-plane publishes\n * to when a playbook arms a campaign mid-session.\n * The SDK does NOT open SSE on that topic today —\n * we rely on the 5-minute poll + an explicit\n * `refresh()` hook that app code (AegisInAppManager,\n * AegisInbox) call on relevant user actions.\n *\n * This is the cornerstone of the preload-first contract from\n * docs/architecture/IN_APP_MESSAGES_EXPANSION_PLAN.md §1. The render\n * path must NEVER hit the network at trigger time — the bundle is\n * populated at init, and everything renders from memory.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface PrefetchBundleCampaign {\n id: string;\n type: string;\n sub_type?: string;\n title: string;\n body: string;\n image_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 | null;\n frequency?: {\n max_impressions?: number;\n max_impressions_per_day?: number;\n cooldown_seconds?: number;\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 inbox_enabled?: boolean;\n}\n\nexport interface PrefetchBundleInboxEntry {\n id: string;\n source: string;\n campaign_id: string | null;\n title: string;\n body: string;\n media_url: string | null;\n cta_url: string | null;\n metadata: Record<string, unknown> | null;\n read: boolean;\n read_at: string | null;\n created_at: string | null;\n expires_at: string | null;\n}\n\nexport interface PrefetchBundleInbox {\n unread_count: number;\n page: PrefetchBundleInboxEntry[];\n cursor: string | null;\n}\n\nexport interface PrefetchBundle {\n etag: string;\n generated_at: string;\n ttl_seconds: number;\n invalidation_topic: string;\n campaigns: PrefetchBundleCampaign[];\n inbox: PrefetchBundleInbox;\n}\n\nexport interface PrefetchBundleContext {\n device_type?: string;\n page_url?: string;\n geo?: string;\n is_new_user?: boolean;\n}\n\nexport interface PrefetchBundleClientOptions {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n contactId?: string;\n userId?: string;\n propertyId?: string;\n /** Cached AB assignments from localStorage, base64-json. */\n abAssignments?: Record<string, string>;\n /** Polling cadence; defaults to the bundle's own `ttl_seconds` (300s). */\n pollIntervalMs?: number;\n /** Factory for client context — re-evaluated on each fetch so device/page\n * state stays fresh without forcing callers to re-instantiate the client. */\n contextProvider?: () => PrefetchBundleContext;\n}\n\nexport type PrefetchBundleListener = (bundle: PrefetchBundle) => void;\n\nconst DEFAULT_POLL_MS = 300_000; // 5 minutes — aligns with cell-plane TTL\n\nexport class PrefetchBundleClient {\n private apiHost: string;\n private writeKey: string;\n private organizationId?: string;\n private contactId?: string;\n private userId?: string;\n private propertyId?: string;\n private abAssignments: Record<string, string>;\n private pollIntervalMs: number;\n private contextProvider: () => PrefetchBundleContext;\n\n private currentETag: string | null = null;\n private currentBundle: PrefetchBundle | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private listeners: PrefetchBundleListener[] = [];\n private inflightRefetch: Promise<PrefetchBundle | null> | null = null;\n\n constructor(options: PrefetchBundleClientOptions) {\n this.apiHost = options.apiHost;\n this.writeKey = options.writeKey;\n this.organizationId = options.organizationId;\n this.contactId = options.contactId;\n this.userId = options.userId;\n this.propertyId = options.propertyId;\n this.abAssignments = options.abAssignments ?? {};\n this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_MS;\n this.contextProvider = options.contextProvider ?? (() => ({}));\n }\n\n /**\n * Initial fetch + start the background ETag poll. Resolves to the bundle\n * (or `null` if the first fetch failed — callers should fall back to an\n * empty campaign list, not abort SDK init).\n */\n async start(): Promise<PrefetchBundle | null> {\n const bundle = await this.fetch();\n this.pollTimer = setInterval(() => {\n this.fetch().catch((err) => logger.warn('prefetch-bundle poll failed:', err));\n }, this.pollIntervalMs);\n return bundle;\n }\n\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n getBundle(): PrefetchBundle | null {\n return this.currentBundle;\n }\n\n getCampaigns(): PrefetchBundleCampaign[] {\n return this.currentBundle?.campaigns ?? [];\n }\n\n getInbox(): PrefetchBundleInbox {\n return this.currentBundle?.inbox ?? { unread_count: 0, page: [], cursor: null };\n }\n\n /** Force a refresh (dedupes concurrent calls). Exposed so inbox mutations\n * and campaign-activation SSE messages can trigger a refetch on demand. */\n async refresh(): Promise<PrefetchBundle | null> {\n if (this.inflightRefetch) return this.inflightRefetch;\n this.inflightRefetch = this.fetch();\n try {\n return await this.inflightRefetch;\n } finally {\n this.inflightRefetch = null;\n }\n }\n\n /** Subscribe to bundle changes (emits on first fetch + on any content\n * change — ETag 304 does NOT fire the listener). Returns an unsubscribe. */\n onChange(listener: PrefetchBundleListener): () => void {\n this.listeners.push(listener);\n return () => {\n const idx = this.listeners.indexOf(listener);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n /**\n * Update the identity tuple — called by AegisInAppManager when the host\n * app resolves a contactId post-init (e.g., after login). Triggers an\n * immediate refresh since the eligible campaigns + inbox will differ.\n */\n updateIdentity(partial: {\n contactId?: string;\n userId?: string;\n organizationId?: string;\n propertyId?: string;\n }): void {\n let changed = false;\n if (partial.contactId !== undefined && partial.contactId !== this.contactId) {\n this.contactId = partial.contactId;\n changed = true;\n }\n if (partial.userId !== undefined && partial.userId !== this.userId) {\n this.userId = partial.userId;\n changed = true;\n }\n if (\n partial.organizationId !== undefined &&\n partial.organizationId !== this.organizationId\n ) {\n this.organizationId = partial.organizationId;\n changed = true;\n }\n if (partial.propertyId !== undefined && partial.propertyId !== this.propertyId) {\n this.propertyId = partial.propertyId;\n changed = true;\n }\n if (changed) {\n // Identity change invalidates ETag — drop the cached tag so the next\n // fetch gets a fresh payload instead of a 304 bound to the old identity.\n this.currentETag = null;\n this.refresh().catch((err) =>\n logger.warn('prefetch-bundle identity-refresh failed:', err),\n );\n }\n }\n\n /** Update cached AB assignments. Called by downstream renderers after\n * they display a variant. Persisted to localStorage by higher layers. */\n setAbAssignments(assignments: Record<string, string>): void {\n this.abAssignments = { ...assignments };\n }\n\n /**\n * Wire an already-open realtime subscriber (from `aegis.realtime.subscribe`\n * or a caller-provided EventSource) so the prefetch bundle refreshes\n * instantly when the cell-plane signals `bundle.invalidate` — covering\n * the window between an event (cart abandon, inbox write) and the\n * 5-min ETag poll.\n *\n * `subscriber.onMessage(handler)` must fire with parsed message bodies\n * from the contact's SSE stream. The handler filters for\n * `type === 'bundle.invalidate'` and calls `refresh()`. Returns an\n * unsubscribe function.\n *\n * Degrades gracefully: if the subscriber is missing or throws, the\n * 5-min poll still keeps state converging.\n */\n subscribeInvalidations(subscriber: {\n onMessage: (handler: (msg: { type?: string; [k: string]: unknown }) => void) => () => void;\n }): () => void {\n try {\n const unsub = subscriber.onMessage((msg) => {\n if (msg && msg.type === 'bundle.invalidate') {\n this.refresh().catch((err) =>\n logger.warn('prefetch-bundle invalidate-refresh failed:', err),\n );\n }\n });\n return unsub;\n } catch (err) {\n logger.warn('prefetch-bundle subscribeInvalidations failed — relying on poll:', err);\n return () => {};\n }\n }\n\n // ── internals ──────────────────────────────────────────────────────────\n\n private async fetch(): Promise<PrefetchBundle | null> {\n const ctx = this.contextProvider();\n const qs = new URLSearchParams();\n if (ctx.device_type) qs.set('device_type', ctx.device_type);\n if (ctx.page_url) qs.set('page_url', ctx.page_url);\n if (ctx.geo) qs.set('geo', ctx.geo);\n qs.set('is_new_user', ctx.is_new_user ? 'true' : 'false');\n\n const url = `${this.apiHost}/v1/sdk/prefetch-bundle?${qs.toString()}`;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n Accept: 'application/json',\n };\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.propertyId) headers['X-Property-Id'] = this.propertyId;\n if (this.currentETag) headers['If-None-Match'] = this.currentETag;\n if (Object.keys(this.abAssignments).length > 0) {\n try {\n headers['X-AB-Assignments'] = btoa(JSON.stringify(this.abAssignments));\n } catch {\n // base64 on non-ASCII campaign IDs — skip rather than 400 the request\n }\n }\n\n let response: Response;\n try {\n response = await fetch(url, { method: 'GET', headers });\n } catch (err) {\n logger.warn('prefetch-bundle fetch network error:', err);\n return this.currentBundle;\n }\n\n // 304 — same bundle; listeners are intentionally NOT fired.\n if (response.status === 304) {\n return this.currentBundle;\n }\n\n if (!response.ok) {\n logger.warn(`prefetch-bundle fetch failed: HTTP ${response.status}`);\n return this.currentBundle;\n }\n\n const etag = response.headers.get('ETag');\n let bundle: PrefetchBundle;\n try {\n bundle = (await response.json()) as PrefetchBundle;\n } catch (err) {\n logger.warn('prefetch-bundle invalid JSON:', err);\n return this.currentBundle;\n }\n\n if (etag) this.currentETag = etag;\n this.currentBundle = bundle;\n\n for (const l of this.listeners) {\n try {\n l(bundle);\n } catch (err) {\n logger.warn('prefetch-bundle listener threw:', err);\n }\n }\n\n return bundle;\n }\n}\n","/**\n * AegisInbox — client-side App Inbox (Message Center).\n *\n * Backs the notification drawer on actii.me WebView and every tenant\n * storefront that embeds the Web SDK. Operates against cell-plane's\n * /v1/in-app/inbox family of endpoints (list, unread-count, read,\n * dismiss, read-all).\n *\n * Design choices:\n * • Hydrate from the prefetch bundle at init — no extra HTTP on first\n * paint. PrefetchBundleClient seeds us; we then own the live copy.\n * • Mutations are optimistic + beacon-backed. Read / dismiss writes to\n * local state immediately, then POSTs with `keepalive: true` so an\n * in-flight dismiss survives page unload.\n * • Badge polling uses the tiny `/unread-count` endpoint on a 60-second\n * cadence — matches the `inbox_poll_interval_ms` from sdk_config's\n * TransportConfig.hybrid mode.\n * • No external dependencies; IndexedDB is optional (we gracefully fall\n * back to in-memory when unavailable, e.g., in private browsing).\n */\n\nimport type { PrefetchBundleClient } from '../core/prefetch-bundle-client';\nimport { logger } from '../utils/logger';\n\nexport interface AegisInboxEntry {\n id: string;\n source: string;\n campaign_id: string | null;\n title: string;\n body: string;\n media_url: string | null;\n cta_url: string | null;\n metadata: Record<string, unknown> | null;\n read: boolean;\n read_at: string | null;\n dismissed_at?: string | null;\n created_at: string | null;\n expires_at: string | null;\n}\n\nexport interface AegisInboxConfig {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n contactId?: string;\n propertyId?: string;\n bundleClient?: PrefetchBundleClient;\n unreadPollIntervalMs?: number;\n}\n\nexport type InboxListener = (state: { entries: AegisInboxEntry[]; unreadCount: number }) => void;\n\nconst DEFAULT_UNREAD_POLL = 60_000;\n\n/** IndexedDB schema version + constants. Offline cache is a nice-to-have,\n * so we never break the app if IDB operations fail. */\nconst IDB_NAME = 'aegis-inbox';\nconst IDB_STORE = 'messages';\nconst IDB_VERSION = 1;\n\nexport class AegisInbox {\n private apiHost: string;\n private writeKey: string;\n private organizationId?: string;\n private contactId?: string;\n private propertyId?: string;\n private bundleClient?: PrefetchBundleClient;\n private unreadPollIntervalMs: number;\n\n private entries: AegisInboxEntry[] = [];\n private unreadCount = 0;\n private cursor: string | null = null;\n private listeners: InboxListener[] = [];\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private bundleUnsub: (() => void) | null = null;\n\n constructor(config: AegisInboxConfig) {\n this.apiHost = config.apiHost;\n this.writeKey = config.writeKey;\n this.organizationId = config.organizationId;\n this.contactId = config.contactId;\n this.propertyId = config.propertyId;\n this.bundleClient = config.bundleClient;\n this.unreadPollIntervalMs = config.unreadPollIntervalMs ?? DEFAULT_UNREAD_POLL;\n }\n\n /** Hydrate from bundle (if available), restore the IDB cache (if any),\n * then start the background unread-count poll. */\n async initialize(): Promise<void> {\n // Inbox is contact-scoped — if the host app hasn't resolved a contact\n // yet, stay dormant. The host will call setIdentity() later.\n if (!this.contactId || !this.propertyId) {\n logger.warn('AegisInbox: no contact/property yet — staying dormant');\n return;\n }\n\n // Try IDB cache for instant paint on cold start.\n const cached = await this.readCache();\n if (cached.length > 0) {\n this.entries = cached;\n this.recomputeUnread();\n this.emit();\n }\n\n // Hydrate from prefetch bundle if we have one — this is the preload\n // path, no additional network round-trip.\n if (this.bundleClient) {\n const inbox = this.bundleClient.getInbox();\n this.seedFromBundle(inbox.page, inbox.unread_count);\n // Keep following bundle changes — when the bundle-poller refreshes,\n // the inbox slice refreshes too.\n this.bundleUnsub = this.bundleClient.onChange((bundle) => {\n this.seedFromBundle(bundle.inbox.page, bundle.inbox.unread_count);\n });\n } else {\n // No bundle client — do one list call to prime.\n await this.refreshList();\n }\n\n this.pollTimer = setInterval(() => {\n this.refreshUnreadCount().catch((err) =>\n logger.warn('inbox unread-count poll failed:', err),\n );\n }, this.unreadPollIntervalMs);\n }\n\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n if (this.bundleUnsub) {\n this.bundleUnsub();\n this.bundleUnsub = null;\n }\n }\n\n /** Update identity after login / property switch. Clears the local\n * inbox since it's intrinsically contact+property scoped. */\n setIdentity(partial: { contactId?: string; propertyId?: string; organizationId?: string }): void {\n let changed = false;\n if (partial.contactId !== undefined && partial.contactId !== this.contactId) {\n this.contactId = partial.contactId;\n changed = true;\n }\n if (partial.propertyId !== undefined && partial.propertyId !== this.propertyId) {\n this.propertyId = partial.propertyId;\n changed = true;\n }\n if (partial.organizationId !== undefined && partial.organizationId !== this.organizationId) {\n this.organizationId = partial.organizationId;\n changed = true;\n }\n if (changed) {\n this.entries = [];\n this.unreadCount = 0;\n this.cursor = null;\n this.emit();\n void this.clearCache();\n void this.refreshList();\n }\n }\n\n // ── Read-side API ────────────────────────────────────────────────────\n\n getEntries(): AegisInboxEntry[] {\n return this.entries;\n }\n\n getUnreadCount(): number {\n return this.unreadCount;\n }\n\n /** Pagination cursor (ISO-8601 timestamp of the oldest entry currently\n * held). Pass it back via `loadMore()` to fetch older history. */\n getCursor(): string | null {\n return this.cursor;\n }\n\n /** Append one more page of older entries using the current cursor. */\n async loadMore(): Promise<void> {\n if (!this.contactId || !this.propertyId || !this.cursor) return;\n try {\n const url = `${this.apiHost}/v1/in-app/inbox?limit=20&cursor=${encodeURIComponent(this.cursor)}`;\n const resp = await fetch(url, { headers: this.headers() });\n if (!resp.ok) return;\n const body = (await resp.json()) as {\n entries: AegisInboxEntry[];\n unread_count: number;\n cursor: string | null;\n };\n const byId = new Set(this.entries.map((e) => e.id));\n for (const e of body.entries) {\n if (!byId.has(e.id)) this.entries.push(e);\n }\n this.cursor = body.cursor;\n void this.writeCache();\n this.emit();\n } catch (err) {\n logger.warn('inbox loadMore failed:', err);\n }\n }\n\n onChange(l: InboxListener): () => void {\n this.listeners.push(l);\n return () => {\n const i = this.listeners.indexOf(l);\n if (i >= 0) this.listeners.splice(i, 1);\n };\n }\n\n async refreshList(): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n const resp = await fetch(\n `${this.apiHost}/v1/in-app/inbox?limit=20`,\n { headers: this.headers() },\n );\n if (!resp.ok) {\n logger.warn(`inbox list fetch failed: HTTP ${resp.status}`);\n return;\n }\n const body = (await resp.json()) as {\n entries: AegisInboxEntry[];\n unread_count: number;\n cursor: string | null;\n };\n this.entries = body.entries;\n this.unreadCount = body.unread_count;\n this.cursor = body.cursor;\n void this.writeCache();\n this.emit();\n } catch (err) {\n logger.warn('inbox list fetch error:', err);\n }\n }\n\n async refreshUnreadCount(): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n const resp = await fetch(\n `${this.apiHost}/v1/in-app/inbox/unread-count`,\n { headers: this.headers() },\n );\n if (!resp.ok) return;\n const body = (await resp.json()) as { unread_count: number };\n if (body.unread_count !== this.unreadCount) {\n this.unreadCount = body.unread_count;\n this.emit();\n // New messages detected — do a list refresh to get them.\n if (this.unreadCount > 0) {\n void this.refreshList();\n }\n }\n } catch {\n /* swallow — transient network */\n }\n }\n\n // ── Mutations (optimistic + beacon) ──────────────────────────────────\n\n async markRead(messageId: string): Promise<void> {\n const entry = this.entries.find((e) => e.id === messageId);\n if (!entry || entry.read) return;\n entry.read = true;\n entry.read_at = new Date().toISOString();\n this.recomputeUnread();\n void this.writeCache();\n this.emit();\n await this.postBeacon(`/v1/in-app/inbox/${messageId}/read`);\n }\n\n async dismiss(messageId: string): Promise<void> {\n const idx = this.entries.findIndex((e) => e.id === messageId);\n if (idx < 0) return;\n const [entry] = this.entries.splice(idx, 1);\n if (entry && !entry.read) {\n this.recomputeUnread();\n }\n void this.writeCache();\n this.emit();\n await this.postBeacon(`/v1/in-app/inbox/${messageId}/dismiss`);\n }\n\n async markAllRead(): Promise<void> {\n const now = new Date().toISOString();\n for (const e of this.entries) {\n if (!e.read) {\n e.read = true;\n e.read_at = now;\n }\n }\n this.unreadCount = 0;\n void this.writeCache();\n this.emit();\n await this.postBeacon('/v1/in-app/inbox/read-all');\n }\n\n // ── Internals ────────────────────────────────────────────────────────\n\n private seedFromBundle(page: AegisInboxEntry[], unreadCount: number): void {\n // Merge rather than overwrite — an entry we already marked read\n // locally should stay read even if the bundle is slightly stale.\n const byId = new Map(this.entries.map((e) => [e.id, e] as const));\n const merged = page.map((incoming) => {\n const existing = byId.get(incoming.id);\n if (existing && existing.read && !incoming.read) {\n return { ...incoming, read: true, read_at: existing.read_at };\n }\n return incoming;\n });\n // Preserve any locally-cached entries that aren't in this bundle page\n // (e.g., older history not included in the first slice).\n for (const [id, e] of byId) {\n if (!merged.find((m) => m.id === id)) merged.push(e);\n }\n merged.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || ''));\n this.entries = merged;\n this.unreadCount = unreadCount;\n void this.writeCache();\n this.emit();\n }\n\n private recomputeUnread(): void {\n this.unreadCount = this.entries.filter((e) => !e.read).length;\n }\n\n private emit(): void {\n const snapshot = { entries: [...this.entries], unreadCount: this.unreadCount };\n for (const l of this.listeners) {\n try {\n l(snapshot);\n } catch (err) {\n logger.warn('inbox listener threw:', err);\n }\n }\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n Accept: 'application/json',\n };\n if (this.organizationId) h['X-Organization-ID'] = this.organizationId;\n if (this.contactId) h['X-Contact-ID'] = this.contactId;\n if (this.propertyId) h['X-Property-Id'] = this.propertyId;\n return h;\n }\n\n /** Best-effort beacon-style POST. Uses `keepalive: true` so it survives\n * a navigation away from the current page (e.g., user taps the CTA\n * which takes them to another URL right after dismiss). */\n private async postBeacon(path: string): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n await fetch(`${this.apiHost}${path}`, {\n method: 'POST',\n headers: this.headers(),\n keepalive: true,\n });\n } catch (err) {\n // The mutation is already applied locally; failed delivery will be\n // reconciled on the next refreshList().\n logger.warn(`inbox mutation POST ${path} failed:`, err);\n }\n }\n\n // ── IndexedDB cache (non-critical) ───────────────────────────────────\n\n private async openDb(): Promise<IDBDatabase | null> {\n if (typeof indexedDB === 'undefined') return null;\n return new Promise((resolve) => {\n try {\n const req = indexedDB.open(IDB_NAME, IDB_VERSION);\n req.onerror = () => resolve(null);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE)) {\n db.createObjectStore(IDB_STORE);\n }\n };\n req.onsuccess = () => resolve(req.result);\n } catch {\n resolve(null);\n }\n });\n }\n\n private cacheKey(): string | null {\n if (!this.contactId || !this.propertyId) return null;\n return `${this.organizationId || 'default'}:${this.propertyId}:${this.contactId}`;\n }\n\n private async writeCache(): Promise<void> {\n const key = this.cacheKey();\n if (!key) return;\n const db = await this.openDb();\n if (!db) return;\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).put(this.entries, key);\n await new Promise<void>((res, rej) => {\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n } catch {\n /* noop */\n } finally {\n db.close();\n }\n }\n\n private async readCache(): Promise<AegisInboxEntry[]> {\n const key = this.cacheKey();\n if (!key) return [];\n const db = await this.openDb();\n if (!db) return [];\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const req = tx.objectStore(IDB_STORE).get(key);\n return await new Promise<AegisInboxEntry[]>((res) => {\n req.onsuccess = () => res((req.result as AegisInboxEntry[]) || []);\n req.onerror = () => res([]);\n });\n } catch {\n return [];\n } finally {\n db.close();\n }\n }\n\n private async clearCache(): Promise<void> {\n const key = this.cacheKey();\n if (!key) return;\n const db = await this.openDb();\n if (!db) return;\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).delete(key);\n await new Promise<void>((res) => {\n tx.oncomplete = () => res();\n tx.onerror = () => res();\n });\n } catch {\n /* noop */\n } finally {\n db.close();\n }\n }\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 * Workspace cascade reader. Host SDK sets this to\n * `() => aegis.getEffectiveWorkspaceId()` so widget interaction events\n * (impressions, clicks, spin/scratch plays, feedback submissions)\n * arrive at the gateway with the same workspace context the main\n * analytics SDK uses. See PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n */\n getWorkspaceId?: () => string | undefined;\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 private getWorkspaceId?: () => string | undefined;\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 this.getWorkspaceId = config.getWorkspaceId;\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 this.emitEvent('destroyed', {});\n }\n\n /**\n * Fire a lifecycle event to the consumer-supplied callback. Public-API\n * hook configured via `AegisWidgetConfig.onEvent`. Currently only used\n * by external callers passing their own logger; internal widget lifecycle\n * events get wired through here as they're added.\n */\n private emitEvent(eventType: string, data: unknown): 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 // Plumb workspace cascade so feedback submissions are attributed to\n // the same outlet the customer was viewing. See\n // PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n const workspaceId = this.getWorkspaceId?.();\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 workspace_id: workspaceId,\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 const workspaceId = this.getWorkspaceId?.();\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 workspace_id: workspaceId,\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 * 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\n constructor(config: AegisMessageRuntimeConfig) {\n const triggerEngine = config.triggerEngine ?? new TriggerEngine();\n const ownsTriggerEngine = !config.triggerEngine;\n // Ownership of the engine is tracked downstream by WidgetManager\n // (which is the only consumer that needs to call lifecycle methods\n // on it). The facade itself only forwards.\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 getWorkspaceId: config.getWorkspaceId,\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 getWorkspaceId: config.getWorkspaceId,\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.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 * 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 * @deprecated since P15.1 (2026-05-26) — use `locationCodes` instead.\n * Pre-2026-05-26 the path segment after the brand subdomain was a\n * workspace_code; the canonical hierarchy reversal made it a\n * location_code (outlet under a brand). Field name retained for\n * backward compat with SDK consumers that haven't migrated; new\n * consumers MUST read `locationCodes`. Server still populates BOTH\n * with the same array during the deprecation window so a stale\n * SDK keeps working.\n */\n workspaceCodes: string[];\n /**\n * P15.1 — outlet-code allowlist for SDK path-segment detection.\n * Empty array = no outlet codes registered for this org (single-\n * outlet tenant). SDK uses this set to decide whether\n * `location.pathname.split('/')[1]` is a valid outlet code vs a\n * generic route (`/products`, `/collections`). Pass to\n * `aegis.ingestLocationCodes()` after bootstrap completes.\n *\n * Same array contents as `workspaceCodes` during the deprecation\n * window — renaming the field gives semantic clarity (these ARE\n * location codes under the new hierarchy) without breaking\n * existing consumers.\n */\n locationCodes: string[];\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';\n\nconst aegis = new Aegis();\n\nexport default aegis;\n\nexport { Aegis } from './core/analytics';\nexport type { AegisConfig, CellEndpoint, CellRegion } from './types/config';\nexport type {\n AegisEvent,\n TrackEvent,\n IdentifyEvent,\n PageEvent,\n ScreenEvent,\n GroupEvent,\n AliasEvent,\n EventContext,\n BatchPayload,\n BatchResponse,\n} from './types/events';\nexport { UserNamespace } from './core/user-namespace';\nexport type { OptInChannel } from './core/user-namespace';\nexport type { Plugin, PluginRegistry } from './types/plugin';\nexport { debounce, throttle } from './utils/debounce';\nexport type {\n ConsentPreferences,\n ConsentCategory,\n ConsentStatus,\n} from './utils/consent';\n// In-app + widget types are re-exported for callers that configure\n// AegisMessageRuntime or read campaign objects. The underlying manager\n// classes are intentionally NOT exported — use AegisMessageRuntime.\nexport type {\n InAppCampaign,\n AegisInAppConfig,\n CampaignClickEvent,\n CampaignDismissEvent,\n AegisErrorEvent,\n InAppLifecycleEventMap,\n} from './inapp';\nexport { renderPreview } from './inapp';\n\nexport { AegisPlacementManager } from './placements/AegisPlacementManager';\nexport type {\n PlacementContent,\n PlacementSlot,\n AegisPlacementConfig,\n} from './placements/AegisPlacementManager';\n\nexport type {\n WidgetConfig,\n GamificationPrize,\n AegisWidgetConfig,\n} from './widgets';\n\nexport { TriggerEngine } from './triggers';\nexport type {\n TriggerRule,\n ScrollDepthConfig,\n TimeOnPageConfig,\n ExitIntentConfig,\n InactivityConfig,\n TriggerEvent,\n} from './triggers';\n\nexport { SdkConfigPoller } from './core/sdk-config-poller';\nexport type { SdkConfig, SdkConfigPollerOptions, ConfigChangeCallback } from './core/sdk-config-poller';\n\n// Preload-first bundle (2026-04-22) — fetches armed campaigns + inbox\n// slice once at init; everything renders from memory on trigger.\nexport { PrefetchBundleClient } from './core/prefetch-bundle-client';\nexport type {\n PrefetchBundle,\n PrefetchBundleCampaign,\n PrefetchBundleInbox,\n PrefetchBundleInboxEntry,\n PrefetchBundleClientOptions,\n PrefetchBundleContext,\n PrefetchBundleListener,\n} from './core/prefetch-bundle-client';\n\n// App Inbox — persistent message-center client.\nexport { AegisInbox } from './inbox';\nexport type { AegisInboxConfig, AegisInboxEntry, InboxListener } from './inbox';\n\n// Unified message runtime — the single entry point for in-app + widgets.\n// All 20 in-app types (modal/banner/tooltip/full_screen/spin_wheel/\n// scratch_card/nps_survey/quiz/countdown_offer/star_rating/...) flow\n// through this one class. The underlying AegisInAppManager +\n// AegisWidgetManager implementations are internal to the package.\nexport { AegisMessageRuntime } from './runtime';\nexport type { AegisMessageRuntimeConfig } from './runtime';\n\nexport { AegisWebPush } from './push/AegisWebPush';\nexport type {\n AegisWebPushConfig,\n AegisAPIClient,\n ContactIdentity,\n PushEventTracker,\n} from './push/AegisWebPush';\n\nexport {\n bootstrap,\n readFirstPartyCookie,\n writeFirstPartyCookie,\n deriveDeviceFingerprint,\n BootstrapError,\n} from './core/bootstrap';\nexport type { BootstrapRequest, BootstrapResult } from './core/bootstrap';\n\nexport { RateLimiter } from './core/rate-limiter';\nexport type { RateLimiterOptions } from './core/rate-limiter';\n\n// Event-governance — SDK-side cap enforcement. The NameGovernor is wired\n// into `Aegis.captureEvent()` automatically; callers only interact with it\n// via `aegis.ingestGovernanceHint(bootstrapResult.eventGovernance)`.\nexport { NameGovernor, BloomFilter, murmurhash3_x86_32 } from './governance';\nexport type { EventGovernanceHint, DropReport, BloomFilterParams } from './governance';\n\n// NOTE: SSE-based realtime subscription is intentionally NOT exported from the\n// public SDK surface. The Aegis Web SDK uses HTTP batch uplink + HTTP polling\n// downstream (via AegisInAppManager) + Web Push (via AegisWebPush). Tenant\n// dashboards that need SSE open it directly via their own Next.js API routes,\n// not through this SDK. See RFC 2026-04-16 §A.\n\nexport { EcommerceTracker } from './ecommerce';\nexport type {\n EcommerceProduct,\n EcommerceCart,\n EcommerceCheckout,\n EcommerceOrder,\n EcommerceCoupon,\n EcommerceSearch,\n EcommerceProductList,\n EcommerceWishlist,\n EcommerceWaitlist,\n EcommercePromotion,\n} from './ecommerce';\n"],"names":["goto","readAnonIdFromStorage","m","isMobile","mobileConfig"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/utils/debounce.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/renderers/product-recommendation.ts","../src/inapp/AegisInAppManager.ts","../src/inapp/renderPreview.ts","../src/placements/AegisPlacementManager.ts","../src/triggers/TriggerEngine.ts","../src/triggers/IntentRuleEvaluator.ts","../src/triggers/ContactScoresFetcher.ts","../src/core/sdk-config-poller.ts","../src/core/prefetch-bundle-client.ts","../src/inbox/AegisInbox.ts","../src/widgets/AegisWidgetManager.ts","../src/runtime/AegisMessageRuntime.ts","../src/core/bootstrap.ts","../src/index.ts"],"sourcesContent":["export function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n return function debounced(...args: Parameters<T>): void {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n\n timeoutId = setTimeout(() => {\n func(...args);\n timeoutId = null;\n }, wait);\n };\n}\n\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n limit: number\n): (...args: Parameters<T>) => void {\n let inThrottle = false;\n\n return function throttled(...args: Parameters<T>): void {\n if (!inThrottle) {\n func(...args);\n inThrottle = true;\n setTimeout(() => {\n inThrottle = false;\n }, limit);\n }\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 * 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 * 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 // F2 — campaign-delivery surface selection. When the array contains\n // 'embedded_card' AND the page has a `[data-aegis-slot=\"<widget_category>\"]`\n // anchor, the SDK renders this campaign INTO the slot (in addition to or\n // instead of an overlay; see `renderIntoSlots`). Defaults to\n // `['in_app_overlay']` server-side so legacy campaigns keep auto-overlay\n // behavior unchanged.\n delivery_modes?: Array<'in_app_overlay' | 'embedded_card' | 'standalone_page'>;\n // F3 — wide grouping discriminator used as the slot lookup key. A campaign\n // with `widget_category='feedback'` will fill the first\n // `[data-aegis-slot=\"feedback\"]` element on the page (if `embedded_card` is\n // among its delivery_modes).\n widget_category?: 'feedback' | 'loyalty' | 'promo' | 'commerce' | 'support' | 'custom';\n // F2 — page-key for `standalone_page` delivery mode. Read by the Next.js\n // route handler in `apps/cashier-portal/src/app/s/[slug]/[workspace]/[page_key]`.\n // Matches the existing storefront vocabulary (`rewards`/`members`)\n // in apps/cashier-portal/src/app/s/[slug]/{rewards,members}/page.tsx.\n page_key?: 'bill' | 'rewards' | 'feedback' | 'reviews' | 'members';\n}\n\n/**\n * Payload for `campaign-click` lifecycle event. CANCELLABLE — return `false`\n * (or call `evt.preventDefault()`) from the handler to suppress the SDK's\n * default `window.location.href` navigation, e.g. to route via a SPA router.\n */\nexport interface CampaignClickEvent {\n campaign: InAppCampaign;\n /** Sanitized destination URL — already passed through `sanitizeUrl()`. */\n action_url: string;\n /** Best-effort button identifier — populated when the click came from a\n * named button in a multi-button campaign (modals, alerts). `cta` for the\n * primary CTA on single-button campaigns. */\n button_id?: string;\n /** Mutate via `evt.preventDefault()` to signal the SDK to skip its\n * default hard-navigation. Identical semantics to DOM CustomEvent. */\n preventDefault: () => void;\n defaultPrevented: boolean;\n}\n\n/** Payload for `campaign-dismiss` lifecycle event. */\nexport interface CampaignDismissEvent {\n campaign: InAppCampaign;\n /** Source of dismissal — close button, swipe, ESC key, programmatic. */\n source: 'close_button' | 'overlay' | 'esc' | 'auto_timeout' | 'programmatic';\n}\n\n/** Payload for `error` lifecycle event. Aggregates non-fatal SDK errors so\n * host apps can wire them into Sentry / Datadog RUM / similar. */\nexport interface AegisErrorEvent {\n message: string;\n error: unknown;\n /** Optional structured context — `{ event: 'campaign-click' }` for handler\n * throws, `{ campaign_id, stage }` for render path failures, etc. */\n context: Record<string, unknown>;\n}\n\n/**\n * Map of lifecycle event name → handler signature. Used by the typed\n * `on(event, handler)` overload below so TS correctly narrows the payload\n * type per event without a discriminated union at the call site.\n */\nexport interface InAppLifecycleEventMap {\n 'campaigns-loaded': (campaigns: InAppCampaign[]) => void;\n 'campaign-will-show': (campaign: InAppCampaign) => void | false;\n 'campaign-shown': (campaign: InAppCampaign) => void;\n 'campaign-click': (evt: CampaignClickEvent) => void | false;\n 'campaign-dismiss': (evt: CampaignDismissEvent) => void;\n 'error': (evt: AegisErrorEvent) => void;\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 * Workspace cascade reader. Set this from the host SDK as\n * `getWorkspaceId: () => aegis.getEffectiveWorkspaceId()` so in-app\n * impressions/clicks/dismisses carry the same workspace context the\n * main analytics SDK sees (URL path slug, ?ws=, setWorkspace runtime).\n * Without it, in-app engagement events arrive at event-ingress with\n * no workspace_id stamped → cross-outlet attribution silently falls\n * back to the org's primary workspace.\n */\n getWorkspaceId?: () => string | undefined;\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 private getWorkspaceId?: () => string | undefined;\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 // ── Lifecycle event bus (1.8.0) ────────────────────────────────────────\n // Typed callback registry — host apps register handlers via the public\n // `on*` methods below. Each handler is stored once; calling the\n // returned unsubscribe fn removes it. Multiple subscribers per event are\n // supported. Callbacks that return `false` (or call `evt.preventDefault()`\n // on cancellable events) signal the SDK to skip its default behaviour.\n //\n // Industry parity: matches CleverTap `notificationCallback`, WebEngage\n // `onCallback`, MoEngage `onSelfHandledClick`, Iterable url-delegate, etc.\n // The DOM CustomEvent path (window.dispatchEvent('aegis:campaign-click'))\n // is preserved for backward compat + advanced multi-subscriber + pre-init\n // patterns where typed methods aren't reachable yet.\n private hooks = new Map<string, Set<(...args: unknown[]) => void | false | undefined>>();\n // `aegis.inApp.ready` resolves when the first refreshCampaigns completes\n // — matches CleverTap `onLoad`, WebEngage `onReady`. Lets host apps await\n // a known-good state before reading `campaigns` or registering handlers\n // that need armed campaigns visible.\n private readyResolve!: () => void;\n readonly ready: Promise<void> = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n\n private emit<T>(eventName: string, payload: T): boolean {\n const handlers = this.hooks.get(eventName);\n if (!handlers || handlers.size === 0) return true;\n let proceed = true;\n for (const handler of handlers) {\n try {\n const result = (handler as (p: T) => void | false | undefined)(payload);\n if (result === false) proceed = false;\n } catch (err) {\n // Don't let a misbehaving host handler crash the SDK render path.\n // Surface via onError but keep going for the remaining handlers.\n this.emitError(err, { event: eventName });\n }\n }\n return proceed;\n }\n\n private emitError(err: unknown, context?: Record<string, unknown>): void {\n const handlers = this.hooks.get('error');\n if (!handlers || handlers.size === 0) {\n // No subscriber — log to console so errors aren't completely silent.\n this.log(`Active Reach SDK error: ${err instanceof Error ? err.message : String(err)}`, 'error');\n return;\n }\n for (const handler of handlers) {\n try {\n (handler as (e: AegisErrorEvent) => void)({\n message: err instanceof Error ? err.message : String(err),\n error: err,\n context: context ?? {},\n });\n } catch {\n // ignore — we already tried to surface\n }\n }\n }\n\n private register<T>(\n eventName: string,\n handler: (payload: T) => void | false | undefined,\n ): () => void {\n if (!this.hooks.has(eventName)) this.hooks.set(eventName, new Set());\n this.hooks.get(eventName)!.add(handler as (...args: unknown[]) => void | false | undefined);\n return () => {\n this.hooks.get(eventName)?.delete(handler as (...args: unknown[]) => void | false | undefined);\n };\n }\n\n /**\n * Subscribe to in-app message lifecycle events. Returns an unsubscribe\n * function — call to remove the handler (matches React `useEffect` cleanup\n * convention).\n *\n * Supported events: `campaigns-loaded`, `campaign-will-show` (cancellable),\n * `campaign-shown`, `campaign-click` (cancellable), `campaign-dismiss`,\n * `error`. Cancellable events: handler returns `false` to suppress the\n * SDK's default behaviour (e.g., prevent the hard navigation on click,\n * skip rendering on will-show).\n */\n on<E extends keyof InAppLifecycleEventMap>(\n event: E,\n handler: InAppLifecycleEventMap[E],\n ): () => void {\n return this.register(event, handler as never);\n }\n\n /** Sugar: subscribe to `campaigns-loaded`. Fires after every successful\n * `/v1/in-app/active` poll with the full active-campaign list. */\n onCampaignsLoaded(\n handler: (campaigns: InAppCampaign[]) => void,\n ): () => void {\n return this.register('campaigns-loaded', handler);\n }\n\n /** Sugar: subscribe to `campaign-will-show`. CANCELLABLE — return `false`\n * to suppress rendering this campaign (host-side suppression rules,\n * route-aware blocking, etc.). */\n onCampaignWillShow(\n handler: (campaign: InAppCampaign) => void | false,\n ): () => void {\n return this.register('campaign-will-show', handler);\n }\n\n /** Sugar: subscribe to `campaign-shown`. Fires after the SDK has painted\n * the campaign to the DOM (post-impression). */\n onCampaignShown(\n handler: (campaign: InAppCampaign) => void,\n ): () => void {\n return this.register('campaign-shown', handler);\n }\n\n /** Sugar: subscribe to `campaign-click`. CANCELLABLE — return `false` (or\n * call `evt.preventDefault()`) to suppress the SDK's default\n * `window.location.href` navigation, e.g. to route via a SPA router. */\n onCampaignClick(\n handler: (evt: CampaignClickEvent) => void | false,\n ): () => void {\n return this.register('campaign-click', handler);\n }\n\n /** Sugar: subscribe to `campaign-dismiss`. Fires when user closes/swipes\n * away the campaign before clicking through. */\n onCampaignDismiss(\n handler: (evt: CampaignDismissEvent) => void,\n ): () => void {\n return this.register('campaign-dismiss', handler);\n }\n\n /** Sugar: subscribe to `error`. Aggregates non-fatal SDK errors — fetch\n * failures, render exceptions, host-handler throws. Wire this into your\n * error monitoring (Sentry, Datadog RUM, etc.). */\n onError(\n handler: (evt: AegisErrorEvent) => void,\n ): () => void {\n return this.register('error', handler);\n }\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 Active Reach 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 this.getWorkspaceId = config.getWorkspaceId;\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 // --- Qualifying-event refresh (DLR Tracker 1 / P1, 2026-05-28) ---------\n //\n // Burst-coalescing debounce timer for `refreshOnEvent`. Cleared and\n // re-armed on every call so a flurry of `aegis.track('cart_item_added')`\n // calls (e.g. 10 within 100ms while a shopper rapidly adds items)\n // collapses to a single `/v1/in-app/active` fetch ~300ms after the last\n // call. Without this debounce, an active storefront would hammer the\n // endpoint and our connection-load budget — see\n // memory/feedback_web_sdk_rest_not_sse.md for why polling has to stay\n // gentle.\n private refreshDebounceTimer?: ReturnType<typeof setTimeout>;\n private static readonly REFRESH_DEBOUNCE_MS = 300;\n\n /**\n * Qualifying-event refresh — schedule a debounced `refreshCampaigns()`\n * call in response to a host-app SDK event (`aegis.page()`,\n * `aegis.screen()`, `aegis.track(name)`). Matches CleverTap / MoEngage /\n * WebEngage's \"refresh on qualifying event\" shape, translated to the\n * browser session.\n *\n * Why: new server-side eligibility opens on these events (a `page` view\n * arms route-targeted campaigns; a `track('product_viewed')` arms\n * trigger-gated campaigns whose `client_trigger.config.event` matches).\n * Pre-P1, the SDK only refreshed on `initialize()` + `updateContactId()`\n * + the SSE update channel (which storefront has disabled by design),\n * so newly armed campaigns were invisible until the next identity flip.\n *\n * Debounce: 300ms. Five `page()` calls inside the window coalesce to\n * one fetch; a sixth call ≥300ms after the prior burst starts a new\n * fetch. The trailing-edge schedule (re-arm on every call) is correct\n * for storefront rage-clicks + SPA route bursts — we want the LATEST\n * URL's eligibility, not the first.\n *\n * Safe to call on the server (no-op when `setTimeout` is unavailable\n * — though that's vanishingly rare in any modern environment we ship to).\n *\n * `eventName` is currently used only for the debug log line; it's\n * preserved on the signature so a future P-phase can pass it through\n * to `/v1/in-app/active?trigger_event=<name>` for the optional\n * server-side eligibility-on-this-event optimization noted in the\n * P1 plan.\n */\n refreshOnEvent(eventName: string): void {\n if (!this.isInitialized) {\n // Pre-init events are silently dropped — the first refresh fires\n // from `initialize()` so there's nothing to coalesce against yet.\n this.log(`refreshOnEvent(${eventName}) before initialize — ignored`);\n return;\n }\n if (this.refreshDebounceTimer) {\n clearTimeout(this.refreshDebounceTimer);\n }\n this.refreshDebounceTimer = setTimeout(() => {\n this.refreshDebounceTimer = undefined;\n this.log(`refreshOnEvent(${eventName}) — firing refreshCampaigns()`);\n void this.refreshCampaigns();\n }, AegisInAppManager.REFRESH_DEBOUNCE_MS);\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', () => {\n this.log('SSE heartbeat received');\n });\n\n this.eventSource.addEventListener('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 // Lifecycle: `campaigns-loaded` — fires after every successful refresh\n // with the full active-campaign list. Host apps subscribe to drive\n // route-aware allowlists, sticky inboxes, badge counts, etc.\n this.emit('campaigns-loaded', this.campaigns);\n\n // Resolve `aegis.inApp.ready` after the FIRST successful poll so host\n // apps can `await aegis.inApp.ready` before reading `campaigns` or\n // making decisions that depend on a known-good initial state. Idempotent\n // — calling resolve() twice is a no-op for an already-settled promise.\n this.readyResolve();\n\n this.tryDisplayNextCampaign();\n\n // F2/F3 / U8 — fill any `[data-aegis-slot]` anchors with matching\n // `embedded_card`-mode campaigns. Independent of the overlay path:\n // a campaign with delivery_modes=[overlay,card] renders both ways\n // (overlay if conditions match + card if the page has a slot).\n // No-op when no slots are on the page.\n this.renderIntoSlots();\n\n // PR-B U7 — also fill any `[data-aegis-token-data]` anchors with\n // a server-injected campaign payload. Used by the standalone-page\n // route at `/s/[slug]/[workspace]/[page_key]?t=<token>`: the page\n // handler verifies the token server-side (via F16 internal),\n // embeds the resolved campaign data inline, and the SDK uses the\n // SAME renderer dispatch as the slot path. No separate widget\n // code, no public token-resolve endpoint.\n this.renderTokenAnchors();\n\n } catch (error) {\n this.emitError(error, { stage: 'refresh-campaigns' });\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 // --- F2/F3 / U8: embedded-card slot rendering ---------------------------\n //\n // Tracks slot DOM elements we've already filled so a second\n // refresh-cycle (SSE update, polling tick) doesn't re-render the same\n // campaign on top of itself. WeakSet so DOM removals get GC'd.\n private filledSlots = new WeakSet<Element>();\n\n /**\n * Scan the page for `[data-aegis-slot]` anchors and render any\n * campaign whose `widget_category` matches the slot key AND whose\n * `delivery_modes` includes `'embedded_card'`.\n *\n * Runs after every refresh-campaigns success — the WeakSet guard\n * keeps it idempotent across re-fetches. The slot key is the campaign's\n * `widget_category` (the wide grouping discriminator from F3), so a\n * `<div data-aegis-slot=\"feedback\">` will accept the first active\n * campaign with `widget_category='feedback'` + embedded_card mode.\n */\n private renderIntoSlots(): void {\n if (typeof document === 'undefined') return;\n const slots = document.querySelectorAll('[data-aegis-slot]');\n if (slots.length === 0) return;\n\n // First-active-per-category wins. Caller-side ordering of\n // `this.campaigns` is priority-sorted by the cell-plane endpoint.\n const eligibleByCategory = new Map<string, InAppCampaign>();\n for (const c of this.campaigns) {\n const modes = c.delivery_modes;\n const category = c.widget_category;\n if (!modes || !modes.includes('embedded_card')) continue;\n if (!category) continue;\n if (!eligibleByCategory.has(category)) {\n eligibleByCategory.set(category, c);\n }\n }\n if (eligibleByCategory.size === 0) return;\n\n slots.forEach((slot) => {\n if (this.filledSlots.has(slot)) return;\n const key = slot.getAttribute('data-aegis-slot');\n if (!key) return;\n const campaign = eligibleByCategory.get(key);\n if (!campaign) return;\n this.renderCampaignIntoSlot(campaign, slot as HTMLElement);\n this.filledSlots.add(slot);\n });\n }\n\n /**\n * U7 — render server-injected token-bound campaigns.\n *\n * The standalone-page route at `apps/cashier-portal/src/app/s/[slug]/\n * [workspace]/[page_key]/page.tsx` (and the `/c/[token]` Aegis-hosted\n * fallback) verify the URL token server-side via the F16 internal\n * endpoint, then embed the resolved campaign payload as JSON inside\n * a `<div data-aegis-token-data=\"...\">` anchor. This SDK method\n * scans for those anchors, parses the payload, and dispatches to\n * the SAME `renderCampaignIntoSlot` used by the [data-aegis-slot]\n * path — so widget rendering code is single-sourced.\n *\n * Why server-injected (not client-fetched): keeps INTERNAL_API_SECRET\n * server-side, avoids an extra browser round-trip for verify, gives\n * Next.js SSR-friendly initial HTML for SEO/no-JS users (rendered\n * via the page handler's React tree alongside the SDK anchor).\n *\n * Idempotency: filledSlots is the same WeakSet used by\n * renderIntoSlots — re-running on SSE/poll refresh is a no-op for\n * already-filled anchors.\n */\n private renderTokenAnchors(): void {\n if (typeof document === 'undefined') return;\n const anchors = document.querySelectorAll('[data-aegis-token-data]');\n if (anchors.length === 0) return;\n\n anchors.forEach((anchor) => {\n if (this.filledSlots.has(anchor)) return;\n const raw = anchor.getAttribute('data-aegis-token-data');\n if (!raw) return;\n\n let payload:\n | { campaign?: InAppCampaign; submit_url?: string }\n | null = null;\n try {\n payload = JSON.parse(raw);\n } catch (e) {\n this.log(\n `data-aegis-token-data: invalid JSON, skipping anchor (${e})`,\n 'warn',\n );\n this.filledSlots.add(anchor); // don't retry on next refresh\n return;\n }\n if (!payload || !payload.campaign || !payload.campaign.id) {\n this.log(\n 'data-aegis-token-data: missing `campaign` in payload, skipping',\n 'warn',\n );\n this.filledSlots.add(anchor);\n return;\n }\n\n // U7 step 3 — pass the submit_url through to the renderer so\n // click handlers can POST the structured response (rating value,\n // NPS score, etc.) and atomically consume the token.\n this.renderCampaignIntoSlot(\n payload.campaign,\n anchor as HTMLElement,\n { submitUrl: payload.submit_url },\n );\n this.filledSlots.add(anchor);\n });\n }\n\n /**\n * Slot-mode counterpart to `displayCampaign`. Reuses the existing\n * lifecycle hooks (`campaign-will-show`, `displayedCampaigns`,\n * `campaign-shown`, impression tracking) so analytics + frequency\n * caps work the same way as overlay renders.\n *\n * Only the sub_types that make UX sense embedded are handled; the\n * rest (modal, full_screen, half_interstitial, alert, pip) silently\n * skip — those types only make sense as fullscreen overlays.\n */\n private renderCampaignIntoSlot(\n campaign: InAppCampaign,\n target: HTMLElement,\n options?: { submitUrl?: string },\n ): void {\n const proceed = this.emit('campaign-will-show', campaign);\n if (!proceed) {\n this.log(\n `slot campaign ${campaign.id} suppressed by campaign-will-show handler`,\n );\n return;\n }\n\n this.displayedCampaigns.add(campaign.id);\n this.addAnimationStyles();\n\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 const submitUrl = options?.submitUrl;\n\n let rendered = false;\n switch (campaign.sub_type) {\n case 'star_rating':\n rendered = this.renderStarRatingSlot(\n campaign, ic, bg, text, target, submitUrl,\n );\n break;\n case 'nps_survey':\n rendered = this.renderNPSSurveySlot(\n campaign, ic, bg, text, target, submitUrl,\n );\n break;\n // Future sub_types (quick_poll, countdown_offer, quiz, sticky_bar,\n // progress_bar, carousel_cards, product_recommendation) get added\n // here as merchants need them embedded. Until then, fall through\n // to the warn below — campaigns will still render as overlays via\n // the parallel `tryDisplayNextCampaign` path.\n default:\n this.log(\n `slot mode not yet supported for sub_type: ${campaign.sub_type ?? campaign.type}`,\n 'warn',\n );\n // Roll back the displayed marker so the overlay path can still\n // run — slot fallback shouldn't burn the campaign.\n this.displayedCampaigns.delete(campaign.id);\n return;\n }\n\n if (!rendered) return;\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n }\n\n /**\n * Slot-mode wrappers. They build a small card container (no overlay\n * positioning, no close button) and append the SHARED body element\n * the overlay path also uses. Body construction lives in the\n * `_buildXxxBody` helpers below so visual output stays identical\n * between overlay and slot modes — adding a renderer feature in\n * one place updates both.\n */\n private renderStarRatingSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n submitUrl?: string,\n ): boolean {\n const card = this._wrapInSlotCard(\n 'aegis-in-app-rating-card', campaign.id, bg, text,\n );\n card.appendChild(\n this._buildStarRatingBody(campaign, ic, text, 'slot', submitUrl),\n );\n target.appendChild(card);\n return true;\n }\n\n private renderNPSSurveySlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n submitUrl?: string,\n ): boolean {\n const card = this._wrapInSlotCard(\n 'aegis-in-app-nps-card', campaign.id, bg, text,\n );\n card.appendChild(\n this._buildNPSSurveyBody(campaign, ic, text, 'slot', submitUrl),\n );\n target.appendChild(card);\n return true;\n }\n\n /**\n * Token-bound submission helper. POSTs the structured response to\n * the per-token submit URL the page handler embedded. Best-effort\n * — failure is logged but doesn't throw (the customer already\n * clicked; we can't undo their interaction).\n */\n private _submitTokenResponse(\n submitUrl: string,\n payload: Record<string, unknown>,\n ): void {\n if (!submitUrl) return;\n // Fire-and-forget; we don't gate the UI on the response.\n fetch(submitUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ response: payload }),\n keepalive: true,\n }).catch((err) => {\n this.log(`token submit failed: ${err}`, 'warn');\n });\n }\n\n // --- Shared body builders (used by both overlay + slot paths) ----------\n //\n // Sizing: `'overlay'` matches the legacy fullscreen-modal scale (24px\n // padding, 18px title, 32px stars). `'slot'` is the embedded card\n // scale (20px padding, 16px title, 28px stars) — proportional, doesn't\n // dwarf merchant page chrome. Adding a new variant means a new tuple\n // here, not a new renderer.\n\n private _wrapInSlotCard(\n className: string,\n campaignId: string,\n bg: string,\n text: string,\n ): HTMLElement {\n const card = document.createElement('div');\n card.className = className;\n card.setAttribute('data-campaign-id', campaignId);\n card.style.cssText = `\n width: 100%; border-radius: 12px; overflow: hidden;\n background: ${bg}; color: ${text};\n box-shadow: 0 4px 12px rgba(0,0,0,0.06);\n `;\n return card;\n }\n\n private _buildStarRatingBody(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n text: string,\n variant: 'overlay' | 'slot',\n submitUrl?: string,\n ): HTMLElement {\n const isOverlay = variant === 'overlay';\n const padding = isOverlay ? '24px' : '20px';\n const titleSize = isOverlay ? '18px' : '16px';\n const titleWeight = isOverlay ? '700' : '600';\n const titleMargin = isOverlay ? '16px' : '12px';\n const starSize = isOverlay ? '32px' : '28px';\n const starsMarginBottom = isOverlay ? '16px' : '0';\n const hoverScale = isOverlay ? '1.2' : '1.15';\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${padding}; text-align: center;`;\n\n const title = document.createElement('div');\n title.style.cssText =\n `font-size: ${titleSize}; font-weight: ${titleWeight}; margin-bottom: ${titleMargin};`;\n title.textContent = campaign.title || 'Rate your experience';\n body.appendChild(title);\n\n const stars = document.createElement('div');\n stars.style.cssText =\n `display: flex; gap: 8px; justify-content: center;` +\n (starsMarginBottom !== '0' ? ` margin-bottom: ${starsMarginBottom};` : '');\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 =\n `font-size: ${starSize}; cursor: pointer; transition: transform 0.1s; user-select: none;` +\n (text ? ` color: ${text};` : '');\n star.textContent = '☆'; // ☆\n const value = i;\n star.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, {\n sub_type: 'star_rating', value,\n });\n }\n });\n star.addEventListener('mouseenter', () => {\n star.style.transform = `scale(${hoverScale})`;\n });\n star.addEventListener('mouseleave', () => {\n star.style.transform = 'scale(1)';\n });\n stars.appendChild(star);\n }\n body.appendChild(stars);\n return body;\n }\n\n private _buildNPSSurveyBody(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n text: string,\n variant: 'overlay' | 'slot',\n submitUrl?: string,\n ): HTMLElement {\n const isOverlay = variant === 'overlay';\n const padding = isOverlay ? '24px' : '20px';\n const titleAlign = isOverlay ? 'center' : 'center';\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${padding};` +\n (isOverlay ? ' text-align: center;' : '');\n\n const title = document.createElement('div');\n title.style.cssText =\n `font-size: 16px; font-weight: ${isOverlay ? '700' : '600'}; ` +\n `margin-bottom: ${isOverlay ? '16px' : '12px'}; text-align: ${titleAlign};`;\n title.textContent =\n (ic.nps_question as string) || campaign.title ||\n 'How likely are you to recommend us?';\n body.appendChild(title);\n\n if (isOverlay) {\n // Overlay variant uses the round-pip scale + Not/Very labels\n // below — keeps the legacy modal look pixel-identical.\n const scale = document.createElement('div');\n scale.style.cssText =\n '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 const value = i;\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, {\n sub_type: 'nps_survey', value,\n });\n }\n });\n scale.appendChild(btn);\n }\n body.appendChild(scale);\n\n const labels = document.createElement('div');\n labels.style.cssText =\n '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 return body;\n }\n\n // Slot variant: 11-column grid of bordered buttons — fits inline\n // card width without scrolling. No Not/Very labels (slot is small\n // enough that the customer sees both ends without prompting).\n const grid = document.createElement('div');\n grid.style.cssText =\n 'display: grid; grid-template-columns: repeat(11, 1fr); gap: 4px;';\n for (let n = 0; n <= 10; n++) {\n const btn = document.createElement('button');\n btn.style.cssText = `\n padding: 8px 0; border-radius: 6px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 13px; font-weight: 600;\n cursor: pointer; transition: background 0.15s;\n `;\n btn.textContent = String(n);\n const value = n;\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, {\n sub_type: 'nps_survey', value,\n });\n }\n });\n grid.appendChild(btn);\n }\n body.appendChild(grid);\n return body;\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 // Lifecycle: `campaign-will-show` — CANCELLABLE. Host returns `false` to\n // suppress render (e.g. route-aware blocking, host-side frequency caps,\n // self-handled mode). When suppressed we DO NOT mark the campaign as\n // displayed so a subsequent `tryDisplayNextCampaign` (after the host\n // unblocks) can re-evaluate it.\n const proceed = this.emit('campaign-will-show', campaign);\n if (!proceed) {\n this.log(`campaign ${campaign.id} suppressed by campaign-will-show handler`);\n return;\n }\n\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 this.emit('campaign-shown', campaign);\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 this.emit('campaign-shown', campaign);\n return;\n case 'sticky_bar':\n renderStickyBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'progress_bar':\n renderProgressBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\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 this.emit('campaign-shown', campaign);\n return;\n case 'product_recommendation':\n renderProductRecommendation(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n }\n\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\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 = this._buildNPSSurveyBody(campaign, ic, text, 'overlay');\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 = this._buildStarRatingBody(campaign, ic, text, 'overlay');\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(\n campaign: InAppCampaign,\n safeUrl: string,\n buttonId: string = 'cta',\n ): void {\n if (typeof window === 'undefined') return;\n\n // Typed lifecycle hook (1.8.0). Mirror the DOM `preventDefault` contract\n // — a handler returning `false` OR mutating `defaultPrevented` via the\n // helper suppresses the SDK's hard-nav. Built first so handlers attached\n // via the typed API see the click before the DOM event fires.\n let typedDefaultPrevented = false;\n const typedEvent: CampaignClickEvent = {\n campaign,\n action_url: safeUrl,\n button_id: buttonId,\n preventDefault: () => {\n typedDefaultPrevented = true;\n typedEvent.defaultPrevented = true;\n },\n defaultPrevented: false,\n };\n const typedProceed = this.emit('campaign-click', typedEvent);\n\n // DOM CustomEvent path — preserved for backward compat (1.7.x consumers\n // already listen for `aegis:campaign-click`) and for advanced patterns\n // (multi-frame embeds, host-app code that runs before the SDK is\n // instantiated, debugging via DevTools event listener panel).\n const domEvent = new CustomEvent('aegis:campaign-click', {\n detail: {\n campaign_id: campaign.id,\n campaign_type: campaign.type,\n action_url: safeUrl,\n button_id: buttonId,\n },\n cancelable: true,\n });\n const domProceed = window.dispatchEvent(domEvent);\n\n // Either path can suppress the hard-nav. We OR the prevent signals so\n // host apps don't have to remember to handle both — registering on\n // either API is enough.\n const suppressed =\n !typedProceed ||\n typedDefaultPrevented ||\n !domProceed ||\n domEvent.defaultPrevented;\n\n if (!suppressed) {\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 // Lifecycle: `campaign-dismiss` — fire from this single chokepoint so\n // every renderer (8 sites today + future ones) emits consistently.\n // Source granularity (close_button / overlay / esc / auto_timeout) can\n // be refined in a future minor by passing source through to trackEvent;\n // for 1.8.0 we surface the event itself since that's the high-value\n // signal host apps need (inbox state updates, dismiss analytics).\n if (eventType === 'dismissed') {\n const campaign = this.campaigns.find((c) => c.id === campaignId);\n if (campaign) {\n this.emit('campaign-dismiss', {\n campaign,\n source: 'close_button',\n });\n }\n }\n\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 // Plumb the same workspace cascade the main analytics SDK uses\n // (config → ?ws= → URL path slug → setWorkspace runtime → session\n // storage). Without this, in-app engagement events arrive at\n // event-ingress unscoped and fall back to the org's primary\n // workspace — see PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n const workspaceId = this.getWorkspaceId?.();\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 workspace_id: workspaceId,\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 // P1 — clear any pending qualifying-event refresh so a destroy() during\n // the debounce window doesn't fire a stray fetch after the manager is gone.\n if (this.refreshDebounceTimer) {\n clearTimeout(this.refreshDebounceTimer);\n this.refreshDebounceTimer = undefined;\n }\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 // F2/F3 / U8 — slot-rendered card classes\n '.aegis-in-app-rating-card, .aegis-in-app-nps-card'\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 * renderPreview — Static Preview Renderer for Dashboard iframe (Critical Fix A)\n *\n * Used exclusively by the sandboxed iframe preview route\n * (`/api/preview/in-app/route.tsx`). Renders a single campaign into the\n * current document body using the same rendering logic as the production SDK.\n *\n * Data flow:\n * editor-sidebar.tsx → onChange → formState → postMessage({type:'preview_update', config})\n * → iframe receives message → calls renderPreview(config)\n *\n * This ensures 100% fidelity between the dashboard editor preview and\n * production rendering — both use the same SDK code.\n */\n\nimport type { InAppCampaign } from './AegisInAppManager';\nimport { AegisInAppManager } from './AegisInAppManager';\n\n/**\n * Renders a single in-app campaign into the current document for preview.\n *\n * Creates a temporary AegisInAppManager with preview-only config (no tracking,\n * no SSE, no network requests). Calls the same rendering pipeline as production.\n */\nexport function renderPreview(config: InAppCampaign & { interactive_config?: Record<string, unknown> }): void {\n // Clear previous preview\n document.querySelectorAll(\n '[class^=\"aegis-in-app-\"]'\n ).forEach((el) => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n });\n\n if (!config) return;\n\n // Create a lightweight preview-only manager\n const manager = new AegisInAppManager({\n writeKey: 'preview-mode',\n apiHost: '',\n debugMode: false,\n enableSSE: false,\n });\n\n // Override trackEvent to be a no-op in preview mode\n // Access private via any cast — preview only, not production code\n const m = manager as unknown as {\n displayCampaign: (campaign: InAppCampaign) => void;\n trackEvent: (campaignId: string, eventType: string) => Promise<void>;\n addAnimationStyles: () => void;\n };\n\n // No-op tracking for preview\n m.trackEvent = async () => {};\n\n // Ensure animation styles are injected\n m.addAnimationStyles();\n\n // Render the campaign\n m.displayCampaign(config);\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 * Workspace cascade reader. Host SDK sets this to\n * `() => aegis.getEffectiveWorkspaceId()` so placement\n * impression/click/conversion events arrive at the gateway with the\n * same workspace context the main analytics SDK uses. See\n * PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n */\n getWorkspaceId?: () => string | undefined;\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 private getWorkspaceId?: () => string | undefined;\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 this.getWorkspaceId = config.getWorkspaceId;\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', () => {\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 // Plumb the same workspace cascade the main analytics SDK uses\n // (config → ?ws= → URL path slug → setWorkspace runtime → session\n // storage). Without this, placement events arrive at event-ingress\n // unscoped and silently attribute to the org's primary workspace.\n const workspaceId = this.getWorkspaceId?.();\n\n const body = {\n placement_id: placementId,\n variant_id: variantId,\n event_type: eventType,\n workspace_id: workspaceId,\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', () => {\n this.log('SSE heartbeat received');\n });\n\n this.eventSource.addEventListener('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","/**\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\n/**\n * Rage-click detection (Micro-Intent Engine P2 Task 1).\n *\n * Per-intent ring buffer: when ≥ `threshold` clicks land on the same\n * intent inside `windowMs`, the engine emits `rage_click` with the\n * intent name + current count + window. Frustration signal used by the\n * Stuck-at-Checkout pattern (e.g., rage-clicking the coupon input four\n * times in 800ms).\n *\n * Defaults match the plan:\n * threshold = 3 clicks\n * windowMs = 1000 ms\n *\n * TriggerEngine does NOT attach its own pointerdown listener — the\n * SelectorBinder (P1 Task 5) owns the global, delegated listener and\n * dispatches per-intent click events. The IntentSnapshotCollector\n * (P2 Task 5) wires `SelectorBinder.onIntent` to\n * `TriggerEngine.noteClick(intent)` so TriggerEngine sees a clean\n * intent-stamped stream instead of raw DOM events.\n */\nexport interface RageClickConfig {\n threshold: number;\n windowMs: number;\n}\n\n/** Payload emitted on the `rage_click` event. */\nexport interface RageClickData {\n intent: string;\n count: number;\n window_ms: number;\n}\n\n/**\n * Hover-dwell tracking (Micro-Intent Engine P2 Task 2).\n *\n * Tracks per-intent hover duration in milliseconds. `getHoverMs(intent)`\n * returns:\n * - if currently hovering the intent: ms since hover_start (live)\n * - else: ms duration of the most recent hover on that intent (sticky)\n * - if never hovered: 0\n *\n * The sticky behaviour is deliberate. The canonical use case\n * (MICRO_INTENT_ENGINE.md Story 1):\n * \"Priya hovers price for 1.8s, considers, moves cursor away.\n * Exit_intent fires. Rule checks price_hover_ms >= 1500 → true.\"\n * The rule evaluator queries `price_hover_ms` AFTER the hover ends. If\n * we reset to 0 on hover_end, the rule never matches the very pattern\n * the engine exists to detect.\n *\n * Threshold-based emission: when a hover crosses one of the registered\n * dwell targets (e.g. 1500ms), a `<intent>_hover_dwell_<ms>` event\n * fires. Useful for journeys that want event-style hooks; the\n * snapshot-style `getHoverMs` is the primary surface for the\n * compound-rule evaluator.\n */\nexport interface HoverDwellConfig {\n /** Dwell thresholds (ms) per intent. The engine fires\n * `<intent>_hover_dwell_<ms>` when an active hover crosses each\n * threshold. Defaults: price→[1500], cta→[1500]. */\n thresholdsByIntent?: Partial<Record<string, ReadonlyArray<number>>>;\n}\n\n/**\n * Mouse velocity toward the viewport top (Micro-Intent Engine P2 Task 3).\n *\n * Detects the early phase of exit-intent: the mouse moving rapidly\n * upward before it actually crosses out of the viewport. The signal is\n * a continuous px/ms value (positive = moving up), updated as samples\n * arrive. When velocity crosses `threshold`, a `mouse_velocity_to_top`\n * event fires (once per session-window cooldown to avoid spamming on a\n * single gesture).\n *\n * Sampling: callers feed positions via `noteMousePosition(x, y, ts)`.\n * The engine keeps a sliding `windowMs` ring buffer of samples and\n * computes velocity as the average dy / dt over samples in the window.\n * Per the plan: sampled at 100ms, 400ms window. That bound is\n * configurable.\n *\n * Why \"to top\" specifically: exit-intent fires only when y crosses 0;\n * we want the warning BEFORE that. A typical exit-intent gesture has\n * upward velocity well above any normal browsing motion.\n */\nexport interface MouseVelocityConfig {\n /** Threshold in px/ms (positive = moving up). Default 1.5 px/ms,\n * ≈ moving 600px in 400ms, which only happens during a deliberate\n * upward sweep. */\n threshold: number;\n /** Rolling-window length over which to compute velocity. */\n windowMs: number;\n /** Cooldown after a fire before the signal can fire again. */\n cooldownMs: number;\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 // Rage-click state (P2 Task 1). Buffer indexed by intent name (price /\n // cta / coupon / checkout). Per-intent so rage-clicking the coupon\n // input doesn't get conflated with rapid CTA presses.\n private rageClickEnabled = false;\n private rageClickConfig: RageClickConfig = { threshold: 3, windowMs: 1000 };\n private rageClickBuffer = new Map<string, number[]>();\n /** Tracks whether a rage_click event has already fired for an intent\n * in the current burst. Reset when the buffer empties below threshold.\n * Prevents the same burst from firing the event N-2 times as each\n * click after threshold pushes the count higher. */\n private rageClickFiredInBurst = new Set<string>();\n\n // Hover-dwell state (P2 Task 2). Tracks live + sticky-last dwell per\n // intent. `hoverStartAt` undefined means no active hover.\n private hoverEnabled = false;\n private hoverStartAt = new Map<string, number>();\n private hoverLastMs = new Map<string, number>();\n private hoverThresholds = new Map<string, ReadonlyArray<number>>([\n ['price', [1500]],\n ['cta', [1500]],\n ]);\n /** Track which (intent, threshold) pairs have already fired in the\n * current hover so a single long hover doesn't double-fire as time\n * marches on. Reset on hover_start. */\n private hoverThresholdsFired = new Map<string, Set<number>>();\n /** Pending threshold timers, keyed by intent. Cleared on hover_end. */\n private hoverThresholdTimers = new Map<string, number[]>();\n\n // Mouse-velocity-to-top state (P2 Task 3).\n private mouseVelEnabled = false;\n private mouseVelConfig: MouseVelocityConfig = {\n threshold: 1.5,\n windowMs: 400,\n cooldownMs: 5000,\n };\n /** Ring buffer of (x, y, ts) samples within the rolling window. */\n private mouseSamples: Array<{ x: number; y: number; ts: number }> = [];\n /** Last computed velocity-to-top in px/ms (positive = moving up). */\n private mouseVelLast = 0;\n /** Epoch ms when the velocity event last fired — gates cooldown. */\n private mouseVelLastFiredAt = 0;\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 /**\n * Enable rage-click detection (P2 Task 1).\n *\n * After calling this, feed click events via `noteClick(intent)`.\n * SelectorBinder (P1 Task 5) is the upstream source; the wiring lives\n * in IntentSnapshotCollector (P2 Task 5). Calling `noteClick` without\n * a prior `registerRageClick()` is a no-op so legacy callers don't\n * accidentally enable the feature.\n */\n registerRageClick(config?: Partial<RageClickConfig>): void {\n this.rageClickEnabled = true;\n if (config) {\n this.rageClickConfig = {\n threshold: config.threshold ?? this.rageClickConfig.threshold,\n windowMs: config.windowMs ?? this.rageClickConfig.windowMs,\n };\n }\n }\n\n /**\n * Feed a click event for rage-click detection. Returns the current\n * count within-window for the intent — useful for the snapshot\n * collector (P2 Task 5) which updates IntentRuleEvaluator with\n * `rage_click_count` continuously, not just at the burst threshold.\n *\n * Idempotent w.r.t. `registerRageClick` — when not enabled, this\n * returns 0 without buffering.\n */\n noteClick(intent: string, timestamp: number = Date.now()): number {\n if (!this.rageClickEnabled) return 0;\n const buf = this.rageClickBuffer.get(intent) ?? [];\n const cutoff = timestamp - this.rageClickConfig.windowMs;\n // Drop expired timestamps (clicks older than the window).\n // The buffer is append-only and timestamps are non-decreasing in\n // practice (Date.now is monotonic per device, modulo system-clock\n // adjustments), so an in-place trim from the head is correct.\n let trimStart = 0;\n while (trimStart < buf.length && buf[trimStart] < cutoff) trimStart++;\n const recent = trimStart === 0 ? buf : buf.slice(trimStart);\n recent.push(timestamp);\n this.rageClickBuffer.set(intent, recent);\n\n // Burst reset: when the recent count drops below threshold (because\n // older clicks aged out), the burst is over — re-arm the per-intent\n // fire-once latch so a fresh burst can fire again.\n if (recent.length < this.rageClickConfig.threshold) {\n this.rageClickFiredInBurst.delete(intent);\n }\n\n if (\n recent.length >= this.rageClickConfig.threshold &&\n !this.rageClickFiredInBurst.has(intent)\n ) {\n this.rageClickFiredInBurst.add(intent);\n this.emit('rage_click', {\n intent,\n count: recent.length,\n window_ms: this.rageClickConfig.windowMs,\n });\n }\n\n return recent.length;\n }\n\n /** Snapshot the current rage_click count for an intent. The\n * IntentSnapshotCollector (P2 Task 5) calls this when building the\n * `rage_click_count` signal value for the IntentRuleEvaluator. */\n getRageClickCount(intent: string): number {\n if (!this.rageClickEnabled) return 0;\n const buf = this.rageClickBuffer.get(intent);\n if (!buf) return 0;\n const cutoff = Date.now() - this.rageClickConfig.windowMs;\n // Lazy prune on read so the count reflects only currently-valid\n // clicks. Cheap because buffers are tiny (cap at threshold + 1 in\n // practice — older entries get dropped on every note).\n let live = 0;\n for (const ts of buf) {\n if (ts >= cutoff) live++;\n }\n return live;\n }\n\n /**\n * Enable hover-dwell tracking (P2 Task 2). After registration, feed\n * hover events via `noteHoverStart(intent, ts)` / `noteHoverEnd`.\n * SelectorBinder (P1 Task 5) is the upstream source; wiring lands in\n * P2 Task 5.\n */\n registerHoverDwell(config?: HoverDwellConfig): void {\n this.hoverEnabled = true;\n if (config?.thresholdsByIntent) {\n for (const [intent, thresholds] of Object.entries(config.thresholdsByIntent)) {\n if (thresholds) this.hoverThresholds.set(intent, thresholds);\n }\n }\n }\n\n /** Record the start of a hover on the named intent. Schedules\n * per-threshold timers that emit `<intent>_hover_dwell_<ms>` when\n * the active hover passes each registered threshold. */\n noteHoverStart(intent: string, timestamp: number = Date.now()): void {\n if (!this.hoverEnabled) return;\n // If a prior hover is still pending (no hover_end fired — possible\n // when the DOM node was unmounted mid-hover), close it out first to\n // keep `hoverLastMs` consistent.\n if (this.hoverStartAt.has(intent)) {\n this.noteHoverEnd(intent, timestamp);\n }\n this.hoverStartAt.set(intent, timestamp);\n this.hoverThresholdsFired.set(intent, new Set());\n\n // Schedule threshold timers. Uses the global setTimeout (works in\n // both browser and node, and vitest's fake-timers stub the global).\n // registerHoverDwell with no thresholds for an intent => no events,\n // only the snapshot value.\n const thresholds = this.hoverThresholds.get(intent);\n if (thresholds) {\n const timers: number[] = [];\n for (const ms of thresholds) {\n const timerId = setTimeout(() => {\n // Only fire if still hovering this intent — the event must\n // not fire after hover_end.\n if (!this.hoverStartAt.has(intent)) return;\n const firedSet = this.hoverThresholdsFired.get(intent);\n if (firedSet?.has(ms)) return;\n firedSet?.add(ms);\n this.emit(`${intent}_hover_dwell_${ms}`, {\n intent,\n threshold_ms: ms,\n actual_ms: Date.now() - timestamp,\n });\n }, ms) as unknown as number;\n timers.push(timerId);\n }\n this.hoverThresholdTimers.set(intent, timers);\n }\n }\n\n /** Record the end of a hover on the named intent. Updates the sticky\n * `lastHoverMs` so `getHoverMs` keeps returning the last-known\n * duration until the next hover_start. */\n noteHoverEnd(intent: string, timestamp: number = Date.now()): void {\n if (!this.hoverEnabled) return;\n const startAt = this.hoverStartAt.get(intent);\n if (startAt === undefined) return;\n const dwell = Math.max(0, timestamp - startAt);\n this.hoverLastMs.set(intent, dwell);\n this.hoverStartAt.delete(intent);\n // Clear pending threshold timers for this intent.\n const pending = this.hoverThresholdTimers.get(intent);\n if (pending) {\n for (const id of pending) clearTimeout(id);\n this.hoverThresholdTimers.delete(intent);\n }\n this.hoverThresholdsFired.delete(intent);\n }\n\n /**\n * Enable mouse-velocity-to-top tracking (P2 Task 3). After\n * registration, feed positions via `noteMousePosition(x, y, ts?)`.\n * IntentSnapshotCollector (P2 Task 5) wires window 'mousemove' to\n * this method, with throttling to ~100ms per the plan.\n */\n registerMouseVelocityToTop(config?: Partial<MouseVelocityConfig>): void {\n this.mouseVelEnabled = true;\n if (config) {\n this.mouseVelConfig = {\n threshold: config.threshold ?? this.mouseVelConfig.threshold,\n windowMs: config.windowMs ?? this.mouseVelConfig.windowMs,\n cooldownMs: config.cooldownMs ?? this.mouseVelConfig.cooldownMs,\n };\n }\n }\n\n /** Feed a mouse-position sample. Recomputes the rolling-window\n * velocity-to-top and fires `mouse_velocity_to_top` when the value\n * crosses the configured threshold (subject to cooldown). */\n noteMousePosition(x: number, y: number, timestamp: number = Date.now()): number {\n if (!this.mouseVelEnabled) return 0;\n const cutoff = timestamp - this.mouseVelConfig.windowMs;\n // Trim expired samples from the head; keep the buffer small.\n let trimStart = 0;\n while (trimStart < this.mouseSamples.length && this.mouseSamples[trimStart].ts < cutoff) {\n trimStart++;\n }\n if (trimStart > 0) this.mouseSamples = this.mouseSamples.slice(trimStart);\n this.mouseSamples.push({ x, y, ts: timestamp });\n\n // Velocity-to-top = -(dy / dt) over the oldest-to-newest pair in\n // the window. Positive value = moving up. With 2+ samples this is\n // the instantaneous slope across the window; with 1 sample we\n // return 0 (cannot compute velocity from a single point).\n if (this.mouseSamples.length < 2) {\n this.mouseVelLast = 0;\n return 0;\n }\n const oldest = this.mouseSamples[0];\n const newest = this.mouseSamples[this.mouseSamples.length - 1];\n const dt = newest.ts - oldest.ts;\n if (dt <= 0) {\n this.mouseVelLast = 0;\n return 0;\n }\n const velocity = -(newest.y - oldest.y) / dt; // px/ms; up = +\n this.mouseVelLast = velocity;\n\n // Threshold + cooldown firing. Initial state allows the first fire\n // — only subsequent fires within cooldownMs of the prior are gated.\n const cooldownOk =\n this.mouseVelLastFiredAt === 0 ||\n timestamp - this.mouseVelLastFiredAt >= this.mouseVelConfig.cooldownMs;\n if (velocity >= this.mouseVelConfig.threshold && cooldownOk) {\n this.mouseVelLastFiredAt = timestamp;\n this.emit('mouse_velocity_to_top', {\n velocity,\n threshold: this.mouseVelConfig.threshold,\n window_ms: this.mouseVelConfig.windowMs,\n samples: this.mouseSamples.length,\n });\n }\n return velocity;\n }\n\n /** Snapshot the current velocity-to-top in px/ms (positive = up).\n * Returns 0 when not enabled or insufficient samples. */\n getMouseVelocityToTop(): number {\n return this.mouseVelEnabled ? this.mouseVelLast : 0;\n }\n\n /**\n * Snapshot the hover dwell for an intent.\n * - Currently hovering: returns `Date.now() - hover_start_at`.\n * - Hovered before, not currently: returns the most recent hover's\n * duration (sticky — the rule evaluator queries this AFTER\n * mouseleave to see \"did Priya hover the price ≥ 1.5s?\").\n * - Never hovered: returns 0.\n */\n getHoverMs(intent: string): number {\n if (!this.hoverEnabled) return 0;\n const startAt = this.hoverStartAt.get(intent);\n if (startAt !== undefined) {\n return Math.max(0, Date.now() - startAt);\n }\n return this.hoverLastMs.get(intent) ?? 0;\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 * Micro-Intent Engine — compound rule evaluator (P1 Task 4).\n *\n * Pure, side-effect-free evaluation of an IntentRule predicate tree against\n * a current snapshot of Layer-1 (identity) + Layer-2 (session) signal values.\n *\n * Why a separate class from TriggerEngine\n * ----------------------------------------\n * TriggerEngine.ts owns signal CAPTURE (scroll, time-on-page, exit-intent,\n * etc.) and emits named events like `scroll_depth_50`. IntentRuleEvaluator\n * owns rule EVALUATION — given a compound predicate and the current state\n * of all known signals, return whether the rule fires now. The two\n * concerns separate cleanly: capture is global per-page (one engine\n * instance), evaluation is per-rule (the manager re-runs every armed\n * rule when a `fire_on` signal fires).\n *\n * Type strategy\n * -------------\n * Types are declared LOCALLY in this file rather than imported from\n * `@aegis/shared-types`. The SDK is published standalone on npm and\n * cannot pull in workspace packages at runtime. A drift-check test\n * (`libs/web-sdk/tests/intent-evaluator-shared-types-drift.test.ts`)\n * parses both files and asserts the local types and the canonical\n * `libs/shared-types/src/intent.ts` declare the same set of signal /\n * comparator values.\n *\n * Plan reference: docs/architecture/MICRO_INTENT_ENGINE.md §\"Schemas\"\n */\n\n// ───────────────────────────────────────────────────────────────────────────\n// Types — local mirror of libs/shared-types/src/intent.ts\n// ───────────────────────────────────────────────────────────────────────────\n\nexport type IntentSignal =\n // Layer-2 session\n | 'scroll_depth'\n | 'time_on_page'\n | 'exit_intent'\n | 'back_button'\n | 'scroll_velocity'\n | 'inactivity'\n | 'visibility_change'\n | 'rage_click'\n | 'price_hover_ms'\n | 'cta_hover_ms'\n | 'cum_dwell_sku'\n | 'session_count_sku'\n | 'cart_value'\n | 'converted_in_session'\n // Layer-1 identity scores\n | 'rfm_segment'\n | 'rfm_score'\n | 'lifecycle_stage'\n | 'purchase_intent_score'\n | 'purchase_intent_tier'\n | 'churn_risk_score'\n | 'churn_risk_tier'\n | 'predicted_ltv'\n | 'predicted_ltv_tier'\n | 'uninstall_risk_tier'\n | 'engagement_level'\n | 'price_tier'\n | 'price_sensitivity_score'\n | 'top_category'\n | 'avg_cart_value'\n | 'scoring_tier';\n\nexport type Comparator = 'gte' | 'lte' | 'gt' | 'lt' | 'eq' | 'neq' | 'in' | 'nin';\n\nexport type IntentLeafValue =\n | number\n | string\n | boolean\n | ReadonlyArray<number | string | boolean>;\n\nexport interface IntentLeaf {\n signal: IntentSignal;\n op: Comparator;\n value: IntentLeafValue;\n}\n\nexport interface IntentNode {\n op: 'AND' | 'OR' | 'NOT';\n operands: ReadonlyArray<IntentExpr>;\n}\n\nexport type IntentExpr = IntentNode | IntentLeaf;\n\nexport interface IntentRule {\n fire_on: ReadonlyArray<IntentSignal>;\n when: IntentExpr;\n priority: number;\n suppress_competing: boolean;\n}\n\n/** A scalar a signal can hold in the snapshot. null = signal not (yet)\n * populated — happens for Layer-1 scores on anonymous sessions and for\n * Layer-2 signals before the user triggers them. */\nexport type SignalValue = number | string | boolean | null;\n\n/** Current state of every known signal. Missing keys are treated the\n * same as `null`. */\nexport type IntentSnapshot = Partial<Record<IntentSignal, SignalValue>>;\n\n// ───────────────────────────────────────────────────────────────────────────\n// Type guards\n// ───────────────────────────────────────────────────────────────────────────\n\nexport function isIntentLeaf(expr: IntentExpr): expr is IntentLeaf {\n return 'signal' in expr;\n}\n\nexport function isIntentNode(expr: IntentExpr): expr is IntentNode {\n return 'operands' in expr;\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Pure leaf evaluator\n// ───────────────────────────────────────────────────────────────────────────\n\n/**\n * Evaluate a single leaf comparison against a snapshot.\n *\n * Missing-signal semantics (per the plan's \"Graceful degradation rules\"):\n * - The CALLER (evaluateExpr) decides AND/OR semantics on missing\n * operands; this function answers strictly for THIS leaf.\n * - When the signal is missing from the snapshot, the leaf is\n * \"unknown\" → return null so the parent node can interpret it.\n *\n * Comparator semantics:\n * - gte/lte/gt/lt: numeric only; comparing strings/bools returns false.\n * - eq/neq: any type; strict equality.\n * - in/nin: leaf value must be a list; membership test on the snapshot\n * value. `nin` returns true for missing snapshot values (the\n * contact's RFM segment is \"not in\" the forbidden list if we don't\n * know it yet — conservative).\n */\nexport function evaluateLeaf(leaf: IntentLeaf, snapshot: IntentSnapshot): boolean | null {\n const actual = snapshot[leaf.signal];\n if (actual === undefined || actual === null) {\n // Missing signal — let the parent decide.\n return null;\n }\n\n const want = leaf.value;\n\n switch (leaf.op) {\n case 'gte':\n case 'lte':\n case 'gt':\n case 'lt': {\n if (typeof actual !== 'number' || typeof want !== 'number') return false;\n if (leaf.op === 'gte') return actual >= want;\n if (leaf.op === 'lte') return actual <= want;\n if (leaf.op === 'gt') return actual > want;\n return actual < want; // lt\n }\n case 'eq':\n return actual === want;\n case 'neq':\n return actual !== want;\n case 'in':\n case 'nin': {\n if (!Array.isArray(want)) return false;\n const isMember = want.some((v) => v === actual);\n return leaf.op === 'in' ? isMember : !isMember;\n }\n default: {\n // Exhaustiveness check — TS will flag a new Comparator that doesn't\n // have a case here, but the runtime fallback returns false.\n const _exhaustive: never = leaf.op;\n void _exhaustive;\n return false;\n }\n }\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Pure tree evaluator\n// ───────────────────────────────────────────────────────────────────────────\n\n/**\n * Evaluate the full predicate tree.\n *\n * AND/OR/NOT semantics with missing-value handling (per plan §\"Graceful\n * degradation rules\"):\n *\n * AND(a, b, c) where any operand is null → false (conservative; the\n * rule doesn't fire when we can't prove all conditions).\n * OR(a, b, c) where some operands are null → if any non-null operand\n * is true, returns true. If all operands are null OR all are\n * false, returns false.\n * NOT(a) where a is null → null (parent decides). When this propagates\n * to the top-level evaluateExpr, the rule does NOT fire.\n *\n * The \"AND treats missing as unmet\" + \"OR treats missing as inert\" rule\n * from the plan maps exactly onto this implementation: AND short-circuits\n * to false on any null operand; OR ignores nulls and looks at the rest.\n *\n * Top-level: a null result from the root expression means the rule\n * cannot be evaluated yet — do NOT fire.\n */\nexport function evaluateExpr(expr: IntentExpr, snapshot: IntentSnapshot): boolean | null {\n if (isIntentLeaf(expr)) {\n return evaluateLeaf(expr, snapshot);\n }\n\n switch (expr.op) {\n case 'AND': {\n // AND requires ALL operands true. Any null = unprovable = false.\n for (const operand of expr.operands) {\n const v = evaluateExpr(operand, snapshot);\n if (v === null) return false;\n if (!v) return false;\n }\n return true;\n }\n case 'OR': {\n // OR is satisfied by any true operand. Nulls are skipped (inert).\n let allNull = true;\n for (const operand of expr.operands) {\n const v = evaluateExpr(operand, snapshot);\n if (v === true) return true;\n if (v !== null) allNull = false;\n }\n // If every operand was null, propagate null upward — caller decides.\n // Otherwise all operands evaluated false.\n return allNull ? null : false;\n }\n case 'NOT': {\n // Validator at write time guarantees operands.length === 1; the\n // evaluator trusts that and reads operands[0].\n const v = evaluateExpr(expr.operands[0], snapshot);\n if (v === null) return null;\n return !v;\n }\n default: {\n // Exhaustiveness check — if a new op is added to IntentExpr and\n // not handled above, TypeScript narrows `expr` to `never` here\n // and assigning it to a non-`never` would fail at compile time.\n // The earlier draft did `expr.op` which itself dereferences\n // `never` and explodes; assign `expr` directly instead.\n const _exhaustive: never = expr;\n void _exhaustive;\n return false;\n }\n }\n}\n\n/** Top-level \"does the rule fire right now?\" check. Treats a null\n * evaluation result as \"do not fire\" (we can't prove the rule's\n * conditions are met). */\nexport function evaluateRule(rule: IntentRule, snapshot: IntentSnapshot): boolean {\n const result = evaluateExpr(rule.when, snapshot);\n return result === true;\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Stateful evaluator class — what AegisInAppManager talks to\n// ───────────────────────────────────────────────────────────────────────────\n\n/** A campaign carrying a compound rule, in the SDK's runtime shape.\n * Mirrors the cell-plane payload at /v1/in-app/active when\n * client_trigger.type === 'micro_intent'. */\nexport interface ArmedCampaign {\n id: string;\n rule: IntentRule;\n}\n\n/** The decision the evaluator returns when a signal fires.\n *\n * fire : caller should display this campaign now.\n * suppress : caller should silence the listed competing campaign IDs\n * for the rest of the session (the bouncing-researcher\n * pattern — a rule whose only job is to silence others).\n * none : no rule matched, do nothing.\n */\nexport interface EvaluationDecision {\n kind: 'fire' | 'suppress' | 'none';\n campaignId?: string;\n suppressIds?: ReadonlyArray<string>;\n}\n\nexport class IntentRuleEvaluator {\n /** All campaigns currently armed on this page. Caller (the\n * AegisInAppManager) replaces this on every refresh. */\n private armed: ArmedCampaign[] = [];\n\n /** Latest signal values. Caller pushes updates via updateSignal /\n * updateSnapshot whenever TriggerEngine emits a state change or\n * contact-scores fetch completes. */\n private snapshot: IntentSnapshot = {};\n\n /** Campaigns that have already fired this session — never re-fire. */\n private firedThisSession = new Set<string>();\n\n /** Campaigns silenced by a prior `suppress_competing` win. The set\n * resets on session boundary (new tab / new pageview after timeout).\n * The AegisInAppManager owns durability semantics; this set is\n * in-memory only. */\n private silencedThisSession = new Set<string>();\n\n // ─── snapshot management ───\n\n updateSignal(signal: IntentSignal, value: SignalValue): void {\n this.snapshot[signal] = value;\n }\n\n updateSnapshot(partial: IntentSnapshot): void {\n Object.assign(this.snapshot, partial);\n }\n\n getSnapshot(): Readonly<IntentSnapshot> {\n return this.snapshot;\n }\n\n // ─── armed-campaign management ───\n\n setArmed(campaigns: ArmedCampaign[]): void {\n this.armed = [...campaigns];\n }\n\n getArmed(): ReadonlyArray<ArmedCampaign> {\n return this.armed;\n }\n\n markFired(campaignId: string): void {\n this.firedThisSession.add(campaignId);\n }\n\n /** Clear all per-session state. Caller invokes on logout or explicit\n * session reset. */\n reset(): void {\n this.firedThisSession.clear();\n this.silencedThisSession.clear();\n }\n\n // ─── the main dispatch ───\n\n /**\n * Called every time a signal value changes meaningfully (e.g. a\n * TriggerEngine `exit_intent` event, or a `scroll_depth_50` crossing\n * threshold, or the Layer-1 fetch finishing). Returns the decision the\n * caller should act on.\n *\n * Algorithm:\n * 1. Filter armed campaigns to those whose `fire_on` includes the\n * signal that just changed.\n * 2. Drop already-fired and silenced campaigns.\n * 3. Sort the remainder by priority DESC, tie-broken by campaign id\n * lexicographic (per plan §\"Pattern ordering rules\").\n * 4. Walk the sorted list:\n * - If a suppress_competing rule matches, emit a 'suppress'\n * decision listing every lower-priority armed campaign id.\n * Mark those as silenced internally too.\n * - Otherwise the first matching rule emits 'fire'.\n * 5. If nothing matches, return 'none'.\n */\n onSignalChanged(signal: IntentSignal): EvaluationDecision {\n const candidates = this.armed\n .filter((c) => c.rule.fire_on.includes(signal))\n .filter((c) => !this.firedThisSession.has(c.id))\n .filter((c) => !this.silencedThisSession.has(c.id))\n .sort((a, b) => {\n if (b.rule.priority !== a.rule.priority) {\n return b.rule.priority - a.rule.priority;\n }\n // Tie-break: lexicographic on id, ascending.\n return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;\n });\n\n for (let i = 0; i < candidates.length; i++) {\n const c = candidates[i];\n if (!evaluateRule(c.rule, this.snapshot)) continue;\n\n if (c.rule.suppress_competing) {\n // Silence every other armed campaign for the rest of session.\n // Specifically: every armed campaign EXCEPT this one. We don't\n // restrict to \"lower priority\" because suppress_competing is\n // explicitly a bouncing-researcher / margin-protection signal —\n // it means \"if this matches, don't show ANYTHING\".\n const suppressIds = this.armed\n .filter((other) => other.id !== c.id)\n .map((other) => other.id);\n suppressIds.forEach((id) => this.silencedThisSession.add(id));\n return {\n kind: 'suppress',\n campaignId: c.id,\n suppressIds,\n };\n }\n\n return { kind: 'fire', campaignId: c.id };\n }\n\n return { kind: 'none' };\n }\n}\n\n// Re-export pure helpers so tests can reach them without instantiating\n// the class.\nexport const MAX_RULE_DEPTH = 3 as const;\n","/**\n * Micro-Intent Engine — contact-scores fetcher (P4a bridge).\n *\n * Bridges `GET /v1/sdk/contact-scores` into the SDK's\n * `IntentRuleEvaluator` snapshot. Without this, identified-contact\n * micro-intent patterns (VIP Whisper, Win-back At-Risk, Price-Sensitive\n * Nudge, etc.) cannot fire because their AND-compound rules evaluate\n * `rfm_segment` / `lifecycle_stage` / `churn_risk_tier` /\n * `predicted_ltv_tier` / `price_sensitivity_score` against an empty\n * snapshot and always return false.\n *\n * Lifecycle\n * ---------\n * AegisMessageRuntime.initialize() → fetch if contactId known\n * AegisMessageRuntime.updateContactId → fetch for the new contact\n *\n * The fetcher is session-deduped: a second `fetchForContact(sameId)`\n * call within `dedupWindowMs` is a no-op. This stops a hot navigation\n * loop from hammering the endpoint when SPA route changes re-call\n * identify() with the same id.\n *\n * Empty state\n * -----------\n * The endpoint returns 204 for unknown contacts AND for contacts whose\n * `scoring_tier='none'`. Either way the fetcher leaves the snapshot\n * unchanged — the evaluator's leaf eval treats absent Layer-1 keys as\n * null, which fail-closes any AND clause involving them. Anonymous\n * patterns continue to work normally.\n *\n * Privacy posture\n * ---------------\n * The endpoint's default response is the tiered form (`predicted_ltv_tier`).\n * Tenants who opt into raw `predicted_ltv` via\n * `organizations.settings.score_serving_raw_ltv = true` will see the\n * float on the snapshot too. Both are valid IntentSignals; rule\n * authors pick whichever matches their tenant config.\n *\n * Plan reference: docs/architecture/MICRO_INTENT_ENGINE.md §P4a.\n */\n\nimport type { IntentRuleEvaluator, IntentSnapshot } from './IntentRuleEvaluator';\n\n/** Shape of the Layer-1 score response from /v1/sdk/contact-scores. */\nexport interface ContactScoresResponse {\n rfm_segment?: string;\n lifecycle_stage?: string;\n churn_risk_tier?: 'low' | 'medium' | 'high';\n predicted_ltv_tier?: 'low' | 'medium' | 'high';\n predicted_ltv?: number;\n price_sensitivity_score?: number;\n scoring_tier?: string;\n scores_updated_at?: string | null;\n}\n\nexport interface ContactScoresFetcherConfig {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n /** Optional. When provided, the fetcher pushes the response into the\n * evaluator's snapshot automatically on every successful fetch. */\n evaluator?: IntentRuleEvaluator;\n /** Minimum time between repeat fetches for the same contactId.\n * Default 60 seconds. */\n dedupWindowMs?: number;\n /** Override for tests / non-browser environments. */\n fetchImpl?: typeof fetch;\n /** Console.warn channel. */\n onError?: (err: unknown, contactId: string) => void;\n}\n\nexport class ContactScoresFetcher {\n private readonly apiHost: string;\n private readonly writeKey: string;\n private organizationId?: string;\n private readonly evaluator?: IntentRuleEvaluator;\n private readonly dedupWindowMs: number;\n private readonly fetchImpl: typeof fetch;\n private readonly onError?: (err: unknown, contactId: string) => void;\n\n private lastFetchedContactId?: string;\n private lastFetchedAt = 0;\n private latestSnapshot: ContactScoresResponse | null = null;\n\n constructor(cfg: ContactScoresFetcherConfig) {\n this.apiHost = cfg.apiHost.replace(/\\/$/, '');\n this.writeKey = cfg.writeKey;\n this.organizationId = cfg.organizationId;\n this.evaluator = cfg.evaluator;\n this.dedupWindowMs = cfg.dedupWindowMs ?? 60_000;\n this.fetchImpl = cfg.fetchImpl ?? (typeof fetch !== 'undefined' ? fetch.bind(globalThis) : (() => Promise.reject(new Error('fetch unavailable'))) as typeof fetch);\n this.onError = cfg.onError;\n }\n\n /** Update the org so subsequent fetches scope correctly (e.g. when\n * the SDK resolves an org id after init). */\n updateOrganizationId(organizationId: string | undefined): void {\n this.organizationId = organizationId;\n }\n\n /** Most recent successful response. `null` when no fetch has succeeded\n * yet, OR when the endpoint returned 204 (unscored). Consumers can\n * poll this for diagnostic UIs; campaign evaluation does not need to\n * read it directly because the evaluator (if configured) already has\n * the snapshot applied. */\n getSnapshot(): Readonly<ContactScoresResponse> | null {\n return this.latestSnapshot;\n }\n\n /** Fetch scores for `contactId` and apply to the configured evaluator\n * (if any). Returns the response on success, null on 204 / error.\n *\n * Session-dedup: repeat calls for the same contactId within\n * `dedupWindowMs` are no-ops. Pass `force: true` to override. */\n async fetchForContact(\n contactId: string,\n opts: { force?: boolean } = {},\n ): Promise<ContactScoresResponse | null> {\n if (!contactId) return null;\n\n const now = Date.now();\n if (\n !opts.force &&\n this.lastFetchedContactId === contactId &&\n now - this.lastFetchedAt < this.dedupWindowMs\n ) {\n return this.latestSnapshot;\n }\n\n this.lastFetchedContactId = contactId;\n this.lastFetchedAt = now;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Contact-ID': contactId,\n 'X-User-ID': contactId,\n };\n if (this.organizationId) {\n headers['X-Organization-ID'] = this.organizationId;\n }\n\n try {\n const resp = await this.fetchImpl(\n `${this.apiHost}/v1/sdk/contact-scores`,\n {\n method: 'GET',\n headers,\n credentials: 'include',\n },\n );\n if (resp.status === 204) {\n this.latestSnapshot = null;\n return null;\n }\n if (!resp.ok) {\n this.latestSnapshot = null;\n return null;\n }\n const payload = (await resp.json()) as ContactScoresResponse;\n this.latestSnapshot = payload;\n if (this.evaluator) {\n this.evaluator.updateSnapshot(toIntentSnapshot(payload));\n }\n return payload;\n } catch (err) {\n // Network errors / aborted fetches must not block in-app rendering.\n // Anonymous patterns keep working; identified-contact patterns\n // simply don't fire this session.\n this.onError?.(err, contactId);\n return null;\n }\n }\n}\n\n/** Project the wire response onto the evaluator's IntentSnapshot shape.\n * Strings (rfm_segment / lifecycle_stage / *_tier) map straight across;\n * numerics (price_sensitivity_score / predicted_ltv) are passed through\n * as numbers. Missing keys are omitted so the evaluator's leaf eval\n * treats them as null (per IntentRuleEvaluator semantics).\n *\n * Exported for the smoke test — drift guard pins the mapping. */\nexport function toIntentSnapshot(r: ContactScoresResponse): IntentSnapshot {\n const snap: IntentSnapshot = {};\n if (r.rfm_segment) snap.rfm_segment = r.rfm_segment;\n if (r.lifecycle_stage) snap.lifecycle_stage = r.lifecycle_stage;\n if (r.churn_risk_tier) snap.churn_risk_tier = r.churn_risk_tier;\n if (r.predicted_ltv_tier) snap.predicted_ltv_tier = r.predicted_ltv_tier;\n if (typeof r.predicted_ltv === 'number') snap.predicted_ltv = r.predicted_ltv;\n if (typeof r.price_sensitivity_score === 'number') {\n snap.price_sensitivity_score = r.price_sensitivity_score;\n }\n if (r.scoring_tier) snap.scoring_tier = r.scoring_tier;\n return snap;\n}\n","/**\n * SDK Config Poller\n *\n * Fetches non-sensitive SDK configuration from GET /v1/sdk/config\n * with ETag/If-None-Match support for 304 responses.\n *\n * Polls every 5 minutes by default. Config changes are applied\n * to push/in-app managers without re-initialization.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface SdkConfig {\n version: string;\n push: {\n enabled: boolean;\n vapid_public_key: string | null;\n platforms: string[];\n };\n in_app: {\n enabled: boolean;\n };\n consent: {\n channels_requiring_opt_in: string[];\n };\n}\n\nexport interface SdkConfigPollerOptions {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n pollIntervalMs?: number;\n}\n\nexport type ConfigChangeCallback = (config: SdkConfig) => void;\n\nexport class SdkConfigPoller {\n private options: Required<Omit<SdkConfigPollerOptions, 'organizationId'>> & { organizationId?: string };\n private currentETag: string | null = null;\n private currentConfig: SdkConfig | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private listeners: ConfigChangeCallback[] = [];\n\n constructor(options: SdkConfigPollerOptions) {\n this.options = {\n pollIntervalMs: 300_000, // 5 minutes\n ...options,\n };\n }\n\n /**\n * Fetch config once (on init) and start polling.\n */\n async start(): Promise<SdkConfig | null> {\n const config = await this.fetchConfig();\n\n this.pollTimer = setInterval(() => {\n this.fetchConfig().catch((err) => {\n logger.warn('SDK config poll failed:', err);\n });\n }, this.options.pollIntervalMs);\n\n return config;\n }\n\n /**\n * Stop polling.\n */\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n /**\n * Register a callback for config changes.\n */\n onChange(callback: ConfigChangeCallback): () => void {\n this.listeners.push(callback);\n return () => {\n const idx = this.listeners.indexOf(callback);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n /**\n * Get current cached config.\n */\n getConfig(): SdkConfig | null {\n return this.currentConfig;\n }\n\n /**\n * Fetch config with ETag/304 support.\n */\n private async fetchConfig(): Promise<SdkConfig | null> {\n try {\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.options.writeKey,\n 'Accept': 'application/json',\n };\n\n if (this.options.organizationId) {\n headers['X-Organization-ID'] = this.options.organizationId;\n }\n\n if (this.currentETag) {\n headers['If-None-Match'] = this.currentETag;\n }\n\n const response = await fetch(`${this.options.apiHost}/v1/sdk/config`, {\n method: 'GET',\n headers,\n });\n\n // 304 Not Modified — config unchanged\n if (response.status === 304) {\n return this.currentConfig;\n }\n\n if (!response.ok) {\n logger.warn(`SDK config fetch failed: HTTP ${response.status}`);\n return this.currentConfig;\n }\n\n const config: SdkConfig = await response.json();\n const newETag = response.headers.get('ETag');\n\n if (newETag) {\n this.currentETag = newETag;\n }\n\n // Detect changes\n const changed = !this.currentConfig ||\n JSON.stringify(this.currentConfig) !== JSON.stringify(config);\n\n this.currentConfig = config;\n\n if (changed) {\n for (const listener of this.listeners) {\n try {\n listener(config);\n } catch (err) {\n logger.warn('SDK config change listener error:', err);\n }\n }\n }\n\n return config;\n } catch (err) {\n logger.warn('SDK config fetch error:', err);\n return this.currentConfig;\n }\n }\n}\n","/**\n * PrefetchBundleClient — unified init-time resolver for in-app state.\n *\n * Fetches /v1/sdk/prefetch-bundle at SDK init and on a 5-minute ETag\n * refresh cadence. The bundle payload carries:\n * • `campaigns[]` — eligible, property-scoped, A/B-assigned campaigns\n * armed for this contact. EVERY in-app type is in\n * here (modal, banner, spin_wheel, carousel_cards,\n * sticky_bar, progress_bar, coachmark_tour, etc.).\n * • `inbox` — first page + unread count for the notification\n * drawer; lets AegisInbox hydrate without a second\n * round-trip.\n * • `etag` — content-hashed, stable when state is unchanged;\n * 304 responses cost ~50ms and consume no body.\n * • `invalidation_topic` — SSE channel name the cell-plane publishes\n * to when a playbook arms a campaign mid-session.\n * The SDK does NOT open SSE on that topic today —\n * we rely on the 5-minute poll + an explicit\n * `refresh()` hook that app code (AegisInAppManager,\n * AegisInbox) call on relevant user actions.\n *\n * This is the cornerstone of the preload-first contract from\n * docs/architecture/IN_APP_MESSAGES_EXPANSION_PLAN.md §1. The render\n * path must NEVER hit the network at trigger time — the bundle is\n * populated at init, and everything renders from memory.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface PrefetchBundleCampaign {\n id: string;\n type: string;\n sub_type?: string;\n title: string;\n body: string;\n image_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 | null;\n frequency?: {\n max_impressions?: number;\n max_impressions_per_day?: number;\n cooldown_seconds?: number;\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 inbox_enabled?: boolean;\n}\n\nexport interface PrefetchBundleInboxEntry {\n id: string;\n source: string;\n campaign_id: string | null;\n title: string;\n body: string;\n media_url: string | null;\n cta_url: string | null;\n metadata: Record<string, unknown> | null;\n read: boolean;\n read_at: string | null;\n created_at: string | null;\n expires_at: string | null;\n}\n\nexport interface PrefetchBundleInbox {\n unread_count: number;\n page: PrefetchBundleInboxEntry[];\n cursor: string | null;\n}\n\nexport interface PrefetchBundle {\n etag: string;\n generated_at: string;\n ttl_seconds: number;\n invalidation_topic: string;\n campaigns: PrefetchBundleCampaign[];\n inbox: PrefetchBundleInbox;\n}\n\nexport interface PrefetchBundleContext {\n device_type?: string;\n page_url?: string;\n geo?: string;\n is_new_user?: boolean;\n}\n\nexport interface PrefetchBundleClientOptions {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n contactId?: string;\n userId?: string;\n propertyId?: string;\n /** Cached AB assignments from localStorage, base64-json. */\n abAssignments?: Record<string, string>;\n /** Polling cadence; defaults to the bundle's own `ttl_seconds` (300s). */\n pollIntervalMs?: number;\n /** Factory for client context — re-evaluated on each fetch so device/page\n * state stays fresh without forcing callers to re-instantiate the client. */\n contextProvider?: () => PrefetchBundleContext;\n}\n\nexport type PrefetchBundleListener = (bundle: PrefetchBundle) => void;\n\nconst DEFAULT_POLL_MS = 300_000; // 5 minutes — aligns with cell-plane TTL\n\nexport class PrefetchBundleClient {\n private apiHost: string;\n private writeKey: string;\n private organizationId?: string;\n private contactId?: string;\n private userId?: string;\n private propertyId?: string;\n private abAssignments: Record<string, string>;\n private pollIntervalMs: number;\n private contextProvider: () => PrefetchBundleContext;\n\n private currentETag: string | null = null;\n private currentBundle: PrefetchBundle | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private listeners: PrefetchBundleListener[] = [];\n private inflightRefetch: Promise<PrefetchBundle | null> | null = null;\n\n constructor(options: PrefetchBundleClientOptions) {\n this.apiHost = options.apiHost;\n this.writeKey = options.writeKey;\n this.organizationId = options.organizationId;\n this.contactId = options.contactId;\n this.userId = options.userId;\n this.propertyId = options.propertyId;\n this.abAssignments = options.abAssignments ?? {};\n this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_MS;\n this.contextProvider = options.contextProvider ?? (() => ({}));\n }\n\n /**\n * Initial fetch + start the background ETag poll. Resolves to the bundle\n * (or `null` if the first fetch failed — callers should fall back to an\n * empty campaign list, not abort SDK init).\n */\n async start(): Promise<PrefetchBundle | null> {\n const bundle = await this.fetch();\n this.pollTimer = setInterval(() => {\n this.fetch().catch((err) => logger.warn('prefetch-bundle poll failed:', err));\n }, this.pollIntervalMs);\n return bundle;\n }\n\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n getBundle(): PrefetchBundle | null {\n return this.currentBundle;\n }\n\n getCampaigns(): PrefetchBundleCampaign[] {\n return this.currentBundle?.campaigns ?? [];\n }\n\n getInbox(): PrefetchBundleInbox {\n return this.currentBundle?.inbox ?? { unread_count: 0, page: [], cursor: null };\n }\n\n /** Force a refresh (dedupes concurrent calls). Exposed so inbox mutations\n * and campaign-activation SSE messages can trigger a refetch on demand. */\n async refresh(): Promise<PrefetchBundle | null> {\n if (this.inflightRefetch) return this.inflightRefetch;\n this.inflightRefetch = this.fetch();\n try {\n return await this.inflightRefetch;\n } finally {\n this.inflightRefetch = null;\n }\n }\n\n /** Subscribe to bundle changes (emits on first fetch + on any content\n * change — ETag 304 does NOT fire the listener). Returns an unsubscribe. */\n onChange(listener: PrefetchBundleListener): () => void {\n this.listeners.push(listener);\n return () => {\n const idx = this.listeners.indexOf(listener);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n /**\n * Update the identity tuple — called by AegisInAppManager when the host\n * app resolves a contactId post-init (e.g., after login). Triggers an\n * immediate refresh since the eligible campaigns + inbox will differ.\n */\n updateIdentity(partial: {\n contactId?: string;\n userId?: string;\n organizationId?: string;\n propertyId?: string;\n }): void {\n let changed = false;\n if (partial.contactId !== undefined && partial.contactId !== this.contactId) {\n this.contactId = partial.contactId;\n changed = true;\n }\n if (partial.userId !== undefined && partial.userId !== this.userId) {\n this.userId = partial.userId;\n changed = true;\n }\n if (\n partial.organizationId !== undefined &&\n partial.organizationId !== this.organizationId\n ) {\n this.organizationId = partial.organizationId;\n changed = true;\n }\n if (partial.propertyId !== undefined && partial.propertyId !== this.propertyId) {\n this.propertyId = partial.propertyId;\n changed = true;\n }\n if (changed) {\n // Identity change invalidates ETag — drop the cached tag so the next\n // fetch gets a fresh payload instead of a 304 bound to the old identity.\n this.currentETag = null;\n this.refresh().catch((err) =>\n logger.warn('prefetch-bundle identity-refresh failed:', err),\n );\n }\n }\n\n /** Update cached AB assignments. Called by downstream renderers after\n * they display a variant. Persisted to localStorage by higher layers. */\n setAbAssignments(assignments: Record<string, string>): void {\n this.abAssignments = { ...assignments };\n }\n\n /**\n * Wire an already-open realtime subscriber (from `aegis.realtime.subscribe`\n * or a caller-provided EventSource) so the prefetch bundle refreshes\n * instantly when the cell-plane signals `bundle.invalidate` — covering\n * the window between an event (cart abandon, inbox write) and the\n * 5-min ETag poll.\n *\n * `subscriber.onMessage(handler)` must fire with parsed message bodies\n * from the contact's SSE stream. The handler filters for\n * `type === 'bundle.invalidate'` and calls `refresh()`. Returns an\n * unsubscribe function.\n *\n * Degrades gracefully: if the subscriber is missing or throws, the\n * 5-min poll still keeps state converging.\n */\n subscribeInvalidations(subscriber: {\n onMessage: (handler: (msg: { type?: string; [k: string]: unknown }) => void) => () => void;\n }): () => void {\n try {\n const unsub = subscriber.onMessage((msg) => {\n if (msg && msg.type === 'bundle.invalidate') {\n this.refresh().catch((err) =>\n logger.warn('prefetch-bundle invalidate-refresh failed:', err),\n );\n }\n });\n return unsub;\n } catch (err) {\n logger.warn('prefetch-bundle subscribeInvalidations failed — relying on poll:', err);\n return () => {};\n }\n }\n\n // ── internals ──────────────────────────────────────────────────────────\n\n private async fetch(): Promise<PrefetchBundle | null> {\n const ctx = this.contextProvider();\n const qs = new URLSearchParams();\n if (ctx.device_type) qs.set('device_type', ctx.device_type);\n if (ctx.page_url) qs.set('page_url', ctx.page_url);\n if (ctx.geo) qs.set('geo', ctx.geo);\n qs.set('is_new_user', ctx.is_new_user ? 'true' : 'false');\n\n const url = `${this.apiHost}/v1/sdk/prefetch-bundle?${qs.toString()}`;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n Accept: 'application/json',\n };\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.propertyId) headers['X-Property-Id'] = this.propertyId;\n if (this.currentETag) headers['If-None-Match'] = this.currentETag;\n if (Object.keys(this.abAssignments).length > 0) {\n try {\n headers['X-AB-Assignments'] = btoa(JSON.stringify(this.abAssignments));\n } catch {\n // base64 on non-ASCII campaign IDs — skip rather than 400 the request\n }\n }\n\n let response: Response;\n try {\n response = await fetch(url, { method: 'GET', headers });\n } catch (err) {\n logger.warn('prefetch-bundle fetch network error:', err);\n return this.currentBundle;\n }\n\n // 304 — same bundle; listeners are intentionally NOT fired.\n if (response.status === 304) {\n return this.currentBundle;\n }\n\n if (!response.ok) {\n logger.warn(`prefetch-bundle fetch failed: HTTP ${response.status}`);\n return this.currentBundle;\n }\n\n const etag = response.headers.get('ETag');\n let bundle: PrefetchBundle;\n try {\n bundle = (await response.json()) as PrefetchBundle;\n } catch (err) {\n logger.warn('prefetch-bundle invalid JSON:', err);\n return this.currentBundle;\n }\n\n if (etag) this.currentETag = etag;\n this.currentBundle = bundle;\n\n for (const l of this.listeners) {\n try {\n l(bundle);\n } catch (err) {\n logger.warn('prefetch-bundle listener threw:', err);\n }\n }\n\n return bundle;\n }\n}\n","/**\n * AegisInbox — client-side App Inbox (Message Center).\n *\n * Backs the notification drawer on actii.me WebView and every tenant\n * storefront that embeds the Web SDK. Operates against cell-plane's\n * /v1/in-app/inbox family of endpoints (list, unread-count, read,\n * dismiss, read-all).\n *\n * Design choices:\n * • Hydrate from the prefetch bundle at init — no extra HTTP on first\n * paint. PrefetchBundleClient seeds us; we then own the live copy.\n * • Mutations are optimistic + beacon-backed. Read / dismiss writes to\n * local state immediately, then POSTs with `keepalive: true` so an\n * in-flight dismiss survives page unload.\n * • Badge polling uses the tiny `/unread-count` endpoint on a 60-second\n * cadence — matches the `inbox_poll_interval_ms` from sdk_config's\n * TransportConfig.hybrid mode.\n * • No external dependencies; IndexedDB is optional (we gracefully fall\n * back to in-memory when unavailable, e.g., in private browsing).\n */\n\nimport type { PrefetchBundleClient } from '../core/prefetch-bundle-client';\nimport { logger } from '../utils/logger';\n\nexport interface AegisInboxEntry {\n id: string;\n source: string;\n campaign_id: string | null;\n title: string;\n body: string;\n media_url: string | null;\n cta_url: string | null;\n metadata: Record<string, unknown> | null;\n read: boolean;\n read_at: string | null;\n dismissed_at?: string | null;\n created_at: string | null;\n expires_at: string | null;\n}\n\nexport interface AegisInboxConfig {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n contactId?: string;\n propertyId?: string;\n bundleClient?: PrefetchBundleClient;\n unreadPollIntervalMs?: number;\n}\n\nexport type InboxListener = (state: { entries: AegisInboxEntry[]; unreadCount: number }) => void;\n\nconst DEFAULT_UNREAD_POLL = 60_000;\n\n/** IndexedDB schema version + constants. Offline cache is a nice-to-have,\n * so we never break the app if IDB operations fail. */\nconst IDB_NAME = 'aegis-inbox';\nconst IDB_STORE = 'messages';\nconst IDB_VERSION = 1;\n\nexport class AegisInbox {\n private apiHost: string;\n private writeKey: string;\n private organizationId?: string;\n private contactId?: string;\n private propertyId?: string;\n private bundleClient?: PrefetchBundleClient;\n private unreadPollIntervalMs: number;\n\n private entries: AegisInboxEntry[] = [];\n private unreadCount = 0;\n private cursor: string | null = null;\n private listeners: InboxListener[] = [];\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private bundleUnsub: (() => void) | null = null;\n\n constructor(config: AegisInboxConfig) {\n this.apiHost = config.apiHost;\n this.writeKey = config.writeKey;\n this.organizationId = config.organizationId;\n this.contactId = config.contactId;\n this.propertyId = config.propertyId;\n this.bundleClient = config.bundleClient;\n this.unreadPollIntervalMs = config.unreadPollIntervalMs ?? DEFAULT_UNREAD_POLL;\n }\n\n /** Hydrate from bundle (if available), restore the IDB cache (if any),\n * then start the background unread-count poll. */\n async initialize(): Promise<void> {\n // Inbox is contact-scoped — if the host app hasn't resolved a contact\n // yet, stay dormant. The host will call setIdentity() later.\n if (!this.contactId || !this.propertyId) {\n logger.warn('AegisInbox: no contact/property yet — staying dormant');\n return;\n }\n\n // Try IDB cache for instant paint on cold start.\n const cached = await this.readCache();\n if (cached.length > 0) {\n this.entries = cached;\n this.recomputeUnread();\n this.emit();\n }\n\n // Hydrate from prefetch bundle if we have one — this is the preload\n // path, no additional network round-trip.\n if (this.bundleClient) {\n const inbox = this.bundleClient.getInbox();\n this.seedFromBundle(inbox.page, inbox.unread_count);\n // Keep following bundle changes — when the bundle-poller refreshes,\n // the inbox slice refreshes too.\n this.bundleUnsub = this.bundleClient.onChange((bundle) => {\n this.seedFromBundle(bundle.inbox.page, bundle.inbox.unread_count);\n });\n } else {\n // No bundle client — do one list call to prime.\n await this.refreshList();\n }\n\n this.pollTimer = setInterval(() => {\n this.refreshUnreadCount().catch((err) =>\n logger.warn('inbox unread-count poll failed:', err),\n );\n }, this.unreadPollIntervalMs);\n }\n\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n if (this.bundleUnsub) {\n this.bundleUnsub();\n this.bundleUnsub = null;\n }\n }\n\n /** Update identity after login / property switch. Clears the local\n * inbox since it's intrinsically contact+property scoped. */\n setIdentity(partial: { contactId?: string; propertyId?: string; organizationId?: string }): void {\n let changed = false;\n if (partial.contactId !== undefined && partial.contactId !== this.contactId) {\n this.contactId = partial.contactId;\n changed = true;\n }\n if (partial.propertyId !== undefined && partial.propertyId !== this.propertyId) {\n this.propertyId = partial.propertyId;\n changed = true;\n }\n if (partial.organizationId !== undefined && partial.organizationId !== this.organizationId) {\n this.organizationId = partial.organizationId;\n changed = true;\n }\n if (changed) {\n this.entries = [];\n this.unreadCount = 0;\n this.cursor = null;\n this.emit();\n void this.clearCache();\n void this.refreshList();\n }\n }\n\n // ── Read-side API ────────────────────────────────────────────────────\n\n getEntries(): AegisInboxEntry[] {\n return this.entries;\n }\n\n getUnreadCount(): number {\n return this.unreadCount;\n }\n\n /** Pagination cursor (ISO-8601 timestamp of the oldest entry currently\n * held). Pass it back via `loadMore()` to fetch older history. */\n getCursor(): string | null {\n return this.cursor;\n }\n\n /** Append one more page of older entries using the current cursor. */\n async loadMore(): Promise<void> {\n if (!this.contactId || !this.propertyId || !this.cursor) return;\n try {\n const url = `${this.apiHost}/v1/in-app/inbox?limit=20&cursor=${encodeURIComponent(this.cursor)}`;\n const resp = await fetch(url, { headers: this.headers() });\n if (!resp.ok) return;\n const body = (await resp.json()) as {\n entries: AegisInboxEntry[];\n unread_count: number;\n cursor: string | null;\n };\n const byId = new Set(this.entries.map((e) => e.id));\n for (const e of body.entries) {\n if (!byId.has(e.id)) this.entries.push(e);\n }\n this.cursor = body.cursor;\n void this.writeCache();\n this.emit();\n } catch (err) {\n logger.warn('inbox loadMore failed:', err);\n }\n }\n\n onChange(l: InboxListener): () => void {\n this.listeners.push(l);\n return () => {\n const i = this.listeners.indexOf(l);\n if (i >= 0) this.listeners.splice(i, 1);\n };\n }\n\n async refreshList(): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n const resp = await fetch(\n `${this.apiHost}/v1/in-app/inbox?limit=20`,\n { headers: this.headers() },\n );\n if (!resp.ok) {\n logger.warn(`inbox list fetch failed: HTTP ${resp.status}`);\n return;\n }\n const body = (await resp.json()) as {\n entries: AegisInboxEntry[];\n unread_count: number;\n cursor: string | null;\n };\n this.entries = body.entries;\n this.unreadCount = body.unread_count;\n this.cursor = body.cursor;\n void this.writeCache();\n this.emit();\n } catch (err) {\n logger.warn('inbox list fetch error:', err);\n }\n }\n\n async refreshUnreadCount(): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n const resp = await fetch(\n `${this.apiHost}/v1/in-app/inbox/unread-count`,\n { headers: this.headers() },\n );\n if (!resp.ok) return;\n const body = (await resp.json()) as { unread_count: number };\n if (body.unread_count !== this.unreadCount) {\n this.unreadCount = body.unread_count;\n this.emit();\n // New messages detected — do a list refresh to get them.\n if (this.unreadCount > 0) {\n void this.refreshList();\n }\n }\n } catch {\n /* swallow — transient network */\n }\n }\n\n // ── Mutations (optimistic + beacon) ──────────────────────────────────\n\n async markRead(messageId: string): Promise<void> {\n const entry = this.entries.find((e) => e.id === messageId);\n if (!entry || entry.read) return;\n entry.read = true;\n entry.read_at = new Date().toISOString();\n this.recomputeUnread();\n void this.writeCache();\n this.emit();\n await this.postBeacon(`/v1/in-app/inbox/${messageId}/read`);\n }\n\n async dismiss(messageId: string): Promise<void> {\n const idx = this.entries.findIndex((e) => e.id === messageId);\n if (idx < 0) return;\n const [entry] = this.entries.splice(idx, 1);\n if (entry && !entry.read) {\n this.recomputeUnread();\n }\n void this.writeCache();\n this.emit();\n await this.postBeacon(`/v1/in-app/inbox/${messageId}/dismiss`);\n }\n\n async markAllRead(): Promise<void> {\n const now = new Date().toISOString();\n for (const e of this.entries) {\n if (!e.read) {\n e.read = true;\n e.read_at = now;\n }\n }\n this.unreadCount = 0;\n void this.writeCache();\n this.emit();\n await this.postBeacon('/v1/in-app/inbox/read-all');\n }\n\n // ── Internals ────────────────────────────────────────────────────────\n\n private seedFromBundle(page: AegisInboxEntry[], unreadCount: number): void {\n // Merge rather than overwrite — an entry we already marked read\n // locally should stay read even if the bundle is slightly stale.\n const byId = new Map(this.entries.map((e) => [e.id, e] as const));\n const merged = page.map((incoming) => {\n const existing = byId.get(incoming.id);\n if (existing && existing.read && !incoming.read) {\n return { ...incoming, read: true, read_at: existing.read_at };\n }\n return incoming;\n });\n // Preserve any locally-cached entries that aren't in this bundle page\n // (e.g., older history not included in the first slice).\n for (const [id, e] of byId) {\n if (!merged.find((m) => m.id === id)) merged.push(e);\n }\n merged.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || ''));\n this.entries = merged;\n this.unreadCount = unreadCount;\n void this.writeCache();\n this.emit();\n }\n\n private recomputeUnread(): void {\n this.unreadCount = this.entries.filter((e) => !e.read).length;\n }\n\n private emit(): void {\n const snapshot = { entries: [...this.entries], unreadCount: this.unreadCount };\n for (const l of this.listeners) {\n try {\n l(snapshot);\n } catch (err) {\n logger.warn('inbox listener threw:', err);\n }\n }\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n Accept: 'application/json',\n };\n if (this.organizationId) h['X-Organization-ID'] = this.organizationId;\n if (this.contactId) h['X-Contact-ID'] = this.contactId;\n if (this.propertyId) h['X-Property-Id'] = this.propertyId;\n return h;\n }\n\n /** Best-effort beacon-style POST. Uses `keepalive: true` so it survives\n * a navigation away from the current page (e.g., user taps the CTA\n * which takes them to another URL right after dismiss). */\n private async postBeacon(path: string): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n await fetch(`${this.apiHost}${path}`, {\n method: 'POST',\n headers: this.headers(),\n keepalive: true,\n });\n } catch (err) {\n // The mutation is already applied locally; failed delivery will be\n // reconciled on the next refreshList().\n logger.warn(`inbox mutation POST ${path} failed:`, err);\n }\n }\n\n // ── IndexedDB cache (non-critical) ───────────────────────────────────\n\n private async openDb(): Promise<IDBDatabase | null> {\n if (typeof indexedDB === 'undefined') return null;\n return new Promise((resolve) => {\n try {\n const req = indexedDB.open(IDB_NAME, IDB_VERSION);\n req.onerror = () => resolve(null);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE)) {\n db.createObjectStore(IDB_STORE);\n }\n };\n req.onsuccess = () => resolve(req.result);\n } catch {\n resolve(null);\n }\n });\n }\n\n private cacheKey(): string | null {\n if (!this.contactId || !this.propertyId) return null;\n return `${this.organizationId || 'default'}:${this.propertyId}:${this.contactId}`;\n }\n\n private async writeCache(): Promise<void> {\n const key = this.cacheKey();\n if (!key) return;\n const db = await this.openDb();\n if (!db) return;\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).put(this.entries, key);\n await new Promise<void>((res, rej) => {\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n } catch {\n /* noop */\n } finally {\n db.close();\n }\n }\n\n private async readCache(): Promise<AegisInboxEntry[]> {\n const key = this.cacheKey();\n if (!key) return [];\n const db = await this.openDb();\n if (!db) return [];\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const req = tx.objectStore(IDB_STORE).get(key);\n return await new Promise<AegisInboxEntry[]>((res) => {\n req.onsuccess = () => res((req.result as AegisInboxEntry[]) || []);\n req.onerror = () => res([]);\n });\n } catch {\n return [];\n } finally {\n db.close();\n }\n }\n\n private async clearCache(): Promise<void> {\n const key = this.cacheKey();\n if (!key) return;\n const db = await this.openDb();\n if (!db) return;\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).delete(key);\n await new Promise<void>((res) => {\n tx.oncomplete = () => res();\n tx.onerror = () => res();\n });\n } catch {\n /* noop */\n } finally {\n db.close();\n }\n }\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 * Workspace cascade reader. Host SDK sets this to\n * `() => aegis.getEffectiveWorkspaceId()` so widget interaction events\n * (impressions, clicks, spin/scratch plays, feedback submissions)\n * arrive at the gateway with the same workspace context the main\n * analytics SDK uses. See PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n */\n getWorkspaceId?: () => string | undefined;\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 private getWorkspaceId?: () => string | undefined;\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 this.getWorkspaceId = config.getWorkspaceId;\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 this.emitEvent('destroyed', {});\n }\n\n /**\n * Fire a lifecycle event to the consumer-supplied callback. Public-API\n * hook configured via `AegisWidgetConfig.onEvent`. Currently only used\n * by external callers passing their own logger; internal widget lifecycle\n * events get wired through here as they're added.\n */\n private emitEvent(eventType: string, data: unknown): 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 // Plumb workspace cascade so feedback submissions are attributed to\n // the same outlet the customer was viewing. See\n // PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n const workspaceId = this.getWorkspaceId?.();\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 workspace_id: workspaceId,\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 const workspaceId = this.getWorkspaceId?.();\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 workspace_id: workspaceId,\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 * 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';\nimport { IntentRuleEvaluator } from '../triggers/IntentRuleEvaluator';\nimport { ContactScoresFetcher } from '../triggers/ContactScoresFetcher';\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 /** Shared IntentRuleEvaluator for identified-contact micro-intent\n * patterns. The ContactScoresFetcher writes Layer-1 signals into its\n * snapshot; IntentSnapshotCollector (if wired by the consumer) writes\n * Layer-2 signals. Exposed so apps that pre-existed P4a can swap in\n * their own evaluator if they need to. */\n readonly intentRuleEvaluator: IntentRuleEvaluator;\n /** Bridges GET /v1/sdk/contact-scores into the evaluator snapshot.\n * Triggered automatically on initialize() and updateContactId(). */\n readonly contactScores: ContactScoresFetcher;\n private contactId?: string;\n private initialized = false;\n\n constructor(config: AegisMessageRuntimeConfig) {\n const triggerEngine = config.triggerEngine ?? new TriggerEngine();\n const ownsTriggerEngine = !config.triggerEngine;\n this.contactId = config.contactId;\n // Ownership of the engine is tracked downstream by WidgetManager\n // (which is the only consumer that needs to call lifecycle methods\n // on it). The facade itself only forwards.\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 getWorkspaceId: config.getWorkspaceId,\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 getWorkspaceId: config.getWorkspaceId,\n });\n\n this.intentRuleEvaluator = new IntentRuleEvaluator();\n this.contactScores = new ContactScoresFetcher({\n // Falls back to same-origin when no apiHost configured (storefront\n // typical case) — matches WidgetManager/InAppManager handling\n // where `config.apiHost` is also `string | undefined`.\n apiHost: config.apiHost ?? '',\n writeKey: config.writeKey,\n organizationId: config.organizationId,\n evaluator: this.intentRuleEvaluator,\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 // Fire-and-forget the Layer-1 score fetch when we already know the\n // contact at init. Identified-contact micro-intent patterns need\n // this snapshot — without it their AND-compound rules eval to\n // false. Anonymous patterns are unaffected.\n if (this.contactId) {\n void this.contactScores.fetchForContact(this.contactId);\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.contactId = contactId;\n this.inApp.updateContactId?.(contactId);\n await this.widgets.updateContactId(contactId);\n // Re-fetch Layer-1 scores for the new identity. Session-dedup in\n // the fetcher means a repeat call with the same contactId is a\n // no-op, so SPA navigation that re-calls identify() is cheap.\n void this.contactScores.fetchForContact(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 // --- Qualifying-event refresh facade (DLR Tracker 1 / P1, 2026-05-28) ---\n //\n // `track`, `page`, and `screen` here are thin trigger taps for the\n // in-app subsystem — they tell `AegisInAppManager.refreshOnEvent` that\n // a host-app event happened, and the debounced refresh re-fetches\n // `/v1/in-app/active` so newly armed campaigns become visible without\n // waiting for the next identity flip. They are NOT a substitute for\n // the main analytics SDK (`Aegis` in `core/analytics.ts`) — those\n // methods own the canonical capture path (batch uplink, governance,\n // workspace resolution, etc.). Integrations that already call\n // `aegis.track(...)` should also call `runtime.track(...)` to drive\n // the in-app refresh. A future P-phase will bridge the two so a single\n // call on the public analytics surface drives both behaviors.\n\n /**\n * Notify the in-app subsystem that a tracked event occurred. Schedules\n * a debounced refresh of armed campaigns so newly eligible in-app\n * messages (e.g., trigger-gated on `cart_item_added`) become visible\n * within ~300ms — bursts coalesce. See\n * `AegisInAppManager.refreshOnEvent` for debounce semantics and why\n * this matters under storefront polling.\n */\n track(eventName: string): void {\n if (!eventName) return;\n this.inApp.refreshOnEvent(eventName);\n }\n\n /**\n * Notify the in-app subsystem that a URL-bound page view occurred.\n * Mirrors `aegis.page()` semantics — fires `'page_view'` as the\n * qualifying event so the trailing debounce covers SPA route bursts\n * (history.pushState rapid-fire) without spamming the endpoint.\n */\n page(name?: string): void {\n this.inApp.refreshOnEvent(name ?? 'page_view');\n }\n\n /**\n * Notify the in-app subsystem that a SPA-logical screen view occurred\n * (cart drawer open, checkout step transition — anywhere `aegis.screen()`\n * is called). Refresh-on-screen lets per-screen-targeted campaigns\n * arm without a URL change.\n */\n screen(name: string): void {\n if (!name) return;\n this.inApp.refreshOnEvent(name);\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.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 * 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 * @deprecated since P15.1 (2026-05-26) — use `locationCodes` instead.\n * Pre-2026-05-26 the path segment after the brand subdomain was a\n * workspace_code; the canonical hierarchy reversal made it a\n * location_code (outlet under a brand). Field name retained for\n * backward compat with SDK consumers that haven't migrated; new\n * consumers MUST read `locationCodes`. Server still populates BOTH\n * with the same array during the deprecation window so a stale\n * SDK keeps working.\n */\n workspaceCodes: string[];\n /**\n * P15.1 — outlet-code allowlist for SDK path-segment detection.\n * Empty array = no outlet codes registered for this org (single-\n * outlet tenant). SDK uses this set to decide whether\n * `location.pathname.split('/')[1]` is a valid outlet code vs a\n * generic route (`/products`, `/collections`). Pass to\n * `aegis.ingestLocationCodes()` after bootstrap completes.\n *\n * Same array contents as `workspaceCodes` during the deprecation\n * window — renaming the field gives semantic clarity (these ARE\n * location codes under the new hierarchy) without breaking\n * existing consumers.\n */\n locationCodes: string[];\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';\n\nconst aegis = new Aegis();\n\nexport default aegis;\n\nexport { Aegis } from './core/analytics';\nexport type { AegisConfig, CellEndpoint, CellRegion } from './types/config';\nexport type {\n AegisEvent,\n TrackEvent,\n IdentifyEvent,\n PageEvent,\n ScreenEvent,\n GroupEvent,\n AliasEvent,\n EventContext,\n BatchPayload,\n BatchResponse,\n} from './types/events';\nexport { UserNamespace } from './core/user-namespace';\nexport type { OptInChannel } from './core/user-namespace';\nexport type { Plugin, PluginRegistry } from './types/plugin';\nexport { debounce, throttle } from './utils/debounce';\nexport type {\n ConsentPreferences,\n ConsentCategory,\n ConsentStatus,\n} from './utils/consent';\n// In-app + widget types are re-exported for callers that configure\n// AegisMessageRuntime or read campaign objects. The underlying manager\n// classes are intentionally NOT exported — use AegisMessageRuntime.\nexport type {\n InAppCampaign,\n AegisInAppConfig,\n CampaignClickEvent,\n CampaignDismissEvent,\n AegisErrorEvent,\n InAppLifecycleEventMap,\n} from './inapp';\nexport { renderPreview } from './inapp';\n\nexport { AegisPlacementManager } from './placements/AegisPlacementManager';\nexport type {\n PlacementContent,\n PlacementSlot,\n AegisPlacementConfig,\n} from './placements/AegisPlacementManager';\n\nexport type {\n WidgetConfig,\n GamificationPrize,\n AegisWidgetConfig,\n} from './widgets';\n\nexport { TriggerEngine } from './triggers';\nexport type {\n TriggerRule,\n ScrollDepthConfig,\n TimeOnPageConfig,\n ExitIntentConfig,\n InactivityConfig,\n TriggerEvent,\n} from './triggers';\n\nexport { SdkConfigPoller } from './core/sdk-config-poller';\nexport type { SdkConfig, SdkConfigPollerOptions, ConfigChangeCallback } from './core/sdk-config-poller';\n\n// Preload-first bundle (2026-04-22) — fetches armed campaigns + inbox\n// slice once at init; everything renders from memory on trigger.\nexport { PrefetchBundleClient } from './core/prefetch-bundle-client';\nexport type {\n PrefetchBundle,\n PrefetchBundleCampaign,\n PrefetchBundleInbox,\n PrefetchBundleInboxEntry,\n PrefetchBundleClientOptions,\n PrefetchBundleContext,\n PrefetchBundleListener,\n} from './core/prefetch-bundle-client';\n\n// App Inbox — persistent message-center client.\nexport { AegisInbox } from './inbox';\nexport type { AegisInboxConfig, AegisInboxEntry, InboxListener } from './inbox';\n\n// Unified message runtime — the single entry point for in-app + widgets.\n// All 20 in-app types (modal/banner/tooltip/full_screen/spin_wheel/\n// scratch_card/nps_survey/quiz/countdown_offer/star_rating/...) flow\n// through this one class. The underlying AegisInAppManager +\n// AegisWidgetManager implementations are internal to the package.\nexport { AegisMessageRuntime } from './runtime';\nexport type { AegisMessageRuntimeConfig } from './runtime';\n\nexport { AegisWebPush } from './push/AegisWebPush';\nexport type {\n AegisWebPushConfig,\n AegisAPIClient,\n ContactIdentity,\n PushEventTracker,\n} from './push/AegisWebPush';\n\nexport {\n bootstrap,\n readFirstPartyCookie,\n writeFirstPartyCookie,\n deriveDeviceFingerprint,\n BootstrapError,\n} from './core/bootstrap';\nexport type { BootstrapRequest, BootstrapResult } from './core/bootstrap';\n\nexport { RateLimiter } from './core/rate-limiter';\nexport type { RateLimiterOptions } from './core/rate-limiter';\n\n// Event-governance — SDK-side cap enforcement. The NameGovernor is wired\n// into `Aegis.captureEvent()` automatically; callers only interact with it\n// via `aegis.ingestGovernanceHint(bootstrapResult.eventGovernance)`.\nexport { NameGovernor, BloomFilter, murmurhash3_x86_32 } from './governance';\nexport type { EventGovernanceHint, DropReport, BloomFilterParams } from './governance';\n\n// NOTE: SSE-based realtime subscription is intentionally NOT exported from the\n// public SDK surface. The Aegis Web SDK uses HTTP batch uplink + HTTP polling\n// downstream (via AegisInAppManager) + Web Push (via AegisWebPush). Tenant\n// dashboards that need SSE open it directly via their own Next.js API routes,\n// not through this SDK. See RFC 2026-04-16 §A.\n\nexport { EcommerceTracker } from './ecommerce';\nexport type {\n EcommerceProduct,\n EcommerceCart,\n EcommerceCheckout,\n EcommerceOrder,\n EcommerceCoupon,\n EcommerceSearch,\n EcommerceProductList,\n EcommerceWishlist,\n EcommerceWaitlist,\n EcommercePromotion,\n} from './ecommerce';\n"],"names":["goto","readAnonIdFromStorage","m","isMobile","mobileConfig"],"mappings":"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"}