@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 CHANGED
@@ -70,6 +70,20 @@ widget.on("trigger_hidden", () => (dot.hidden = true));
70
70
 
71
71
  `triggers: false` switches proactive messages off, `widget.disableTriggers()` and `enableTriggers()` do it at runtime. The widget's elements carry `data-bitpalm-launcher`, `data-bitpalm-trigger` and `data-bitpalm-chat`. In React, `<BitPalmAgent onReady={(widget) => …} />` hands you the instance.
72
72
 
73
+ ## Quick links from your code
74
+
75
+ The buttons under the greeting can come from your code instead of the dashboard, for example after login:
76
+
77
+ ```js
78
+ widget.setQuickLinks([
79
+ { label: { en: "My rent", de: "Meine Miete" }, question: "When is my rent due?" },
80
+ { label: "Open a ticket", question: "I want to report a problem.", pages: "/portal/*" },
81
+ ]);
82
+ widget.setQuickLinks(null); // back to the ones from the dashboard
83
+ ```
84
+
85
+ Also as `createWidget({ quickLinks })`, as `<BitPalmAgent quickLinks={…} />` and, with the script tag, as the `bitpalm-quick-links` event. Quick links per role and a greeting with the user's first name work from the dashboard with a [verified user token](https://agents.bitpalm.ai/docs/identify#quick-links-per-role-and-greeting-by-name).
86
+
73
87
  ## Your own chat UI
74
88
 
75
89
  Design the chat yourself and let BitPalm answer behind it, in a website or an app (Capacitor, Ionic, React Native). Needs an app key (`bp_pk_…`) from the dashboard and the Pro plan.
package/dist/headless.cjs CHANGED
@@ -1,13 +1,13 @@
1
- "use strict";var x=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var A=(t,a)=>{for(var r in a)x(t,r,{get:a[r],enumerable:!0})},D=(t,a,r,o)=>{if(a&&typeof a=="object"||typeof a=="function")for(let l of U(a))!R.call(t,l)&&l!==r&&x(t,l,{get:()=>a[l],enumerable:!(o=$(a,l))||o.enumerable});return t};var O=t=>D(x({},"__esModule",{value:!0}),t);var M={};A(M,{BitPalmApiError:()=>u,createChatClient:()=>q});module.exports=O(M);function T(t){let a=t.split(`
1
+ "use strict";var C=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var j=(n,a)=>{for(var r in a)C(n,r,{get:a[r],enumerable:!0})},D=(n,a,r,o)=>{if(a&&typeof a=="object"||typeof a=="function")for(let l of R(a))!A.call(n,l)&&l!==r&&C(n,l,{get:()=>a[l],enumerable:!(o=E(a,l))||o.enumerable});return n};var _=n=>D(C({},"__esModule",{value:!0}),n);var J={};j(J,{BitPalmApiError:()=>p,createChatClient:()=>N});module.exports=_(J);function L(n){let a=n.split(`
2
2
  `).filter(r=>r.startsWith("data:")).map(r=>r.slice(5).trimStart()).join(`
3
- `);if(!a)return null;try{let r=JSON.parse(a);return r&&typeof r.type=="string"?r:null}catch{return null}}function h(t){let a=[],r=t.replace(/\r\n/g,`
3
+ `);if(!a)return null;try{let r=JSON.parse(a);return r&&typeof r.type=="string"?r:null}catch{return null}}function h(n){let a=[],r=n.replace(/\r\n/g,`
4
4
  `),o=r.indexOf(`
5
5
 
6
- `);for(;o>=0;){let l=T(r.slice(0,o));l&&a.push(l),r=r.slice(o+2),o=r.indexOf(`
6
+ `);for(;o>=0;){let l=L(r.slice(0,o));l&&a.push(l),r=r.slice(o+2),o=r.indexOf(`
7
7
 
8
- `)}return{events:a,rest:r}}function S(t){return h(`${t}
8
+ `)}return{events:a,rest:r}}function k(n){return h(`${n}
9
9
 
10
- `).events}var u=class extends Error{constructor(r,o,l){super(o);this.code=r;this.status=l;this.name="BitPalmApiError"}},j="https://agents.bitpalm.ai";function _(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function L(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`v-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`}async function B(t){let a=await t.json().catch(()=>null);return new u(a?.error?.code??"server_error",a?.error?.message??`Request failed (${t.status})`,t.status)}function q(t){if(!t?.key?.startsWith("bp_pk_"))throw new Error("createChatClient needs an app key (bp_pk_\u2026) from the BitPalm dashboard.");let a=(t.baseUrl??j).replace(/\/+$/,""),r=t.storage===void 0?_():t.storage,o=`bitpalm:${t.key.slice(0,14)}`,l=n=>{try{return r?.getItem(`${o}:${n}`)??null}catch{return null}},b=(n,e)=>{try{e===null?r?.removeItem(`${o}:${n}`):r?.setItem(`${o}:${n}`,e)}catch{}},c=t.visitorId??l("visitor")??L();t.visitorId||b("visitor",c);let d=l("conversation"),f=!1,w={Authorization:`Bearer ${t.key}`},g=async(n,e)=>{let i=await fetch(`${a}${n}`,{...e,headers:{...w,...e?.headers??{}}});if(!i.ok)throw await B(i);return i},m=n=>{d=n,b("conversation",n)},y=(n,e,i)=>{for(let s of n)if(s.type==="delta")e.text+=s.text,i?.(s.text,e.text);else if(s.type==="replace")e.text=s.text,i?.("",e.text);else if(s.type==="done")e.result={text:e.text,conversationId:s.conversationId,...s.cards?{cards:s.cards}:{},...s.handoff?{handoff:!0}:{}};else if(s.type==="error")throw new u("server_error",s.message,500)};return{visitorId:c,get conversationId(){return d},get handoff(){return f},async agent(n){let e=new URLSearchParams({locale:t.locale??"en"});return n?.url&&e.set("url",n.url),(await g(`/api/v1/agent?${e.toString()}`)).json()},async send(n,e={}){let i=await g("/api/v1/chat",{method:"POST",headers:{"Content-Type":"application/json"},signal:e.signal,body:JSON.stringify({message:n,visitorId:c,conversationId:d??void 0,context:e.context,fileIds:e.fileIds})}),s={text:"",result:null},C=i.body&&typeof i.body.getReader=="function"?i.body.getReader():null;if(C){let k=new TextDecoder,v="";for(;;){let{done:E,value:P}=await C.read();if(E)break;let I=h(v+k.decode(P,{stream:!0}));v=I.rest,y(I.events,s,e.onDelta)}y(h(`${v}
10
+ `).events}var p=class extends Error{constructor(r,o,l){super(o);this.code=r;this.status=l;this.name="BitPalmApiError"}},O="https://agents.bitpalm.ai";function B(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function M(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`v-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`}async function q(n){let a=await n.json().catch(()=>null);return new p(a?.error?.code??"server_error",a?.error?.message??`Request failed (${n.status})`,n.status)}function N(n){if(!n?.key?.startsWith("bp_pk_"))throw new Error("createChatClient needs an app key (bp_pk_\u2026) from the BitPalm dashboard.");let a=(n.baseUrl??O).replace(/\/+$/,""),r=n.storage===void 0?B():n.storage,o=`bitpalm:${n.key.slice(0,14)}`,l=t=>{try{return r?.getItem(`${o}:${t}`)??null}catch{return null}},x=(t,e)=>{try{e===null?r?.removeItem(`${o}:${t}`):r?.setItem(`${o}:${t}`,e)}catch{}},c=n.visitorId??l("visitor")??M();n.visitorId||x("visitor",c);let d=l("conversation"),f=!1,g=null,I=t=>{for(let e of t)e.fromHuman&&e.createdAt&&(!g||e.createdAt>g)&&(g=e.createdAt)},P={Authorization:`Bearer ${n.key}`},u=async(t,e)=>{let s=await fetch(`${a}${t}`,{...e,headers:{...P,...e?.headers??{}}});if(!s.ok)throw await q(s);return s},y=t=>{d=t,x("conversation",t)},v=(t,e,s)=>{for(let i of t)if(i.type==="delta")e.text+=i.text,s?.(i.text,e.text);else if(i.type==="replace")e.text=i.text,s?.("",e.text);else if(i.type==="done")e.result={text:e.text,conversationId:i.conversationId,...i.cards?{cards:i.cards}:{},...i.handoff?{handoff:!0}:{}};else if(i.type==="error")throw new p("server_error",i.message,500)};return{visitorId:c,get conversationId(){return d},get handoff(){return f},async agent(t){let e=new URLSearchParams({locale:n.locale??"en"});t?.url&&e.set("url",t.url);let s=t?.userToken?{headers:{"X-BitPalm-User-Token":t.userToken}}:void 0;return(await u(`/api/v1/agent?${e.toString()}`,s)).json()},async send(t,e={}){let s=await u("/api/v1/chat",{method:"POST",headers:{"Content-Type":"application/json"},signal:e.signal,body:JSON.stringify({message:t,visitorId:c,conversationId:d??void 0,context:e.context,fileIds:e.fileIds})}),i={text:"",result:null},S=s.body&&typeof s.body.getReader=="function"?s.body.getReader():null;if(S){let T=new TextDecoder,b="";for(;;){let{done:U,value:$}=await S.read();if(U)break;let w=h(b+T.decode($,{stream:!0}));b=w.rest,v(w.events,i,e.onDelta)}v(h(`${b}
11
11
 
12
- `).events,s,e.onDelta)}else y(S(await i.text()),s,e.onDelta);let p=s.result??{text:s.text,conversationId:d??""};return p.conversationId&&m(p.conversationId),f=p.handoff===!0,p},async history(){let n=new URLSearchParams({visitorId:c});d&&n.set("conversationId",d);let e=await(await g(`/api/v1/chat/history?${n.toString()}`)).json();return e.conversationId&&m(e.conversationId),f=e.handoff===!0,e.messages},async identify(n){await g("/api/v1/identify",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...n,visitorId:c})})},async upload(n,e="photo.jpg"){let i=new FormData;i.append("file",n,e),i.append("visitorId",c),d&&i.append("conversationId",d);let s=await(await g("/api/v1/chat/upload",{method:"POST",body:i})).json();return{id:s.id,url:s.url}},async feedback(n,e){if(!d)throw new u("bad_request","There is no conversation yet.",400);await g("/api/v1/chat/feedback",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({visitorId:c,conversationId:d,messageIndex:n,feedback:e})})},reset(){m(null),f=!1}}}0&&(module.exports={BitPalmApiError,createChatClient});
12
+ `).events,i,e.onDelta)}else v(k(await s.text()),i,e.onDelta);let m=i.result??{text:i.text,conversationId:d??""};return m.conversationId&&y(m.conversationId),f=m.handoff===!0,m},async history(){let t=new URLSearchParams({visitorId:c});d&&t.set("conversationId",d);let e=await(await u(`/api/v1/chat/history?${t.toString()}`)).json();return e.conversationId&&y(e.conversationId),f=e.handoff===!0,g=null,I(e.messages),e.messages},async updates(){if(!d)return{handoff:!1,teamTyping:!1,messages:[]};let t=new URLSearchParams({visitorId:c,conversationId:d});g&&t.set("after",g);let e=await(await u(`/api/v1/chat/updates?${t.toString()}`)).json(),s=e.messages??[];return I(s),f=e.handoff===!0,{handoff:f,teamTyping:e.teamTyping===!0,messages:s}},async identify(t){await u("/api/v1/identify",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...t,visitorId:c})})},async upload(t,e="photo.jpg"){let s=new FormData;s.append("file",t,e),s.append("visitorId",c),d&&s.append("conversationId",d);let i=await(await u("/api/v1/chat/upload",{method:"POST",body:s})).json();return{id:i.id,url:i.url}},async feedback(t,e){if(!d)throw new p("bad_request","There is no conversation yet.",400);await u("/api/v1/chat/feedback",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({visitorId:c,conversationId:d,messageIndex:t,feedback:e})})},reset(){y(null),f=!1,g=null}}}0&&(module.exports={BitPalmApiError,createChatClient});
13
13
  //# sourceMappingURL=headless.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/headless.ts","../src/sse.ts"],"sourcesContent":["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","/*\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"],"mappings":"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","names":["headless_exports","__export","BitPalmApiError","createChatClient","__toCommonJS","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"]}
1
+ {"version":3,"sources":["../src/headless.ts","../src/sse.ts"],"sourcesContent":["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","/*\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"],"mappings":"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","names":["headless_exports","__export","BitPalmApiError","createChatClient","__toCommonJS","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"]}
@@ -13,6 +13,8 @@ interface ChatCard {
13
13
  };
14
14
  }
15
15
  interface ChatMessage {
16
+ /** Set on messages from history() and updates(). */
17
+ id?: string;
16
18
  role: "user" | "assistant";
17
19
  text: string;
18
20
  createdAt?: string;
@@ -81,6 +83,15 @@ interface SendResult {
81
83
  */
82
84
  handoff?: boolean;
83
85
  }
86
+ /** What happened while your team has the conversation. */
87
+ interface ChatUpdates {
88
+ /** False once your team gave the conversation back to the agent. */
89
+ handoff: boolean;
90
+ /** Someone of your team is typing right now. */
91
+ teamTyping: boolean;
92
+ /** Replies of your team since the last call, oldest first. */
93
+ messages: ChatMessage[];
94
+ }
84
95
  interface Identity {
85
96
  name?: string;
86
97
  email?: string;
@@ -99,13 +110,20 @@ interface ChatClient {
99
110
  readonly conversationId: string | null;
100
111
  /** True while your team has the conversation. Updated by send() and history(). */
101
112
  readonly handoff: boolean;
102
- /** Name, greeting, quick links and whether "Powered by BitPalm" has to show. */
113
+ /**
114
+ * Name, greeting, quick links and whether "Powered by BitPalm" has to show.
115
+ * With the signed userToken of a logged-in user, quick links for their role
116
+ * show and the greeting can use their first name.
117
+ */
103
118
  agent(options?: {
104
119
  url?: string;
120
+ userToken?: string;
105
121
  }): Promise<AgentConfig>;
106
122
  send(message: string, options?: SendOptions): Promise<SendResult>;
107
123
  /** The messages of the current conversation, or of the latest one of this visitor. */
108
124
  history(): Promise<ChatMessage[]>;
125
+ /** New replies of your team and whether someone is typing. Call it every few seconds while handoff is true. */
126
+ updates(): Promise<ChatUpdates>;
109
127
  /** Tells BitPalm who the logged-in user is. */
110
128
  identify(identity: Identity): Promise<void>;
111
129
  /** A photo for the next message, when the agent takes photos. */
@@ -120,4 +138,4 @@ interface ChatClient {
120
138
  }
121
139
  declare function createChatClient(options: ChatClientOptions): ChatClient;
122
140
 
123
- export { type AgentConfig, BitPalmApiError, type ChatCard, type ChatClient, type ChatClientOptions, type ChatMessage, type Identity, type QuickLink, type SendOptions, type SendResult, createChatClient };
141
+ export { type AgentConfig, BitPalmApiError, type ChatCard, type ChatClient, type ChatClientOptions, type ChatMessage, type ChatUpdates, type Identity, type QuickLink, type SendOptions, type SendResult, createChatClient };
@@ -13,6 +13,8 @@ interface ChatCard {
13
13
  };
14
14
  }
15
15
  interface ChatMessage {
16
+ /** Set on messages from history() and updates(). */
17
+ id?: string;
16
18
  role: "user" | "assistant";
17
19
  text: string;
18
20
  createdAt?: string;
@@ -81,6 +83,15 @@ interface SendResult {
81
83
  */
82
84
  handoff?: boolean;
83
85
  }
86
+ /** What happened while your team has the conversation. */
87
+ interface ChatUpdates {
88
+ /** False once your team gave the conversation back to the agent. */
89
+ handoff: boolean;
90
+ /** Someone of your team is typing right now. */
91
+ teamTyping: boolean;
92
+ /** Replies of your team since the last call, oldest first. */
93
+ messages: ChatMessage[];
94
+ }
84
95
  interface Identity {
85
96
  name?: string;
86
97
  email?: string;
@@ -99,13 +110,20 @@ interface ChatClient {
99
110
  readonly conversationId: string | null;
100
111
  /** True while your team has the conversation. Updated by send() and history(). */
101
112
  readonly handoff: boolean;
102
- /** Name, greeting, quick links and whether "Powered by BitPalm" has to show. */
113
+ /**
114
+ * Name, greeting, quick links and whether "Powered by BitPalm" has to show.
115
+ * With the signed userToken of a logged-in user, quick links for their role
116
+ * show and the greeting can use their first name.
117
+ */
103
118
  agent(options?: {
104
119
  url?: string;
120
+ userToken?: string;
105
121
  }): Promise<AgentConfig>;
106
122
  send(message: string, options?: SendOptions): Promise<SendResult>;
107
123
  /** The messages of the current conversation, or of the latest one of this visitor. */
108
124
  history(): Promise<ChatMessage[]>;
125
+ /** New replies of your team and whether someone is typing. Call it every few seconds while handoff is true. */
126
+ updates(): Promise<ChatUpdates>;
109
127
  /** Tells BitPalm who the logged-in user is. */
110
128
  identify(identity: Identity): Promise<void>;
111
129
  /** A photo for the next message, when the agent takes photos. */
@@ -120,4 +138,4 @@ interface ChatClient {
120
138
  }
121
139
  declare function createChatClient(options: ChatClientOptions): ChatClient;
122
140
 
123
- export { type AgentConfig, BitPalmApiError, type ChatCard, type ChatClient, type ChatClientOptions, type ChatMessage, type Identity, type QuickLink, type SendOptions, type SendResult, createChatClient };
141
+ export { type AgentConfig, BitPalmApiError, type ChatCard, type ChatClient, type ChatClientOptions, type ChatMessage, type ChatUpdates, type Identity, type QuickLink, type SendOptions, type SendResult, createChatClient };
package/dist/headless.js CHANGED
@@ -1,13 +1,13 @@
1
- function P(r){let i=r.split(`
2
- `).filter(a=>a.startsWith("data:")).map(a=>a.slice(5).trimStart()).join(`
3
- `);if(!i)return null;try{let a=JSON.parse(i);return a&&typeof a.type=="string"?a:null}catch{return null}}function h(r){let i=[],a=r.replace(/\r\n/g,`
4
- `),o=a.indexOf(`
1
+ function $(a){let o=a.split(`
2
+ `).filter(s=>s.startsWith("data:")).map(s=>s.slice(5).trimStart()).join(`
3
+ `);if(!o)return null;try{let s=JSON.parse(o);return s&&typeof s.type=="string"?s:null}catch{return null}}function h(a){let o=[],s=a.replace(/\r\n/g,`
4
+ `),l=s.indexOf(`
5
5
 
6
- `);for(;o>=0;){let c=P(a.slice(0,o));c&&i.push(c),a=a.slice(o+2),o=a.indexOf(`
6
+ `);for(;l>=0;){let u=$(s.slice(0,l));u&&o.push(u),s=s.slice(l+2),l=s.indexOf(`
7
7
 
8
- `)}return{events:i,rest:a}}function I(r){return h(`${r}
8
+ `)}return{events:o,rest:s}}function w(a){return h(`${a}
9
9
 
10
- `).events}var u=class extends Error{constructor(a,o,c){super(o);this.code=a;this.status=c;this.name="BitPalmApiError"}},$="https://agents.bitpalm.ai";function U(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function R(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`v-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`}async function A(r){let i=await r.json().catch(()=>null);return new u(i?.error?.code??"server_error",i?.error?.message??`Request failed (${r.status})`,r.status)}function T(r){if(!r?.key?.startsWith("bp_pk_"))throw new Error("createChatClient needs an app key (bp_pk_\u2026) from the BitPalm dashboard.");let i=(r.baseUrl??$).replace(/\/+$/,""),a=r.storage===void 0?U():r.storage,o=`bitpalm:${r.key.slice(0,14)}`,c=t=>{try{return a?.getItem(`${o}:${t}`)??null}catch{return null}},x=(t,e)=>{try{e===null?a?.removeItem(`${o}:${t}`):a?.setItem(`${o}:${t}`,e)}catch{}},d=r.visitorId??c("visitor")??R();r.visitorId||x("visitor",d);let l=c("conversation"),f=!1,S={Authorization:`Bearer ${r.key}`},g=async(t,e)=>{let s=await fetch(`${i}${t}`,{...e,headers:{...S,...e?.headers??{}}});if(!s.ok)throw await A(s);return s},m=t=>{l=t,x("conversation",t)},y=(t,e,s)=>{for(let n of t)if(n.type==="delta")e.text+=n.text,s?.(n.text,e.text);else if(n.type==="replace")e.text=n.text,s?.("",e.text);else if(n.type==="done")e.result={text:e.text,conversationId:n.conversationId,...n.cards?{cards:n.cards}:{},...n.handoff?{handoff:!0}:{}};else if(n.type==="error")throw new u("server_error",n.message,500)};return{visitorId:d,get conversationId(){return l},get handoff(){return f},async agent(t){let e=new URLSearchParams({locale:r.locale??"en"});return t?.url&&e.set("url",t.url),(await g(`/api/v1/agent?${e.toString()}`)).json()},async send(t,e={}){let s=await g("/api/v1/chat",{method:"POST",headers:{"Content-Type":"application/json"},signal:e.signal,body:JSON.stringify({message:t,visitorId:d,conversationId:l??void 0,context:e.context,fileIds:e.fileIds})}),n={text:"",result:null},b=s.body&&typeof s.body.getReader=="function"?s.body.getReader():null;if(b){let w=new TextDecoder,v="";for(;;){let{done:k,value:E}=await b.read();if(k)break;let C=h(v+w.decode(E,{stream:!0}));v=C.rest,y(C.events,n,e.onDelta)}y(h(`${v}
10
+ `).events}var p=class extends Error{constructor(s,l,u){super(l);this.code=s;this.status=u;this.name="BitPalmApiError"}},E="https://agents.bitpalm.ai";function R(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function A(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`v-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`}async function j(a){let o=await a.json().catch(()=>null);return new p(o?.error?.code??"server_error",o?.error?.message??`Request failed (${a.status})`,a.status)}function L(a){if(!a?.key?.startsWith("bp_pk_"))throw new Error("createChatClient needs an app key (bp_pk_\u2026) from the BitPalm dashboard.");let o=(a.baseUrl??E).replace(/\/+$/,""),s=a.storage===void 0?R():a.storage,l=`bitpalm:${a.key.slice(0,14)}`,u=t=>{try{return s?.getItem(`${l}:${t}`)??null}catch{return null}},C=(t,e)=>{try{e===null?s?.removeItem(`${l}:${t}`):s?.setItem(`${l}:${t}`,e)}catch{}},d=a.visitorId??u("visitor")??A();a.visitorId||C("visitor",d);let i=u("conversation"),f=!1,c=null,x=t=>{for(let e of t)e.fromHuman&&e.createdAt&&(!c||e.createdAt>c)&&(c=e.createdAt)},k={Authorization:`Bearer ${a.key}`},g=async(t,e)=>{let n=await fetch(`${o}${t}`,{...e,headers:{...k,...e?.headers??{}}});if(!n.ok)throw await j(n);return n},y=t=>{i=t,C("conversation",t)},v=(t,e,n)=>{for(let r of t)if(r.type==="delta")e.text+=r.text,n?.(r.text,e.text);else if(r.type==="replace")e.text=r.text,n?.("",e.text);else if(r.type==="done")e.result={text:e.text,conversationId:r.conversationId,...r.cards?{cards:r.cards}:{},...r.handoff?{handoff:!0}:{}};else if(r.type==="error")throw new p("server_error",r.message,500)};return{visitorId:d,get conversationId(){return i},get handoff(){return f},async agent(t){let e=new URLSearchParams({locale:a.locale??"en"});t?.url&&e.set("url",t.url);let n=t?.userToken?{headers:{"X-BitPalm-User-Token":t.userToken}}:void 0;return(await g(`/api/v1/agent?${e.toString()}`,n)).json()},async send(t,e={}){let n=await g("/api/v1/chat",{method:"POST",headers:{"Content-Type":"application/json"},signal:e.signal,body:JSON.stringify({message:t,visitorId:d,conversationId:i??void 0,context:e.context,fileIds:e.fileIds})}),r={text:"",result:null},I=n.body&&typeof n.body.getReader=="function"?n.body.getReader():null;if(I){let P=new TextDecoder,b="";for(;;){let{done:T,value:U}=await I.read();if(T)break;let S=h(b+P.decode(U,{stream:!0}));b=S.rest,v(S.events,r,e.onDelta)}v(h(`${b}
11
11
 
12
- `).events,n,e.onDelta)}else y(I(await s.text()),n,e.onDelta);let p=n.result??{text:n.text,conversationId:l??""};return p.conversationId&&m(p.conversationId),f=p.handoff===!0,p},async history(){let t=new URLSearchParams({visitorId:d});l&&t.set("conversationId",l);let e=await(await g(`/api/v1/chat/history?${t.toString()}`)).json();return e.conversationId&&m(e.conversationId),f=e.handoff===!0,e.messages},async identify(t){await g("/api/v1/identify",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...t,visitorId:d})})},async upload(t,e="photo.jpg"){let s=new FormData;s.append("file",t,e),s.append("visitorId",d),l&&s.append("conversationId",l);let n=await(await g("/api/v1/chat/upload",{method:"POST",body:s})).json();return{id:n.id,url:n.url}},async feedback(t,e){if(!l)throw new u("bad_request","There is no conversation yet.",400);await g("/api/v1/chat/feedback",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({visitorId:d,conversationId:l,messageIndex:t,feedback:e})})},reset(){m(null),f=!1}}}export{u as BitPalmApiError,T as createChatClient};
12
+ `).events,r,e.onDelta)}else v(w(await n.text()),r,e.onDelta);let m=r.result??{text:r.text,conversationId:i??""};return m.conversationId&&y(m.conversationId),f=m.handoff===!0,m},async history(){let t=new URLSearchParams({visitorId:d});i&&t.set("conversationId",i);let e=await(await g(`/api/v1/chat/history?${t.toString()}`)).json();return e.conversationId&&y(e.conversationId),f=e.handoff===!0,c=null,x(e.messages),e.messages},async updates(){if(!i)return{handoff:!1,teamTyping:!1,messages:[]};let t=new URLSearchParams({visitorId:d,conversationId:i});c&&t.set("after",c);let e=await(await g(`/api/v1/chat/updates?${t.toString()}`)).json(),n=e.messages??[];return x(n),f=e.handoff===!0,{handoff:f,teamTyping:e.teamTyping===!0,messages:n}},async identify(t){await g("/api/v1/identify",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...t,visitorId:d})})},async upload(t,e="photo.jpg"){let n=new FormData;n.append("file",t,e),n.append("visitorId",d),i&&n.append("conversationId",i);let r=await(await g("/api/v1/chat/upload",{method:"POST",body:n})).json();return{id:r.id,url:r.url}},async feedback(t,e){if(!i)throw new p("bad_request","There is no conversation yet.",400);await g("/api/v1/chat/feedback",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({visitorId:d,conversationId:i,messageIndex:t,feedback:e})})},reset(){y(null),f=!1,c=null}}}export{p as BitPalmApiError,L as createChatClient};
13
13
  //# sourceMappingURL=headless.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sse.ts","../src/headless.ts"],"sourcesContent":["/*\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":["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"]}
1
+ {"version":3,"sources":["../src/sse.ts","../src/headless.ts"],"sourcesContent":["/*\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":["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"]}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var Se=Object.defineProperty;var St=Object.getOwnPropertyDescriptor;var Lt=Object.getOwnPropertyNames;var It=Object.prototype.hasOwnProperty;var _t=(t,n)=>{for(var a in n)Se(t,a,{get:n[a],enumerable:!0})},At=(t,n,a,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let d of Lt(n))!It.call(t,d)&&d!==a&&Se(t,d,{get:()=>n[d],enumerable:!(r=St(n,d))||r.enumerable});return t};var Ct=t=>At(Se({},"__esModule",{value:!0}),t);var zt={};_t(zt,{createWidget:()=>le,detectHostTheme:()=>O});module.exports=Ct(zt);function ae(t){if(t===!1)return"off";if(typeof t=="string"){let n=t.trim().toLowerCase();if(["false","off","0","no","none"].includes(n))return"off";if(n==="events")return"events"}return"bubble"}function rt(t){return t==="off"?!1:t==="events"?"events":!0}function at(t,n){let a=t.createElement("div");a.setAttribute("data-bitpalm-trigger",""),a.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:${n.zIndex-1};font-family:system-ui,sans-serif;animation:_bp_fade .3s;`,a.style.position="fixed",a.style.right="24px",a.style.bottom=`${n.bottom}px`;let r=t.createElement("p");r.style.cssText="font-size:14px;color:#1f2937;margin:0;",r.textContent=n.message;let d=t.createElement("div");d.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;";let u=t.createElement("button");return u.type="button",u.setAttribute("aria-label","Close"),u.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;",u.textContent="\u2715",u.onclick=g=>{g.stopPropagation(),n.onDismiss()},a.onclick=()=>n.onEngage(),a.append(r,d,u),a}var Mt=["dark","dark-mode","dark-theme","theme-dark"],kt=["light","light-mode","light-theme","theme-light"],dt=["data-theme","data-color-scheme","data-color-mode","data-mode","data-bs-theme"],mt="(prefers-color-scheme: dark)";function R(t){return t==="light"||t==="dark"?t:"auto"}function lt(t){if(!t)return null;if(Mt.some(n=>t.classList.contains(n)))return"dark";if(kt.some(n=>t.classList.contains(n)))return"light";for(let n of dt){let a=(t.getAttribute(n)||"").toLowerCase();if(a.includes("dark"))return"dark";if(a.includes("light"))return"light"}return null}function Le(t){let n=t/255;return n<=.03928?n/12.92:((n+.055)/1.055)**2.4}function ct(t,n){if(!t)return null;let a=n.getComputedStyle(t).backgroundColor.match(/rgba?\(([^)]+)\)/);if(!a)return null;let[r,d,u,g=1]=a[1].split(/[\s,/]+/).filter(Boolean).map(Number);return[r,d,u,g].some(l=>Number.isNaN(l))||g<.5?null:.2126*Le(r)+.7152*Le(d)+.0722*Le(u)<.2?"dark":"light"}function Bt(t,n){let a=n.getComputedStyle(t.documentElement).colorScheme||"",r=t.querySelector('meta[name="color-scheme"]')?.getAttribute("content")||"",d=`${a} ${r}`.toLowerCase();return d.includes("dark")?d.includes("light")?n.matchMedia?.(mt).matches?"dark":"light":"dark":null}function O(t=document,n=window){return lt(t.documentElement)??lt(t.body)??ct(t.body,n)??ct(t.documentElement,n)??Bt(t,n)??"light"}function Ie(t,n=document,a=window){let r=O(n,a),d=!1,u=()=>{d=!1;let c=O(n,a);c!==r&&(r=c,t(c))},g=()=>{d||(d=!0,typeof a.requestAnimationFrame=="function"?a.requestAnimationFrame(u):setTimeout(u,16))},T=typeof MutationObserver<"u"?new MutationObserver(g):null,l={attributes:!0,attributeFilter:["class","style",...dt]};T?.observe(n.documentElement,l),n.body&&T?.observe(n.body,l);let h=typeof a.matchMedia=="function"?a.matchMedia(mt):null;return h?.addEventListener?.("change",g),()=>{T?.disconnect(),h?.removeEventListener?.("change",g)}}var Pt="https://agents.bitpalm.ai",v="_bp_",Ht=new Set(["password","file","checkbox","radio","submit","button","reset","image"]),$t=8e3,ut=4096,ft=`${v}identify_signature`,gt=`${v}identify_fingerprint`,pt=`${v}identify_sent_at`,ht="0 4px 14px rgba(0,0,0,0.18)";function Ot(t){return[t.external_user_id||"",t.email||"",t.phone||"",t.name||"",t.company||"",t.signature||"",t.signed_at!=null?String(t.signed_at):"",t.signature_version||"",t.identify_source||""].join("|").toLowerCase()}function m(t,n=180){return t?t.replace(/\s+/g," ").trim().slice(0,n):""}function Dt(t){return t?` ${t.toLowerCase().replace(/[_-]+/g," ").replace(/[^a-z0-9\s@.]/g," ").replace(/\s+/g," ").trim()} `:""}function F(t,n){for(let a of n)if(t.includes(a))return!0;return!1}function M(t){return/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i.test(t)}function _(t){let n=m(t,50);if(!n)return"";let a=n.startsWith("+"),r=n.replace(/\D/g,"");return r.length<6?"":`${a?"+":""}${r.slice(0,20)}`}function yt(t){let n=m(t,140).toLowerCase();return!n||!M(n)?"":n}function U(t,n){for(let a of n){let r=t.querySelector(a),d=m(r?.value);if(d)return d}return""}function Nt(t){return m(t.getAttribute("data-bp-field")||t.getAttribute("data-bitpalm-field"),64).toLowerCase().replace(/[_\s]+/g,"-")}function Wt(t){return t.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Rt(t,n){let a=[],r=(l,h=140)=>{let c=m(l,h);c&&a.push(c)};r(n.name),r(n.id),r(n.getAttribute("autocomplete")),r(n.getAttribute("placeholder")),r(n.getAttribute("aria-label")),r(n.getAttribute("data-field")),r(n.getAttribute("data-name")),r(n.getAttribute("data-label")),r(n.getAttribute("data-bp-field")),r(n.getAttribute("data-bitpalm-field"));let d=new Set,u=l=>{let h=m(l,200);!h||d.has(h)||(d.add(h),a.push(h))};for(let l of Array.from(n.labels||[]))u(l.textContent);if(n.id){let l=t.querySelector(`label[for="${Wt(n.id)}"]`);u(l?.textContent)}let g=n.closest("label");u(g?.textContent);let T=n.getAttribute("aria-labelledby");if(T)for(let l of T.split(/\s+/)){if(!l)continue;let h=t.ownerDocument.getElementById(l);u(h?.textContent)}return a}function Ft(t){let n=m(U(t,["[data-bp-email]","[data-bitpalm-email]"]),140).toLowerCase(),a=_(U(t,["[data-bp-phone]","[data-bitpalm-phone]"])),r=m(U(t,["[data-bp-name]","[data-bitpalm-name]","[data-bp-full-name]","[data-bitpalm-full-name]"])),d=m(U(t,["[data-bp-first-name]","[data-bitpalm-first-name]"])),u=m(U(t,["[data-bp-last-name]","[data-bitpalm-last-name]"])),g=m(U(t,["[data-bp-company]","[data-bitpalm-company]"]));for(let c of Array.from(t.elements)){if(!(c instanceof HTMLInputElement||c instanceof HTMLTextAreaElement||c instanceof HTMLSelectElement)||c.disabled||c instanceof HTMLInputElement&&Ht.has(c.type.toLowerCase()))continue;let y=Nt(c),z=c.hasAttribute("data-bp-email")||c.hasAttribute("data-bitpalm-email")||c.hasAttribute("data-bp-phone")||c.hasAttribute("data-bitpalm-phone")||c.hasAttribute("data-bp-name")||c.hasAttribute("data-bitpalm-name")||c.hasAttribute("data-bp-full-name")||c.hasAttribute("data-bitpalm-full-name")||c.hasAttribute("data-bp-first-name")||c.hasAttribute("data-bitpalm-first-name")||c.hasAttribute("data-bp-last-name")||c.hasAttribute("data-bitpalm-last-name")||c.hasAttribute("data-bp-company")||c.hasAttribute("data-bitpalm-company")||!!y;if(c instanceof HTMLInputElement&&c.type.toLowerCase()==="hidden"&&!z)continue;let f=m(c.value);if(!f)continue;let A=c instanceof HTMLInputElement?c.type.toLowerCase():"",s=Dt(Rt(t,c).join(" "));if(!n&&y==="email"&&M(f)){n=f.toLowerCase();continue}if(!a&&(y==="phone"||y==="tel"||y==="mobile"||y==="whatsapp")){let S=_(f);if(S){a=S;continue}}if(!g&&y==="company"){g=m(f,160);continue}if(!d&&(y==="first-name"||y==="firstname")){d=m(f,100);continue}if(!u&&(y==="last-name"||y==="lastname"||y==="surname")){u=m(f,100);continue}if(!r&&(y==="name"||y==="full-name"||y==="fullname")){!M(f)&&!_(f)&&(r=m(f,140));continue}let K=A==="email"||F(s,[" email "," e mail "," mail "," email adresse "," mailadresse "," correo "]),D=A==="tel"||F(s,[" phone "," phone number "," mobile "," tel "," telefon "," telefonnummer "," whatsapp "," handy "," kontakt "," nummer "]),ce=F(s,[" company "," company name "," firma "," firmenname "," organization "," organisation "," business "," unternehmen "," agency "," brokerage "]),p=F(s,[" first name "," firstname "," given name "," givenname "," vorname "," fname "]),k=F(s,[" last name "," lastname "," family name "," familyname "," surname "," nachname "," lname "]),j=F(s,[" full name "," fullname "," contact name "," name "])&&!K&&!D;if(!n&&K&&M(f)){n=f.toLowerCase();continue}if(!a&&D){let S=_(f);if(S){a=S;continue}}if(!g&&ce){g=m(f,160);continue}if(!d&&p){d=m(f,100);continue}if(!u&&k){u=m(f,100);continue}if(!r&&j&&!M(f)&&!_(f)){r=m(f,140);continue}!n&&M(f)&&(n=f.toLowerCase())}if(r&&(M(r)||_(r))&&(r=""),g&&(M(g)||_(g))&&(g=""),r||(r=m([d,u].filter(Boolean).join(" "),140)),r&&n&&r.toLowerCase()===n.toLowerCase()&&(r=""),!!!(n||a)&&!!!(r&&g))return null;let h={...r?{name:r}:{},...n?{email:n}:{},...a?{phone:a}:{},...g?{company:g}:{}};return Object.keys(h).length>0?h:null}function Ut(){if(typeof document<"u"){let t=document.documentElement.lang;if(t)return t.slice(0,2).toLowerCase()}return"en"}function _e(t,n=1200){if(typeof window<"u"&&"requestIdleCallback"in window){window.requestIdleCallback(t,{timeout:n});return}setTimeout(t,Math.min(n,300))}function Ae(){if(typeof window>"u")return!1;let t=typeof navigator<"u"?navigator.userAgent:"";if(/Android|iPhone|iPad|iPod|IEMobile|Windows Phone|Mobile/i.test(t))return!0;let a=window.matchMedia("(pointer: coarse)").matches,r=window.matchMedia("(hover: none)").matches,d=Math.min(window.screen?.width||window.innerWidth,window.screen?.height||window.innerHeight);return a&&r&&d<=900}function le(t){let{slug:n,locale:a=Ut(),baseUrl:r=Pt,token:d,zIndex:u=9999,autoIdentify:g=!0,launcher:T=!0}=t,l=document,h=R(t.theme),c=h==="auto"?O():h,y=null,z=ae(t.triggers),f=z,A=null,s=l.createElement("iframe");s.setAttribute("data-bitpalm-chat","");let K=`${r}/t/${n}/widget`,D=new URLSearchParams({locale:a,theme:c});d&&D.set("token",d),f==="off"&&D.set("triggers","off"),s.src=`${K}?${D.toString()}`,s.allow="clipboard-write; microphone",s.setAttribute("allowtransparency","true"),s.loading="lazy",s.style.cssText=`position:fixed;bottom:0;right:0;width:1px;height:1px;border:none;z-index:${u};background:transparent;color-scheme:normal;opacity:0;pointer-events:none;`;let ce=new URL(s.src).origin,p=l.createElement("div");if(p.setAttribute("role","button"),p.setAttribute("aria-label","Chat"),p.setAttribute("data-bitpalm-launcher",""),p.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:${u-1};background:#171717;box-shadow:${ht};transition:transform .2s,opacity .3s;opacity:0;`,p.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>',p.onmouseenter=()=>{p.style.transform="scale(1.05)"},p.onmouseleave=()=>{p.style.transform="scale(1)"},p.onclick=()=>J(),T&&l.body.appendChild(p),!l.getElementById("_bp_fade")){let e=l.createElement("style");e.id="_bp_fade",e.textContent="@keyframes _bp_fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}",l.head.appendChild(e)}let k=null,j=!1,S=!1,Ce=!1,de=!1,V=!1,X=()=>{Ce||(Ce=!0,l.body.appendChild(s))},Z=!1,me=0,Q={overflow:"",overscrollBehavior:""},E={overflow:"",overscrollBehavior:"",position:"",top:"",left:"",right:"",width:""},Me=()=>{if(Z||!Ae())return;let o=l.documentElement,i=l.body;me=window.scrollY||window.pageYOffset||0,Q.overflow=o.style.overflow,Q.overscrollBehavior=o.style.overscrollBehavior,E.overflow=i.style.overflow,E.overscrollBehavior=i.style.overscrollBehavior,E.position=i.style.position,E.top=i.style.top,E.left=i.style.left,E.right=i.style.right,E.width=i.style.width,o.style.overflow="hidden",o.style.overscrollBehavior="none",i.style.overflow="hidden",i.style.overscrollBehavior="none",i.style.position="fixed",i.style.top=`-${me}px`,i.style.left="0",i.style.right="0",i.style.width="100%",Z=!0},N=()=>{if(!Z)return;let e=l.documentElement,o=l.body;e.style.overflow=Q.overflow,e.style.overscrollBehavior=Q.overscrollBehavior,o.style.overflow=E.overflow,o.style.overscrollBehavior=E.overscrollBehavior,o.style.position=E.position,o.style.top=E.top,o.style.left=E.left,o.style.right=E.right,o.style.width=E.width,window.scrollTo(0,me),Z=!1},ke=()=>{let e=Ae();s.style.display==="none"&&(s.style.display=""),e?(s.style.width="100vw",s.style.height="100dvh",s.style.left="0",s.style.top="0",s.style.bottom="0",s.style.right="0",Me()):(s.style.width="420px",s.style.height="620px",s.style.bottom="24px",s.style.right="24px",s.style.left="",s.style.top="",N()),s.style.opacity="1",s.style.pointerEvents="auto"},C=()=>{k&&(k.remove(),k=null)},ee=()=>{A!==null&&(A=null,q("trigger_hidden"))},Be=()=>{s.contentWindow?.postMessage({type:"bitpalm-triggers",enabled:f!=="off"},"*")},te=()=>{},ue=()=>{},W=!1,B=new Map;function q(e,o){let i=B.get(e);if(i)for(let b of i)try{b(o)}catch{}}let Pe=e=>{if(e.origin===ce){if(e.data?.type==="bitpalm-widget-config"){S=!1,j=!0,s.style.display==="none"&&(s.style.display=""),e.data.primaryColor&&(p.style.background=e.data.primaryColor,p.style.boxShadow=e.data.chatShadow==="none"?"none":ht);let o=e.data.chatButtonIconColor||"black";if(e.data.chatButtonIconSvg){p.innerHTML="";let i=l.createElement("span");i.style.cssText=`display:flex;align-items:center;justify-content:center;width:24px;height:24px;color:${o}`;let w=new DOMParser().parseFromString(e.data.chatButtonIconSvg,"image/svg+xml").querySelector("svg");w?(w.querySelectorAll("script,foreignObject").forEach(H=>H.remove()),w.querySelectorAll("*").forEach(H=>{for(let $ of[...H.attributes])($.name.startsWith("on")||$.value&&$.value.includes("javascript:"))&&H.removeAttribute($.name)}),w.setAttribute("width","24"),w.setAttribute("height","24"),w.style.display="block",i.appendChild(w)):i.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>',p.appendChild(i)}else{let i=p.querySelector("svg");i&&(i.style.stroke=o)}T&&(p.style.display="flex",requestAnimationFrame(()=>{p.style.opacity="1"})),Be()}if(e.data?.type==="bitpalm-widget-resize"){let o=e.data.width>0,i=W;W=o,o&&!i&&q("widget_opened"),!o&&i&&q("widget_closed");let b=Ae();o?(s.style.width=b?"100vw":`${e.data.width}px`,s.style.height=b?"100dvh":`${e.data.height}px`,b?(s.style.left="0",s.style.top="0",s.style.bottom="0",s.style.right="0",Me()):N(),s.style.opacity="1",s.style.pointerEvents="auto"):(N(),s.style.width="1px",s.style.height="1px",s.style.left="",s.style.top="",s.style.opacity="0",s.style.pointerEvents="none"),p.style.display=o||!T?"none":"flex"}if(e.data?.type==="bitpalm-trigger-show"){if(S||!j||f==="off")return;let o=typeof e.data.message=="string"?e.data.message:"";if(!o)return;if(f==="events"){A=o,q("trigger_shown",{message:o,triggerId:e.data.triggerId,triggerType:e.data.triggerType});return}C(),k=at(l,{message:o,zIndex:u,bottom:T?90:24,onDismiss:()=>{C(),s.contentWindow?.postMessage({type:"bitpalm-trigger-dismiss"},"*")},onEngage:()=>{if(C(),p.style.display="none",ke(),X(),!de){V=!0;return}s.contentWindow?.postMessage({type:"bitpalm-trigger-engaged",message:o},"*")}}),l.body.appendChild(k)}e.data?.type==="bitpalm-trigger-hide"&&(C(),ee()),e.data?.type==="bitpalm-request-context"&&te(),e.data?.type==="bitpalm-chat-event"&&e.data.event&&q(e.data.event,e.data.data),e.data?.type==="bitpalm-widget-blocked"&&(S=!0,j=!1,p.style.display="none",C(),ee(),N(),s.style.display="none")}};window.addEventListener("message",Pe);let L=!1;try{L=localStorage.getItem(`${v}optout`)==="1"}catch{}let ne=`${v}vid`,x="";if(!L){try{x=localStorage.getItem(ne)||""}catch{}if(!x){let e=l.cookie.match(new RegExp(`(?:^|; )${ne}=([^;]+)`));x=e?decodeURIComponent(e[1]):""}x||(x=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2,11)}`);try{localStorage.setItem(ne,x)}catch{}try{l.cookie=`${ne}=${encodeURIComponent(x)};path=/;max-age=31536000;SameSite=Lax`}catch{}}L||_e(()=>{try{let e=new URLSearchParams(location.search),o={};for(let I of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){let w=e.get(I);w&&(o[I]=w)}let i=JSON.stringify({tenant_slug:n,visitor_id:x,url:location.href,referrer:l.referrer||void 0,...Object.keys(o).length>0?{utm:o}:{}}),b=`${r}/api/widget/impression`;typeof navigator.sendBeacon=="function"?navigator.sendBeacon(b,new Blob([i],{type:"application/json"})):fetch(b,{method:"POST",body:i,headers:{"Content-Type":"application/json"},keepalive:!0}).catch(()=>{})}catch{}},2e3);let fe="",ge="",pe=0;try{fe=sessionStorage.getItem(ft)||"",ge=sessionStorage.getItem(gt)||"";let e=parseInt(sessionStorage.getItem(pt)||"0",10);Number.isFinite(e)&&e>0&&(pe=e)}catch{}let He=(e,o="")=>{if(L||!x)return;let i={},b=m(e.name,140),I=yt(e.email),w=_(e.phone),H=m(e.company,160),$=m(e.external_user_id,140),ot=m(e.signature,260),Ee=Number(e.signed_at);if(b&&(i.name=b),I&&(i.email=I),w&&(i.phone=w),H&&(i.company=H),$&&(i.external_user_id=$),ot&&(i.signature=ot),Number.isFinite(Ee)&&Ee>0&&(i.signed_at=Math.floor(Ee)),(e.signature_version==="v1"||i.signature)&&(i.signature_version="v1"),(e.identify_source==="manual"||e.identify_source==="form")&&(i.identify_source=e.identify_source),!i.name&&!i.email&&!i.phone&&!i.company&&!i.external_user_id)return;let re=Ot(i),Te=[o.toLowerCase(),re].filter(Boolean).join("|"),xe=Date.now();if(!(xe-pe<$t&&(Te===fe||re===ge))){fe=Te,ge=re,pe=xe;try{sessionStorage.setItem(ft,Te),sessionStorage.setItem(gt,re),sessionStorage.setItem(pt,String(xe))}catch{}try{let it=JSON.stringify({tenant_slug:n,visitor_id:x,url:location.href,referrer:l.referrer||void 0,...i}),st=`${r}/api/widget/identify`;typeof navigator.sendBeacon=="function"?navigator.sendBeacon(st,new Blob([it],{type:"application/json"})):fetch(st,{method:"POST",body:it,headers:{"Content-Type":"application/json"},keepalive:!0}).catch(()=>{})}catch{}}},$e=e=>{if(L||!g||!x)return;let o=e.target instanceof HTMLFormElement?e.target:e.target instanceof Element?e.target.closest("form"):null;if(!(o instanceof HTMLFormElement))return;let i=(o.getAttribute("data-bp-identify")||o.getAttribute("data-bitpalm-identify")||"").toLowerCase();if(i==="off"||i==="false"||i==="0")return;let b=Ft(o);if(!b)return;let I=[o.getAttribute("id")||"",o.getAttribute("name")||"",o.getAttribute("action")||""].join("|");He({...b,identify_source:"form"},I)};!L&&g&&l.addEventListener("submit",$e,!0);let Y=parseInt(sessionStorage.getItem(`${v}pages`)||"0")+1;sessionStorage.setItem(`${v}pages`,String(Y));let P=JSON.parse(sessionStorage.getItem(`${v}hist`)||"[]");P.push(location.href),P.length>20&&(P=P.slice(-20)),sessionStorage.setItem(`${v}hist`,JSON.stringify(P));let Oe=Date.now(),oe=parseInt(sessionStorage.getItem(`${v}site_start`)||"0");oe||(oe=Oe,sessionStorage.setItem(`${v}site_start`,String(oe)));let De=[];te=()=>{let e=!1;try{e=!!localStorage.getItem(`${v}visited`)}catch{e=!1}if(s.contentWindow?.postMessage({type:"bitpalm-parent-context",url:location.href,title:l.title,returning:e,pageCount:Y,pageHistory:P,loadedAt:Oe,siteStart:oe,locale:a,visitorId:L?"":x},"*"),Ge(),!e&&!L)try{localStorage.setItem(`${v}visited`,"1")}catch{}},s.addEventListener("load",()=>{de=!0,te(),[120,450,1100].forEach(e=>{let o=setTimeout(()=>te(),e);De.push(o)}),V&&(V=!1,ue())}),l.readyState==="loading"?l.addEventListener("DOMContentLoaded",()=>_e(X,1600),{once:!0}):_e(X,1600);let Ne=history.pushState.bind(history),We=history.replaceState.bind(history),ie=()=>{Y++,sessionStorage.setItem(`${v}pages`,String(Y));let e=JSON.parse(sessionStorage.getItem(`${v}hist`)||"[]");if(e.push(location.href),e.length>20&&e.splice(0,e.length-20),P=e,sessionStorage.setItem(`${v}hist`,JSON.stringify(e)),s.contentWindow?.postMessage({type:"bitpalm-page-change",url:location.href,title:l.title,pageCount:Y,pageHistory:e,loadedAt:Date.now()},"*"),!L)try{let o=JSON.stringify({tenant_slug:n,visitor_id:x,url:location.href}),i=`${r}/api/widget/impression`;typeof navigator.sendBeacon=="function"?navigator.sendBeacon(i,new Blob([o],{type:"application/json"})):fetch(i,{method:"POST",body:o,headers:{"Content-Type":"application/json"},keepalive:!0}).catch(()=>{})}catch{}};history.pushState=function(...e){Ne(...e),ie()},history.replaceState=function(...e){We(...e),ie()},window.addEventListener("popstate",ie);let Re=-1,he,Fe=()=>{clearTimeout(he),he=setTimeout(()=>{let e=Math.max(l.documentElement.scrollHeight,l.body.scrollHeight)-window.innerHeight,o=e>0?Math.round(window.scrollY/e*100):100;o!==Re&&(Re=o,s.contentWindow?.postMessage({type:"bitpalm-scroll-depth",percent:o},"*"))},500)};window.addEventListener("scroll",Fe,{passive:!0});let Ue=e=>{e.clientY<=0&&s.contentWindow?.postMessage({type:"bitpalm-exit-intent"},"*")};l.addEventListener("mouseout",Ue);let ye,ze=!1,be=()=>{clearTimeout(ye),!ze&&(ye=setTimeout(()=>{ze=!0,s.contentWindow?.postMessage({type:"bitpalm-inactivity"},"*")},15e3))},je=["mousemove","keydown","scroll","touchstart"];je.forEach(e=>l.addEventListener(e,be,{passive:!0})),be(),ue=()=>{s.contentWindow?.postMessage({type:"bitpalm-open"},"*");let e=s.src.split("#")[0];s.src=`${e}#bp-open-${Date.now()}`};let J=()=>{if(p.style.display="none",C(),ke(),X(),!de){V=!0;return}if(A!==null){let e=A;ee(),s.contentWindow?.postMessage({type:"bitpalm-trigger-engaged",message:e},"*");return}ue()},qe=e=>{f=e,e==="off"&&(C(),ee()),Be()},vt=()=>qe("off"),wt=()=>qe(z==="off"?"bubble":z),ve=()=>{N(),s.contentWindow?.postMessage({type:"bitpalm-close"},"*")},Ye=e=>{!e||typeof e!="object"||He({external_user_id:m(e.externalUserId,140)||void 0,name:m(e.name,140)||void 0,email:yt(e.email)||void 0,phone:_(e.phone)||void 0,company:m(e.company,160)||void 0,signature:m(e.signature,260)||void 0,signed_at:Number.isFinite(Number(e.signedAt))?Math.floor(Number(e.signedAt)):void 0,signature_version:e.signatureVersion==="v1"?"v1":void 0,identify_source:"manual"},"manual")},Et=()=>{W?ve():J()},Tt=()=>W,Je=e=>{if(!e||typeof e!="string")return;let o=e.trim().slice(0,1e4);o&&(W||J(),setTimeout(()=>{s.contentWindow?.postMessage({type:"bitpalm-send-message",message:o},"*")},W?50:500))};function Ge(){s.contentWindow?.postMessage({type:"bitpalm-theme",theme:c},"*")}let se=e=>{e!==c&&(c=e,Ge())},Ke=e=>{h=R(e),y?.(),y=null,h==="auto"?(y=Ie(se),se(O())):se(h)};h==="auto"&&(y=Ie(se));let Ve=e=>{let o=e.detail;if(!o||typeof o!="object")return;let i=m(o.slug,120);i&&i!==n||Ke(R(o.theme))};window.addEventListener("bitpalm-theme",Ve);let G={},Xe=e=>{if(!e||typeof e!="object"||Array.isArray(e))return;G={...G,...e};let o=JSON.stringify(G);o.length>ut&&console.warn(`[BitPalm] Custom context exceeds ${ut} bytes (${o.length}). It may be truncated.`),s.contentWindow?.postMessage({type:"bitpalm-custom-context",data:G},"*")},xt=()=>{G={},s.contentWindow?.postMessage({type:"bitpalm-custom-context",data:{}},"*")},Ze=e=>{let i=e.detail;if(!i||typeof i!="object")return;let b=m(i.slug,120);if(b&&b!==n)return;let{slug:I,...w}=i;Xe(w)};window.addEventListener("bitpalm-context",Ze);let Qe=e=>{let i=e.detail;if(!i||typeof i!="object")return;let b=m(i.slug,120);b&&b!==n||Ye(i)};window.addEventListener("bitpalm-identify",Qe);let we=e=>{let o=e.detail,i=m(o?.slug,120);return!i||i===n},et=e=>{we(e)&&J()},tt=e=>{we(e)&&ve()},nt=e=>{if(!we(e))return;let o=e.detail?.message;typeof o=="string"&&Je(o)};return window.addEventListener("bitpalm-open",et),window.addEventListener("bitpalm-close",tt),window.addEventListener("bitpalm-send",nt),{open:J,close:ve,toggle:Et,isOpen:Tt,identify:Ye,context:Xe,resetContext:xt,send:Je,on:(e,o)=>(B.has(e)||B.set(e,new Set),B.get(e).add(o),()=>B.get(e)?.delete(o)),off:(e,o)=>{B.get(e)?.delete(o)},setTheme:Ke,disableTriggers:vt,enableTriggers:wt,destroy:()=>{window.removeEventListener("message",Pe),window.removeEventListener("scroll",Fe),window.removeEventListener("popstate",ie),l.removeEventListener("mouseout",Ue),l.removeEventListener("submit",$e,!0),je.forEach(e=>l.removeEventListener(e,be)),clearTimeout(he),clearTimeout(ye),De.forEach(e=>clearTimeout(e)),history.pushState=Ne,history.replaceState=We,window.removeEventListener("bitpalm-identify",Qe),window.removeEventListener("bitpalm-context",Ze),window.removeEventListener("bitpalm-theme",Ve),window.removeEventListener("bitpalm-open",et),window.removeEventListener("bitpalm-close",tt),window.removeEventListener("bitpalm-send",nt),y?.(),B.clear(),N(),C(),p.remove(),s.remove()}}}function bt(t){if(t==null)return;let n=t.trim().toLowerCase();if(["1","true","yes","on"].includes(n))return!0;if(["0","false","no","off"].includes(n))return!1}if(typeof document<"u"){let t=document.currentScript;if(t?.dataset.slug){let n=()=>{le({slug:t.dataset.slug,locale:t.dataset.locale,baseUrl:t.dataset.baseUrl,token:t.dataset.token,zIndex:t.dataset.zIndex?Number(t.dataset.zIndex):void 0,autoIdentify:bt(t.dataset.autoIdentify),theme:R(t.dataset.theme),launcher:bt(t.dataset.launcher),triggers:t.dataset.triggers===void 0?void 0:rt(ae(t.dataset.triggers))})};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",n):n()}}0&&(module.exports={createWidget,detectHostTheme});
1
+ "use strict";var Le=Object.defineProperty;var Ct=Object.getOwnPropertyDescriptor;var Mt=Object.getOwnPropertyNames;var Bt=Object.prototype.hasOwnProperty;var Pt=(t,n)=>{for(var a in n)Le(t,a,{get:n[a],enumerable:!0})},Ht=(t,n,a,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let d of Mt(n))!Bt.call(t,d)&&d!==a&&Le(t,d,{get:()=>n[d],enumerable:!(r=Ct(n,d))||r.enumerable});return t};var $t=t=>Ht(Le({},"__esModule",{value:!0}),t);var Gt={};Pt(Gt,{createWidget:()=>le,detectHostTheme:()=>W});module.exports=$t(Gt);function ae(t){if(t===!1)return"off";if(typeof t=="string"){let n=t.trim().toLowerCase();if(["false","off","0","no","none"].includes(n))return"off";if(n==="events")return"events"}return"bubble"}function mt(t){return t==="off"?!1:t==="events"?"events":!0}function ut(t,n){let a=t.createElement("div");a.setAttribute("data-bitpalm-trigger",""),a.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:${n.zIndex-1};font-family:system-ui,sans-serif;animation:_bp_fade .3s;`,a.style.position="fixed",a.style.right="24px",a.style.bottom=`${n.bottom}px`;let r=t.createElement("p");r.style.cssText="font-size:14px;color:#1f2937;margin:0;",r.textContent=n.message;let d=t.createElement("div");d.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;";let u=t.createElement("button");return u.type="button",u.setAttribute("aria-label","Close"),u.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;",u.textContent="\u2715",u.onclick=g=>{g.stopPropagation(),n.onDismiss()},a.onclick=()=>n.onEngage(),a.append(r,d,u),a}var Ot=["dark","dark-mode","dark-theme","theme-dark"],Wt=["light","light-mode","light-theme","theme-light"],pt=["data-theme","data-color-scheme","data-color-mode","data-mode","data-bs-theme"],ht="(prefers-color-scheme: dark)";function F(t){return t==="light"||t==="dark"?t:"auto"}function ft(t){if(!t)return null;if(Ot.some(n=>t.classList.contains(n)))return"dark";if(Wt.some(n=>t.classList.contains(n)))return"light";for(let n of pt){let a=(t.getAttribute(n)||"").toLowerCase();if(a.includes("dark"))return"dark";if(a.includes("light"))return"light"}return null}function ke(t){let n=t/255;return n<=.03928?n/12.92:((n+.055)/1.055)**2.4}function gt(t,n){if(!t)return null;let a=n.getComputedStyle(t).backgroundColor.match(/rgba?\(([^)]+)\)/);if(!a)return null;let[r,d,u,g=1]=a[1].split(/[\s,/]+/).filter(Boolean).map(Number);return[r,d,u,g].some(l=>Number.isNaN(l))||g<.5?null:.2126*ke(r)+.7152*ke(d)+.0722*ke(u)<.2?"dark":"light"}function Dt(t,n){let a=n.getComputedStyle(t.documentElement).colorScheme||"",r=t.querySelector('meta[name="color-scheme"]')?.getAttribute("content")||"",d=`${a} ${r}`.toLowerCase();return d.includes("dark")?d.includes("light")?n.matchMedia?.(ht).matches?"dark":"light":"dark":null}function W(t=document,n=window){return ft(t.documentElement)??ft(t.body)??gt(t.body,n)??gt(t.documentElement,n)??Dt(t,n)??"light"}function Ie(t,n=document,a=window){let r=W(n,a),d=!1,u=()=>{d=!1;let c=W(n,a);c!==r&&(r=c,t(c))},g=()=>{d||(d=!0,typeof a.requestAnimationFrame=="function"?a.requestAnimationFrame(u):setTimeout(u,16))},T=typeof MutationObserver<"u"?new MutationObserver(g):null,l={attributes:!0,attributeFilter:["class","style",...pt]};T?.observe(n.documentElement,l),n.body&&T?.observe(n.body,l);let h=typeof a.matchMedia=="function"?a.matchMedia(ht):null;return h?.addEventListener?.("change",g),()=>{T?.disconnect(),h?.removeEventListener?.("change",g)}}var Nt="https://agents.bitpalm.ai",v="_bp_",Rt=new Set(["password","file","checkbox","radio","submit","button","reset","image"]),Ft=8e3,yt=4096,bt=`${v}identify_signature`,vt=`${v}identify_fingerprint`,wt=`${v}identify_sent_at`,Et="0 4px 14px rgba(0,0,0,0.18)";function Ut(t){return[t.external_user_id||"",t.email||"",t.phone||"",t.name||"",t.company||"",t.signature||"",t.signed_at!=null?String(t.signed_at):"",t.signature_version||"",t.identify_source||""].join("|").toLowerCase()}function m(t,n=180){return t?t.replace(/\s+/g," ").trim().slice(0,n):""}function jt(t){return t?` ${t.toLowerCase().replace(/[_-]+/g," ").replace(/[^a-z0-9\s@.]/g," ").replace(/\s+/g," ").trim()} `:""}function U(t,n){for(let a of n)if(t.includes(a))return!0;return!1}function C(t){return/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i.test(t)}function I(t){let n=m(t,50);if(!n)return"";let a=n.startsWith("+"),r=n.replace(/\D/g,"");return r.length<6?"":`${a?"+":""}${r.slice(0,20)}`}function Tt(t){let n=m(t,140).toLowerCase();return!n||!C(n)?"":n}function j(t,n){for(let a of n){let r=t.querySelector(a),d=m(r?.value);if(d)return d}return""}function qt(t){return m(t.getAttribute("data-bp-field")||t.getAttribute("data-bitpalm-field"),64).toLowerCase().replace(/[_\s]+/g,"-")}function zt(t){return t.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Yt(t,n){let a=[],r=(l,h=140)=>{let c=m(l,h);c&&a.push(c)};r(n.name),r(n.id),r(n.getAttribute("autocomplete")),r(n.getAttribute("placeholder")),r(n.getAttribute("aria-label")),r(n.getAttribute("data-field")),r(n.getAttribute("data-name")),r(n.getAttribute("data-label")),r(n.getAttribute("data-bp-field")),r(n.getAttribute("data-bitpalm-field"));let d=new Set,u=l=>{let h=m(l,200);!h||d.has(h)||(d.add(h),a.push(h))};for(let l of Array.from(n.labels||[]))u(l.textContent);if(n.id){let l=t.querySelector(`label[for="${zt(n.id)}"]`);u(l?.textContent)}let g=n.closest("label");u(g?.textContent);let T=n.getAttribute("aria-labelledby");if(T)for(let l of T.split(/\s+/)){if(!l)continue;let h=t.ownerDocument.getElementById(l);u(h?.textContent)}return a}function Qt(t){let n=m(j(t,["[data-bp-email]","[data-bitpalm-email]"]),140).toLowerCase(),a=I(j(t,["[data-bp-phone]","[data-bitpalm-phone]"])),r=m(j(t,["[data-bp-name]","[data-bitpalm-name]","[data-bp-full-name]","[data-bitpalm-full-name]"])),d=m(j(t,["[data-bp-first-name]","[data-bitpalm-first-name]"])),u=m(j(t,["[data-bp-last-name]","[data-bitpalm-last-name]"])),g=m(j(t,["[data-bp-company]","[data-bitpalm-company]"]));for(let c of Array.from(t.elements)){if(!(c instanceof HTMLInputElement||c instanceof HTMLTextAreaElement||c instanceof HTMLSelectElement)||c.disabled||c instanceof HTMLInputElement&&Rt.has(c.type.toLowerCase()))continue;let y=qt(c),q=c.hasAttribute("data-bp-email")||c.hasAttribute("data-bitpalm-email")||c.hasAttribute("data-bp-phone")||c.hasAttribute("data-bitpalm-phone")||c.hasAttribute("data-bp-name")||c.hasAttribute("data-bitpalm-name")||c.hasAttribute("data-bp-full-name")||c.hasAttribute("data-bitpalm-full-name")||c.hasAttribute("data-bp-first-name")||c.hasAttribute("data-bitpalm-first-name")||c.hasAttribute("data-bp-last-name")||c.hasAttribute("data-bitpalm-last-name")||c.hasAttribute("data-bp-company")||c.hasAttribute("data-bitpalm-company")||!!y;if(c instanceof HTMLInputElement&&c.type.toLowerCase()==="hidden"&&!q)continue;let f=m(c.value);if(!f)continue;let A=c instanceof HTMLInputElement?c.type.toLowerCase():"",s=jt(Yt(t,c).join(" "));if(!n&&y==="email"&&C(f)){n=f.toLowerCase();continue}if(!a&&(y==="phone"||y==="tel"||y==="mobile"||y==="whatsapp")){let S=I(f);if(S){a=S;continue}}if(!g&&y==="company"){g=m(f,160);continue}if(!d&&(y==="first-name"||y==="firstname")){d=m(f,100);continue}if(!u&&(y==="last-name"||y==="lastname"||y==="surname")){u=m(f,100);continue}if(!r&&(y==="name"||y==="full-name"||y==="fullname")){!C(f)&&!I(f)&&(r=m(f,140));continue}let G=A==="email"||U(s,[" email "," e mail "," mail "," email adresse "," mailadresse "," correo "]),D=A==="tel"||U(s,[" phone "," phone number "," mobile "," tel "," telefon "," telefonnummer "," whatsapp "," handy "," kontakt "," nummer "]),ce=U(s,[" company "," company name "," firma "," firmenname "," organization "," organisation "," business "," unternehmen "," agency "," brokerage "]),p=U(s,[" first name "," firstname "," given name "," givenname "," vorname "," fname "]),M=U(s,[" last name "," lastname "," family name "," familyname "," surname "," nachname "," lname "]),z=U(s,[" full name "," fullname "," contact name "," name "])&&!G&&!D;if(!n&&G&&C(f)){n=f.toLowerCase();continue}if(!a&&D){let S=I(f);if(S){a=S;continue}}if(!g&&ce){g=m(f,160);continue}if(!d&&p){d=m(f,100);continue}if(!u&&M){u=m(f,100);continue}if(!r&&z&&!C(f)&&!I(f)){r=m(f,140);continue}!n&&C(f)&&(n=f.toLowerCase())}if(r&&(C(r)||I(r))&&(r=""),g&&(C(g)||I(g))&&(g=""),r||(r=m([d,u].filter(Boolean).join(" "),140)),r&&n&&r.toLowerCase()===n.toLowerCase()&&(r=""),!!!(n||a)&&!!!(r&&g))return null;let h={...r?{name:r}:{},...n?{email:n}:{},...a?{phone:a}:{},...g?{company:g}:{}};return Object.keys(h).length>0?h:null}function Jt(){if(typeof document<"u"){let t=document.documentElement.lang;if(t)return t.slice(0,2).toLowerCase()}return"en"}function Ae(t,n=1200){if(typeof window<"u"&&"requestIdleCallback"in window){window.requestIdleCallback(t,{timeout:n});return}setTimeout(t,Math.min(n,300))}function _e(){if(typeof window>"u")return!1;let t=typeof navigator<"u"?navigator.userAgent:"";if(/Android|iPhone|iPad|iPod|IEMobile|Windows Phone|Mobile/i.test(t))return!0;let a=window.matchMedia("(pointer: coarse)").matches,r=window.matchMedia("(hover: none)").matches,d=Math.min(window.screen?.width||window.innerWidth,window.screen?.height||window.innerHeight);return a&&r&&d<=900}function le(t){let{slug:n,locale:a=Jt(),baseUrl:r=Nt,token:d,zIndex:u=9999,autoIdentify:g=!0,launcher:T=!0}=t,l=document,h=F(t.theme),c=h==="auto"?W():h,y=null,q=ae(t.triggers),f=q,A=null,s=l.createElement("iframe");s.setAttribute("data-bitpalm-chat","");let G=`${r}/t/${n}/widget`,D=new URLSearchParams({locale:a,theme:c});d&&D.set("token",d),f==="off"&&D.set("triggers","off"),s.src=`${G}?${D.toString()}`,s.allow="clipboard-write; microphone",s.setAttribute("allowtransparency","true"),s.loading="lazy",s.style.cssText=`position:fixed;bottom:0;right:0;width:1px;height:1px;border:none;z-index:${u};background:transparent;color-scheme:normal;opacity:0;pointer-events:none;`;let ce=new URL(s.src).origin,p=l.createElement("div");if(p.setAttribute("role","button"),p.setAttribute("aria-label","Chat"),p.setAttribute("data-bitpalm-launcher",""),p.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:${u-1};background:#171717;box-shadow:${Et};transition:transform .2s,opacity .3s;opacity:0;`,p.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>',p.onmouseenter=()=>{p.style.transform="scale(1.05)"},p.onmouseleave=()=>{p.style.transform="scale(1)"},p.onclick=()=>J(),T&&l.body.appendChild(p),!l.getElementById("_bp_fade")){let e=l.createElement("style");e.id="_bp_fade",e.textContent="@keyframes _bp_fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}",l.head.appendChild(e)}let M=null,z=!1,S=!1,Ce=!1,de=!1,K=!1,V=()=>{Ce||(Ce=!0,l.body.appendChild(s))},X=!1,me=0,Z={overflow:"",overscrollBehavior:""},E={overflow:"",overscrollBehavior:"",position:"",top:"",left:"",right:"",width:""},Me=()=>{if(X||!_e())return;let i=l.documentElement,o=l.body;me=window.scrollY||window.pageYOffset||0,Z.overflow=i.style.overflow,Z.overscrollBehavior=i.style.overscrollBehavior,E.overflow=o.style.overflow,E.overscrollBehavior=o.style.overscrollBehavior,E.position=o.style.position,E.top=o.style.top,E.left=o.style.left,E.right=o.style.right,E.width=o.style.width,i.style.overflow="hidden",i.style.overscrollBehavior="none",o.style.overflow="hidden",o.style.overscrollBehavior="none",o.style.position="fixed",o.style.top=`-${me}px`,o.style.left="0",o.style.right="0",o.style.width="100%",X=!0},N=()=>{if(!X)return;let e=l.documentElement,i=l.body;e.style.overflow=Z.overflow,e.style.overscrollBehavior=Z.overscrollBehavior,i.style.overflow=E.overflow,i.style.overscrollBehavior=E.overscrollBehavior,i.style.position=E.position,i.style.top=E.top,i.style.left=E.left,i.style.right=E.right,i.style.width=E.width,window.scrollTo(0,me),X=!1},Be=()=>{let e=_e();s.style.display==="none"&&(s.style.display=""),e?(s.style.width="100vw",s.style.height="100dvh",s.style.left="0",s.style.top="0",s.style.bottom="0",s.style.right="0",Me()):(s.style.width="420px",s.style.height="620px",s.style.bottom="24px",s.style.right="24px",s.style.left="",s.style.top="",N()),s.style.opacity="1",s.style.pointerEvents="auto"},_=()=>{M&&(M.remove(),M=null)},ee=()=>{A!==null&&(A=null,Y("trigger_hidden"))},Pe=()=>{s.contentWindow?.postMessage({type:"bitpalm-triggers",enabled:f!=="off"},"*")},te=()=>{},ue=()=>{},R=!1,B=new Map;function Y(e,i){let o=B.get(e);if(o)for(let b of o)try{b(i)}catch{}}let He=e=>{if(e.origin===ce){if(e.data?.type==="bitpalm-widget-config"){S=!1,z=!0,s.style.display==="none"&&(s.style.display=""),e.data.primaryColor&&(p.style.background=e.data.primaryColor,p.style.boxShadow=e.data.chatShadow==="none"?"none":Et);let i=e.data.chatButtonIconColor||"black";if(e.data.chatButtonIconSvg){p.innerHTML="";let o=l.createElement("span");o.style.cssText=`display:flex;align-items:center;justify-content:center;width:24px;height:24px;color:${i}`;let w=new DOMParser().parseFromString(e.data.chatButtonIconSvg,"image/svg+xml").querySelector("svg");w?(w.querySelectorAll("script,foreignObject").forEach($=>$.remove()),w.querySelectorAll("*").forEach($=>{for(let O of[...$.attributes])(O.name.startsWith("on")||O.value&&O.value.includes("javascript:"))&&$.removeAttribute(O.name)}),w.setAttribute("width","24"),w.setAttribute("height","24"),w.style.display="block",o.appendChild(w)):o.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>',p.appendChild(o)}else{let o=p.querySelector("svg");o&&(o.style.stroke=i)}T&&(p.style.display="flex",requestAnimationFrame(()=>{p.style.opacity="1"})),Pe()}if(e.data?.type==="bitpalm-widget-resize"){let i=e.data.width>0,o=R;R=i,i&&!o&&Y("widget_opened"),!i&&o&&Y("widget_closed");let b=_e();i?(s.style.width=b?"100vw":`${e.data.width}px`,s.style.height=b?"100dvh":`${e.data.height}px`,b?(s.style.left="0",s.style.top="0",s.style.bottom="0",s.style.right="0",Me()):N(),s.style.opacity="1",s.style.pointerEvents="auto"):(N(),s.style.width="1px",s.style.height="1px",s.style.left="",s.style.top="",s.style.opacity="0",s.style.pointerEvents="none"),p.style.display=i||!T?"none":"flex"}if(e.data?.type==="bitpalm-trigger-show"){if(S||!z||f==="off")return;let i=typeof e.data.message=="string"?e.data.message:"";if(!i)return;if(f==="events"){A=i,Y("trigger_shown",{message:i,triggerId:e.data.triggerId,triggerType:e.data.triggerType});return}_(),M=ut(l,{message:i,zIndex:u,bottom:T?90:24,onDismiss:()=>{_(),s.contentWindow?.postMessage({type:"bitpalm-trigger-dismiss"},"*")},onEngage:()=>{if(_(),p.style.display="none",Be(),V(),!de){K=!0;return}s.contentWindow?.postMessage({type:"bitpalm-trigger-engaged",message:i},"*")}}),l.body.appendChild(M)}e.data?.type==="bitpalm-trigger-hide"&&(_(),ee()),e.data?.type==="bitpalm-request-context"&&te(),e.data?.type==="bitpalm-chat-event"&&e.data.event&&Y(e.data.event,e.data.data),e.data?.type==="bitpalm-widget-blocked"&&(S=!0,z=!1,p.style.display="none",_(),ee(),N(),s.style.display="none")}};window.addEventListener("message",He);let L=!1;try{L=localStorage.getItem(`${v}optout`)==="1"}catch{}let ne=`${v}vid`,x="";if(!L){try{x=localStorage.getItem(ne)||""}catch{}if(!x){let e=l.cookie.match(new RegExp(`(?:^|; )${ne}=([^;]+)`));x=e?decodeURIComponent(e[1]):""}x||(x=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2,11)}`);try{localStorage.setItem(ne,x)}catch{}try{l.cookie=`${ne}=${encodeURIComponent(x)};path=/;max-age=31536000;SameSite=Lax`}catch{}}L||Ae(()=>{try{let e=new URLSearchParams(location.search),i={};for(let k of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){let w=e.get(k);w&&(i[k]=w)}let o=JSON.stringify({tenant_slug:n,visitor_id:x,url:location.href,referrer:l.referrer||void 0,...Object.keys(i).length>0?{utm:i}:{}}),b=`${r}/api/widget/impression`;typeof navigator.sendBeacon=="function"?navigator.sendBeacon(b,new Blob([o],{type:"application/json"})):fetch(b,{method:"POST",body:o,headers:{"Content-Type":"application/json"},keepalive:!0}).catch(()=>{})}catch{}},2e3);let fe="",ge="",pe=0;try{fe=sessionStorage.getItem(bt)||"",ge=sessionStorage.getItem(vt)||"";let e=parseInt(sessionStorage.getItem(wt)||"0",10);Number.isFinite(e)&&e>0&&(pe=e)}catch{}let $e=(e,i="")=>{if(L||!x)return;let o={},b=m(e.name,140),k=Tt(e.email),w=I(e.phone),$=m(e.company,160),O=m(e.external_user_id,140),lt=m(e.signature,260),Te=Number(e.signed_at);if(b&&(o.name=b),k&&(o.email=k),w&&(o.phone=w),$&&(o.company=$),O&&(o.external_user_id=O),lt&&(o.signature=lt),Number.isFinite(Te)&&Te>0&&(o.signed_at=Math.floor(Te)),(e.signature_version==="v1"||o.signature)&&(o.signature_version="v1"),(e.identify_source==="manual"||e.identify_source==="form")&&(o.identify_source=e.identify_source),!o.name&&!o.email&&!o.phone&&!o.company&&!o.external_user_id)return;let re=Ut(o),xe=[i.toLowerCase(),re].filter(Boolean).join("|"),Se=Date.now();if(!(Se-pe<Ft&&(xe===fe||re===ge))){fe=xe,ge=re,pe=Se;try{sessionStorage.setItem(bt,xe),sessionStorage.setItem(vt,re),sessionStorage.setItem(wt,String(Se))}catch{}try{let ct=JSON.stringify({tenant_slug:n,visitor_id:x,url:location.href,referrer:l.referrer||void 0,...o}),dt=`${r}/api/widget/identify`;typeof navigator.sendBeacon=="function"?navigator.sendBeacon(dt,new Blob([ct],{type:"application/json"})):fetch(dt,{method:"POST",body:ct,headers:{"Content-Type":"application/json"},keepalive:!0}).catch(()=>{})}catch{}}},Oe=e=>{if(L||!g||!x)return;let i=e.target instanceof HTMLFormElement?e.target:e.target instanceof Element?e.target.closest("form"):null;if(!(i instanceof HTMLFormElement))return;let o=(i.getAttribute("data-bp-identify")||i.getAttribute("data-bitpalm-identify")||"").toLowerCase();if(o==="off"||o==="false"||o==="0")return;let b=Qt(i);if(!b)return;let k=[i.getAttribute("id")||"",i.getAttribute("name")||"",i.getAttribute("action")||""].join("|");$e({...b,identify_source:"form"},k)};!L&&g&&l.addEventListener("submit",Oe,!0);let Q=parseInt(sessionStorage.getItem(`${v}pages`)||"0")+1;sessionStorage.setItem(`${v}pages`,String(Q));let P=JSON.parse(sessionStorage.getItem(`${v}hist`)||"[]");P.push(location.href),P.length>20&&(P=P.slice(-20)),sessionStorage.setItem(`${v}hist`,JSON.stringify(P));let We=Date.now(),ie=parseInt(sessionStorage.getItem(`${v}site_start`)||"0");ie||(ie=We,sessionStorage.setItem(`${v}site_start`,String(ie)));let De=[];te=()=>{let e=!1;try{e=!!localStorage.getItem(`${v}visited`)}catch{e=!1}if(s.contentWindow?.postMessage({type:"bitpalm-parent-context",url:location.href,title:l.title,returning:e,pageCount:Q,pageHistory:P,loadedAt:We,siteStart:ie,locale:a,visitorId:L?"":x},"*"),Ge(),_t(),!e&&!L)try{localStorage.setItem(`${v}visited`,"1")}catch{}},s.addEventListener("load",()=>{de=!0,te(),[120,450,1100].forEach(e=>{let i=setTimeout(()=>te(),e);De.push(i)}),K&&(K=!1,ue())}),l.readyState==="loading"?l.addEventListener("DOMContentLoaded",()=>Ae(V,1600),{once:!0}):Ae(V,1600);let Ne=history.pushState.bind(history),Re=history.replaceState.bind(history),oe=()=>{Q++,sessionStorage.setItem(`${v}pages`,String(Q));let e=JSON.parse(sessionStorage.getItem(`${v}hist`)||"[]");if(e.push(location.href),e.length>20&&e.splice(0,e.length-20),P=e,sessionStorage.setItem(`${v}hist`,JSON.stringify(e)),s.contentWindow?.postMessage({type:"bitpalm-page-change",url:location.href,title:l.title,pageCount:Q,pageHistory:e,loadedAt:Date.now()},"*"),!L)try{let i=JSON.stringify({tenant_slug:n,visitor_id:x,url:location.href}),o=`${r}/api/widget/impression`;typeof navigator.sendBeacon=="function"?navigator.sendBeacon(o,new Blob([i],{type:"application/json"})):fetch(o,{method:"POST",body:i,headers:{"Content-Type":"application/json"},keepalive:!0}).catch(()=>{})}catch{}};history.pushState=function(...e){Ne(...e),oe()},history.replaceState=function(...e){Re(...e),oe()},window.addEventListener("popstate",oe);let Fe=-1,he,Ue=()=>{clearTimeout(he),he=setTimeout(()=>{let e=Math.max(l.documentElement.scrollHeight,l.body.scrollHeight)-window.innerHeight,i=e>0?Math.round(window.scrollY/e*100):100;i!==Fe&&(Fe=i,s.contentWindow?.postMessage({type:"bitpalm-scroll-depth",percent:i},"*"))},500)};window.addEventListener("scroll",Ue,{passive:!0});let je=e=>{e.clientY<=0&&s.contentWindow?.postMessage({type:"bitpalm-exit-intent"},"*")};l.addEventListener("mouseout",je);let ye,qe=!1,be=()=>{clearTimeout(ye),!qe&&(ye=setTimeout(()=>{qe=!0,s.contentWindow?.postMessage({type:"bitpalm-inactivity"},"*")},15e3))},ze=["mousemove","keydown","scroll","touchstart"];ze.forEach(e=>l.addEventListener(e,be,{passive:!0})),be(),ue=()=>{s.contentWindow?.postMessage({type:"bitpalm-open"},"*");let e=s.src.split("#")[0];s.src=`${e}#bp-open-${Date.now()}`};let J=()=>{if(p.style.display="none",_(),Be(),V(),!de){K=!0;return}if(A!==null){let e=A;ee(),s.contentWindow?.postMessage({type:"bitpalm-trigger-engaged",message:e},"*");return}ue()},Ye=e=>{f=e,e==="off"&&(_(),ee()),Pe()},St=()=>Ye("off"),Lt=()=>Ye(q==="off"?"bubble":q),ve=()=>{N(),s.contentWindow?.postMessage({type:"bitpalm-close"},"*")},Qe=e=>{!e||typeof e!="object"||$e({external_user_id:m(e.externalUserId,140)||void 0,name:m(e.name,140)||void 0,email:Tt(e.email)||void 0,phone:I(e.phone)||void 0,company:m(e.company,160)||void 0,signature:m(e.signature,260)||void 0,signed_at:Number.isFinite(Number(e.signedAt))?Math.floor(Number(e.signedAt)):void 0,signature_version:e.signatureVersion==="v1"?"v1":void 0,identify_source:"manual"},"manual")},kt=()=>{R?ve():J()},It=()=>R,Je=e=>{if(!e||typeof e!="string")return;let i=e.trim().slice(0,1e4);i&&(R||J(),setTimeout(()=>{s.contentWindow?.postMessage({type:"bitpalm-send-message",message:i},"*")},R?50:500))};function Ge(){s.contentWindow?.postMessage({type:"bitpalm-theme",theme:c},"*")}let se=e=>{e!==c&&(c=e,Ge())},Ke=e=>{h=F(e),y?.(),y=null,h==="auto"?(y=Ie(se),se(W())):se(h)};h==="auto"&&(y=Ie(se));let Ve=e=>{let i=e.detail;if(!i||typeof i!="object")return;let o=m(i.slug,120);o&&o!==n||Ke(F(i.theme))};window.addEventListener("bitpalm-theme",Ve);let H={},Xe=e=>{if(!e||typeof e!="object"||Array.isArray(e))return;H={...H,...e};let i=JSON.stringify(H);i.length>yt&&console.warn(`[BitPalm] Custom context exceeds ${yt} bytes (${i.length}). It may be truncated.`),s.contentWindow?.postMessage({type:"bitpalm-custom-context",data:H},"*")},At=()=>{H={},s.contentWindow?.postMessage({type:"bitpalm-custom-context",data:{}},"*")},we=Array.isArray(t.quickLinks)?t.quickLinks:null,Ze=we!==null,et=()=>{s.contentWindow?.postMessage({type:"bitpalm-quick-links",links:we},"*")},tt=e=>{we=Array.isArray(e)?e.slice(0,8):null,Ze=!0,et()};function _t(){Object.keys(H).length>0&&s.contentWindow?.postMessage({type:"bitpalm-custom-context",data:H},"*"),Ze&&et()}let nt=e=>{let i=e.detail;if(!i||typeof i!="object")return;let o=m(i.slug,120);o&&o!==n||tt(i.links??null)};window.addEventListener("bitpalm-quick-links",nt);let it=e=>{let o=e.detail;if(!o||typeof o!="object")return;let b=m(o.slug,120);if(b&&b!==n)return;let{slug:k,...w}=o;Xe(w)};window.addEventListener("bitpalm-context",it);let ot=e=>{let o=e.detail;if(!o||typeof o!="object")return;let b=m(o.slug,120);b&&b!==n||Qe(o)};window.addEventListener("bitpalm-identify",ot);let Ee=e=>{let i=e.detail,o=m(i?.slug,120);return!o||o===n},st=e=>{Ee(e)&&J()},rt=e=>{Ee(e)&&ve()},at=e=>{if(!Ee(e))return;let i=e.detail?.message;typeof i=="string"&&Je(i)};return window.addEventListener("bitpalm-open",st),window.addEventListener("bitpalm-close",rt),window.addEventListener("bitpalm-send",at),{open:J,close:ve,toggle:kt,isOpen:It,identify:Qe,context:Xe,resetContext:At,setQuickLinks:tt,send:Je,on:(e,i)=>(B.has(e)||B.set(e,new Set),B.get(e).add(i),()=>B.get(e)?.delete(i)),off:(e,i)=>{B.get(e)?.delete(i)},setTheme:Ke,disableTriggers:St,enableTriggers:Lt,destroy:()=>{window.removeEventListener("message",He),window.removeEventListener("scroll",Ue),window.removeEventListener("popstate",oe),l.removeEventListener("mouseout",je),l.removeEventListener("submit",Oe,!0),ze.forEach(e=>l.removeEventListener(e,be)),clearTimeout(he),clearTimeout(ye),De.forEach(e=>clearTimeout(e)),history.pushState=Ne,history.replaceState=Re,window.removeEventListener("bitpalm-identify",ot),window.removeEventListener("bitpalm-context",it),window.removeEventListener("bitpalm-quick-links",nt),window.removeEventListener("bitpalm-theme",Ve),window.removeEventListener("bitpalm-open",st),window.removeEventListener("bitpalm-close",rt),window.removeEventListener("bitpalm-send",at),y?.(),B.clear(),N(),_(),p.remove(),s.remove()}}}function xt(t){if(t==null)return;let n=t.trim().toLowerCase();if(["1","true","yes","on"].includes(n))return!0;if(["0","false","no","off"].includes(n))return!1}if(typeof document<"u"){let t=document.currentScript;if(t?.dataset.slug){let n=()=>{le({slug:t.dataset.slug,locale:t.dataset.locale,baseUrl:t.dataset.baseUrl,token:t.dataset.token,zIndex:t.dataset.zIndex?Number(t.dataset.zIndex):void 0,autoIdentify:xt(t.dataset.autoIdentify),theme:F(t.dataset.theme),launcher:xt(t.dataset.launcher),triggers:t.dataset.triggers===void 0?void 0:mt(ae(t.dataset.triggers))})};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",n):n()}}0&&(module.exports={createWidget,detectHostTheme});
2
2
  //# sourceMappingURL=index.cjs.map