@bitpalm/ai-agents 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/headless.cjs +6 -6
- package/dist/headless.cjs.map +1 -1
- package/dist/headless.d.cts +20 -2
- package/dist/headless.d.ts +20 -2
- package/dist/headless.js +8 -8
- package/dist/headless.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +7 -7
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +56 -2
- package/dist/react.d.ts +56 -2
- package/dist/react.js +8 -8
- package/dist/react.js.map +1 -1
- package/dist/widget.global.js +1 -1
- package/dist/widget.global.js.map +1 -1
- package/package.json +1 -1
package/dist/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react.ts","../src/triggers.ts","../src/theme.ts","../src/widget.ts","../src/sse.ts","../src/headless.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createWidget } from \"./widget\";\nimport {\n BitPalmApiError,\n createChatClient,\n type AgentConfig,\n type ChatClient,\n type ChatClientOptions,\n type ChatMessage,\n type SendOptions,\n type SendResult,\n} from \"./headless\";\nimport type { BitPalmAgentOptions, BitPalmAgentInstance } from \"./types\";\n\nexport type { BitPalmAgentOptions, BitPalmAgentInstance } from \"./types\";\nexport type { AgentConfig, ChatCard, ChatClient, ChatClientOptions, ChatMessage, QuickLink, SendOptions, SendResult } from \"./headless\";\nexport { BitPalmApiError } from \"./headless\";\n\nexport interface BitPalmAgentProps extends BitPalmAgentOptions {\n /**\n * Called once with the widget, for open(), on('trigger_shown', …) and\n * the rest of the API. Needed with launcher={false} and a button of\n * your own.\n */\n onReady?: (widget: BitPalmAgentInstance) => void;\n}\n\n/**\n * React component that mounts the BitPalm AI agent widget.\n *\n * @example\n * ```tsx\n * import { BitPalmAgent } from '@bitpalm/ai-agents/react';\n *\n * export default function App() {\n * return <BitPalmAgent slug=\"my-agent\" />;\n * }\n * ```\n */\nexport function BitPalmAgent(props: BitPalmAgentProps): null {\n const instanceRef = useRef<BitPalmAgentInstance | null>(null);\n const mountedRef = useRef(false);\n\n // The widget mounts once, later theme prop changes go through setTheme.\n useEffect(() => {\n instanceRef.current?.setTheme(props.theme ?? \"auto\");\n }, [props.theme]);\n\n useEffect(() => {\n if (mountedRef.current) return;\n mountedRef.current = true;\n\n const { onReady, ...options } = props;\n instanceRef.current = createWidget(options);\n onReady?.(instanceRef.current);\n\n return () => {\n instanceRef.current?.destroy();\n instanceRef.current = null;\n mountedRef.current = false;\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n return null;\n}\n\nexport type ChatStatus = \"idle\" | \"streaming\" | \"error\";\n\nexport interface UseBitPalmChatOptions extends ChatClientOptions {\n /** Load the last conversation of this visitor on start. Defaults to true. */\n loadHistory?: boolean;\n}\n\n/** The last message, replaced. Used while the answer streams in. */\nfunction withLast(messages: ChatMessage[], last: ChatMessage): ChatMessage[] {\n return [...messages.slice(0, -1), last];\n}\n\n/** Drops an empty answer bubble at the end. The user's message stays. */\nfunction withoutEmptyAnswer(messages: ChatMessage[]): ChatMessage[] {\n const last = messages[messages.length - 1];\n return last?.role === \"assistant\" && !last.text && !last.cards?.length ? messages.slice(0, -1) : messages;\n}\n\n/**\n * Your own chat UI in React, with BitPalm behind it. Keeps the messages,\n * streams the answer into the last one and remembers the conversation.\n *\n * @example\n * ```tsx\n * const { messages, send, status, agent } = useBitPalmChat({ key: \"bp_pk_…\" });\n * ```\n */\nexport function useBitPalmChat(options: UseBitPalmChatOptions) {\n // Created once, on the first render. Later option changes don't make a new client.\n const [client] = useState<ChatClient>(() => createChatClient(options));\n\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [status, setStatus] = useState<ChatStatus>(\"idle\");\n const [error, setError] = useState<BitPalmApiError | null>(null);\n const [agent, setAgent] = useState<AgentConfig | null>(null);\n const [handoff, setHandoff] = useState(false);\n const sending = useRef(false);\n const sends = useRef(0);\n const loadHistory = options.loadHistory !== false;\n\n useEffect(() => {\n let alive = true;\n client.agent().then((config) => alive && setAgent(config)).catch(() => {});\n if (loadHistory) {\n client\n .history()\n .then((list) => {\n if (!alive) return;\n // A message sent before the history arrived wins, the old conversation is then not shown.\n setMessages((current) => (current.length ? current : list));\n setHandoff(client.handoff);\n })\n .catch(() => {});\n }\n return () => {\n alive = false;\n };\n }, [client, loadHistory]);\n\n const send = useCallback(\n async (text: string, sendOptions: Omit<SendOptions, \"onDelta\"> = {}): Promise<SendResult | null> => {\n const message = text.trim();\n if (!message && !sendOptions.fileIds?.length) return null;\n setMessages((list) => [...list, { role: \"user\", text: message }, { role: \"assistant\", text: \"\" }]);\n setStatus(\"streaming\");\n setError(null);\n sending.current = true;\n sends.current += 1;\n try {\n const result = await client.send(message, {\n ...sendOptions,\n onDelta: (_piece, answer) => setMessages((list) => withLast(list, { role: \"assistant\", text: answer })),\n });\n // While the team has the conversation the agent stays silent, so there may be nothing to show.\n setMessages((list) =>\n withoutEmptyAnswer(withLast(list, { role: \"assistant\", text: result.text, ...(result.cards ? { cards: result.cards } : {}) })),\n );\n setHandoff(result.handoff === true);\n setStatus(\"idle\");\n return result;\n } catch (err) {\n const apiError = err instanceof BitPalmApiError ? err : new BitPalmApiError(\"network_error\", String(err), 0);\n setMessages(withoutEmptyAnswer);\n setError(apiError);\n setStatus(\"error\");\n return null;\n } finally {\n sending.current = false;\n }\n },\n [client],\n );\n\n /** Loads the conversation again, for example to show your team's replies while handoff is true. */\n const refresh = useCallback(async () => {\n if (sending.current) return;\n const sendsBefore = sends.current;\n const list = await client.history();\n // A message sent meanwhile is newer than this list.\n if (sending.current || sends.current !== sendsBefore) return;\n setMessages(list);\n setHandoff(client.handoff);\n }, [client]);\n\n const reset = useCallback(() => {\n client.reset();\n setMessages([]);\n setError(null);\n setHandoff(false);\n setStatus(\"idle\");\n }, [client]);\n\n return { messages, send, status, error, agent, handoff, refresh, reset, client };\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","/*\n * Reading the event stream of /api/v1/chat: blocks separated by a blank\n * line, \"data: {json}\" lines inside, \": ping\" to keep the line open.\n */\n\nexport type ChatStreamEvent =\n | { type: \"delta\"; text: string }\n | { type: \"replace\"; text: string }\n | { type: \"done\"; conversationId: string; cards?: unknown[]; handoff?: boolean }\n | { type: \"error\"; message: string };\n\nfunction parseBlock(block: string): ChatStreamEvent | null {\n const data = block\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).trimStart())\n .join(\"\\n\");\n if (!data) return null;\n try {\n const event = JSON.parse(data) as ChatStreamEvent;\n return event && typeof event.type === \"string\" ? event : null;\n } catch {\n return null;\n }\n}\n\n/** Takes what arrived so far, returns the complete events and what is still open. */\nexport function takeEvents(buffer: string): { events: ChatStreamEvent[]; rest: string } {\n const events: ChatStreamEvent[] = [];\n let rest = buffer.replace(/\\r\\n/g, \"\\n\");\n let boundary = rest.indexOf(\"\\n\\n\");\n while (boundary >= 0) {\n const event = parseBlock(rest.slice(0, boundary));\n if (event) events.push(event);\n rest = rest.slice(boundary + 2);\n boundary = rest.indexOf(\"\\n\\n\");\n }\n return { events, rest };\n}\n\n/** The whole body at once, for runtimes whose fetch can't stream (React Native). */\nexport function parseAllEvents(body: string): ChatStreamEvent[] {\n return takeEvents(`${body}\\n\\n`).events;\n}\n","import { parseAllEvents, takeEvents, type ChatStreamEvent } from \"./sse\";\n\n/*\n * Your own chat UI on top of BitPalm: this client talks to /api/v1 with an\n * app key and handles the visitor id, the conversation and the stream.\n * No UI in here. Works in browsers, Capacitor and Ionic apps, and in React\n * Native (without streaming, the answer then arrives at once).\n */\n\nexport interface ChatCard {\n kind?: string;\n title: string;\n image?: string;\n subtitle?: string;\n fields?: { label: string; value: string }[];\n cta?: { label: string; url: string };\n}\n\nexport interface ChatMessage {\n role: \"user\" | \"assistant\";\n text: string;\n createdAt?: string;\n cards?: ChatCard[];\n /** Photos the user sent, as links. */\n images?: string[];\n /** Written by a person of the team, not by the agent. */\n fromHuman?: boolean;\n}\n\nexport interface QuickLink {\n id: string;\n label: string;\n /** Send this as the user's message. */\n message?: string;\n /** Or open this address. */\n url?: string;\n}\n\nexport interface AgentConfig {\n name: string;\n logoUrl: string | null;\n primaryColor: string;\n welcomeMessage: string;\n inputPlaceholder: string;\n quickLinks: QuickLink[];\n photoUploads: boolean;\n /** When required is true, show text linked to url in your chat UI. */\n branding: { required: boolean; text: string; url: string };\n}\n\nexport interface ChatClientOptions {\n /** App key from the dashboard, starts with bp_pk_. */\n key: string;\n /** Defaults to https://agents.bitpalm.ai. */\n baseUrl?: string;\n /**\n * Id that holds the conversation together. Leave it out: the client\n * creates a random one and remembers it. If you set it, make it\n * unguessable. Never use a plain user id, anyone with the app key could\n * read that user's chats.\n */\n visitorId?: string;\n /** Language for greeting, placeholder and quick links, like \"de\". */\n locale?: string;\n /** Where visitor and conversation are remembered. Defaults to localStorage when there is one. */\n storage?: Pick<Storage, \"getItem\" | \"setItem\" | \"removeItem\"> | null;\n}\n\nexport interface SendOptions {\n /** Facts for this answer, like the cart or the user's plan. At most 4 KB. */\n context?: Record<string, unknown>;\n /** Ids of photos from upload(). */\n fileIds?: string[];\n /** Called as the answer grows: the new piece and the whole answer so far. */\n onDelta?: (piece: string, answer: string) => void;\n signal?: AbortSignal;\n}\n\nexport interface SendResult {\n text: string;\n conversationId: string;\n cards?: ChatCard[];\n /**\n * Your team has the conversation now. The agent stays silent in it until\n * the team closes it, the team's replies come with history().\n */\n handoff?: boolean;\n}\n\nexport interface Identity {\n name?: string;\n email?: string;\n phone?: string;\n company?: string;\n externalUserId?: string;\n}\n\n/** An error of the API, with its code, like \"invalid_key\" or \"rate_limited\". */\nexport class BitPalmApiError extends Error {\n constructor(\n readonly code: string,\n message: string,\n readonly status: number,\n ) {\n super(message);\n this.name = \"BitPalmApiError\";\n }\n}\n\nexport interface ChatClient {\n readonly visitorId: string;\n readonly conversationId: string | null;\n /** True while your team has the conversation. Updated by send() and history(). */\n readonly handoff: boolean;\n /** Name, greeting, quick links and whether \"Powered by BitPalm\" has to show. */\n agent(options?: { url?: string }): Promise<AgentConfig>;\n send(message: string, options?: SendOptions): Promise<SendResult>;\n /** The messages of the current conversation, or of the latest one of this visitor. */\n history(): Promise<ChatMessage[]>;\n /** Tells BitPalm who the logged-in user is. */\n identify(identity: Identity): Promise<void>;\n /** A photo for the next message, when the agent takes photos. */\n upload(file: Blob, fileName?: string): Promise<{ id: string; url: string }>;\n /** Thumbs up or down for the agent's answer number index (0 is the first answer). */\n feedback(index: number, value: \"up\" | \"down\"): Promise<void>;\n /** Starts a new conversation. */\n reset(): void;\n}\n\nconst DEFAULT_BASE_URL = \"https://agents.bitpalm.ai\";\n\nfunction defaultStorage(): ChatClientOptions[\"storage\"] {\n try {\n return typeof localStorage === \"undefined\" ? null : localStorage;\n } catch {\n return null;\n }\n}\n\nfunction newVisitorId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") return crypto.randomUUID();\n return `v-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;\n}\n\nasync function failure(response: Response): Promise<BitPalmApiError> {\n const body = (await response.json().catch(() => null)) as { error?: { code?: string; message?: string } } | null;\n return new BitPalmApiError(body?.error?.code ?? \"server_error\", body?.error?.message ?? `Request failed (${response.status})`, response.status);\n}\n\nexport function createChatClient(options: ChatClientOptions): ChatClient {\n if (!options?.key?.startsWith(\"bp_pk_\")) throw new Error(\"createChatClient needs an app key (bp_pk_…) from the BitPalm dashboard.\");\n const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n const storage = options.storage === undefined ? defaultStorage() : options.storage;\n const space = `bitpalm:${options.key.slice(0, 14)}`;\n const read = (name: string) => {\n try {\n return storage?.getItem(`${space}:${name}`) ?? null;\n } catch {\n return null;\n }\n };\n const write = (name: string, value: string | null) => {\n try {\n if (value === null) storage?.removeItem(`${space}:${name}`);\n else storage?.setItem(`${space}:${name}`, value);\n } catch {\n // Private mode or full storage, the client still works for this session.\n }\n };\n\n const visitorId = options.visitorId ?? read(\"visitor\") ?? newVisitorId();\n if (!options.visitorId) write(\"visitor\", visitorId);\n let conversationId = read(\"conversation\");\n let handoff = false;\n\n const headers = { Authorization: `Bearer ${options.key}` };\n const call = async (path: string, init?: RequestInit) => {\n const response = await fetch(`${baseUrl}${path}`, { ...init, headers: { ...headers, ...(init?.headers ?? {}) } });\n if (!response.ok) throw await failure(response);\n return response;\n };\n const remember = (id: string | null) => {\n conversationId = id;\n write(\"conversation\", id);\n };\n\n const applyEvents = (events: ChatStreamEvent[], state: { text: string; result: SendResult | null }, onDelta?: SendOptions[\"onDelta\"]) => {\n for (const event of events) {\n if (event.type === \"delta\") {\n state.text += event.text;\n onDelta?.(event.text, state.text);\n } else if (event.type === \"replace\") {\n state.text = event.text;\n onDelta?.(\"\", state.text);\n } else if (event.type === \"done\") {\n state.result = {\n text: state.text,\n conversationId: event.conversationId,\n ...(event.cards ? { cards: event.cards as ChatCard[] } : {}),\n ...(event.handoff ? { handoff: true } : {}),\n };\n } else if (event.type === \"error\") {\n throw new BitPalmApiError(\"server_error\", event.message, 500);\n }\n }\n };\n\n return {\n visitorId,\n get conversationId() {\n return conversationId;\n },\n get handoff() {\n return handoff;\n },\n\n async agent(agentOptions) {\n const params = new URLSearchParams({ locale: options.locale ?? \"en\" });\n if (agentOptions?.url) params.set(\"url\", agentOptions.url);\n return (await call(`/api/v1/agent?${params.toString()}`)).json() as Promise<AgentConfig>;\n },\n\n async send(message, sendOptions = {}) {\n const response = await call(\"/api/v1/chat\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n signal: sendOptions.signal,\n body: JSON.stringify({\n message,\n visitorId,\n conversationId: conversationId ?? undefined,\n context: sendOptions.context,\n fileIds: sendOptions.fileIds,\n }),\n });\n\n const state: { text: string; result: SendResult | null } = { text: \"\", result: null };\n const reader = response.body && typeof response.body.getReader === \"function\" ? response.body.getReader() : null;\n if (reader) {\n const decoder = new TextDecoder();\n let buffer = \"\";\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n const taken = takeEvents(buffer + decoder.decode(value, { stream: true }));\n buffer = taken.rest;\n applyEvents(taken.events, state, sendOptions.onDelta);\n }\n applyEvents(takeEvents(`${buffer}\\n\\n`).events, state, sendOptions.onDelta);\n } else {\n applyEvents(parseAllEvents(await response.text()), state, sendOptions.onDelta);\n }\n\n const result = state.result ?? { text: state.text, conversationId: conversationId ?? \"\" };\n if (result.conversationId) remember(result.conversationId);\n handoff = result.handoff === true;\n return result;\n },\n\n async history() {\n const params = new URLSearchParams({ visitorId });\n if (conversationId) params.set(\"conversationId\", conversationId);\n const body = (await (await call(`/api/v1/chat/history?${params.toString()}`)).json()) as {\n conversationId: string | null;\n handoff?: boolean;\n messages: ChatMessage[];\n };\n if (body.conversationId) remember(body.conversationId);\n handoff = body.handoff === true;\n return body.messages;\n },\n\n async identify(identity) {\n await call(\"/api/v1/identify\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ ...identity, visitorId }),\n });\n },\n\n async upload(file, fileName = \"photo.jpg\") {\n const form = new FormData();\n form.append(\"file\", file, fileName);\n form.append(\"visitorId\", visitorId);\n if (conversationId) form.append(\"conversationId\", conversationId);\n const body = (await (await call(\"/api/v1/chat/upload\", { method: \"POST\", body: form })).json()) as { id: string; url: string };\n return { id: body.id, url: body.url };\n },\n\n async feedback(index, value) {\n if (!conversationId) throw new BitPalmApiError(\"bad_request\", \"There is no conversation yet.\", 400);\n await call(\"/api/v1/chat/feedback\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ visitorId, conversationId, messageIndex: index, feedback: value }),\n });\n },\n\n reset() {\n remember(null);\n handoff = false;\n },\n };\n}\n"],"mappings":"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","names":["react_exports","__export","BitPalmAgent","BitPalmApiError","useBitPalmChat","__toCommonJS","import_react","parseTriggerMode","value","normalized","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","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","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","parseBlock","block","data","line","event","takeEvents","buffer","events","rest","boundary","parseAllEvents","body","BitPalmApiError","code","message","status","DEFAULT_BASE_URL","defaultStorage","newVisitorId","failure","response","body","createChatClient","options","baseUrl","storage","space","read","name","write","value","visitorId","conversationId","handoff","headers","call","path","init","remember","id","applyEvents","events","state","onDelta","event","agentOptions","params","sendOptions","reader","decoder","buffer","done","taken","takeEvents","parseAllEvents","result","identity","file","fileName","form","index","BitPalmAgent","props","instanceRef","mountedRef","onReady","options","createWidget","withLast","messages","last","withoutEmptyAnswer","useBitPalmChat","client","createChatClient","setMessages","status","setStatus","error","setError","agent","setAgent","handoff","setHandoff","sending","sends","loadHistory","alive","config","list","current","send","text","sendOptions","message","result","_piece","answer","err","apiError","BitPalmApiError","refresh","sendsBefore","reset"]}
|
|
1
|
+
{"version":3,"sources":["../src/react.ts","../src/triggers.ts","../src/theme.ts","../src/widget.ts","../src/sse.ts","../src/headless.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createWidget } from \"./widget\";\nimport {\n BitPalmApiError,\n createChatClient,\n type AgentConfig,\n type ChatClient,\n type ChatClientOptions,\n type ChatMessage,\n type SendOptions,\n type SendResult,\n} from \"./headless\";\nimport type { BitPalmAgentOptions, BitPalmAgentInstance, BitPalmQuickLink } from \"./types\";\n\nexport type { BitPalmAgentOptions, BitPalmAgentInstance, BitPalmQuickLink } from \"./types\";\nexport type { AgentConfig, ChatCard, ChatClient, ChatClientOptions, ChatMessage, ChatUpdates, QuickLink, SendOptions, SendResult } from \"./headless\";\nexport { BitPalmApiError } from \"./headless\";\n\nexport interface BitPalmAgentProps extends BitPalmAgentOptions {\n /**\n * Called once with the widget, for open(), on('trigger_shown', …) and\n * the rest of the API. Needed with launcher={false} and a button of\n * your own.\n */\n onReady?: (widget: BitPalmAgentInstance) => void;\n}\n\n/**\n * React component that mounts the BitPalm AI agent widget.\n *\n * @example\n * ```tsx\n * import { BitPalmAgent } from '@bitpalm/ai-agents/react';\n *\n * export default function App() {\n * return <BitPalmAgent slug=\"my-agent\" />;\n * }\n * ```\n */\nexport function BitPalmAgent(props: BitPalmAgentProps): null {\n const instanceRef = useRef<BitPalmAgentInstance | null>(null);\n const mountedRef = useRef(false);\n\n // The widget mounts once, later theme prop changes go through setTheme.\n useEffect(() => {\n instanceRef.current?.setTheme(props.theme ?? \"auto\");\n }, [props.theme]);\n\n // Same for quick links: a new list, for example after login, shows at once.\n const quickLinksKey = props.quickLinks === undefined ? undefined : JSON.stringify(props.quickLinks);\n const firstQuickLinks = useRef(quickLinksKey);\n useEffect(() => {\n if (quickLinksKey === firstQuickLinks.current) return;\n firstQuickLinks.current = quickLinksKey;\n instanceRef.current?.setQuickLinks(quickLinksKey === undefined ? null : (JSON.parse(quickLinksKey) as BitPalmQuickLink[]));\n }, [quickLinksKey]);\n\n useEffect(() => {\n if (mountedRef.current) return;\n mountedRef.current = true;\n\n const { onReady, ...options } = props;\n instanceRef.current = createWidget(options);\n onReady?.(instanceRef.current);\n\n return () => {\n instanceRef.current?.destroy();\n instanceRef.current = null;\n mountedRef.current = false;\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n return null;\n}\n\nexport type ChatStatus = \"idle\" | \"streaming\" | \"error\";\n\nexport interface UseBitPalmChatOptions extends ChatClientOptions {\n /** Load the last conversation of this visitor on start. Defaults to true. */\n loadHistory?: boolean;\n /** Show your team's replies as they come while it has the conversation. Defaults to true. */\n live?: boolean;\n}\n\n/** Same pace as the widget. */\nconst LIVE_INTERVAL_MS = 3000;\n\nfunction pageHidden(): boolean {\n return typeof document !== \"undefined\" && document.visibilityState === \"hidden\";\n}\n\n/** The last message, replaced. Used while the answer streams in. */\nfunction withLast(messages: ChatMessage[], last: ChatMessage): ChatMessage[] {\n return [...messages.slice(0, -1), last];\n}\n\n/** Adds replies of your team that aren't shown yet. */\nfunction withTeamReplies(messages: ChatMessage[], replies: ChatMessage[]): ChatMessage[] {\n const shown = new Set(messages.map((message) => message.id).filter(Boolean));\n const fresh = replies.filter((reply) => !reply.id || !shown.has(reply.id));\n return fresh.length ? [...messages, ...fresh] : messages;\n}\n\n/** Drops an empty answer bubble at the end. The user's message stays. */\nfunction withoutEmptyAnswer(messages: ChatMessage[]): ChatMessage[] {\n const last = messages[messages.length - 1];\n return last?.role === \"assistant\" && !last.text && !last.cards?.length ? messages.slice(0, -1) : messages;\n}\n\n/**\n * Your own chat UI in React, with BitPalm behind it. Keeps the messages,\n * streams the answer into the last one and remembers the conversation.\n *\n * @example\n * ```tsx\n * const { messages, send, status, agent } = useBitPalmChat({ key: \"bp_pk_…\" });\n * ```\n */\nexport function useBitPalmChat(options: UseBitPalmChatOptions) {\n // Created once, on the first render. Later option changes don't make a new client.\n const [client] = useState<ChatClient>(() => createChatClient(options));\n\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [status, setStatus] = useState<ChatStatus>(\"idle\");\n const [error, setError] = useState<BitPalmApiError | null>(null);\n const [agent, setAgent] = useState<AgentConfig | null>(null);\n const [handoff, setHandoff] = useState(false);\n const [teamTyping, setTeamTyping] = useState(false);\n const sending = useRef(false);\n const sends = useRef(0);\n const loadHistory = options.loadHistory !== false;\n const live = options.live !== false;\n\n useEffect(() => {\n let alive = true;\n client.agent().then((config) => alive && setAgent(config)).catch(() => {});\n if (loadHistory) {\n client\n .history()\n .then((list) => {\n if (!alive) return;\n // A message sent before the history arrived wins, the old conversation is then not shown.\n setMessages((current) => (current.length ? current : list));\n setHandoff(client.handoff);\n })\n .catch(() => {});\n }\n return () => {\n alive = false;\n };\n }, [client, loadHistory]);\n\n // While your team has the conversation, its replies come in as they are written.\n useEffect(() => {\n if (!live || !handoff) return;\n let stopped = false;\n let busy = false;\n const poll = async () => {\n if (stopped || busy || pageHidden()) return;\n busy = true;\n try {\n const update = await client.updates();\n if (stopped) return;\n setTeamTyping(update.teamTyping);\n if (update.messages.length) setMessages((list) => withTeamReplies(list, update.messages));\n if (!update.handoff) setHandoff(false);\n } catch {\n // Offline for a moment, the next round tries again.\n } finally {\n busy = false;\n }\n };\n const onVisible = () => void poll();\n void poll();\n const timer = setInterval(() => void poll(), LIVE_INTERVAL_MS);\n if (typeof document !== \"undefined\") document.addEventListener(\"visibilitychange\", onVisible);\n return () => {\n stopped = true;\n clearInterval(timer);\n if (typeof document !== \"undefined\") document.removeEventListener(\"visibilitychange\", onVisible);\n };\n }, [client, handoff, live]);\n\n const send = useCallback(\n async (text: string, sendOptions: Omit<SendOptions, \"onDelta\"> = {}): Promise<SendResult | null> => {\n const message = text.trim();\n if (!message && !sendOptions.fileIds?.length) return null;\n setMessages((list) => [...list, { role: \"user\", text: message }, { role: \"assistant\", text: \"\" }]);\n setStatus(\"streaming\");\n setError(null);\n sending.current = true;\n sends.current += 1;\n try {\n const result = await client.send(message, {\n ...sendOptions,\n onDelta: (_piece, answer) => setMessages((list) => withLast(list, { role: \"assistant\", text: answer })),\n });\n // While the team has the conversation the agent stays silent, so there may be nothing to show.\n setMessages((list) =>\n withoutEmptyAnswer(withLast(list, { role: \"assistant\", text: result.text, ...(result.cards ? { cards: result.cards } : {}) })),\n );\n setHandoff(result.handoff === true);\n setStatus(\"idle\");\n return result;\n } catch (err) {\n const apiError = err instanceof BitPalmApiError ? err : new BitPalmApiError(\"network_error\", String(err), 0);\n setMessages(withoutEmptyAnswer);\n setError(apiError);\n setStatus(\"error\");\n return null;\n } finally {\n sending.current = false;\n }\n },\n [client],\n );\n\n /** Loads the conversation again, for example to show your team's replies while handoff is true. */\n const refresh = useCallback(async () => {\n if (sending.current) return;\n const sendsBefore = sends.current;\n const list = await client.history();\n // A message sent meanwhile is newer than this list.\n if (sending.current || sends.current !== sendsBefore) return;\n setMessages(list);\n setHandoff(client.handoff);\n }, [client]);\n\n const reset = useCallback(() => {\n client.reset();\n setMessages([]);\n setError(null);\n setHandoff(false);\n setStatus(\"idle\");\n }, [client]);\n\n return { messages, send, status, error, agent, handoff, teamTyping: handoff && teamTyping, refresh, reset, client };\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, BitPalmQuickLink } 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 // Context and quick links set before the chat had loaded would be lost otherwise.\n sendSavedState();\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 // --- Quick links from the website's code ---\n let quickLinks: BitPalmQuickLink[] | null = Array.isArray(options.quickLinks) ? options.quickLinks : null;\n let quickLinksSet = quickLinks !== null;\n\n const sendQuickLinks = () => {\n iframe.contentWindow?.postMessage({ type: \"bitpalm-quick-links\", links: quickLinks }, \"*\");\n };\n\n const setQuickLinks = (links: BitPalmQuickLink[] | null) => {\n quickLinks = Array.isArray(links) ? links.slice(0, 8) : null;\n quickLinksSet = true;\n sendQuickLinks();\n };\n\n function sendSavedState() {\n if (Object.keys(customContext).length > 0) {\n iframe.contentWindow?.postMessage({ type: \"bitpalm-custom-context\", data: customContext }, \"*\");\n }\n if (quickLinksSet) sendQuickLinks();\n }\n\n const handleQuickLinksEvent = (event: Event) => {\n const detail = (event as CustomEvent<{ slug?: string; links?: BitPalmQuickLink[] | null }>).detail;\n if (!detail || typeof detail !== \"object\") return;\n const targetSlug = normalizeText(detail.slug, 120);\n if (targetSlug && targetSlug !== slug) return;\n setQuickLinks(detail.links ?? null);\n };\n window.addEventListener(\"bitpalm-quick-links\", handleQuickLinksEvent as EventListener);\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-quick-links\", handleQuickLinksEvent 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 setQuickLinks,\n send: sendMessage,\n on: onEvent,\n off: offEvent,\n setTheme,\n disableTriggers,\n enableTriggers,\n destroy,\n };\n}\n","/*\n * Reading the event stream of /api/v1/chat: blocks separated by a blank\n * line, \"data: {json}\" lines inside, \": ping\" to keep the line open.\n */\n\nexport type ChatStreamEvent =\n | { type: \"delta\"; text: string }\n | { type: \"replace\"; text: string }\n | { type: \"done\"; conversationId: string; cards?: unknown[]; handoff?: boolean }\n | { type: \"error\"; message: string };\n\nfunction parseBlock(block: string): ChatStreamEvent | null {\n const data = block\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).trimStart())\n .join(\"\\n\");\n if (!data) return null;\n try {\n const event = JSON.parse(data) as ChatStreamEvent;\n return event && typeof event.type === \"string\" ? event : null;\n } catch {\n return null;\n }\n}\n\n/** Takes what arrived so far, returns the complete events and what is still open. */\nexport function takeEvents(buffer: string): { events: ChatStreamEvent[]; rest: string } {\n const events: ChatStreamEvent[] = [];\n let rest = buffer.replace(/\\r\\n/g, \"\\n\");\n let boundary = rest.indexOf(\"\\n\\n\");\n while (boundary >= 0) {\n const event = parseBlock(rest.slice(0, boundary));\n if (event) events.push(event);\n rest = rest.slice(boundary + 2);\n boundary = rest.indexOf(\"\\n\\n\");\n }\n return { events, rest };\n}\n\n/** The whole body at once, for runtimes whose fetch can't stream (React Native). */\nexport function parseAllEvents(body: string): ChatStreamEvent[] {\n return takeEvents(`${body}\\n\\n`).events;\n}\n","import { parseAllEvents, takeEvents, type ChatStreamEvent } from \"./sse\";\n\n/*\n * Your own chat UI on top of BitPalm: this client talks to /api/v1 with an\n * app key and handles the visitor id, the conversation and the stream.\n * No UI in here. Works in browsers, Capacitor and Ionic apps, and in React\n * Native (without streaming, the answer then arrives at once).\n */\n\nexport interface ChatCard {\n kind?: string;\n title: string;\n image?: string;\n subtitle?: string;\n fields?: { label: string; value: string }[];\n cta?: { label: string; url: string };\n}\n\nexport interface ChatMessage {\n /** Set on messages from history() and updates(). */\n id?: string;\n role: \"user\" | \"assistant\";\n text: string;\n createdAt?: string;\n cards?: ChatCard[];\n /** Photos the user sent, as links. */\n images?: string[];\n /** Written by a person of the team, not by the agent. */\n fromHuman?: boolean;\n}\n\nexport interface QuickLink {\n id: string;\n label: string;\n /** Send this as the user's message. */\n message?: string;\n /** Or open this address. */\n url?: string;\n}\n\nexport interface AgentConfig {\n name: string;\n logoUrl: string | null;\n primaryColor: string;\n welcomeMessage: string;\n inputPlaceholder: string;\n quickLinks: QuickLink[];\n photoUploads: boolean;\n /** When required is true, show text linked to url in your chat UI. */\n branding: { required: boolean; text: string; url: string };\n}\n\nexport interface ChatClientOptions {\n /** App key from the dashboard, starts with bp_pk_. */\n key: string;\n /** Defaults to https://agents.bitpalm.ai. */\n baseUrl?: string;\n /**\n * Id that holds the conversation together. Leave it out: the client\n * creates a random one and remembers it. If you set it, make it\n * unguessable. Never use a plain user id, anyone with the app key could\n * read that user's chats.\n */\n visitorId?: string;\n /** Language for greeting, placeholder and quick links, like \"de\". */\n locale?: string;\n /** Where visitor and conversation are remembered. Defaults to localStorage when there is one. */\n storage?: Pick<Storage, \"getItem\" | \"setItem\" | \"removeItem\"> | null;\n}\n\nexport interface SendOptions {\n /** Facts for this answer, like the cart or the user's plan. At most 4 KB. */\n context?: Record<string, unknown>;\n /** Ids of photos from upload(). */\n fileIds?: string[];\n /** Called as the answer grows: the new piece and the whole answer so far. */\n onDelta?: (piece: string, answer: string) => void;\n signal?: AbortSignal;\n}\n\nexport interface SendResult {\n text: string;\n conversationId: string;\n cards?: ChatCard[];\n /**\n * Your team has the conversation now. The agent stays silent in it until\n * the team closes it, the team's replies come with history().\n */\n handoff?: boolean;\n}\n\n/** What happened while your team has the conversation. */\nexport interface ChatUpdates {\n /** False once your team gave the conversation back to the agent. */\n handoff: boolean;\n /** Someone of your team is typing right now. */\n teamTyping: boolean;\n /** Replies of your team since the last call, oldest first. */\n messages: ChatMessage[];\n}\n\nexport interface Identity {\n name?: string;\n email?: string;\n phone?: string;\n company?: string;\n externalUserId?: string;\n}\n\n/** An error of the API, with its code, like \"invalid_key\" or \"rate_limited\". */\nexport class BitPalmApiError extends Error {\n constructor(\n readonly code: string,\n message: string,\n readonly status: number,\n ) {\n super(message);\n this.name = \"BitPalmApiError\";\n }\n}\n\nexport interface ChatClient {\n readonly visitorId: string;\n readonly conversationId: string | null;\n /** True while your team has the conversation. Updated by send() and history(). */\n readonly handoff: boolean;\n /**\n * Name, greeting, quick links and whether \"Powered by BitPalm\" has to show.\n * With the signed userToken of a logged-in user, quick links for their role\n * show and the greeting can use their first name.\n */\n agent(options?: { url?: string; userToken?: string }): Promise<AgentConfig>;\n send(message: string, options?: SendOptions): Promise<SendResult>;\n /** The messages of the current conversation, or of the latest one of this visitor. */\n history(): Promise<ChatMessage[]>;\n /** New replies of your team and whether someone is typing. Call it every few seconds while handoff is true. */\n updates(): Promise<ChatUpdates>;\n /** Tells BitPalm who the logged-in user is. */\n identify(identity: Identity): Promise<void>;\n /** A photo for the next message, when the agent takes photos. */\n upload(file: Blob, fileName?: string): Promise<{ id: string; url: string }>;\n /** Thumbs up or down for the agent's answer number index (0 is the first answer). */\n feedback(index: number, value: \"up\" | \"down\"): Promise<void>;\n /** Starts a new conversation. */\n reset(): void;\n}\n\nconst DEFAULT_BASE_URL = \"https://agents.bitpalm.ai\";\n\nfunction defaultStorage(): ChatClientOptions[\"storage\"] {\n try {\n return typeof localStorage === \"undefined\" ? null : localStorage;\n } catch {\n return null;\n }\n}\n\nfunction newVisitorId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") return crypto.randomUUID();\n return `v-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;\n}\n\nasync function failure(response: Response): Promise<BitPalmApiError> {\n const body = (await response.json().catch(() => null)) as { error?: { code?: string; message?: string } } | null;\n return new BitPalmApiError(body?.error?.code ?? \"server_error\", body?.error?.message ?? `Request failed (${response.status})`, response.status);\n}\n\nexport function createChatClient(options: ChatClientOptions): ChatClient {\n if (!options?.key?.startsWith(\"bp_pk_\")) throw new Error(\"createChatClient needs an app key (bp_pk_…) from the BitPalm dashboard.\");\n const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n const storage = options.storage === undefined ? defaultStorage() : options.storage;\n const space = `bitpalm:${options.key.slice(0, 14)}`;\n const read = (name: string) => {\n try {\n return storage?.getItem(`${space}:${name}`) ?? null;\n } catch {\n return null;\n }\n };\n const write = (name: string, value: string | null) => {\n try {\n if (value === null) storage?.removeItem(`${space}:${name}`);\n else storage?.setItem(`${space}:${name}`, value);\n } catch {\n // Private mode or full storage, the client still works for this session.\n }\n };\n\n const visitorId = options.visitorId ?? read(\"visitor\") ?? newVisitorId();\n if (!options.visitorId) write(\"visitor\", visitorId);\n let conversationId = read(\"conversation\");\n let handoff = false;\n // The newest reply of the team we know of, so updates() only brings newer ones.\n let teamCursor: string | null = null;\n const noteTeamReplies = (messages: ChatMessage[]) => {\n for (const message of messages) {\n if (message.fromHuman && message.createdAt && (!teamCursor || message.createdAt > teamCursor)) teamCursor = message.createdAt;\n }\n };\n\n const headers = { Authorization: `Bearer ${options.key}` };\n const call = async (path: string, init?: RequestInit) => {\n const response = await fetch(`${baseUrl}${path}`, { ...init, headers: { ...headers, ...(init?.headers ?? {}) } });\n if (!response.ok) throw await failure(response);\n return response;\n };\n const remember = (id: string | null) => {\n conversationId = id;\n write(\"conversation\", id);\n };\n\n const applyEvents = (events: ChatStreamEvent[], state: { text: string; result: SendResult | null }, onDelta?: SendOptions[\"onDelta\"]) => {\n for (const event of events) {\n if (event.type === \"delta\") {\n state.text += event.text;\n onDelta?.(event.text, state.text);\n } else if (event.type === \"replace\") {\n state.text = event.text;\n onDelta?.(\"\", state.text);\n } else if (event.type === \"done\") {\n state.result = {\n text: state.text,\n conversationId: event.conversationId,\n ...(event.cards ? { cards: event.cards as ChatCard[] } : {}),\n ...(event.handoff ? { handoff: true } : {}),\n };\n } else if (event.type === \"error\") {\n throw new BitPalmApiError(\"server_error\", event.message, 500);\n }\n }\n };\n\n return {\n visitorId,\n get conversationId() {\n return conversationId;\n },\n get handoff() {\n return handoff;\n },\n\n async agent(agentOptions) {\n const params = new URLSearchParams({ locale: options.locale ?? \"en\" });\n if (agentOptions?.url) params.set(\"url\", agentOptions.url);\n // In a header, so the token does not end up in logs with the url.\n const init = agentOptions?.userToken ? { headers: { \"X-BitPalm-User-Token\": agentOptions.userToken } } : undefined;\n return (await call(`/api/v1/agent?${params.toString()}`, init)).json() as Promise<AgentConfig>;\n },\n\n async send(message, sendOptions = {}) {\n const response = await call(\"/api/v1/chat\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n signal: sendOptions.signal,\n body: JSON.stringify({\n message,\n visitorId,\n conversationId: conversationId ?? undefined,\n context: sendOptions.context,\n fileIds: sendOptions.fileIds,\n }),\n });\n\n const state: { text: string; result: SendResult | null } = { text: \"\", result: null };\n const reader = response.body && typeof response.body.getReader === \"function\" ? response.body.getReader() : null;\n if (reader) {\n const decoder = new TextDecoder();\n let buffer = \"\";\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n const taken = takeEvents(buffer + decoder.decode(value, { stream: true }));\n buffer = taken.rest;\n applyEvents(taken.events, state, sendOptions.onDelta);\n }\n applyEvents(takeEvents(`${buffer}\\n\\n`).events, state, sendOptions.onDelta);\n } else {\n applyEvents(parseAllEvents(await response.text()), state, sendOptions.onDelta);\n }\n\n const result = state.result ?? { text: state.text, conversationId: conversationId ?? \"\" };\n if (result.conversationId) remember(result.conversationId);\n handoff = result.handoff === true;\n return result;\n },\n\n async history() {\n const params = new URLSearchParams({ visitorId });\n if (conversationId) params.set(\"conversationId\", conversationId);\n const body = (await (await call(`/api/v1/chat/history?${params.toString()}`)).json()) as {\n conversationId: string | null;\n handoff?: boolean;\n messages: ChatMessage[];\n };\n if (body.conversationId) remember(body.conversationId);\n handoff = body.handoff === true;\n teamCursor = null;\n noteTeamReplies(body.messages);\n return body.messages;\n },\n\n async updates() {\n if (!conversationId) return { handoff: false, teamTyping: false, messages: [] };\n const params = new URLSearchParams({ visitorId, conversationId });\n if (teamCursor) params.set(\"after\", teamCursor);\n const body = (await (await call(`/api/v1/chat/updates?${params.toString()}`)).json()) as Partial<ChatUpdates>;\n const messages = body.messages ?? [];\n noteTeamReplies(messages);\n handoff = body.handoff === true;\n return { handoff, teamTyping: body.teamTyping === true, messages };\n },\n\n async identify(identity) {\n await call(\"/api/v1/identify\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ ...identity, visitorId }),\n });\n },\n\n async upload(file, fileName = \"photo.jpg\") {\n const form = new FormData();\n form.append(\"file\", file, fileName);\n form.append(\"visitorId\", visitorId);\n if (conversationId) form.append(\"conversationId\", conversationId);\n const body = (await (await call(\"/api/v1/chat/upload\", { method: \"POST\", body: form })).json()) as { id: string; url: string };\n return { id: body.id, url: body.url };\n },\n\n async feedback(index, value) {\n if (!conversationId) throw new BitPalmApiError(\"bad_request\", \"There is no conversation yet.\", 400);\n await call(\"/api/v1/chat/feedback\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ visitorId, conversationId, messageIndex: index, feedback: value }),\n });\n },\n\n reset() {\n remember(null);\n handoff = false;\n teamCursor = null;\n },\n };\n}\n"],"mappings":"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","names":["react_exports","__export","BitPalmAgent","BitPalmApiError","useBitPalmChat","__toCommonJS","import_react","parseTriggerMode","value","normalized","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","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","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","sendSavedState","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","quickLinks","quickLinksSet","sendQuickLinks","setQuickLinks","links","handleQuickLinksEvent","handleContextEvent","_s","contextData","handleIdentifyEvent","targetsThisWidget","handleOpenEvent","handleCloseEvent","handleSendEvent","callback","t","parseBlock","block","data","line","event","takeEvents","buffer","events","rest","boundary","parseAllEvents","body","BitPalmApiError","code","message","status","DEFAULT_BASE_URL","defaultStorage","newVisitorId","failure","response","body","createChatClient","options","baseUrl","storage","space","read","name","write","value","visitorId","conversationId","handoff","teamCursor","noteTeamReplies","messages","headers","call","path","init","remember","id","applyEvents","events","state","onDelta","event","agentOptions","params","sendOptions","reader","decoder","buffer","done","taken","takeEvents","parseAllEvents","result","identity","file","fileName","form","index","BitPalmAgent","props","instanceRef","mountedRef","quickLinksKey","firstQuickLinks","onReady","options","createWidget","LIVE_INTERVAL_MS","pageHidden","withLast","messages","last","withTeamReplies","replies","shown","message","fresh","reply","withoutEmptyAnswer","useBitPalmChat","client","createChatClient","setMessages","status","setStatus","error","setError","agent","setAgent","handoff","setHandoff","teamTyping","setTeamTyping","sending","sends","loadHistory","live","alive","config","list","current","stopped","busy","poll","update","onVisible","timer","send","text","sendOptions","result","_piece","answer","err","apiError","BitPalmApiError","refresh","sendsBefore","reset"]}
|