@bitpalm/ai-agents 0.5.0 → 0.7.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/theme.ts","../src/widget.ts"],"sourcesContent":["export { createWidget } from \"./widget\";\nexport { detectHostTheme } from \"./theme\";\nexport type { BitPalmAgentOptions, BitPalmAgentInstance, BitPalmIdentifyPayload, BitPalmCustomContext, BitPalmEventType, BitPalmEventCallback, BitPalmTheme } from \"./types\";\n\nimport { createWidget } from \"./widget\";\nimport { normalizeThemeSetting } from \"./theme\";\n\nfunction parseBoolean(value: string | undefined): boolean | undefined {\n if (value == null) return undefined;\n const normalized = value.trim().toLowerCase();\n if ([\"1\", \"true\", \"yes\", \"on\"].includes(normalized)) return true;\n if ([\"0\", \"false\", \"no\", \"off\"].includes(normalized)) return false;\n return undefined;\n}\n\n/**\n * Auto-init from script tag:\n * <script src=\"https://cdn.bitpalm.ai/widget.js\" data-slug=\"my-agent\"></script>\n */\nif (typeof document !== \"undefined\") {\n const script = document.currentScript as HTMLScriptElement | null;\n if (script?.dataset.slug) {\n const init = () => {\n createWidget({\n slug: script!.dataset.slug!,\n locale: script!.dataset.locale,\n baseUrl: script!.dataset.baseUrl,\n token: script!.dataset.token,\n zIndex: script!.dataset.zIndex ? Number(script!.dataset.zIndex) : undefined,\n autoIdentify: parseBoolean(script!.dataset.autoIdentify),\n theme: normalizeThemeSetting(script!.dataset.theme),\n });\n };\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", init);\n } else {\n init();\n }\n }\n}\n","import type { BitPalmTheme } from \"./types\";\n\nexport type HostTheme = \"light\" | \"dark\";\n\nconst DARK_CLASSES = [\"dark\", \"dark-mode\", \"dark-theme\", \"theme-dark\"];\nconst LIGHT_CLASSES = [\"light\", \"light-mode\", \"light-theme\", \"theme-light\"];\nconst THEME_ATTRIBUTES = [\"data-theme\", \"data-color-scheme\", \"data-color-mode\", \"data-mode\", \"data-bs-theme\"];\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\";\n\nexport function normalizeThemeSetting(value: unknown): BitPalmTheme {\n return value === \"light\" || value === \"dark\" ? value : \"auto\";\n}\n\n/** Theme set explicitly on an element: a class like \"dark\" or an attribute like data-theme=\"dark\". */\nfunction explicitTheme(el: Element | null): HostTheme | null {\n if (!el) return null;\n if (DARK_CLASSES.some((name) => el.classList.contains(name))) return \"dark\";\n if (LIGHT_CLASSES.some((name) => el.classList.contains(name))) return \"light\";\n for (const attr of THEME_ATTRIBUTES) {\n const value = (el.getAttribute(attr) || \"\").toLowerCase();\n if (value.includes(\"dark\")) return \"dark\";\n if (value.includes(\"light\")) return \"light\";\n }\n return null;\n}\n\nfunction channel(value: number): number {\n const s = value / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n}\n\n/** Dark or light from an element's own opaque background color. */\nfunction backgroundTheme(el: Element | null, win: Window): HostTheme | null {\n if (!el) return null;\n const match = win.getComputedStyle(el).backgroundColor.match(/rgba?\\(([^)]+)\\)/);\n if (!match) return null;\n const [r, g, b, a = 1] = match[1].split(/[\\s,/]+/).filter(Boolean).map(Number);\n if ([r, g, b, a].some((n) => Number.isNaN(n)) || a < 0.5) return null;\n const luminance = 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);\n return luminance < 0.2 ? \"dark\" : \"light\";\n}\n\n/** The site declares color-scheme: only dark, or both and the visitor's system decides. */\nfunction colorSchemeTheme(doc: Document, win: Window): HostTheme | null {\n const computed = win.getComputedStyle(doc.documentElement).colorScheme || \"\";\n const meta = doc.querySelector('meta[name=\"color-scheme\"]')?.getAttribute(\"content\") || \"\";\n const scheme = `${computed} ${meta}`.toLowerCase();\n if (!scheme.includes(\"dark\")) return null;\n if (!scheme.includes(\"light\")) return \"dark\";\n return win.matchMedia?.(DARK_QUERY).matches ? \"dark\" : \"light\";\n}\n\n/**\n * Best guess of the host page's current theme, most explicit signal first:\n * theme classes and attributes on <html> or <body>, then the page background,\n * then a declared color-scheme. Pages without any of these count as light, so\n * a light-only site never gets a dark widget just because the visitor's\n * system is dark.\n */\nexport function detectHostTheme(doc: Document = document, win: Window = window): HostTheme {\n return (\n explicitTheme(doc.documentElement) ??\n explicitTheme(doc.body) ??\n backgroundTheme(doc.body, win) ??\n backgroundTheme(doc.documentElement, win) ??\n colorSchemeTheme(doc, win) ??\n \"light\"\n );\n}\n\n/**\n * Calls onChange when the detected theme changes: class or attribute changes\n * on <html> and <body>, and system theme changes. Returns a stop function.\n */\nexport function watchHostTheme(\n onChange: (theme: HostTheme) => void,\n doc: Document = document,\n win: Window = window,\n): () => void {\n let last = detectHostTheme(doc, win);\n let scheduled = false;\n\n const check = () => {\n scheduled = false;\n const next = detectHostTheme(doc, win);\n if (next === last) return;\n last = next;\n onChange(next);\n };\n // Theme switches often touch several attributes at once, check once per frame.\n const schedule = () => {\n if (scheduled) return;\n scheduled = true;\n if (typeof win.requestAnimationFrame === \"function\") win.requestAnimationFrame(check);\n else setTimeout(check, 16);\n };\n\n const observer = typeof MutationObserver !== \"undefined\" ? new MutationObserver(schedule) : null;\n const observed = { attributes: true, attributeFilter: [\"class\", \"style\", ...THEME_ATTRIBUTES] };\n observer?.observe(doc.documentElement, observed);\n if (doc.body) observer?.observe(doc.body, observed);\n\n const media = typeof win.matchMedia === \"function\" ? win.matchMedia(DARK_QUERY) : null;\n media?.addEventListener?.(\"change\", schedule);\n\n return () => {\n observer?.disconnect();\n media?.removeEventListener?.(\"change\", schedule);\n };\n}\n","import type { BitPalmAgentOptions, BitPalmAgentInstance, BitPalmIdentifyPayload, BitPalmCustomContext, BitPalmEventType, BitPalmEventCallback, BitPalmTheme } from \"./types\";\nimport { detectHostTheme, normalizeThemeSetting, watchHostTheme, type HostTheme } from \"./theme\";\n\nconst DEFAULT_BASE_URL = \"https://agents.bitpalm.ai\";\nconst STORAGE_PREFIX = \"_bp_\";\nconst IGNORED_INPUT_TYPES = new Set([\"password\", \"file\", \"checkbox\", \"radio\", \"submit\", \"button\", \"reset\", \"image\"]);\nconst IDENTITY_DEDUPE_WINDOW_MS = 8_000;\nconst CUSTOM_CONTEXT_MAX_BYTES = 4096;\nconst IDENTITY_SIGNATURE_KEY = `${STORAGE_PREFIX}identify_signature`;\nconst IDENTITY_FINGERPRINT_KEY = `${STORAGE_PREFIX}identify_fingerprint`;\nconst IDENTITY_SENT_AT_KEY = `${STORAGE_PREFIX}identify_sent_at`;\nconst LAUNCHER_SHADOW = \"0 4px 14px rgba(0,0,0,0.18)\";\n\ntype FormFieldElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n\ntype IdentityPayload = {\n name?: string;\n email?: string;\n phone?: string;\n company?: string;\n};\n\ntype IdentifyRequestPayload = IdentityPayload & {\n external_user_id?: string;\n signature?: string;\n signed_at?: number;\n signature_version?: \"v1\";\n identify_source?: \"manual\" | \"form\";\n};\n\nfunction buildIdentityFingerprint(payload: IdentifyRequestPayload): string {\n return [\n payload.external_user_id || \"\",\n payload.email || \"\",\n payload.phone || \"\",\n payload.name || \"\",\n payload.company || \"\",\n payload.signature || \"\",\n payload.signed_at != null ? String(payload.signed_at) : \"\",\n payload.signature_version || \"\",\n payload.identify_source || \"\",\n ]\n .join(\"|\")\n .toLowerCase();\n}\n\nfunction normalizeText(value: string | null | undefined, maxLen = 180): string {\n if (!value) return \"\";\n return value.replace(/\\s+/g, \" \").trim().slice(0, maxLen);\n}\n\nfunction normalizeTokens(value: string | null | undefined): string {\n if (!value) return \"\";\n return ` ${value.toLowerCase().replace(/[_-]+/g, \" \").replace(/[^a-z0-9\\s@.]/g, \" \").replace(/\\s+/g, \" \").trim()} `;\n}\n\nfunction includesAny(haystack: string, needles: string[]): boolean {\n for (const needle of needles) {\n if (haystack.includes(needle)) return true;\n }\n return false;\n}\n\nfunction isEmail(value: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/i.test(value);\n}\n\nfunction normalizePhone(value: string | null | undefined): string {\n const trimmed = normalizeText(value, 50);\n if (!trimmed) return \"\";\n const hasPlus = trimmed.startsWith(\"+\");\n const digits = trimmed.replace(/\\D/g, \"\");\n if (digits.length < 6) return \"\";\n return `${hasPlus ? \"+\" : \"\"}${digits.slice(0, 20)}`;\n}\n\nfunction normalizeEmail(value: string | null | undefined): string {\n const normalized = normalizeText(value, 140).toLowerCase();\n if (!normalized) return \"\";\n if (!isEmail(normalized)) return \"\";\n return normalized;\n}\n\nfunction getExplicitValue(form: HTMLFormElement, selectors: string[]): string {\n for (const selector of selectors) {\n const el = form.querySelector<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(selector);\n const value = normalizeText(el?.value);\n if (value) return value;\n }\n return \"\";\n}\n\nfunction getFieldHint(el: FormFieldElement): string {\n return normalizeText(el.getAttribute(\"data-bp-field\") || el.getAttribute(\"data-bitpalm-field\"), 64)\n .toLowerCase()\n .replace(/[_\\s]+/g, \"-\");\n}\n\nfunction escapeAttrSelectorValue(value: string): string {\n return value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n}\n\nfunction collectElementTokenParts(form: HTMLFormElement, el: FormFieldElement): string[] {\n const parts: string[] = [];\n const pushText = (value: string | null | undefined, maxLen = 140) => {\n const clean = normalizeText(value, maxLen);\n if (clean) parts.push(clean);\n };\n\n pushText(el.name);\n pushText(el.id);\n pushText(el.getAttribute(\"autocomplete\"));\n pushText(el.getAttribute(\"placeholder\"));\n pushText(el.getAttribute(\"aria-label\"));\n pushText(el.getAttribute(\"data-field\"));\n pushText(el.getAttribute(\"data-name\"));\n pushText(el.getAttribute(\"data-label\"));\n pushText(el.getAttribute(\"data-bp-field\"));\n pushText(el.getAttribute(\"data-bitpalm-field\"));\n\n const seenLabels = new Set<string>();\n const pushLabel = (value: string | null | undefined) => {\n const label = normalizeText(value, 200);\n if (!label || seenLabels.has(label)) return;\n seenLabels.add(label);\n parts.push(label);\n };\n\n for (const label of Array.from(el.labels || [])) {\n pushLabel(label.textContent);\n }\n\n if (el.id) {\n const forLabel = form.querySelector(`label[for=\"${escapeAttrSelectorValue(el.id)}\"]`);\n pushLabel(forLabel?.textContent);\n }\n\n const nearestLabel = el.closest(\"label\");\n pushLabel(nearestLabel?.textContent);\n\n const ariaLabelledBy = el.getAttribute(\"aria-labelledby\");\n if (ariaLabelledBy) {\n for (const id of ariaLabelledBy.split(/\\s+/)) {\n if (!id) continue;\n const ref = form.ownerDocument.getElementById(id);\n pushLabel(ref?.textContent);\n }\n }\n\n return parts;\n}\n\nfunction extractIdentityFromForm(form: HTMLFormElement): IdentityPayload | null {\n let email = normalizeText(getExplicitValue(form, [\n \"[data-bp-email]\",\n \"[data-bitpalm-email]\",\n ]), 140).toLowerCase();\n\n let phone = normalizePhone(getExplicitValue(form, [\n \"[data-bp-phone]\",\n \"[data-bitpalm-phone]\",\n ]));\n\n let name = normalizeText(getExplicitValue(form, [\n \"[data-bp-name]\",\n \"[data-bitpalm-name]\",\n \"[data-bp-full-name]\",\n \"[data-bitpalm-full-name]\",\n ]));\n\n let firstName = normalizeText(getExplicitValue(form, [\n \"[data-bp-first-name]\",\n \"[data-bitpalm-first-name]\",\n ]));\n\n let lastName = normalizeText(getExplicitValue(form, [\n \"[data-bp-last-name]\",\n \"[data-bitpalm-last-name]\",\n ]));\n\n let company = normalizeText(getExplicitValue(form, [\n \"[data-bp-company]\",\n \"[data-bitpalm-company]\",\n ]));\n\n for (const rawEl of Array.from(form.elements)) {\n if (!(rawEl instanceof HTMLInputElement || rawEl instanceof HTMLTextAreaElement || rawEl instanceof HTMLSelectElement)) continue;\n if (rawEl.disabled) continue;\n if (rawEl instanceof HTMLInputElement && IGNORED_INPUT_TYPES.has(rawEl.type.toLowerCase())) continue;\n const fieldHint = getFieldHint(rawEl);\n\n const explicitField =\n rawEl.hasAttribute(\"data-bp-email\") ||\n rawEl.hasAttribute(\"data-bitpalm-email\") ||\n rawEl.hasAttribute(\"data-bp-phone\") ||\n rawEl.hasAttribute(\"data-bitpalm-phone\") ||\n rawEl.hasAttribute(\"data-bp-name\") ||\n rawEl.hasAttribute(\"data-bitpalm-name\") ||\n rawEl.hasAttribute(\"data-bp-full-name\") ||\n rawEl.hasAttribute(\"data-bitpalm-full-name\") ||\n rawEl.hasAttribute(\"data-bp-first-name\") ||\n rawEl.hasAttribute(\"data-bitpalm-first-name\") ||\n rawEl.hasAttribute(\"data-bp-last-name\") ||\n rawEl.hasAttribute(\"data-bitpalm-last-name\") ||\n rawEl.hasAttribute(\"data-bp-company\") ||\n rawEl.hasAttribute(\"data-bitpalm-company\") ||\n !!fieldHint;\n\n if (rawEl instanceof HTMLInputElement && rawEl.type.toLowerCase() === \"hidden\" && !explicitField) continue;\n\n const value = normalizeText(rawEl.value);\n if (!value) continue;\n\n const type = rawEl instanceof HTMLInputElement ? rawEl.type.toLowerCase() : \"\";\n const tokens = normalizeTokens(collectElementTokenParts(form, rawEl).join(\" \"));\n\n if (!email && fieldHint === \"email\" && isEmail(value)) {\n email = value.toLowerCase();\n continue;\n }\n if (!phone && (fieldHint === \"phone\" || fieldHint === \"tel\" || fieldHint === \"mobile\" || fieldHint === \"whatsapp\")) {\n const normalized = normalizePhone(value);\n if (normalized) {\n phone = normalized;\n continue;\n }\n }\n if (!company && fieldHint === \"company\") {\n company = normalizeText(value, 160);\n continue;\n }\n if (!firstName && (fieldHint === \"first-name\" || fieldHint === \"firstname\")) {\n firstName = normalizeText(value, 100);\n continue;\n }\n if (!lastName && (fieldHint === \"last-name\" || fieldHint === \"lastname\" || fieldHint === \"surname\")) {\n lastName = normalizeText(value, 100);\n continue;\n }\n if (!name && (fieldHint === \"name\" || fieldHint === \"full-name\" || fieldHint === \"fullname\")) {\n if (!isEmail(value) && !normalizePhone(value)) name = normalizeText(value, 140);\n continue;\n }\n\n const emailLike = type === \"email\" || includesAny(tokens, [\" email \", \" e mail \", \" mail \", \" email adresse \", \" mailadresse \", \" correo \"]);\n const phoneLike = type === \"tel\" || includesAny(tokens, [\" phone \", \" phone number \", \" mobile \", \" tel \", \" telefon \", \" telefonnummer \", \" whatsapp \", \" handy \", \" kontakt \", \" nummer \"]);\n const companyLike = includesAny(tokens, [\" company \", \" company name \", \" firma \", \" firmenname \", \" organization \", \" organisation \", \" business \", \" unternehmen \", \" agency \", \" brokerage \"]);\n const firstNameLike = includesAny(tokens, [\" first name \", \" firstname \", \" given name \", \" givenname \", \" vorname \", \" fname \"]);\n const lastNameLike = includesAny(tokens, [\" last name \", \" lastname \", \" family name \", \" familyname \", \" surname \", \" nachname \", \" lname \"]);\n const fullNameLike = includesAny(tokens, [\" full name \", \" fullname \", \" contact name \", \" name \"]) && !emailLike && !phoneLike;\n\n if (!email && emailLike && isEmail(value)) {\n email = value.toLowerCase();\n continue;\n }\n if (!phone && phoneLike) {\n const normalized = normalizePhone(value);\n if (normalized) {\n phone = normalized;\n continue;\n }\n }\n if (!company && companyLike) {\n company = normalizeText(value, 160);\n continue;\n }\n if (!firstName && firstNameLike) {\n firstName = normalizeText(value, 100);\n continue;\n }\n if (!lastName && lastNameLike) {\n lastName = normalizeText(value, 100);\n continue;\n }\n if (!name && fullNameLike && !isEmail(value) && !normalizePhone(value)) {\n name = normalizeText(value, 140);\n continue;\n }\n\n if (!email && isEmail(value)) {\n email = value.toLowerCase();\n }\n }\n\n if (name && (isEmail(name) || normalizePhone(name))) {\n name = \"\";\n }\n if (company && (isEmail(company) || normalizePhone(company))) {\n company = \"\";\n }\n\n if (!name) {\n name = normalizeText([firstName, lastName].filter(Boolean).join(\" \"), 140);\n }\n\n if (name && email && name.toLowerCase() === email.toLowerCase()) {\n name = \"\";\n }\n\n const hasContactSignal = !!(email || phone);\n const hasStrongProfileSignal = !!(name && company);\n if (!hasContactSignal && !hasStrongProfileSignal) {\n return null;\n }\n\n const identity: IdentityPayload = {\n ...(name ? { name } : {}),\n ...(email ? { email } : {}),\n ...(phone ? { phone } : {}),\n ...(company ? { company } : {}),\n };\n\n return Object.keys(identity).length > 0 ? identity : null;\n}\n\nfunction detectLocale(): string {\n if (typeof document !== \"undefined\") {\n const lang = document.documentElement.lang;\n if (lang) return lang.slice(0, 2).toLowerCase();\n }\n return \"en\";\n}\n\nfunction runWhenIdle(task: () => void, timeout = 1200) {\n if (typeof window !== \"undefined\" && \"requestIdleCallback\" in window) {\n (\n window as unknown as {\n requestIdleCallback: (cb: () => void, opts?: { timeout?: number }) => number;\n }\n ).requestIdleCallback(task, { timeout });\n return;\n }\n setTimeout(task, Math.min(timeout, 300));\n}\n\nfunction isMobileWidgetDevice(): boolean {\n if (typeof window === \"undefined\") return false;\n const userAgent = typeof navigator !== \"undefined\" ? navigator.userAgent : \"\";\n const isMobileUa = /Android|iPhone|iPad|iPod|IEMobile|Windows Phone|Mobile/i.test(userAgent);\n if (isMobileUa) return true;\n\n const coarsePointer = window.matchMedia(\"(pointer: coarse)\").matches;\n const noHover = window.matchMedia(\"(hover: none)\").matches;\n const minScreenSide = Math.min(\n window.screen?.width || window.innerWidth,\n window.screen?.height || window.innerHeight,\n );\n return coarsePointer && noHover && minScreenSide <= 900;\n}\n\nexport function createWidget(options: BitPalmAgentOptions): BitPalmAgentInstance {\n const {\n slug,\n locale = detectLocale(),\n baseUrl = DEFAULT_BASE_URL,\n token,\n zIndex = 9999,\n autoIdentify = true,\n } = options;\n\n const d = document;\n\n // --- Theme ---\n let themeSetting: BitPalmTheme = normalizeThemeSetting(options.theme);\n let currentTheme: HostTheme = themeSetting === \"auto\" ? detectHostTheme() : themeSetting;\n let stopThemeWatch: (() => void) | null = null;\n\n // --- Iframe ---\n const iframe = d.createElement(\"iframe\");\n const widgetUrl = `${baseUrl}/t/${slug}/widget`;\n const qs = new URLSearchParams({ locale, theme: currentTheme });\n if (token) qs.set(\"token\", token);\n iframe.src = `${widgetUrl}?${qs.toString()}`;\n // Explicitly grant the iframe permission to use the visitor's\n // microphone — required for the voice-input feature on cross-origin\n // iframes. Without this, Chrome silently denies getUserMedia /\n // SpeechRecognition without ever prompting the user.\n iframe.allow = \"clipboard-write; microphone\";\n iframe.setAttribute(\"allowtransparency\", \"true\");\n iframe.loading = \"lazy\";\n iframe.style.cssText = `position:fixed;bottom:0;right:0;width:1px;height:1px;border:none;z-index:${zIndex};background:transparent;color-scheme:normal;opacity:0;pointer-events:none;`;\n\n const origin = new URL(iframe.src).origin;\n\n // --- Native launcher button ---\n const btn = d.createElement(\"div\");\n btn.setAttribute(\"role\", \"button\");\n btn.setAttribute(\"aria-label\", \"Chat\");\n btn.style.cssText = `position:fixed;bottom:24px;right:24px;width:56px;height:56px;border-radius:50%;display:none;align-items:center;justify-content:center;cursor:pointer;z-index:${zIndex - 1};background:#171717;box-shadow:${LAUNCHER_SHADOW};transition:transform .2s,opacity .3s;opacity:0;`;\n btn.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M7.9 20A9 9 0 1 0 4 16.1L2 22Z\"/></svg>';\n btn.onmouseenter = () => { btn.style.transform = \"scale(1.05)\"; };\n btn.onmouseleave = () => { btn.style.transform = \"scale(1)\"; };\n btn.onclick = () => openWidget();\n d.body.appendChild(btn);\n\n // --- Fade animation for trigger bubbles ---\n if (!d.getElementById(\"_bp_fade\")) {\n const s = d.createElement(\"style\");\n s.id = \"_bp_fade\";\n s.textContent = \"@keyframes _bp_fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\";\n d.head.appendChild(s);\n }\n\n // --- Trigger bubble ---\n let bubble: HTMLDivElement | null = null;\n let launcherReady = false;\n let widgetBlocked = false;\n let iframeMounted = false;\n let iframeReady = false;\n let pendingOpen = false;\n const mountIframe = () => {\n if (iframeMounted) return;\n iframeMounted = true;\n d.body.appendChild(iframe);\n };\n let mobileScrollLocked = false;\n let scrollLockY = 0;\n const prevHtmlStyle = {\n overflow: \"\",\n overscrollBehavior: \"\",\n };\n const prevBodyStyle = {\n overflow: \"\",\n overscrollBehavior: \"\",\n position: \"\",\n top: \"\",\n left: \"\",\n right: \"\",\n width: \"\",\n };\n const lockMobilePageScroll = () => {\n if (mobileScrollLocked) return;\n const mobile = isMobileWidgetDevice();\n if (!mobile) return;\n const html = d.documentElement;\n const body = d.body;\n scrollLockY = window.scrollY || window.pageYOffset || 0;\n prevHtmlStyle.overflow = html.style.overflow;\n prevHtmlStyle.overscrollBehavior = html.style.overscrollBehavior;\n prevBodyStyle.overflow = body.style.overflow;\n prevBodyStyle.overscrollBehavior = body.style.overscrollBehavior;\n prevBodyStyle.position = body.style.position;\n prevBodyStyle.top = body.style.top;\n prevBodyStyle.left = body.style.left;\n prevBodyStyle.right = body.style.right;\n prevBodyStyle.width = body.style.width;\n html.style.overflow = \"hidden\";\n html.style.overscrollBehavior = \"none\";\n body.style.overflow = \"hidden\";\n body.style.overscrollBehavior = \"none\";\n body.style.position = \"fixed\";\n body.style.top = `-${scrollLockY}px`;\n body.style.left = \"0\";\n body.style.right = \"0\";\n body.style.width = \"100%\";\n mobileScrollLocked = true;\n };\n const unlockMobilePageScroll = () => {\n if (!mobileScrollLocked) return;\n const html = d.documentElement;\n const body = d.body;\n html.style.overflow = prevHtmlStyle.overflow;\n html.style.overscrollBehavior = prevHtmlStyle.overscrollBehavior;\n body.style.overflow = prevBodyStyle.overflow;\n body.style.overscrollBehavior = prevBodyStyle.overscrollBehavior;\n body.style.position = prevBodyStyle.position;\n body.style.top = prevBodyStyle.top;\n body.style.left = prevBodyStyle.left;\n body.style.right = prevBodyStyle.right;\n body.style.width = prevBodyStyle.width;\n window.scrollTo(0, scrollLockY);\n mobileScrollLocked = false;\n };\n const prepareIframeForOpen = () => {\n const mobile = isMobileWidgetDevice();\n if (iframe.style.display === \"none\") iframe.style.display = \"\";\n if (mobile) {\n iframe.style.width = \"100vw\";\n iframe.style.height = \"100dvh\";\n iframe.style.left = \"0\";\n iframe.style.top = \"0\";\n iframe.style.bottom = \"0\";\n iframe.style.right = \"0\";\n lockMobilePageScroll();\n } else {\n // Match desktop widget target size so the opening animation is visible from frame 1.\n iframe.style.width = \"420px\";\n iframe.style.height = \"620px\";\n iframe.style.bottom = \"24px\";\n iframe.style.right = \"24px\";\n iframe.style.left = \"\";\n iframe.style.top = \"\";\n unlockMobilePageScroll();\n }\n iframe.style.opacity = \"1\";\n iframe.style.pointerEvents = \"auto\";\n };\n const removeBubble = () => {\n if (bubble) { bubble.remove(); bubble = null; }\n };\n let sendParentContext = () => {};\n let sendOpenSignal = () => {};\n\n // --- Widget state & event bus ---\n let widgetIsOpen = false;\n const eventListeners = new Map<BitPalmEventType, Set<BitPalmEventCallback>>();\n\n function emit(event: BitPalmEventType, data?: Record<string, unknown>) {\n const listeners = eventListeners.get(event);\n if (!listeners) return;\n for (const cb of listeners) {\n try { cb(data); } catch { /* don't let listener errors break the widget */ }\n }\n }\n\n // --- postMessage handler ---\n const handleMessage = (e: MessageEvent) => {\n if (e.origin !== origin) return;\n\n // Widget config (colors, icon)\n if (e.data?.type === \"bitpalm-widget-config\") {\n widgetBlocked = false;\n launcherReady = true;\n if (iframe.style.display === \"none\") iframe.style.display = \"\";\n if (e.data.primaryColor) {\n btn.style.background = e.data.primaryColor;\n btn.style.boxShadow = e.data.chatShadow === \"none\" ? \"none\" : LAUNCHER_SHADOW;\n }\n const ic = e.data.chatButtonIconColor || \"black\";\n if (e.data.chatButtonIconSvg) {\n btn.innerHTML = \"\";\n const sp = d.createElement(\"span\");\n sp.style.cssText = `display:flex;align-items:center;justify-content:center;width:24px;height:24px;color:${ic}`;\n const parser = new DOMParser();\n const doc = parser.parseFromString(e.data.chatButtonIconSvg, \"image/svg+xml\");\n const svg = doc.querySelector(\"svg\");\n if (svg) {\n // Remove dangerous elements and attributes\n svg.querySelectorAll(\"script,foreignObject\").forEach(el => el.remove());\n svg.querySelectorAll(\"*\").forEach(el => {\n for (const attr of [...el.attributes]) {\n if (attr.name.startsWith(\"on\") || (attr.value && attr.value.includes(\"javascript:\"))) {\n el.removeAttribute(attr.name);\n }\n }\n });\n svg.setAttribute(\"width\", \"24\");\n svg.setAttribute(\"height\", \"24\");\n svg.style.display = \"block\";\n sp.appendChild(svg);\n } else {\n // Fallback: use default icon\n sp.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M7.9 20A9 9 0 1 0 4 16.1L2 22Z\"/></svg>';\n }\n btn.appendChild(sp);\n } else {\n const sv = btn.querySelector(\"svg\");\n if (sv) (sv as SVGElement).style.stroke = ic;\n }\n btn.style.display = \"flex\";\n // Fade in after styles are applied\n requestAnimationFrame(() => { btn.style.opacity = \"1\"; });\n }\n\n // Resize — use full viewport on mobile\n if (e.data?.type === \"bitpalm-widget-resize\") {\n const isOpen = e.data.width > 0;\n const wasOpen = widgetIsOpen;\n widgetIsOpen = isOpen;\n if (isOpen && !wasOpen) emit(\"widget_opened\");\n if (!isOpen && wasOpen) emit(\"widget_closed\");\n const mobile = isMobileWidgetDevice();\n if (isOpen) {\n iframe.style.width = mobile ? \"100vw\" : `${e.data.width}px`;\n iframe.style.height = mobile ? \"100dvh\" : `${e.data.height}px`;\n if (mobile) {\n iframe.style.left = \"0\";\n iframe.style.top = \"0\";\n iframe.style.bottom = \"0\";\n iframe.style.right = \"0\";\n lockMobilePageScroll();\n } else {\n unlockMobilePageScroll();\n }\n iframe.style.opacity = \"1\";\n iframe.style.pointerEvents = \"auto\";\n } else {\n unlockMobilePageScroll();\n iframe.style.width = \"1px\";\n iframe.style.height = \"1px\";\n iframe.style.left = \"\";\n iframe.style.top = \"\";\n iframe.style.opacity = \"0\";\n iframe.style.pointerEvents = \"none\";\n }\n btn.style.display = isOpen ? \"none\" : \"flex\";\n }\n\n // Trigger bubble show\n if (e.data?.type === \"bitpalm-trigger-show\") {\n if (widgetBlocked || !launcherReady) return;\n removeBubble();\n bubble = d.createElement(\"div\");\n bubble.style.cssText = `position:fixed;bottom:90px;right:24px;max-width:240px;background:#fff;border-radius:16px;padding:12px 32px 12px 12px;box-shadow:0 2px 20px rgba(0,0,0,0.08);cursor:pointer;z-index:${zIndex - 1};font-family:system-ui,sans-serif;animation:_bp_fade .3s;`;\n const msg = (e.data.message || \"\").replace(/</g, \"&lt;\");\n bubble.innerHTML = `<p style=\"font-size:14px;color:#1f2937;margin:0;\">${msg}</p><div style=\"position:absolute;bottom:-8px;right:20px;width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #fff;\"></div>`;\n const close = d.createElement(\"button\");\n close.style.cssText = \"position:absolute;top:-8px;right:-8px;width:28px;height:28px;border-radius:50%;background:#fff;border:none;box-shadow:0 1px 4px rgba(0,0,0,0.1);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px;color:#9ca3af;\";\n close.innerHTML = \"&#10005;\";\n close.onclick = (ev) => { ev.stopPropagation(); removeBubble(); iframe.contentWindow?.postMessage({ type: \"bitpalm-trigger-dismiss\" }, \"*\"); };\n bubble.onclick = () => {\n removeBubble();\n btn.style.display = \"none\";\n prepareIframeForOpen();\n mountIframe();\n if (!iframeReady) {\n pendingOpen = true;\n return;\n }\n iframe.contentWindow?.postMessage({ type: \"bitpalm-trigger-engaged\", message: msg }, \"*\");\n };\n bubble.appendChild(close);\n d.body.appendChild(bubble);\n }\n\n // Trigger bubble hide\n if (e.data?.type === \"bitpalm-trigger-hide\") { removeBubble(); }\n\n // Iframe requests latest parent context (avoids first-load race conditions)\n if (e.data?.type === \"bitpalm-request-context\") {\n sendParentContext();\n }\n\n // Chat events from iframe → emit to SDK listeners\n if (e.data?.type === \"bitpalm-chat-event\" && e.data.event) {\n emit(e.data.event as BitPalmEventType, e.data.data);\n }\n\n // Widget blocked (excluded path or access denied) — hide button & iframe\n if (e.data?.type === \"bitpalm-widget-blocked\") {\n widgetBlocked = true;\n launcherReady = false;\n btn.style.display = \"none\";\n removeBubble();\n unlockMobilePageScroll();\n iframe.style.display = \"none\";\n }\n };\n window.addEventListener(\"message\", handleMessage);\n\n // --- Privacy opt-out check ---\n let optedOut = false;\n try { optedOut = localStorage.getItem(`${STORAGE_PREFIX}optout`) === \"1\"; } catch { /* ignore */ }\n\n // --- Persistent Visitor ID (skip if opted out) ---\n const VID_KEY = `${STORAGE_PREFIX}vid`;\n let visitorId = \"\";\n if (!optedOut) {\n try { visitorId = localStorage.getItem(VID_KEY) || \"\"; } catch { /* ignore */ }\n if (!visitorId) {\n // Fallback: try reading from cookie\n const match = d.cookie.match(new RegExp(`(?:^|; )${VID_KEY}=([^;]+)`));\n visitorId = match ? decodeURIComponent(match[1]) : \"\";\n }\n if (!visitorId) {\n visitorId = crypto.randomUUID ? crypto.randomUUID() : (`${Date.now()}-${Math.random().toString(36).slice(2, 11)}`);\n }\n // Persist in both localStorage and cookie (cookie survives Safari ITP clearing localStorage)\n try { localStorage.setItem(VID_KEY, visitorId); } catch { /* ignore */ }\n try {\n const maxAge = 365 * 24 * 60 * 60; // 1 year\n d.cookie = `${VID_KEY}=${encodeURIComponent(visitorId)};path=/;max-age=${maxAge};SameSite=Lax`;\n } catch { /* ignore */ }\n }\n\n // --- Visitor beacon: track page view even without chat (skip if opted out) ---\n if (!optedOut) {\n runWhenIdle(() => {\n try {\n const utmParams = new URLSearchParams(location.search);\n const utm: Record<string, string> = {};\n for (const key of [\"utm_source\", \"utm_medium\", \"utm_campaign\", \"utm_term\", \"utm_content\"]) {\n const val = utmParams.get(key);\n if (val) utm[key] = val;\n }\n const beaconPayload = JSON.stringify({\n tenant_slug: slug,\n visitor_id: visitorId,\n url: location.href,\n referrer: d.referrer || undefined,\n ...(Object.keys(utm).length > 0 ? { utm } : {}),\n });\n const beaconUrl = `${baseUrl}/api/widget/impression`;\n if (typeof navigator.sendBeacon === \"function\") {\n navigator.sendBeacon(beaconUrl, new Blob([beaconPayload], { type: \"application/json\" }));\n } else {\n fetch(beaconUrl, { method: \"POST\", body: beaconPayload, headers: { \"Content-Type\": \"application/json\" }, keepalive: true }).catch(() => {});\n }\n } catch { /* ignore */ }\n }, 2000);\n }\n\n // --- Auto-identify visitor from form submissions on host page ---\n let lastIdentitySignature = \"\";\n let lastIdentityFingerprint = \"\";\n let lastIdentitySentAt = 0;\n try {\n lastIdentitySignature = sessionStorage.getItem(IDENTITY_SIGNATURE_KEY) || \"\";\n lastIdentityFingerprint = sessionStorage.getItem(IDENTITY_FINGERPRINT_KEY) || \"\";\n const storedAt = parseInt(sessionStorage.getItem(IDENTITY_SENT_AT_KEY) || \"0\", 10);\n if (Number.isFinite(storedAt) && storedAt > 0) {\n lastIdentitySentAt = storedAt;\n }\n } catch {\n // ignore\n }\n\n const dispatchIdentify = (payloadInput: IdentifyRequestPayload, scopeSignature = \"\") => {\n if (optedOut || !visitorId) return;\n\n const payload: IdentifyRequestPayload = {};\n const name = normalizeText(payloadInput.name, 140);\n const email = normalizeEmail(payloadInput.email);\n const phone = normalizePhone(payloadInput.phone);\n const company = normalizeText(payloadInput.company, 160);\n const externalUserId = normalizeText(payloadInput.external_user_id, 140);\n const requestSignature = normalizeText(payloadInput.signature, 260);\n const signedAtRaw = Number(payloadInput.signed_at);\n\n if (name) payload.name = name;\n if (email) payload.email = email;\n if (phone) payload.phone = phone;\n if (company) payload.company = company;\n if (externalUserId) payload.external_user_id = externalUserId;\n if (requestSignature) payload.signature = requestSignature;\n if (Number.isFinite(signedAtRaw) && signedAtRaw > 0) {\n payload.signed_at = Math.floor(signedAtRaw);\n }\n if (payloadInput.signature_version === \"v1\" || payload.signature) {\n payload.signature_version = \"v1\";\n }\n if (payloadInput.identify_source === \"manual\" || payloadInput.identify_source === \"form\") {\n payload.identify_source = payloadInput.identify_source;\n }\n\n if (!payload.name && !payload.email && !payload.phone && !payload.company && !payload.external_user_id) {\n return;\n }\n\n const identityFingerprint = buildIdentityFingerprint(payload);\n const dedupeSignature = [scopeSignature.toLowerCase(), identityFingerprint].filter(Boolean).join(\"|\");\n\n const now = Date.now();\n const insideDedupWindow = now - lastIdentitySentAt < IDENTITY_DEDUPE_WINDOW_MS;\n if (insideDedupWindow && (dedupeSignature === lastIdentitySignature || identityFingerprint === lastIdentityFingerprint)) {\n return;\n }\n\n lastIdentitySignature = dedupeSignature;\n lastIdentityFingerprint = identityFingerprint;\n lastIdentitySentAt = now;\n try {\n sessionStorage.setItem(IDENTITY_SIGNATURE_KEY, dedupeSignature);\n sessionStorage.setItem(IDENTITY_FINGERPRINT_KEY, identityFingerprint);\n sessionStorage.setItem(IDENTITY_SENT_AT_KEY, String(now));\n } catch {\n // ignore\n }\n\n try {\n const requestBody = JSON.stringify({\n tenant_slug: slug,\n visitor_id: visitorId,\n url: location.href,\n referrer: d.referrer || undefined,\n ...payload,\n });\n const identifyUrl = `${baseUrl}/api/widget/identify`;\n if (typeof navigator.sendBeacon === \"function\") {\n navigator.sendBeacon(identifyUrl, new Blob([requestBody], { type: \"application/json\" }));\n } else {\n fetch(identifyUrl, { method: \"POST\", body: requestBody, headers: { \"Content-Type\": \"application/json\" }, keepalive: true }).catch(() => {});\n }\n } catch {\n // ignore\n }\n };\n\n const handleFormSubmit = (event: Event) => {\n if (optedOut || !autoIdentify || !visitorId) return;\n\n const form = event.target instanceof HTMLFormElement\n ? event.target\n : event.target instanceof Element\n ? event.target.closest(\"form\")\n : null;\n if (!(form instanceof HTMLFormElement)) return;\n\n const formIdentifySetting = (form.getAttribute(\"data-bp-identify\") || form.getAttribute(\"data-bitpalm-identify\") || \"\").toLowerCase();\n if (formIdentifySetting === \"off\" || formIdentifySetting === \"false\" || formIdentifySetting === \"0\") return;\n\n const identity = extractIdentityFromForm(form);\n if (!identity) return;\n\n const formSignature = [\n form.getAttribute(\"id\") || \"\",\n form.getAttribute(\"name\") || \"\",\n form.getAttribute(\"action\") || \"\",\n ].join(\"|\");\n\n dispatchIdentify({ ...identity, identify_source: \"form\" }, formSignature);\n };\n\n if (!optedOut && autoIdentify) {\n d.addEventListener(\"submit\", handleFormSubmit, true);\n }\n\n // --- Visitor Intelligence: page counter + history ---\n let pageCount = parseInt(sessionStorage.getItem(`${STORAGE_PREFIX}pages`) || \"0\") + 1;\n sessionStorage.setItem(`${STORAGE_PREFIX}pages`, String(pageCount));\n\n let hist: string[] = JSON.parse(sessionStorage.getItem(`${STORAGE_PREFIX}hist`) || \"[]\");\n hist.push(location.href);\n if (hist.length > 20) hist = hist.slice(-20);\n sessionStorage.setItem(`${STORAGE_PREFIX}hist`, JSON.stringify(hist));\n\n const loadedAt = Date.now();\n let siteStart = parseInt(sessionStorage.getItem(`${STORAGE_PREFIX}site_start`) || \"0\");\n if (!siteStart) {\n siteStart = loadedAt;\n sessionStorage.setItem(`${STORAGE_PREFIX}site_start`, String(siteStart));\n }\n\n const contextRetryTimers: ReturnType<typeof setTimeout>[] = [];\n sendParentContext = () => {\n let returning = false;\n try {\n returning = !!localStorage.getItem(`${STORAGE_PREFIX}visited`);\n } catch {\n returning = false;\n }\n iframe.contentWindow?.postMessage({\n type: \"bitpalm-parent-context\",\n url: location.href,\n title: d.title,\n returning,\n pageCount,\n pageHistory: hist,\n loadedAt,\n siteStart,\n locale,\n visitorId: optedOut ? \"\" : visitorId,\n }, \"*\");\n sendTheme();\n if (!returning && !optedOut) {\n try { localStorage.setItem(`${STORAGE_PREFIX}visited`, \"1\"); } catch { /* ignore */ }\n }\n };\n\n // --- Send parent context on iframe load ---\n iframe.addEventListener(\"load\", () => {\n iframeReady = true;\n sendParentContext();\n [120, 450, 1100].forEach((delay) => {\n const timer = setTimeout(() => sendParentContext(), delay);\n contextRetryTimers.push(timer);\n });\n if (pendingOpen) {\n pendingOpen = false;\n sendOpenSignal();\n }\n });\n\n // Lazy-mount iframe after initial paint/idle to reduce impact on host load.\n if (d.readyState === \"loading\") {\n d.addEventListener(\"DOMContentLoaded\", () => runWhenIdle(mountIframe, 1600), { once: true });\n } else {\n runWhenIdle(mountIframe, 1600);\n }\n\n // --- SPA navigation detection ---\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n const onNav = () => {\n pageCount++;\n sessionStorage.setItem(`${STORAGE_PREFIX}pages`, String(pageCount));\n const h: string[] = JSON.parse(sessionStorage.getItem(`${STORAGE_PREFIX}hist`) || \"[]\");\n h.push(location.href);\n if (h.length > 20) h.splice(0, h.length - 20);\n hist = h;\n sessionStorage.setItem(`${STORAGE_PREFIX}hist`, JSON.stringify(h));\n iframe.contentWindow?.postMessage({\n type: \"bitpalm-page-change\",\n url: location.href,\n title: d.title,\n pageCount,\n pageHistory: h,\n loadedAt: Date.now(),\n }, \"*\");\n // Track page view for visitor (skip if opted out)\n if (!optedOut) {\n try {\n const navPayload = JSON.stringify({ tenant_slug: slug, visitor_id: visitorId, url: location.href });\n const navUrl = `${baseUrl}/api/widget/impression`;\n if (typeof navigator.sendBeacon === \"function\") {\n navigator.sendBeacon(navUrl, new Blob([navPayload], { type: \"application/json\" }));\n } else {\n fetch(navUrl, { method: \"POST\", body: navPayload, headers: { \"Content-Type\": \"application/json\" }, keepalive: true }).catch(() => {});\n }\n } catch { /* ignore */ }\n }\n };\n\n history.pushState = function (...args: Parameters<typeof history.pushState>) {\n origPush(...args);\n onNav();\n };\n history.replaceState = function (...args: Parameters<typeof history.replaceState>) {\n origReplace(...args);\n onNav();\n };\n window.addEventListener(\"popstate\", onNav);\n\n // --- Scroll depth tracking ---\n let lastScrollDepth = -1;\n let scrollTimeout: ReturnType<typeof setTimeout>;\n const handleScroll = () => {\n clearTimeout(scrollTimeout);\n scrollTimeout = setTimeout(() => {\n const total = Math.max(d.documentElement.scrollHeight, d.body.scrollHeight) - window.innerHeight;\n const pct = total > 0 ? Math.round(window.scrollY / total * 100) : 100;\n if (pct !== lastScrollDepth) {\n lastScrollDepth = pct;\n iframe.contentWindow?.postMessage({ type: \"bitpalm-scroll-depth\", percent: pct }, \"*\");\n }\n }, 500);\n };\n window.addEventListener(\"scroll\", handleScroll, { passive: true });\n\n // --- Exit intent ---\n const handleMouseOut = (e: MouseEvent) => {\n if (e.clientY <= 0) {\n iframe.contentWindow?.postMessage({ type: \"bitpalm-exit-intent\" }, \"*\");\n }\n };\n d.addEventListener(\"mouseout\", handleMouseOut);\n\n // --- Inactivity detection (15s) ---\n let idleTimer: ReturnType<typeof setTimeout>;\n let idleFired = false;\n const resetIdle = () => {\n clearTimeout(idleTimer);\n if (idleFired) return;\n idleTimer = setTimeout(() => {\n idleFired = true;\n iframe.contentWindow?.postMessage({ type: \"bitpalm-inactivity\" }, \"*\");\n }, 15_000);\n };\n const idleEvents = [\"mousemove\", \"keydown\", \"scroll\", \"touchstart\"] as const;\n idleEvents.forEach((ev) => d.addEventListener(ev, resetIdle, { passive: true }));\n resetIdle();\n\n sendOpenSignal = () => {\n // Primary: postMessage\n iframe.contentWindow?.postMessage({ type: \"bitpalm-open\" }, \"*\");\n // Fallback for mobile: trigger hashchange inside iframe (no reload)\n const base = iframe.src.split(\"#\")[0];\n iframe.src = `${base}#bp-open-${Date.now()}`;\n };\n\n // --- Public API ---\n const openWidget = () => {\n btn.style.display = \"none\";\n removeBubble();\n prepareIframeForOpen();\n mountIframe();\n if (!iframeReady) {\n pendingOpen = true;\n return;\n }\n sendOpenSignal();\n };\n\n const closeWidget = () => {\n unlockMobilePageScroll();\n iframe.contentWindow?.postMessage({ type: \"bitpalm-close\" }, \"*\");\n };\n\n const identify = (input: BitPalmIdentifyPayload) => {\n if (!input || typeof input !== \"object\") return;\n dispatchIdentify({\n external_user_id: normalizeText(input.externalUserId, 140) || undefined,\n name: normalizeText(input.name, 140) || undefined,\n email: normalizeEmail(input.email) || undefined,\n phone: normalizePhone(input.phone) || undefined,\n company: normalizeText(input.company, 160) || undefined,\n signature: normalizeText(input.signature, 260) || undefined,\n signed_at: Number.isFinite(Number(input.signedAt)) ? Math.floor(Number(input.signedAt)) : undefined,\n signature_version: input.signatureVersion === \"v1\" ? \"v1\" : undefined,\n identify_source: \"manual\",\n }, \"manual\");\n };\n\n const toggleWidget = () => {\n if (widgetIsOpen) closeWidget();\n else openWidget();\n };\n\n const getIsOpen = () => widgetIsOpen;\n\n const sendMessage = (message: string) => {\n if (!message || typeof message !== \"string\") return;\n const text = message.trim().slice(0, 10_000);\n if (!text) return;\n if (!widgetIsOpen) openWidget();\n // Small delay to ensure widget is open before sending\n setTimeout(() => {\n iframe.contentWindow?.postMessage({ type: \"bitpalm-send-message\", message: text }, \"*\");\n }, widgetIsOpen ? 50 : 500);\n };\n\n // --- Theme switching ---\n function sendTheme() {\n iframe.contentWindow?.postMessage({ type: \"bitpalm-theme\", theme: currentTheme }, \"*\");\n }\n\n const applyTheme = (theme: HostTheme) => {\n if (theme === currentTheme) return;\n currentTheme = theme;\n sendTheme();\n };\n\n const setTheme = (theme: BitPalmTheme) => {\n themeSetting = normalizeThemeSetting(theme);\n stopThemeWatch?.();\n stopThemeWatch = null;\n if (themeSetting === \"auto\") {\n stopThemeWatch = watchHostTheme(applyTheme);\n applyTheme(detectHostTheme());\n } else {\n applyTheme(themeSetting);\n }\n };\n\n if (themeSetting === \"auto\") stopThemeWatch = watchHostTheme(applyTheme);\n\n const handleThemeEvent = (event: Event) => {\n const detail = (event as CustomEvent<{ slug?: string; theme?: BitPalmTheme }>).detail;\n if (!detail || typeof detail !== \"object\") return;\n const targetSlug = normalizeText(detail.slug, 120);\n if (targetSlug && targetSlug !== slug) return;\n setTheme(normalizeThemeSetting(detail.theme));\n };\n window.addEventListener(\"bitpalm-theme\", handleThemeEvent as EventListener);\n\n // --- Custom context for AI ---\n let customContext: Record<string, unknown> = {};\n\n const setCustomContext = (data: BitPalmCustomContext) => {\n if (!data || typeof data !== \"object\" || Array.isArray(data)) return;\n customContext = { ...customContext, ...data };\n const json = JSON.stringify(customContext);\n if (json.length > CUSTOM_CONTEXT_MAX_BYTES) {\n console.warn(\n `[BitPalm] Custom context exceeds ${CUSTOM_CONTEXT_MAX_BYTES} bytes (${json.length}). It may be truncated.`\n );\n }\n iframe.contentWindow?.postMessage({ type: \"bitpalm-custom-context\", data: customContext }, \"*\");\n };\n\n const clearCustomContext = () => {\n customContext = {};\n iframe.contentWindow?.postMessage({ type: \"bitpalm-custom-context\", data: {} }, \"*\");\n };\n\n const handleContextEvent = (event: Event) => {\n const customEvent = event as CustomEvent<BitPalmCustomContext & { slug?: string }>;\n const detail = customEvent.detail;\n if (!detail || typeof detail !== \"object\") return;\n const targetSlug = normalizeText((detail as Record<string, unknown>).slug as string, 120);\n if (targetSlug && targetSlug !== slug) return;\n const { slug: _s, ...contextData } = detail as Record<string, unknown>;\n setCustomContext(contextData);\n };\n\n window.addEventListener(\"bitpalm-context\", handleContextEvent as EventListener);\n\n const handleIdentifyEvent = (event: Event) => {\n const customEvent = event as CustomEvent<BitPalmIdentifyPayload & { slug?: string }>;\n const detail = customEvent.detail;\n if (!detail || typeof detail !== \"object\") return;\n const targetSlug = normalizeText(detail.slug, 120);\n if (targetSlug && targetSlug !== slug) return;\n identify(detail);\n };\n\n window.addEventListener(\"bitpalm-identify\", handleIdentifyEvent as EventListener);\n\n // open, close and send for setups without an instance (script tag)\n const targetsThisWidget = (event: Event) => {\n const detail = (event as CustomEvent<{ slug?: string }>).detail;\n const targetSlug = normalizeText(detail?.slug, 120);\n return !targetSlug || targetSlug === slug;\n };\n const handleOpenEvent = (event: Event) => { if (targetsThisWidget(event)) openWidget(); };\n const handleCloseEvent = (event: Event) => { if (targetsThisWidget(event)) closeWidget(); };\n const handleSendEvent = (event: Event) => {\n if (!targetsThisWidget(event)) return;\n const message = (event as CustomEvent<{ message?: string }>).detail?.message;\n if (typeof message === \"string\") sendMessage(message);\n };\n window.addEventListener(\"bitpalm-open\", handleOpenEvent);\n window.addEventListener(\"bitpalm-close\", handleCloseEvent);\n window.addEventListener(\"bitpalm-send\", handleSendEvent);\n\n const onEvent = (event: BitPalmEventType, callback: BitPalmEventCallback): (() => void) => {\n if (!eventListeners.has(event)) eventListeners.set(event, new Set());\n eventListeners.get(event)!.add(callback);\n return () => eventListeners.get(event)?.delete(callback);\n };\n\n const offEvent = (event: BitPalmEventType, callback: BitPalmEventCallback) => {\n eventListeners.get(event)?.delete(callback);\n };\n\n const destroy = () => {\n window.removeEventListener(\"message\", handleMessage);\n window.removeEventListener(\"scroll\", handleScroll);\n window.removeEventListener(\"popstate\", onNav);\n d.removeEventListener(\"mouseout\", handleMouseOut);\n d.removeEventListener(\"submit\", handleFormSubmit, true);\n idleEvents.forEach((ev) => d.removeEventListener(ev, resetIdle));\n clearTimeout(scrollTimeout);\n clearTimeout(idleTimer);\n contextRetryTimers.forEach((t) => clearTimeout(t));\n history.pushState = origPush;\n history.replaceState = origReplace;\n window.removeEventListener(\"bitpalm-identify\", handleIdentifyEvent as EventListener);\n window.removeEventListener(\"bitpalm-context\", handleContextEvent as EventListener);\n window.removeEventListener(\"bitpalm-theme\", handleThemeEvent as EventListener);\n window.removeEventListener(\"bitpalm-open\", handleOpenEvent);\n window.removeEventListener(\"bitpalm-close\", handleCloseEvent);\n window.removeEventListener(\"bitpalm-send\", handleSendEvent);\n stopThemeWatch?.();\n eventListeners.clear();\n unlockMobilePageScroll();\n removeBubble();\n btn.remove();\n iframe.remove();\n };\n\n return {\n open: openWidget,\n close: closeWidget,\n toggle: toggleWidget,\n isOpen: getIsOpen,\n identify,\n context: setCustomContext,\n resetContext: clearCustomContext,\n send: sendMessage,\n on: onEvent,\n off: offEvent,\n setTheme,\n destroy,\n };\n}\n"],"mappings":"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","names":["src_exports","__export","createWidget","detectHostTheme","__toCommonJS","DARK_CLASSES","LIGHT_CLASSES","THEME_ATTRIBUTES","DARK_QUERY","normalizeThemeSetting","value","explicitTheme","el","name","attr","channel","s","backgroundTheme","win","match","r","g","b","a","n","colorSchemeTheme","doc","computed","meta","scheme","detectHostTheme","watchHostTheme","onChange","last","scheduled","check","next","schedule","observer","observed","media","DEFAULT_BASE_URL","STORAGE_PREFIX","IGNORED_INPUT_TYPES","IDENTITY_DEDUPE_WINDOW_MS","CUSTOM_CONTEXT_MAX_BYTES","IDENTITY_SIGNATURE_KEY","IDENTITY_FINGERPRINT_KEY","IDENTITY_SENT_AT_KEY","LAUNCHER_SHADOW","buildIdentityFingerprint","payload","normalizeText","value","maxLen","normalizeTokens","includesAny","haystack","needles","needle","isEmail","normalizePhone","trimmed","hasPlus","digits","normalizeEmail","normalized","getExplicitValue","form","selectors","selector","el","getFieldHint","escapeAttrSelectorValue","collectElementTokenParts","parts","pushText","clean","seenLabels","pushLabel","label","forLabel","nearestLabel","ariaLabelledBy","id","ref","extractIdentityFromForm","email","phone","name","firstName","lastName","company","rawEl","fieldHint","explicitField","type","tokens","emailLike","phoneLike","companyLike","firstNameLike","lastNameLike","fullNameLike","identity","detectLocale","lang","runWhenIdle","task","timeout","isMobileWidgetDevice","userAgent","coarsePointer","noHover","minScreenSide","createWidget","options","slug","locale","baseUrl","token","zIndex","autoIdentify","d","themeSetting","normalizeThemeSetting","currentTheme","detectHostTheme","stopThemeWatch","iframe","widgetUrl","qs","origin","btn","openWidget","s","bubble","launcherReady","widgetBlocked","iframeMounted","iframeReady","pendingOpen","mountIframe","mobileScrollLocked","scrollLockY","prevHtmlStyle","prevBodyStyle","lockMobilePageScroll","html","body","unlockMobilePageScroll","prepareIframeForOpen","mobile","removeBubble","sendParentContext","sendOpenSignal","widgetIsOpen","eventListeners","emit","event","data","listeners","cb","handleMessage","ic","sp","svg","attr","sv","isOpen","wasOpen","msg","close","ev","optedOut","VID_KEY","visitorId","match","utmParams","utm","key","val","beaconPayload","beaconUrl","lastIdentitySignature","lastIdentityFingerprint","lastIdentitySentAt","storedAt","dispatchIdentify","payloadInput","scopeSignature","externalUserId","requestSignature","signedAtRaw","identityFingerprint","dedupeSignature","now","requestBody","identifyUrl","handleFormSubmit","formIdentifySetting","formSignature","pageCount","hist","loadedAt","siteStart","contextRetryTimers","returning","sendTheme","delay","timer","origPush","origReplace","onNav","h","navPayload","navUrl","args","lastScrollDepth","scrollTimeout","handleScroll","total","pct","handleMouseOut","idleTimer","idleFired","resetIdle","idleEvents","base","closeWidget","identify","input","toggleWidget","getIsOpen","sendMessage","message","text","applyTheme","theme","setTheme","watchHostTheme","handleThemeEvent","detail","targetSlug","customContext","setCustomContext","json","clearCustomContext","handleContextEvent","_s","contextData","handleIdentifyEvent","targetsThisWidget","handleOpenEvent","handleCloseEvent","handleSendEvent","callback","t","parseBoolean","value","normalized","script","init","createWidget","normalizeThemeSetting"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/triggers.ts","../src/theme.ts","../src/widget.ts"],"sourcesContent":["export { createWidget } from \"./widget\";\nexport { detectHostTheme } from \"./theme\";\nexport type { BitPalmAgentOptions, BitPalmAgentInstance, BitPalmIdentifyPayload, BitPalmCustomContext, BitPalmEventType, BitPalmEventCallback, BitPalmTheme } from \"./types\";\n\nimport { createWidget } from \"./widget\";\nimport { normalizeThemeSetting } from \"./theme\";\nimport { parseTriggerMode, triggersOption } from \"./triggers\";\n\nfunction parseBoolean(value: string | undefined): boolean | undefined {\n if (value == null) return undefined;\n const normalized = value.trim().toLowerCase();\n if ([\"1\", \"true\", \"yes\", \"on\"].includes(normalized)) return true;\n if ([\"0\", \"false\", \"no\", \"off\"].includes(normalized)) return false;\n return undefined;\n}\n\n/**\n * Auto-init from script tag:\n * <script src=\"https://cdn.bitpalm.ai/widget.js\" data-slug=\"my-agent\"></script>\n * Optional: data-launcher=\"false\" and data-triggers=\"events\" or \"false\".\n */\nif (typeof document !== \"undefined\") {\n const script = document.currentScript as HTMLScriptElement | null;\n if (script?.dataset.slug) {\n const init = () => {\n createWidget({\n slug: script!.dataset.slug!,\n locale: script!.dataset.locale,\n baseUrl: script!.dataset.baseUrl,\n token: script!.dataset.token,\n zIndex: script!.dataset.zIndex ? Number(script!.dataset.zIndex) : undefined,\n autoIdentify: parseBoolean(script!.dataset.autoIdentify),\n theme: normalizeThemeSetting(script!.dataset.theme),\n launcher: parseBoolean(script!.dataset.launcher),\n triggers: script!.dataset.triggers === undefined ? undefined : triggersOption(parseTriggerMode(script!.dataset.triggers)),\n });\n };\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", init);\n } else {\n init();\n }\n }\n}\n","/*\n * Trigger messages: the bubble that shows up by itself on the website.\n * Sites with a chat button of their own can take the message as an event\n * instead and show it their way, or switch triggers off.\n */\n\n/** \"bubble\" shows our bubble, \"events\" only fires trigger_shown, \"off\" stops triggers. */\nexport type TriggerMode = \"bubble\" | \"events\" | \"off\";\n\n/** Reads the triggers option, from the SDK or from the script tag's data-triggers. */\nexport function parseTriggerMode(value: unknown): TriggerMode {\n if (value === false) return \"off\";\n if (typeof value === \"string\") {\n const normalized = value.trim().toLowerCase();\n if ([\"false\", \"off\", \"0\", \"no\", \"none\"].includes(normalized)) return \"off\";\n if (normalized === \"events\") return \"events\";\n }\n return \"bubble\";\n}\n\n/** The option value for a mode, the way BitPalmAgentOptions takes it. */\nexport function triggersOption(mode: TriggerMode): boolean | \"events\" {\n return mode === \"off\" ? false : mode === \"events\" ? \"events\" : true;\n}\n\nexport interface TriggerBubbleOptions {\n message: string;\n zIndex: number;\n /** Distance from the bottom edge: above the launcher, or lower without one. */\n bottom: number;\n onEngage: () => void;\n onDismiss: () => void;\n}\n\n/** The bubble on the website. The message goes in as text, never as HTML. */\nexport function createTriggerBubble(d: Document, options: TriggerBubbleOptions): HTMLDivElement {\n const bubble = d.createElement(\"div\");\n bubble.setAttribute(\"data-bitpalm-trigger\", \"\");\n bubble.style.cssText = `max-width:240px;background:#fff;border-radius:16px;padding:12px 32px 12px 12px;box-shadow:0 2px 20px rgba(0,0,0,0.08);cursor:pointer;z-index:${options.zIndex - 1};font-family:system-ui,sans-serif;animation:_bp_fade .3s;`;\n bubble.style.position = \"fixed\";\n bubble.style.right = \"24px\";\n bubble.style.bottom = `${options.bottom}px`;\n\n const text = d.createElement(\"p\");\n text.style.cssText = \"font-size:14px;color:#1f2937;margin:0;\";\n text.textContent = options.message;\n\n const arrow = d.createElement(\"div\");\n arrow.style.cssText = \"position:absolute;bottom:-8px;right:20px;width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #fff;\";\n\n const close = d.createElement(\"button\");\n close.type = \"button\";\n close.setAttribute(\"aria-label\", \"Close\");\n close.style.cssText = \"position:absolute;top:-8px;right:-8px;width:28px;height:28px;border-radius:50%;background:#fff;border:none;box-shadow:0 1px 4px rgba(0,0,0,0.1);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px;color:#9ca3af;\";\n close.textContent = \"✕\";\n close.onclick = (event) => {\n event.stopPropagation();\n options.onDismiss();\n };\n\n bubble.onclick = () => options.onEngage();\n bubble.append(text, arrow, close);\n return bubble;\n}\n","import type { BitPalmTheme } from \"./types\";\n\nexport type HostTheme = \"light\" | \"dark\";\n\nconst DARK_CLASSES = [\"dark\", \"dark-mode\", \"dark-theme\", \"theme-dark\"];\nconst LIGHT_CLASSES = [\"light\", \"light-mode\", \"light-theme\", \"theme-light\"];\nconst THEME_ATTRIBUTES = [\"data-theme\", \"data-color-scheme\", \"data-color-mode\", \"data-mode\", \"data-bs-theme\"];\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\";\n\nexport function normalizeThemeSetting(value: unknown): BitPalmTheme {\n return value === \"light\" || value === \"dark\" ? value : \"auto\";\n}\n\n/** Theme set explicitly on an element: a class like \"dark\" or an attribute like data-theme=\"dark\". */\nfunction explicitTheme(el: Element | null): HostTheme | null {\n if (!el) return null;\n if (DARK_CLASSES.some((name) => el.classList.contains(name))) return \"dark\";\n if (LIGHT_CLASSES.some((name) => el.classList.contains(name))) return \"light\";\n for (const attr of THEME_ATTRIBUTES) {\n const value = (el.getAttribute(attr) || \"\").toLowerCase();\n if (value.includes(\"dark\")) return \"dark\";\n if (value.includes(\"light\")) return \"light\";\n }\n return null;\n}\n\nfunction channel(value: number): number {\n const s = value / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n}\n\n/** Dark or light from an element's own opaque background color. */\nfunction backgroundTheme(el: Element | null, win: Window): HostTheme | null {\n if (!el) return null;\n const match = win.getComputedStyle(el).backgroundColor.match(/rgba?\\(([^)]+)\\)/);\n if (!match) return null;\n const [r, g, b, a = 1] = match[1].split(/[\\s,/]+/).filter(Boolean).map(Number);\n if ([r, g, b, a].some((n) => Number.isNaN(n)) || a < 0.5) return null;\n const luminance = 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);\n return luminance < 0.2 ? \"dark\" : \"light\";\n}\n\n/** The site declares color-scheme: only dark, or both and the visitor's system decides. */\nfunction colorSchemeTheme(doc: Document, win: Window): HostTheme | null {\n const computed = win.getComputedStyle(doc.documentElement).colorScheme || \"\";\n const meta = doc.querySelector('meta[name=\"color-scheme\"]')?.getAttribute(\"content\") || \"\";\n const scheme = `${computed} ${meta}`.toLowerCase();\n if (!scheme.includes(\"dark\")) return null;\n if (!scheme.includes(\"light\")) return \"dark\";\n return win.matchMedia?.(DARK_QUERY).matches ? \"dark\" : \"light\";\n}\n\n/**\n * Best guess of the host page's current theme, most explicit signal first:\n * theme classes and attributes on <html> or <body>, then the page background,\n * then a declared color-scheme. Pages without any of these count as light, so\n * a light-only site never gets a dark widget just because the visitor's\n * system is dark.\n */\nexport function detectHostTheme(doc: Document = document, win: Window = window): HostTheme {\n return (\n explicitTheme(doc.documentElement) ??\n explicitTheme(doc.body) ??\n backgroundTheme(doc.body, win) ??\n backgroundTheme(doc.documentElement, win) ??\n colorSchemeTheme(doc, win) ??\n \"light\"\n );\n}\n\n/**\n * Calls onChange when the detected theme changes: class or attribute changes\n * on <html> and <body>, and system theme changes. Returns a stop function.\n */\nexport function watchHostTheme(\n onChange: (theme: HostTheme) => void,\n doc: Document = document,\n win: Window = window,\n): () => void {\n let last = detectHostTheme(doc, win);\n let scheduled = false;\n\n const check = () => {\n scheduled = false;\n const next = detectHostTheme(doc, win);\n if (next === last) return;\n last = next;\n onChange(next);\n };\n // Theme switches often touch several attributes at once, check once per frame.\n const schedule = () => {\n if (scheduled) return;\n scheduled = true;\n if (typeof win.requestAnimationFrame === \"function\") win.requestAnimationFrame(check);\n else setTimeout(check, 16);\n };\n\n const observer = typeof MutationObserver !== \"undefined\" ? new MutationObserver(schedule) : null;\n const observed = { attributes: true, attributeFilter: [\"class\", \"style\", ...THEME_ATTRIBUTES] };\n observer?.observe(doc.documentElement, observed);\n if (doc.body) observer?.observe(doc.body, observed);\n\n const media = typeof win.matchMedia === \"function\" ? win.matchMedia(DARK_QUERY) : null;\n media?.addEventListener?.(\"change\", schedule);\n\n return () => {\n observer?.disconnect();\n media?.removeEventListener?.(\"change\", schedule);\n };\n}\n","import type { BitPalmAgentOptions, BitPalmAgentInstance, BitPalmIdentifyPayload, BitPalmCustomContext, BitPalmEventType, BitPalmEventCallback, BitPalmTheme } from \"./types\";\nimport { createTriggerBubble, parseTriggerMode, type TriggerMode } from \"./triggers\";\nimport { detectHostTheme, normalizeThemeSetting, watchHostTheme, type HostTheme } from \"./theme\";\n\nconst DEFAULT_BASE_URL = \"https://agents.bitpalm.ai\";\nconst STORAGE_PREFIX = \"_bp_\";\nconst IGNORED_INPUT_TYPES = new Set([\"password\", \"file\", \"checkbox\", \"radio\", \"submit\", \"button\", \"reset\", \"image\"]);\nconst IDENTITY_DEDUPE_WINDOW_MS = 8_000;\nconst CUSTOM_CONTEXT_MAX_BYTES = 4096;\nconst IDENTITY_SIGNATURE_KEY = `${STORAGE_PREFIX}identify_signature`;\nconst IDENTITY_FINGERPRINT_KEY = `${STORAGE_PREFIX}identify_fingerprint`;\nconst IDENTITY_SENT_AT_KEY = `${STORAGE_PREFIX}identify_sent_at`;\nconst LAUNCHER_SHADOW = \"0 4px 14px rgba(0,0,0,0.18)\";\n\ntype FormFieldElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n\ntype IdentityPayload = {\n name?: string;\n email?: string;\n phone?: string;\n company?: string;\n};\n\ntype IdentifyRequestPayload = IdentityPayload & {\n external_user_id?: string;\n signature?: string;\n signed_at?: number;\n signature_version?: \"v1\";\n identify_source?: \"manual\" | \"form\";\n};\n\nfunction buildIdentityFingerprint(payload: IdentifyRequestPayload): string {\n return [\n payload.external_user_id || \"\",\n payload.email || \"\",\n payload.phone || \"\",\n payload.name || \"\",\n payload.company || \"\",\n payload.signature || \"\",\n payload.signed_at != null ? String(payload.signed_at) : \"\",\n payload.signature_version || \"\",\n payload.identify_source || \"\",\n ]\n .join(\"|\")\n .toLowerCase();\n}\n\nfunction normalizeText(value: string | null | undefined, maxLen = 180): string {\n if (!value) return \"\";\n return value.replace(/\\s+/g, \" \").trim().slice(0, maxLen);\n}\n\nfunction normalizeTokens(value: string | null | undefined): string {\n if (!value) return \"\";\n return ` ${value.toLowerCase().replace(/[_-]+/g, \" \").replace(/[^a-z0-9\\s@.]/g, \" \").replace(/\\s+/g, \" \").trim()} `;\n}\n\nfunction includesAny(haystack: string, needles: string[]): boolean {\n for (const needle of needles) {\n if (haystack.includes(needle)) return true;\n }\n return false;\n}\n\nfunction isEmail(value: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/i.test(value);\n}\n\nfunction normalizePhone(value: string | null | undefined): string {\n const trimmed = normalizeText(value, 50);\n if (!trimmed) return \"\";\n const hasPlus = trimmed.startsWith(\"+\");\n const digits = trimmed.replace(/\\D/g, \"\");\n if (digits.length < 6) return \"\";\n return `${hasPlus ? \"+\" : \"\"}${digits.slice(0, 20)}`;\n}\n\nfunction normalizeEmail(value: string | null | undefined): string {\n const normalized = normalizeText(value, 140).toLowerCase();\n if (!normalized) return \"\";\n if (!isEmail(normalized)) return \"\";\n return normalized;\n}\n\nfunction getExplicitValue(form: HTMLFormElement, selectors: string[]): string {\n for (const selector of selectors) {\n const el = form.querySelector<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(selector);\n const value = normalizeText(el?.value);\n if (value) return value;\n }\n return \"\";\n}\n\nfunction getFieldHint(el: FormFieldElement): string {\n return normalizeText(el.getAttribute(\"data-bp-field\") || el.getAttribute(\"data-bitpalm-field\"), 64)\n .toLowerCase()\n .replace(/[_\\s]+/g, \"-\");\n}\n\nfunction escapeAttrSelectorValue(value: string): string {\n return value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n}\n\nfunction collectElementTokenParts(form: HTMLFormElement, el: FormFieldElement): string[] {\n const parts: string[] = [];\n const pushText = (value: string | null | undefined, maxLen = 140) => {\n const clean = normalizeText(value, maxLen);\n if (clean) parts.push(clean);\n };\n\n pushText(el.name);\n pushText(el.id);\n pushText(el.getAttribute(\"autocomplete\"));\n pushText(el.getAttribute(\"placeholder\"));\n pushText(el.getAttribute(\"aria-label\"));\n pushText(el.getAttribute(\"data-field\"));\n pushText(el.getAttribute(\"data-name\"));\n pushText(el.getAttribute(\"data-label\"));\n pushText(el.getAttribute(\"data-bp-field\"));\n pushText(el.getAttribute(\"data-bitpalm-field\"));\n\n const seenLabels = new Set<string>();\n const pushLabel = (value: string | null | undefined) => {\n const label = normalizeText(value, 200);\n if (!label || seenLabels.has(label)) return;\n seenLabels.add(label);\n parts.push(label);\n };\n\n for (const label of Array.from(el.labels || [])) {\n pushLabel(label.textContent);\n }\n\n if (el.id) {\n const forLabel = form.querySelector(`label[for=\"${escapeAttrSelectorValue(el.id)}\"]`);\n pushLabel(forLabel?.textContent);\n }\n\n const nearestLabel = el.closest(\"label\");\n pushLabel(nearestLabel?.textContent);\n\n const ariaLabelledBy = el.getAttribute(\"aria-labelledby\");\n if (ariaLabelledBy) {\n for (const id of ariaLabelledBy.split(/\\s+/)) {\n if (!id) continue;\n const ref = form.ownerDocument.getElementById(id);\n pushLabel(ref?.textContent);\n }\n }\n\n return parts;\n}\n\nfunction extractIdentityFromForm(form: HTMLFormElement): IdentityPayload | null {\n let email = normalizeText(getExplicitValue(form, [\n \"[data-bp-email]\",\n \"[data-bitpalm-email]\",\n ]), 140).toLowerCase();\n\n let phone = normalizePhone(getExplicitValue(form, [\n \"[data-bp-phone]\",\n \"[data-bitpalm-phone]\",\n ]));\n\n let name = normalizeText(getExplicitValue(form, [\n \"[data-bp-name]\",\n \"[data-bitpalm-name]\",\n \"[data-bp-full-name]\",\n \"[data-bitpalm-full-name]\",\n ]));\n\n let firstName = normalizeText(getExplicitValue(form, [\n \"[data-bp-first-name]\",\n \"[data-bitpalm-first-name]\",\n ]));\n\n let lastName = normalizeText(getExplicitValue(form, [\n \"[data-bp-last-name]\",\n \"[data-bitpalm-last-name]\",\n ]));\n\n let company = normalizeText(getExplicitValue(form, [\n \"[data-bp-company]\",\n \"[data-bitpalm-company]\",\n ]));\n\n for (const rawEl of Array.from(form.elements)) {\n if (!(rawEl instanceof HTMLInputElement || rawEl instanceof HTMLTextAreaElement || rawEl instanceof HTMLSelectElement)) continue;\n if (rawEl.disabled) continue;\n if (rawEl instanceof HTMLInputElement && IGNORED_INPUT_TYPES.has(rawEl.type.toLowerCase())) continue;\n const fieldHint = getFieldHint(rawEl);\n\n const explicitField =\n rawEl.hasAttribute(\"data-bp-email\") ||\n rawEl.hasAttribute(\"data-bitpalm-email\") ||\n rawEl.hasAttribute(\"data-bp-phone\") ||\n rawEl.hasAttribute(\"data-bitpalm-phone\") ||\n rawEl.hasAttribute(\"data-bp-name\") ||\n rawEl.hasAttribute(\"data-bitpalm-name\") ||\n rawEl.hasAttribute(\"data-bp-full-name\") ||\n rawEl.hasAttribute(\"data-bitpalm-full-name\") ||\n rawEl.hasAttribute(\"data-bp-first-name\") ||\n rawEl.hasAttribute(\"data-bitpalm-first-name\") ||\n rawEl.hasAttribute(\"data-bp-last-name\") ||\n rawEl.hasAttribute(\"data-bitpalm-last-name\") ||\n rawEl.hasAttribute(\"data-bp-company\") ||\n rawEl.hasAttribute(\"data-bitpalm-company\") ||\n !!fieldHint;\n\n if (rawEl instanceof HTMLInputElement && rawEl.type.toLowerCase() === \"hidden\" && !explicitField) continue;\n\n const value = normalizeText(rawEl.value);\n if (!value) continue;\n\n const type = rawEl instanceof HTMLInputElement ? rawEl.type.toLowerCase() : \"\";\n const tokens = normalizeTokens(collectElementTokenParts(form, rawEl).join(\" \"));\n\n if (!email && fieldHint === \"email\" && isEmail(value)) {\n email = value.toLowerCase();\n continue;\n }\n if (!phone && (fieldHint === \"phone\" || fieldHint === \"tel\" || fieldHint === \"mobile\" || fieldHint === \"whatsapp\")) {\n const normalized = normalizePhone(value);\n if (normalized) {\n phone = normalized;\n continue;\n }\n }\n if (!company && fieldHint === \"company\") {\n company = normalizeText(value, 160);\n continue;\n }\n if (!firstName && (fieldHint === \"first-name\" || fieldHint === \"firstname\")) {\n firstName = normalizeText(value, 100);\n continue;\n }\n if (!lastName && (fieldHint === \"last-name\" || fieldHint === \"lastname\" || fieldHint === \"surname\")) {\n lastName = normalizeText(value, 100);\n continue;\n }\n if (!name && (fieldHint === \"name\" || fieldHint === \"full-name\" || fieldHint === \"fullname\")) {\n if (!isEmail(value) && !normalizePhone(value)) name = normalizeText(value, 140);\n continue;\n }\n\n const emailLike = type === \"email\" || includesAny(tokens, [\" email \", \" e mail \", \" mail \", \" email adresse \", \" mailadresse \", \" correo \"]);\n const phoneLike = type === \"tel\" || includesAny(tokens, [\" phone \", \" phone number \", \" mobile \", \" tel \", \" telefon \", \" telefonnummer \", \" whatsapp \", \" handy \", \" kontakt \", \" nummer \"]);\n const companyLike = includesAny(tokens, [\" company \", \" company name \", \" firma \", \" firmenname \", \" organization \", \" organisation \", \" business \", \" unternehmen \", \" agency \", \" brokerage \"]);\n const firstNameLike = includesAny(tokens, [\" first name \", \" firstname \", \" given name \", \" givenname \", \" vorname \", \" fname \"]);\n const lastNameLike = includesAny(tokens, [\" last name \", \" lastname \", \" family name \", \" familyname \", \" surname \", \" nachname \", \" lname \"]);\n const fullNameLike = includesAny(tokens, [\" full name \", \" fullname \", \" contact name \", \" name \"]) && !emailLike && !phoneLike;\n\n if (!email && emailLike && isEmail(value)) {\n email = value.toLowerCase();\n continue;\n }\n if (!phone && phoneLike) {\n const normalized = normalizePhone(value);\n if (normalized) {\n phone = normalized;\n continue;\n }\n }\n if (!company && companyLike) {\n company = normalizeText(value, 160);\n continue;\n }\n if (!firstName && firstNameLike) {\n firstName = normalizeText(value, 100);\n continue;\n }\n if (!lastName && lastNameLike) {\n lastName = normalizeText(value, 100);\n continue;\n }\n if (!name && fullNameLike && !isEmail(value) && !normalizePhone(value)) {\n name = normalizeText(value, 140);\n continue;\n }\n\n if (!email && isEmail(value)) {\n email = value.toLowerCase();\n }\n }\n\n if (name && (isEmail(name) || normalizePhone(name))) {\n name = \"\";\n }\n if (company && (isEmail(company) || normalizePhone(company))) {\n company = \"\";\n }\n\n if (!name) {\n name = normalizeText([firstName, lastName].filter(Boolean).join(\" \"), 140);\n }\n\n if (name && email && name.toLowerCase() === email.toLowerCase()) {\n name = \"\";\n }\n\n const hasContactSignal = !!(email || phone);\n const hasStrongProfileSignal = !!(name && company);\n if (!hasContactSignal && !hasStrongProfileSignal) {\n return null;\n }\n\n const identity: IdentityPayload = {\n ...(name ? { name } : {}),\n ...(email ? { email } : {}),\n ...(phone ? { phone } : {}),\n ...(company ? { company } : {}),\n };\n\n return Object.keys(identity).length > 0 ? identity : null;\n}\n\nfunction detectLocale(): string {\n if (typeof document !== \"undefined\") {\n const lang = document.documentElement.lang;\n if (lang) return lang.slice(0, 2).toLowerCase();\n }\n return \"en\";\n}\n\nfunction runWhenIdle(task: () => void, timeout = 1200) {\n if (typeof window !== \"undefined\" && \"requestIdleCallback\" in window) {\n (\n window as unknown as {\n requestIdleCallback: (cb: () => void, opts?: { timeout?: number }) => number;\n }\n ).requestIdleCallback(task, { timeout });\n return;\n }\n setTimeout(task, Math.min(timeout, 300));\n}\n\nfunction isMobileWidgetDevice(): boolean {\n if (typeof window === \"undefined\") return false;\n const userAgent = typeof navigator !== \"undefined\" ? navigator.userAgent : \"\";\n const isMobileUa = /Android|iPhone|iPad|iPod|IEMobile|Windows Phone|Mobile/i.test(userAgent);\n if (isMobileUa) return true;\n\n const coarsePointer = window.matchMedia(\"(pointer: coarse)\").matches;\n const noHover = window.matchMedia(\"(hover: none)\").matches;\n const minScreenSide = Math.min(\n window.screen?.width || window.innerWidth,\n window.screen?.height || window.innerHeight,\n );\n return coarsePointer && noHover && minScreenSide <= 900;\n}\n\nexport function createWidget(options: BitPalmAgentOptions): BitPalmAgentInstance {\n const {\n slug,\n locale = detectLocale(),\n baseUrl = DEFAULT_BASE_URL,\n token,\n zIndex = 9999,\n autoIdentify = true,\n launcher = true,\n } = options;\n\n const d = document;\n\n // --- Theme ---\n let themeSetting: BitPalmTheme = normalizeThemeSetting(options.theme);\n let currentTheme: HostTheme = themeSetting === \"auto\" ? detectHostTheme() : themeSetting;\n let stopThemeWatch: (() => void) | null = null;\n\n // --- Triggers ---\n const configuredTriggerMode = parseTriggerMode(options.triggers);\n let triggerMode: TriggerMode = configuredTriggerMode;\n /** With triggers: \"events\", the message waiting for the next open(). */\n let pendingTrigger: string | null = null;\n\n // --- Iframe ---\n const iframe = d.createElement(\"iframe\");\n iframe.setAttribute(\"data-bitpalm-chat\", \"\");\n const widgetUrl = `${baseUrl}/t/${slug}/widget`;\n const qs = new URLSearchParams({ locale, theme: currentTheme });\n if (token) qs.set(\"token\", token);\n if (triggerMode === \"off\") qs.set(\"triggers\", \"off\");\n iframe.src = `${widgetUrl}?${qs.toString()}`;\n // Explicitly grant the iframe permission to use the visitor's\n // microphone — required for the voice-input feature on cross-origin\n // iframes. Without this, Chrome silently denies getUserMedia /\n // SpeechRecognition without ever prompting the user.\n iframe.allow = \"clipboard-write; microphone\";\n iframe.setAttribute(\"allowtransparency\", \"true\");\n iframe.loading = \"lazy\";\n iframe.style.cssText = `position:fixed;bottom:0;right:0;width:1px;height:1px;border:none;z-index:${zIndex};background:transparent;color-scheme:normal;opacity:0;pointer-events:none;`;\n\n const origin = new URL(iframe.src).origin;\n\n // --- Native launcher button ---\n const btn = d.createElement(\"div\");\n btn.setAttribute(\"role\", \"button\");\n btn.setAttribute(\"aria-label\", \"Chat\");\n btn.setAttribute(\"data-bitpalm-launcher\", \"\");\n btn.style.cssText = `position:fixed;bottom:24px;right:24px;width:56px;height:56px;border-radius:50%;display:none;align-items:center;justify-content:center;cursor:pointer;z-index:${zIndex - 1};background:#171717;box-shadow:${LAUNCHER_SHADOW};transition:transform .2s,opacity .3s;opacity:0;`;\n btn.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M7.9 20A9 9 0 1 0 4 16.1L2 22Z\"/></svg>';\n btn.onmouseenter = () => { btn.style.transform = \"scale(1.05)\"; };\n btn.onmouseleave = () => { btn.style.transform = \"scale(1)\"; };\n btn.onclick = () => openWidget();\n // Sites with a chat button of their own call open() instead.\n if (launcher) d.body.appendChild(btn);\n\n // --- Fade animation for trigger bubbles ---\n if (!d.getElementById(\"_bp_fade\")) {\n const s = d.createElement(\"style\");\n s.id = \"_bp_fade\";\n s.textContent = \"@keyframes _bp_fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\";\n d.head.appendChild(s);\n }\n\n // --- Trigger bubble ---\n let bubble: HTMLDivElement | null = null;\n let launcherReady = false;\n let widgetBlocked = false;\n let iframeMounted = false;\n let iframeReady = false;\n let pendingOpen = false;\n const mountIframe = () => {\n if (iframeMounted) return;\n iframeMounted = true;\n d.body.appendChild(iframe);\n };\n let mobileScrollLocked = false;\n let scrollLockY = 0;\n const prevHtmlStyle = {\n overflow: \"\",\n overscrollBehavior: \"\",\n };\n const prevBodyStyle = {\n overflow: \"\",\n overscrollBehavior: \"\",\n position: \"\",\n top: \"\",\n left: \"\",\n right: \"\",\n width: \"\",\n };\n const lockMobilePageScroll = () => {\n if (mobileScrollLocked) return;\n const mobile = isMobileWidgetDevice();\n if (!mobile) return;\n const html = d.documentElement;\n const body = d.body;\n scrollLockY = window.scrollY || window.pageYOffset || 0;\n prevHtmlStyle.overflow = html.style.overflow;\n prevHtmlStyle.overscrollBehavior = html.style.overscrollBehavior;\n prevBodyStyle.overflow = body.style.overflow;\n prevBodyStyle.overscrollBehavior = body.style.overscrollBehavior;\n prevBodyStyle.position = body.style.position;\n prevBodyStyle.top = body.style.top;\n prevBodyStyle.left = body.style.left;\n prevBodyStyle.right = body.style.right;\n prevBodyStyle.width = body.style.width;\n html.style.overflow = \"hidden\";\n html.style.overscrollBehavior = \"none\";\n body.style.overflow = \"hidden\";\n body.style.overscrollBehavior = \"none\";\n body.style.position = \"fixed\";\n body.style.top = `-${scrollLockY}px`;\n body.style.left = \"0\";\n body.style.right = \"0\";\n body.style.width = \"100%\";\n mobileScrollLocked = true;\n };\n const unlockMobilePageScroll = () => {\n if (!mobileScrollLocked) return;\n const html = d.documentElement;\n const body = d.body;\n html.style.overflow = prevHtmlStyle.overflow;\n html.style.overscrollBehavior = prevHtmlStyle.overscrollBehavior;\n body.style.overflow = prevBodyStyle.overflow;\n body.style.overscrollBehavior = prevBodyStyle.overscrollBehavior;\n body.style.position = prevBodyStyle.position;\n body.style.top = prevBodyStyle.top;\n body.style.left = prevBodyStyle.left;\n body.style.right = prevBodyStyle.right;\n body.style.width = prevBodyStyle.width;\n window.scrollTo(0, scrollLockY);\n mobileScrollLocked = false;\n };\n const prepareIframeForOpen = () => {\n const mobile = isMobileWidgetDevice();\n if (iframe.style.display === \"none\") iframe.style.display = \"\";\n if (mobile) {\n iframe.style.width = \"100vw\";\n iframe.style.height = \"100dvh\";\n iframe.style.left = \"0\";\n iframe.style.top = \"0\";\n iframe.style.bottom = \"0\";\n iframe.style.right = \"0\";\n lockMobilePageScroll();\n } else {\n // Match desktop widget target size so the opening animation is visible from frame 1.\n iframe.style.width = \"420px\";\n iframe.style.height = \"620px\";\n iframe.style.bottom = \"24px\";\n iframe.style.right = \"24px\";\n iframe.style.left = \"\";\n iframe.style.top = \"\";\n unlockMobilePageScroll();\n }\n iframe.style.opacity = \"1\";\n iframe.style.pointerEvents = \"auto\";\n };\n const removeBubble = () => {\n if (bubble) { bubble.remove(); bubble = null; }\n };\n const clearPendingTrigger = () => {\n if (pendingTrigger === null) return;\n pendingTrigger = null;\n emit(\"trigger_hidden\");\n };\n /** Tells the iframe whether to run triggers at all. \"events\" still needs them to run. */\n const sendTriggerState = () => {\n iframe.contentWindow?.postMessage({ type: \"bitpalm-triggers\", enabled: triggerMode !== \"off\" }, \"*\");\n };\n let sendParentContext = () => {};\n let sendOpenSignal = () => {};\n\n // --- Widget state & event bus ---\n let widgetIsOpen = false;\n const eventListeners = new Map<BitPalmEventType, Set<BitPalmEventCallback>>();\n\n function emit(event: BitPalmEventType, data?: Record<string, unknown>) {\n const listeners = eventListeners.get(event);\n if (!listeners) return;\n for (const cb of listeners) {\n try { cb(data); } catch { /* don't let listener errors break the widget */ }\n }\n }\n\n // --- postMessage handler ---\n const handleMessage = (e: MessageEvent) => {\n if (e.origin !== origin) return;\n\n // Widget config (colors, icon)\n if (e.data?.type === \"bitpalm-widget-config\") {\n widgetBlocked = false;\n launcherReady = true;\n if (iframe.style.display === \"none\") iframe.style.display = \"\";\n if (e.data.primaryColor) {\n btn.style.background = e.data.primaryColor;\n btn.style.boxShadow = e.data.chatShadow === \"none\" ? \"none\" : LAUNCHER_SHADOW;\n }\n const ic = e.data.chatButtonIconColor || \"black\";\n if (e.data.chatButtonIconSvg) {\n btn.innerHTML = \"\";\n const sp = d.createElement(\"span\");\n sp.style.cssText = `display:flex;align-items:center;justify-content:center;width:24px;height:24px;color:${ic}`;\n const parser = new DOMParser();\n const doc = parser.parseFromString(e.data.chatButtonIconSvg, \"image/svg+xml\");\n const svg = doc.querySelector(\"svg\");\n if (svg) {\n // Remove dangerous elements and attributes\n svg.querySelectorAll(\"script,foreignObject\").forEach(el => el.remove());\n svg.querySelectorAll(\"*\").forEach(el => {\n for (const attr of [...el.attributes]) {\n if (attr.name.startsWith(\"on\") || (attr.value && attr.value.includes(\"javascript:\"))) {\n el.removeAttribute(attr.name);\n }\n }\n });\n svg.setAttribute(\"width\", \"24\");\n svg.setAttribute(\"height\", \"24\");\n svg.style.display = \"block\";\n sp.appendChild(svg);\n } else {\n // Fallback: use default icon\n sp.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M7.9 20A9 9 0 1 0 4 16.1L2 22Z\"/></svg>';\n }\n btn.appendChild(sp);\n } else {\n const sv = btn.querySelector(\"svg\");\n if (sv) (sv as SVGElement).style.stroke = ic;\n }\n if (launcher) {\n btn.style.display = \"flex\";\n // Fade in after styles are applied\n requestAnimationFrame(() => { btn.style.opacity = \"1\"; });\n }\n // The iframe may have loaded after disableTriggers() or enableTriggers().\n sendTriggerState();\n }\n\n // Resize — use full viewport on mobile\n if (e.data?.type === \"bitpalm-widget-resize\") {\n const isOpen = e.data.width > 0;\n const wasOpen = widgetIsOpen;\n widgetIsOpen = isOpen;\n if (isOpen && !wasOpen) emit(\"widget_opened\");\n if (!isOpen && wasOpen) emit(\"widget_closed\");\n const mobile = isMobileWidgetDevice();\n if (isOpen) {\n iframe.style.width = mobile ? \"100vw\" : `${e.data.width}px`;\n iframe.style.height = mobile ? \"100dvh\" : `${e.data.height}px`;\n if (mobile) {\n iframe.style.left = \"0\";\n iframe.style.top = \"0\";\n iframe.style.bottom = \"0\";\n iframe.style.right = \"0\";\n lockMobilePageScroll();\n } else {\n unlockMobilePageScroll();\n }\n iframe.style.opacity = \"1\";\n iframe.style.pointerEvents = \"auto\";\n } else {\n unlockMobilePageScroll();\n iframe.style.width = \"1px\";\n iframe.style.height = \"1px\";\n iframe.style.left = \"\";\n iframe.style.top = \"\";\n iframe.style.opacity = \"0\";\n iframe.style.pointerEvents = \"none\";\n }\n btn.style.display = isOpen || !launcher ? \"none\" : \"flex\";\n }\n\n // A trigger fired inside the iframe: our bubble, or an event for the site's own UI\n if (e.data?.type === \"bitpalm-trigger-show\") {\n if (widgetBlocked || !launcherReady || triggerMode === \"off\") return;\n const message = typeof e.data.message === \"string\" ? e.data.message : \"\";\n if (!message) return;\n if (triggerMode === \"events\") {\n pendingTrigger = message;\n emit(\"trigger_shown\", { message, triggerId: e.data.triggerId, triggerType: e.data.triggerType });\n return;\n }\n removeBubble();\n bubble = createTriggerBubble(d, {\n message,\n zIndex,\n bottom: launcher ? 90 : 24,\n onDismiss: () => {\n removeBubble();\n iframe.contentWindow?.postMessage({ type: \"bitpalm-trigger-dismiss\" }, \"*\");\n },\n onEngage: () => {\n removeBubble();\n btn.style.display = \"none\";\n prepareIframeForOpen();\n mountIframe();\n if (!iframeReady) {\n pendingOpen = true;\n return;\n }\n iframe.contentWindow?.postMessage({ type: \"bitpalm-trigger-engaged\", message }, \"*\");\n },\n });\n d.body.appendChild(bubble);\n }\n\n // Trigger gone (chat opened, dismissed, switched off)\n if (e.data?.type === \"bitpalm-trigger-hide\") {\n removeBubble();\n clearPendingTrigger();\n }\n\n // Iframe requests latest parent context (avoids first-load race conditions)\n if (e.data?.type === \"bitpalm-request-context\") {\n sendParentContext();\n }\n\n // Chat events from iframe → emit to SDK listeners\n if (e.data?.type === \"bitpalm-chat-event\" && e.data.event) {\n emit(e.data.event as BitPalmEventType, e.data.data);\n }\n\n // Widget blocked (excluded path or access denied) — hide button & iframe\n if (e.data?.type === \"bitpalm-widget-blocked\") {\n widgetBlocked = true;\n launcherReady = false;\n btn.style.display = \"none\";\n removeBubble();\n clearPendingTrigger();\n unlockMobilePageScroll();\n iframe.style.display = \"none\";\n }\n };\n window.addEventListener(\"message\", handleMessage);\n\n // --- Privacy opt-out check ---\n let optedOut = false;\n try { optedOut = localStorage.getItem(`${STORAGE_PREFIX}optout`) === \"1\"; } catch { /* ignore */ }\n\n // --- Persistent Visitor ID (skip if opted out) ---\n const VID_KEY = `${STORAGE_PREFIX}vid`;\n let visitorId = \"\";\n if (!optedOut) {\n try { visitorId = localStorage.getItem(VID_KEY) || \"\"; } catch { /* ignore */ }\n if (!visitorId) {\n // Fallback: try reading from cookie\n const match = d.cookie.match(new RegExp(`(?:^|; )${VID_KEY}=([^;]+)`));\n visitorId = match ? decodeURIComponent(match[1]) : \"\";\n }\n if (!visitorId) {\n visitorId = crypto.randomUUID ? crypto.randomUUID() : (`${Date.now()}-${Math.random().toString(36).slice(2, 11)}`);\n }\n // Persist in both localStorage and cookie (cookie survives Safari ITP clearing localStorage)\n try { localStorage.setItem(VID_KEY, visitorId); } catch { /* ignore */ }\n try {\n const maxAge = 365 * 24 * 60 * 60; // 1 year\n d.cookie = `${VID_KEY}=${encodeURIComponent(visitorId)};path=/;max-age=${maxAge};SameSite=Lax`;\n } catch { /* ignore */ }\n }\n\n // --- Visitor beacon: track page view even without chat (skip if opted out) ---\n if (!optedOut) {\n runWhenIdle(() => {\n try {\n const utmParams = new URLSearchParams(location.search);\n const utm: Record<string, string> = {};\n for (const key of [\"utm_source\", \"utm_medium\", \"utm_campaign\", \"utm_term\", \"utm_content\"]) {\n const val = utmParams.get(key);\n if (val) utm[key] = val;\n }\n const beaconPayload = JSON.stringify({\n tenant_slug: slug,\n visitor_id: visitorId,\n url: location.href,\n referrer: d.referrer || undefined,\n ...(Object.keys(utm).length > 0 ? { utm } : {}),\n });\n const beaconUrl = `${baseUrl}/api/widget/impression`;\n if (typeof navigator.sendBeacon === \"function\") {\n navigator.sendBeacon(beaconUrl, new Blob([beaconPayload], { type: \"application/json\" }));\n } else {\n fetch(beaconUrl, { method: \"POST\", body: beaconPayload, headers: { \"Content-Type\": \"application/json\" }, keepalive: true }).catch(() => {});\n }\n } catch { /* ignore */ }\n }, 2000);\n }\n\n // --- Auto-identify visitor from form submissions on host page ---\n let lastIdentitySignature = \"\";\n let lastIdentityFingerprint = \"\";\n let lastIdentitySentAt = 0;\n try {\n lastIdentitySignature = sessionStorage.getItem(IDENTITY_SIGNATURE_KEY) || \"\";\n lastIdentityFingerprint = sessionStorage.getItem(IDENTITY_FINGERPRINT_KEY) || \"\";\n const storedAt = parseInt(sessionStorage.getItem(IDENTITY_SENT_AT_KEY) || \"0\", 10);\n if (Number.isFinite(storedAt) && storedAt > 0) {\n lastIdentitySentAt = storedAt;\n }\n } catch {\n // ignore\n }\n\n const dispatchIdentify = (payloadInput: IdentifyRequestPayload, scopeSignature = \"\") => {\n if (optedOut || !visitorId) return;\n\n const payload: IdentifyRequestPayload = {};\n const name = normalizeText(payloadInput.name, 140);\n const email = normalizeEmail(payloadInput.email);\n const phone = normalizePhone(payloadInput.phone);\n const company = normalizeText(payloadInput.company, 160);\n const externalUserId = normalizeText(payloadInput.external_user_id, 140);\n const requestSignature = normalizeText(payloadInput.signature, 260);\n const signedAtRaw = Number(payloadInput.signed_at);\n\n if (name) payload.name = name;\n if (email) payload.email = email;\n if (phone) payload.phone = phone;\n if (company) payload.company = company;\n if (externalUserId) payload.external_user_id = externalUserId;\n if (requestSignature) payload.signature = requestSignature;\n if (Number.isFinite(signedAtRaw) && signedAtRaw > 0) {\n payload.signed_at = Math.floor(signedAtRaw);\n }\n if (payloadInput.signature_version === \"v1\" || payload.signature) {\n payload.signature_version = \"v1\";\n }\n if (payloadInput.identify_source === \"manual\" || payloadInput.identify_source === \"form\") {\n payload.identify_source = payloadInput.identify_source;\n }\n\n if (!payload.name && !payload.email && !payload.phone && !payload.company && !payload.external_user_id) {\n return;\n }\n\n const identityFingerprint = buildIdentityFingerprint(payload);\n const dedupeSignature = [scopeSignature.toLowerCase(), identityFingerprint].filter(Boolean).join(\"|\");\n\n const now = Date.now();\n const insideDedupWindow = now - lastIdentitySentAt < IDENTITY_DEDUPE_WINDOW_MS;\n if (insideDedupWindow && (dedupeSignature === lastIdentitySignature || identityFingerprint === lastIdentityFingerprint)) {\n return;\n }\n\n lastIdentitySignature = dedupeSignature;\n lastIdentityFingerprint = identityFingerprint;\n lastIdentitySentAt = now;\n try {\n sessionStorage.setItem(IDENTITY_SIGNATURE_KEY, dedupeSignature);\n sessionStorage.setItem(IDENTITY_FINGERPRINT_KEY, identityFingerprint);\n sessionStorage.setItem(IDENTITY_SENT_AT_KEY, String(now));\n } catch {\n // ignore\n }\n\n try {\n const requestBody = JSON.stringify({\n tenant_slug: slug,\n visitor_id: visitorId,\n url: location.href,\n referrer: d.referrer || undefined,\n ...payload,\n });\n const identifyUrl = `${baseUrl}/api/widget/identify`;\n if (typeof navigator.sendBeacon === \"function\") {\n navigator.sendBeacon(identifyUrl, new Blob([requestBody], { type: \"application/json\" }));\n } else {\n fetch(identifyUrl, { method: \"POST\", body: requestBody, headers: { \"Content-Type\": \"application/json\" }, keepalive: true }).catch(() => {});\n }\n } catch {\n // ignore\n }\n };\n\n const handleFormSubmit = (event: Event) => {\n if (optedOut || !autoIdentify || !visitorId) return;\n\n const form = event.target instanceof HTMLFormElement\n ? event.target\n : event.target instanceof Element\n ? event.target.closest(\"form\")\n : null;\n if (!(form instanceof HTMLFormElement)) return;\n\n const formIdentifySetting = (form.getAttribute(\"data-bp-identify\") || form.getAttribute(\"data-bitpalm-identify\") || \"\").toLowerCase();\n if (formIdentifySetting === \"off\" || formIdentifySetting === \"false\" || formIdentifySetting === \"0\") return;\n\n const identity = extractIdentityFromForm(form);\n if (!identity) return;\n\n const formSignature = [\n form.getAttribute(\"id\") || \"\",\n form.getAttribute(\"name\") || \"\",\n form.getAttribute(\"action\") || \"\",\n ].join(\"|\");\n\n dispatchIdentify({ ...identity, identify_source: \"form\" }, formSignature);\n };\n\n if (!optedOut && autoIdentify) {\n d.addEventListener(\"submit\", handleFormSubmit, true);\n }\n\n // --- Visitor Intelligence: page counter + history ---\n let pageCount = parseInt(sessionStorage.getItem(`${STORAGE_PREFIX}pages`) || \"0\") + 1;\n sessionStorage.setItem(`${STORAGE_PREFIX}pages`, String(pageCount));\n\n let hist: string[] = JSON.parse(sessionStorage.getItem(`${STORAGE_PREFIX}hist`) || \"[]\");\n hist.push(location.href);\n if (hist.length > 20) hist = hist.slice(-20);\n sessionStorage.setItem(`${STORAGE_PREFIX}hist`, JSON.stringify(hist));\n\n const loadedAt = Date.now();\n let siteStart = parseInt(sessionStorage.getItem(`${STORAGE_PREFIX}site_start`) || \"0\");\n if (!siteStart) {\n siteStart = loadedAt;\n sessionStorage.setItem(`${STORAGE_PREFIX}site_start`, String(siteStart));\n }\n\n const contextRetryTimers: ReturnType<typeof setTimeout>[] = [];\n sendParentContext = () => {\n let returning = false;\n try {\n returning = !!localStorage.getItem(`${STORAGE_PREFIX}visited`);\n } catch {\n returning = false;\n }\n iframe.contentWindow?.postMessage({\n type: \"bitpalm-parent-context\",\n url: location.href,\n title: d.title,\n returning,\n pageCount,\n pageHistory: hist,\n loadedAt,\n siteStart,\n locale,\n visitorId: optedOut ? \"\" : visitorId,\n }, \"*\");\n sendTheme();\n if (!returning && !optedOut) {\n try { localStorage.setItem(`${STORAGE_PREFIX}visited`, \"1\"); } catch { /* ignore */ }\n }\n };\n\n // --- Send parent context on iframe load ---\n iframe.addEventListener(\"load\", () => {\n iframeReady = true;\n sendParentContext();\n [120, 450, 1100].forEach((delay) => {\n const timer = setTimeout(() => sendParentContext(), delay);\n contextRetryTimers.push(timer);\n });\n if (pendingOpen) {\n pendingOpen = false;\n sendOpenSignal();\n }\n });\n\n // Lazy-mount iframe after initial paint/idle to reduce impact on host load.\n if (d.readyState === \"loading\") {\n d.addEventListener(\"DOMContentLoaded\", () => runWhenIdle(mountIframe, 1600), { once: true });\n } else {\n runWhenIdle(mountIframe, 1600);\n }\n\n // --- SPA navigation detection ---\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n const onNav = () => {\n pageCount++;\n sessionStorage.setItem(`${STORAGE_PREFIX}pages`, String(pageCount));\n const h: string[] = JSON.parse(sessionStorage.getItem(`${STORAGE_PREFIX}hist`) || \"[]\");\n h.push(location.href);\n if (h.length > 20) h.splice(0, h.length - 20);\n hist = h;\n sessionStorage.setItem(`${STORAGE_PREFIX}hist`, JSON.stringify(h));\n iframe.contentWindow?.postMessage({\n type: \"bitpalm-page-change\",\n url: location.href,\n title: d.title,\n pageCount,\n pageHistory: h,\n loadedAt: Date.now(),\n }, \"*\");\n // Track page view for visitor (skip if opted out)\n if (!optedOut) {\n try {\n const navPayload = JSON.stringify({ tenant_slug: slug, visitor_id: visitorId, url: location.href });\n const navUrl = `${baseUrl}/api/widget/impression`;\n if (typeof navigator.sendBeacon === \"function\") {\n navigator.sendBeacon(navUrl, new Blob([navPayload], { type: \"application/json\" }));\n } else {\n fetch(navUrl, { method: \"POST\", body: navPayload, headers: { \"Content-Type\": \"application/json\" }, keepalive: true }).catch(() => {});\n }\n } catch { /* ignore */ }\n }\n };\n\n history.pushState = function (...args: Parameters<typeof history.pushState>) {\n origPush(...args);\n onNav();\n };\n history.replaceState = function (...args: Parameters<typeof history.replaceState>) {\n origReplace(...args);\n onNav();\n };\n window.addEventListener(\"popstate\", onNav);\n\n // --- Scroll depth tracking ---\n let lastScrollDepth = -1;\n let scrollTimeout: ReturnType<typeof setTimeout>;\n const handleScroll = () => {\n clearTimeout(scrollTimeout);\n scrollTimeout = setTimeout(() => {\n const total = Math.max(d.documentElement.scrollHeight, d.body.scrollHeight) - window.innerHeight;\n const pct = total > 0 ? Math.round(window.scrollY / total * 100) : 100;\n if (pct !== lastScrollDepth) {\n lastScrollDepth = pct;\n iframe.contentWindow?.postMessage({ type: \"bitpalm-scroll-depth\", percent: pct }, \"*\");\n }\n }, 500);\n };\n window.addEventListener(\"scroll\", handleScroll, { passive: true });\n\n // --- Exit intent ---\n const handleMouseOut = (e: MouseEvent) => {\n if (e.clientY <= 0) {\n iframe.contentWindow?.postMessage({ type: \"bitpalm-exit-intent\" }, \"*\");\n }\n };\n d.addEventListener(\"mouseout\", handleMouseOut);\n\n // --- Inactivity detection (15s) ---\n let idleTimer: ReturnType<typeof setTimeout>;\n let idleFired = false;\n const resetIdle = () => {\n clearTimeout(idleTimer);\n if (idleFired) return;\n idleTimer = setTimeout(() => {\n idleFired = true;\n iframe.contentWindow?.postMessage({ type: \"bitpalm-inactivity\" }, \"*\");\n }, 15_000);\n };\n const idleEvents = [\"mousemove\", \"keydown\", \"scroll\", \"touchstart\"] as const;\n idleEvents.forEach((ev) => d.addEventListener(ev, resetIdle, { passive: true }));\n resetIdle();\n\n sendOpenSignal = () => {\n // Primary: postMessage\n iframe.contentWindow?.postMessage({ type: \"bitpalm-open\" }, \"*\");\n // Fallback for mobile: trigger hashchange inside iframe (no reload)\n const base = iframe.src.split(\"#\")[0];\n iframe.src = `${base}#bp-open-${Date.now()}`;\n };\n\n // --- Public API ---\n const openWidget = () => {\n btn.style.display = \"none\";\n removeBubble();\n prepareIframeForOpen();\n mountIframe();\n if (!iframeReady) {\n pendingOpen = true;\n return;\n }\n // A waiting trigger message opens with the chat and counts as clicked, like the bubble.\n if (pendingTrigger !== null) {\n const message = pendingTrigger;\n clearPendingTrigger();\n iframe.contentWindow?.postMessage({ type: \"bitpalm-trigger-engaged\", message }, \"*\");\n return;\n }\n sendOpenSignal();\n };\n\n const setTriggerMode = (mode: TriggerMode) => {\n triggerMode = mode;\n if (mode === \"off\") {\n removeBubble();\n clearPendingTrigger();\n }\n sendTriggerState();\n };\n const disableTriggers = () => setTriggerMode(\"off\");\n const enableTriggers = () => setTriggerMode(configuredTriggerMode === \"off\" ? \"bubble\" : configuredTriggerMode);\n\n const closeWidget = () => {\n unlockMobilePageScroll();\n iframe.contentWindow?.postMessage({ type: \"bitpalm-close\" }, \"*\");\n };\n\n const identify = (input: BitPalmIdentifyPayload) => {\n if (!input || typeof input !== \"object\") return;\n dispatchIdentify({\n external_user_id: normalizeText(input.externalUserId, 140) || undefined,\n name: normalizeText(input.name, 140) || undefined,\n email: normalizeEmail(input.email) || undefined,\n phone: normalizePhone(input.phone) || undefined,\n company: normalizeText(input.company, 160) || undefined,\n signature: normalizeText(input.signature, 260) || undefined,\n signed_at: Number.isFinite(Number(input.signedAt)) ? Math.floor(Number(input.signedAt)) : undefined,\n signature_version: input.signatureVersion === \"v1\" ? \"v1\" : undefined,\n identify_source: \"manual\",\n }, \"manual\");\n };\n\n const toggleWidget = () => {\n if (widgetIsOpen) closeWidget();\n else openWidget();\n };\n\n const getIsOpen = () => widgetIsOpen;\n\n const sendMessage = (message: string) => {\n if (!message || typeof message !== \"string\") return;\n const text = message.trim().slice(0, 10_000);\n if (!text) return;\n if (!widgetIsOpen) openWidget();\n // Small delay to ensure widget is open before sending\n setTimeout(() => {\n iframe.contentWindow?.postMessage({ type: \"bitpalm-send-message\", message: text }, \"*\");\n }, widgetIsOpen ? 50 : 500);\n };\n\n // --- Theme switching ---\n function sendTheme() {\n iframe.contentWindow?.postMessage({ type: \"bitpalm-theme\", theme: currentTheme }, \"*\");\n }\n\n const applyTheme = (theme: HostTheme) => {\n if (theme === currentTheme) return;\n currentTheme = theme;\n sendTheme();\n };\n\n const setTheme = (theme: BitPalmTheme) => {\n themeSetting = normalizeThemeSetting(theme);\n stopThemeWatch?.();\n stopThemeWatch = null;\n if (themeSetting === \"auto\") {\n stopThemeWatch = watchHostTheme(applyTheme);\n applyTheme(detectHostTheme());\n } else {\n applyTheme(themeSetting);\n }\n };\n\n if (themeSetting === \"auto\") stopThemeWatch = watchHostTheme(applyTheme);\n\n const handleThemeEvent = (event: Event) => {\n const detail = (event as CustomEvent<{ slug?: string; theme?: BitPalmTheme }>).detail;\n if (!detail || typeof detail !== \"object\") return;\n const targetSlug = normalizeText(detail.slug, 120);\n if (targetSlug && targetSlug !== slug) return;\n setTheme(normalizeThemeSetting(detail.theme));\n };\n window.addEventListener(\"bitpalm-theme\", handleThemeEvent as EventListener);\n\n // --- Custom context for AI ---\n let customContext: Record<string, unknown> = {};\n\n const setCustomContext = (data: BitPalmCustomContext) => {\n if (!data || typeof data !== \"object\" || Array.isArray(data)) return;\n customContext = { ...customContext, ...data };\n const json = JSON.stringify(customContext);\n if (json.length > CUSTOM_CONTEXT_MAX_BYTES) {\n console.warn(\n `[BitPalm] Custom context exceeds ${CUSTOM_CONTEXT_MAX_BYTES} bytes (${json.length}). It may be truncated.`\n );\n }\n iframe.contentWindow?.postMessage({ type: \"bitpalm-custom-context\", data: customContext }, \"*\");\n };\n\n const clearCustomContext = () => {\n customContext = {};\n iframe.contentWindow?.postMessage({ type: \"bitpalm-custom-context\", data: {} }, \"*\");\n };\n\n const handleContextEvent = (event: Event) => {\n const customEvent = event as CustomEvent<BitPalmCustomContext & { slug?: string }>;\n const detail = customEvent.detail;\n if (!detail || typeof detail !== \"object\") return;\n const targetSlug = normalizeText((detail as Record<string, unknown>).slug as string, 120);\n if (targetSlug && targetSlug !== slug) return;\n const { slug: _s, ...contextData } = detail as Record<string, unknown>;\n setCustomContext(contextData);\n };\n\n window.addEventListener(\"bitpalm-context\", handleContextEvent as EventListener);\n\n const handleIdentifyEvent = (event: Event) => {\n const customEvent = event as CustomEvent<BitPalmIdentifyPayload & { slug?: string }>;\n const detail = customEvent.detail;\n if (!detail || typeof detail !== \"object\") return;\n const targetSlug = normalizeText(detail.slug, 120);\n if (targetSlug && targetSlug !== slug) return;\n identify(detail);\n };\n\n window.addEventListener(\"bitpalm-identify\", handleIdentifyEvent as EventListener);\n\n // open, close and send for setups without an instance (script tag)\n const targetsThisWidget = (event: Event) => {\n const detail = (event as CustomEvent<{ slug?: string }>).detail;\n const targetSlug = normalizeText(detail?.slug, 120);\n return !targetSlug || targetSlug === slug;\n };\n const handleOpenEvent = (event: Event) => { if (targetsThisWidget(event)) openWidget(); };\n const handleCloseEvent = (event: Event) => { if (targetsThisWidget(event)) closeWidget(); };\n const handleSendEvent = (event: Event) => {\n if (!targetsThisWidget(event)) return;\n const message = (event as CustomEvent<{ message?: string }>).detail?.message;\n if (typeof message === \"string\") sendMessage(message);\n };\n window.addEventListener(\"bitpalm-open\", handleOpenEvent);\n window.addEventListener(\"bitpalm-close\", handleCloseEvent);\n window.addEventListener(\"bitpalm-send\", handleSendEvent);\n\n const onEvent = (event: BitPalmEventType, callback: BitPalmEventCallback): (() => void) => {\n if (!eventListeners.has(event)) eventListeners.set(event, new Set());\n eventListeners.get(event)!.add(callback);\n return () => eventListeners.get(event)?.delete(callback);\n };\n\n const offEvent = (event: BitPalmEventType, callback: BitPalmEventCallback) => {\n eventListeners.get(event)?.delete(callback);\n };\n\n const destroy = () => {\n window.removeEventListener(\"message\", handleMessage);\n window.removeEventListener(\"scroll\", handleScroll);\n window.removeEventListener(\"popstate\", onNav);\n d.removeEventListener(\"mouseout\", handleMouseOut);\n d.removeEventListener(\"submit\", handleFormSubmit, true);\n idleEvents.forEach((ev) => d.removeEventListener(ev, resetIdle));\n clearTimeout(scrollTimeout);\n clearTimeout(idleTimer);\n contextRetryTimers.forEach((t) => clearTimeout(t));\n history.pushState = origPush;\n history.replaceState = origReplace;\n window.removeEventListener(\"bitpalm-identify\", handleIdentifyEvent as EventListener);\n window.removeEventListener(\"bitpalm-context\", handleContextEvent as EventListener);\n window.removeEventListener(\"bitpalm-theme\", handleThemeEvent as EventListener);\n window.removeEventListener(\"bitpalm-open\", handleOpenEvent);\n window.removeEventListener(\"bitpalm-close\", handleCloseEvent);\n window.removeEventListener(\"bitpalm-send\", handleSendEvent);\n stopThemeWatch?.();\n eventListeners.clear();\n unlockMobilePageScroll();\n removeBubble();\n btn.remove();\n iframe.remove();\n };\n\n return {\n open: openWidget,\n close: closeWidget,\n toggle: toggleWidget,\n isOpen: getIsOpen,\n identify,\n context: setCustomContext,\n resetContext: clearCustomContext,\n send: sendMessage,\n on: onEvent,\n off: offEvent,\n setTheme,\n disableTriggers,\n enableTriggers,\n destroy,\n };\n}\n"],"mappings":"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","names":["src_exports","__export","createWidget","detectHostTheme","__toCommonJS","parseTriggerMode","value","normalized","triggersOption","mode","createTriggerBubble","d","options","bubble","text","arrow","close","event","DARK_CLASSES","LIGHT_CLASSES","THEME_ATTRIBUTES","DARK_QUERY","normalizeThemeSetting","value","explicitTheme","el","name","attr","channel","s","backgroundTheme","win","match","g","b","a","n","colorSchemeTheme","doc","computed","meta","scheme","detectHostTheme","watchHostTheme","onChange","last","scheduled","check","next","schedule","observer","observed","media","DEFAULT_BASE_URL","STORAGE_PREFIX","IGNORED_INPUT_TYPES","IDENTITY_DEDUPE_WINDOW_MS","CUSTOM_CONTEXT_MAX_BYTES","IDENTITY_SIGNATURE_KEY","IDENTITY_FINGERPRINT_KEY","IDENTITY_SENT_AT_KEY","LAUNCHER_SHADOW","buildIdentityFingerprint","payload","normalizeText","value","maxLen","normalizeTokens","includesAny","haystack","needles","needle","isEmail","normalizePhone","trimmed","hasPlus","digits","normalizeEmail","normalized","getExplicitValue","form","selectors","selector","el","getFieldHint","escapeAttrSelectorValue","collectElementTokenParts","parts","pushText","clean","seenLabels","pushLabel","label","forLabel","nearestLabel","ariaLabelledBy","id","ref","extractIdentityFromForm","email","phone","name","firstName","lastName","company","rawEl","fieldHint","explicitField","type","tokens","emailLike","phoneLike","companyLike","firstNameLike","lastNameLike","fullNameLike","identity","detectLocale","lang","runWhenIdle","task","timeout","isMobileWidgetDevice","userAgent","coarsePointer","noHover","minScreenSide","createWidget","options","slug","locale","baseUrl","token","zIndex","autoIdentify","launcher","d","themeSetting","normalizeThemeSetting","currentTheme","detectHostTheme","stopThemeWatch","configuredTriggerMode","parseTriggerMode","triggerMode","pendingTrigger","iframe","widgetUrl","qs","origin","btn","openWidget","s","bubble","launcherReady","widgetBlocked","iframeMounted","iframeReady","pendingOpen","mountIframe","mobileScrollLocked","scrollLockY","prevHtmlStyle","prevBodyStyle","lockMobilePageScroll","html","body","unlockMobilePageScroll","prepareIframeForOpen","mobile","removeBubble","clearPendingTrigger","emit","sendTriggerState","sendParentContext","sendOpenSignal","widgetIsOpen","eventListeners","event","data","listeners","cb","handleMessage","ic","sp","svg","attr","sv","isOpen","wasOpen","message","createTriggerBubble","optedOut","VID_KEY","visitorId","match","utmParams","utm","key","val","beaconPayload","beaconUrl","lastIdentitySignature","lastIdentityFingerprint","lastIdentitySentAt","storedAt","dispatchIdentify","payloadInput","scopeSignature","externalUserId","requestSignature","signedAtRaw","identityFingerprint","dedupeSignature","now","requestBody","identifyUrl","handleFormSubmit","formIdentifySetting","formSignature","pageCount","hist","loadedAt","siteStart","contextRetryTimers","returning","sendTheme","delay","timer","origPush","origReplace","onNav","h","navPayload","navUrl","args","lastScrollDepth","scrollTimeout","handleScroll","total","pct","handleMouseOut","idleTimer","idleFired","resetIdle","idleEvents","ev","base","setTriggerMode","mode","disableTriggers","enableTriggers","closeWidget","identify","input","toggleWidget","getIsOpen","sendMessage","text","applyTheme","theme","setTheme","watchHostTheme","handleThemeEvent","detail","targetSlug","customContext","setCustomContext","json","clearCustomContext","handleContextEvent","_s","contextData","handleIdentifyEvent","targetsThisWidget","handleOpenEvent","handleCloseEvent","handleSendEvent","callback","t","parseBoolean","value","normalized","script","init","createWidget","normalizeThemeSetting","triggersOption","parseTriggerMode"]}
package/dist/index.d.cts CHANGED
@@ -27,6 +27,17 @@ interface BitPalmAgentOptions {
27
27
  * effect when the agent has a dark theme set up in the dashboard.
28
28
  */
29
29
  theme?: BitPalmTheme;
30
+ /**
31
+ * Show the round chat button. Set to false when your site has a chat
32
+ * button of its own that calls open() or toggle(). Defaults to true.
33
+ */
34
+ launcher?: boolean;
35
+ /**
36
+ * Proactive messages set up in the dashboard. true shows them as a
37
+ * bubble (default), "events" shows nothing and fires trigger_shown so
38
+ * you can show the message yourself, false switches them off.
39
+ */
40
+ triggers?: boolean | "events";
30
41
  }
31
42
  interface BitPalmIdentifyPayload {
32
43
  /** Stable user id from the host platform (required for signed identify). */
@@ -58,7 +69,11 @@ interface BitPalmIdentifyPayload {
58
69
  */
59
70
  type BitPalmCustomContext = Record<string, unknown>;
60
71
  /** Event types emitted by the widget. */
61
- type BitPalmEventType = "widget_opened" | "widget_closed" | "conversation_started" | "message_sent" | "message_received" | "lead_captured";
72
+ type BitPalmEventType = "widget_opened" | "widget_closed" | "conversation_started" | "message_sent" | "message_received" | "lead_captured"
73
+ /** A proactive message is waiting, with { message, triggerId, triggerType }. Only with triggers: "events". */
74
+ | "trigger_shown"
75
+ /** The waiting message is gone: the chat was opened, or triggers were switched off. */
76
+ | "trigger_hidden";
62
77
  /** Callback for widget events. */
63
78
  type BitPalmEventCallback = (data?: Record<string, unknown>) => void;
64
79
  interface BitPalmAgentInstance {
@@ -114,6 +129,10 @@ interface BitPalmAgentInstance {
114
129
  * widget.setTheme('dark');
115
130
  */
116
131
  setTheme: (theme: BitPalmTheme) => void;
132
+ /** Switch proactive messages off, for example while a checkout is open. */
133
+ disableTriggers: () => void;
134
+ /** Switch them back on, as a bubble or as events, the way the triggers option says. */
135
+ enableTriggers: () => void;
117
136
  /** Remove the widget and clean up all event listeners. */
118
137
  destroy: () => void;
119
138
  }
package/dist/index.d.ts CHANGED
@@ -27,6 +27,17 @@ interface BitPalmAgentOptions {
27
27
  * effect when the agent has a dark theme set up in the dashboard.
28
28
  */
29
29
  theme?: BitPalmTheme;
30
+ /**
31
+ * Show the round chat button. Set to false when your site has a chat
32
+ * button of its own that calls open() or toggle(). Defaults to true.
33
+ */
34
+ launcher?: boolean;
35
+ /**
36
+ * Proactive messages set up in the dashboard. true shows them as a
37
+ * bubble (default), "events" shows nothing and fires trigger_shown so
38
+ * you can show the message yourself, false switches them off.
39
+ */
40
+ triggers?: boolean | "events";
30
41
  }
31
42
  interface BitPalmIdentifyPayload {
32
43
  /** Stable user id from the host platform (required for signed identify). */
@@ -58,7 +69,11 @@ interface BitPalmIdentifyPayload {
58
69
  */
59
70
  type BitPalmCustomContext = Record<string, unknown>;
60
71
  /** Event types emitted by the widget. */
61
- type BitPalmEventType = "widget_opened" | "widget_closed" | "conversation_started" | "message_sent" | "message_received" | "lead_captured";
72
+ type BitPalmEventType = "widget_opened" | "widget_closed" | "conversation_started" | "message_sent" | "message_received" | "lead_captured"
73
+ /** A proactive message is waiting, with { message, triggerId, triggerType }. Only with triggers: "events". */
74
+ | "trigger_shown"
75
+ /** The waiting message is gone: the chat was opened, or triggers were switched off. */
76
+ | "trigger_hidden";
62
77
  /** Callback for widget events. */
63
78
  type BitPalmEventCallback = (data?: Record<string, unknown>) => void;
64
79
  interface BitPalmAgentInstance {
@@ -114,6 +129,10 @@ interface BitPalmAgentInstance {
114
129
  * widget.setTheme('dark');
115
130
  */
116
131
  setTheme: (theme: BitPalmTheme) => void;
132
+ /** Switch proactive messages off, for example while a checkout is open. */
133
+ disableTriggers: () => void;
134
+ /** Switch them back on, as a bubble or as events, the way the triggers option says. */
135
+ enableTriggers: () => void;
117
136
  /** Remove the widget and clean up all event listeners. */
118
137
  destroy: () => void;
119
138
  }