@bitpalm/ai-agents 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -56,6 +56,32 @@ To set it yourself:
56
56
  widget.setTheme("dark"); // "light", "dark" or "auto"
57
57
  ```
58
58
 
59
+ ## Your own chat button
60
+
61
+ In an app or PWA the chat can open from a button of your own, like a tab in the bottom navigation, and a proactive message can show as a dot on it:
62
+
63
+ ```js
64
+ const widget = createWidget({ slug: "your-agent-slug", launcher: false, triggers: "events" });
65
+
66
+ chatTab.onclick = () => widget.open(); // opens with the waiting message, if there is one
67
+ widget.on("trigger_shown", () => (dot.hidden = false));
68
+ widget.on("trigger_hidden", () => (dot.hidden = true));
69
+ ```
70
+
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
+
73
+ ## Your own chat UI
74
+
75
+ 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.
76
+
77
+ ```tsx
78
+ import { useBitPalmChat } from "@bitpalm/ai-agents/react";
79
+
80
+ const { messages, send, status, agent } = useBitPalmChat({ key: "bp_pk_…" });
81
+ ```
82
+
83
+ Without React: `createChatClient` from `@bitpalm/ai-agents/headless`.
84
+
59
85
  ## Full documentation
60
86
 
61
87
  📚 **[agents.bitpalm.ai/docs](https://agents.bitpalm.ai/docs)**
@@ -68,6 +94,8 @@ widget.setTheme("dark"); // "light", "dark" or "auto"
68
94
  - [Identify logged-in users](https://agents.bitpalm.ai/docs/identify)
69
95
  - [Custom Context (cart, listings, account data)](https://agents.bitpalm.ai/docs/context)
70
96
  - [Events (lead capture, conversation start)](https://agents.bitpalm.ai/docs/events)
97
+ - [Own chat button (apps, PWAs)](https://agents.bitpalm.ai/docs/own-chat-button)
98
+ - [Own chat UI (headless)](https://agents.bitpalm.ai/docs/headless)
71
99
  - [API Reference](https://agents.bitpalm.ai/docs/api-reference)
72
100
  - [Common Errors](https://agents.bitpalm.ai/docs/common-errors)
73
101
 
@@ -0,0 +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(`
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,`
4
+ `),o=r.indexOf(`
5
+
6
+ `);for(;o>=0;){let l=T(r.slice(0,o));l&&a.push(l),r=r.slice(o+2),o=r.indexOf(`
7
+
8
+ `)}return{events:a,rest:r}}function S(t){return h(`${t}
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}
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});
13
+ //# sourceMappingURL=headless.cjs.map
@@ -0,0 +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"]}
@@ -0,0 +1,123 @@
1
+ interface ChatCard {
2
+ kind?: string;
3
+ title: string;
4
+ image?: string;
5
+ subtitle?: string;
6
+ fields?: {
7
+ label: string;
8
+ value: string;
9
+ }[];
10
+ cta?: {
11
+ label: string;
12
+ url: string;
13
+ };
14
+ }
15
+ interface ChatMessage {
16
+ role: "user" | "assistant";
17
+ text: string;
18
+ createdAt?: string;
19
+ cards?: ChatCard[];
20
+ /** Photos the user sent, as links. */
21
+ images?: string[];
22
+ /** Written by a person of the team, not by the agent. */
23
+ fromHuman?: boolean;
24
+ }
25
+ interface QuickLink {
26
+ id: string;
27
+ label: string;
28
+ /** Send this as the user's message. */
29
+ message?: string;
30
+ /** Or open this address. */
31
+ url?: string;
32
+ }
33
+ interface AgentConfig {
34
+ name: string;
35
+ logoUrl: string | null;
36
+ primaryColor: string;
37
+ welcomeMessage: string;
38
+ inputPlaceholder: string;
39
+ quickLinks: QuickLink[];
40
+ photoUploads: boolean;
41
+ /** When required is true, show text linked to url in your chat UI. */
42
+ branding: {
43
+ required: boolean;
44
+ text: string;
45
+ url: string;
46
+ };
47
+ }
48
+ interface ChatClientOptions {
49
+ /** App key from the dashboard, starts with bp_pk_. */
50
+ key: string;
51
+ /** Defaults to https://agents.bitpalm.ai. */
52
+ baseUrl?: string;
53
+ /**
54
+ * Id that holds the conversation together. Leave it out: the client
55
+ * creates a random one and remembers it. If you set it, make it
56
+ * unguessable. Never use a plain user id, anyone with the app key could
57
+ * read that user's chats.
58
+ */
59
+ visitorId?: string;
60
+ /** Language for greeting, placeholder and quick links, like "de". */
61
+ locale?: string;
62
+ /** Where visitor and conversation are remembered. Defaults to localStorage when there is one. */
63
+ storage?: Pick<Storage, "getItem" | "setItem" | "removeItem"> | null;
64
+ }
65
+ interface SendOptions {
66
+ /** Facts for this answer, like the cart or the user's plan. At most 4 KB. */
67
+ context?: Record<string, unknown>;
68
+ /** Ids of photos from upload(). */
69
+ fileIds?: string[];
70
+ /** Called as the answer grows: the new piece and the whole answer so far. */
71
+ onDelta?: (piece: string, answer: string) => void;
72
+ signal?: AbortSignal;
73
+ }
74
+ interface SendResult {
75
+ text: string;
76
+ conversationId: string;
77
+ cards?: ChatCard[];
78
+ /**
79
+ * Your team has the conversation now. The agent stays silent in it until
80
+ * the team closes it, the team's replies come with history().
81
+ */
82
+ handoff?: boolean;
83
+ }
84
+ interface Identity {
85
+ name?: string;
86
+ email?: string;
87
+ phone?: string;
88
+ company?: string;
89
+ externalUserId?: string;
90
+ }
91
+ /** An error of the API, with its code, like "invalid_key" or "rate_limited". */
92
+ declare class BitPalmApiError extends Error {
93
+ readonly code: string;
94
+ readonly status: number;
95
+ constructor(code: string, message: string, status: number);
96
+ }
97
+ interface ChatClient {
98
+ readonly visitorId: string;
99
+ readonly conversationId: string | null;
100
+ /** True while your team has the conversation. Updated by send() and history(). */
101
+ readonly handoff: boolean;
102
+ /** Name, greeting, quick links and whether "Powered by BitPalm" has to show. */
103
+ agent(options?: {
104
+ url?: string;
105
+ }): Promise<AgentConfig>;
106
+ send(message: string, options?: SendOptions): Promise<SendResult>;
107
+ /** The messages of the current conversation, or of the latest one of this visitor. */
108
+ history(): Promise<ChatMessage[]>;
109
+ /** Tells BitPalm who the logged-in user is. */
110
+ identify(identity: Identity): Promise<void>;
111
+ /** A photo for the next message, when the agent takes photos. */
112
+ upload(file: Blob, fileName?: string): Promise<{
113
+ id: string;
114
+ url: string;
115
+ }>;
116
+ /** Thumbs up or down for the agent's answer number index (0 is the first answer). */
117
+ feedback(index: number, value: "up" | "down"): Promise<void>;
118
+ /** Starts a new conversation. */
119
+ reset(): void;
120
+ }
121
+ declare function createChatClient(options: ChatClientOptions): ChatClient;
122
+
123
+ export { type AgentConfig, BitPalmApiError, type ChatCard, type ChatClient, type ChatClientOptions, type ChatMessage, type Identity, type QuickLink, type SendOptions, type SendResult, createChatClient };
@@ -0,0 +1,123 @@
1
+ interface ChatCard {
2
+ kind?: string;
3
+ title: string;
4
+ image?: string;
5
+ subtitle?: string;
6
+ fields?: {
7
+ label: string;
8
+ value: string;
9
+ }[];
10
+ cta?: {
11
+ label: string;
12
+ url: string;
13
+ };
14
+ }
15
+ interface ChatMessage {
16
+ role: "user" | "assistant";
17
+ text: string;
18
+ createdAt?: string;
19
+ cards?: ChatCard[];
20
+ /** Photos the user sent, as links. */
21
+ images?: string[];
22
+ /** Written by a person of the team, not by the agent. */
23
+ fromHuman?: boolean;
24
+ }
25
+ interface QuickLink {
26
+ id: string;
27
+ label: string;
28
+ /** Send this as the user's message. */
29
+ message?: string;
30
+ /** Or open this address. */
31
+ url?: string;
32
+ }
33
+ interface AgentConfig {
34
+ name: string;
35
+ logoUrl: string | null;
36
+ primaryColor: string;
37
+ welcomeMessage: string;
38
+ inputPlaceholder: string;
39
+ quickLinks: QuickLink[];
40
+ photoUploads: boolean;
41
+ /** When required is true, show text linked to url in your chat UI. */
42
+ branding: {
43
+ required: boolean;
44
+ text: string;
45
+ url: string;
46
+ };
47
+ }
48
+ interface ChatClientOptions {
49
+ /** App key from the dashboard, starts with bp_pk_. */
50
+ key: string;
51
+ /** Defaults to https://agents.bitpalm.ai. */
52
+ baseUrl?: string;
53
+ /**
54
+ * Id that holds the conversation together. Leave it out: the client
55
+ * creates a random one and remembers it. If you set it, make it
56
+ * unguessable. Never use a plain user id, anyone with the app key could
57
+ * read that user's chats.
58
+ */
59
+ visitorId?: string;
60
+ /** Language for greeting, placeholder and quick links, like "de". */
61
+ locale?: string;
62
+ /** Where visitor and conversation are remembered. Defaults to localStorage when there is one. */
63
+ storage?: Pick<Storage, "getItem" | "setItem" | "removeItem"> | null;
64
+ }
65
+ interface SendOptions {
66
+ /** Facts for this answer, like the cart or the user's plan. At most 4 KB. */
67
+ context?: Record<string, unknown>;
68
+ /** Ids of photos from upload(). */
69
+ fileIds?: string[];
70
+ /** Called as the answer grows: the new piece and the whole answer so far. */
71
+ onDelta?: (piece: string, answer: string) => void;
72
+ signal?: AbortSignal;
73
+ }
74
+ interface SendResult {
75
+ text: string;
76
+ conversationId: string;
77
+ cards?: ChatCard[];
78
+ /**
79
+ * Your team has the conversation now. The agent stays silent in it until
80
+ * the team closes it, the team's replies come with history().
81
+ */
82
+ handoff?: boolean;
83
+ }
84
+ interface Identity {
85
+ name?: string;
86
+ email?: string;
87
+ phone?: string;
88
+ company?: string;
89
+ externalUserId?: string;
90
+ }
91
+ /** An error of the API, with its code, like "invalid_key" or "rate_limited". */
92
+ declare class BitPalmApiError extends Error {
93
+ readonly code: string;
94
+ readonly status: number;
95
+ constructor(code: string, message: string, status: number);
96
+ }
97
+ interface ChatClient {
98
+ readonly visitorId: string;
99
+ readonly conversationId: string | null;
100
+ /** True while your team has the conversation. Updated by send() and history(). */
101
+ readonly handoff: boolean;
102
+ /** Name, greeting, quick links and whether "Powered by BitPalm" has to show. */
103
+ agent(options?: {
104
+ url?: string;
105
+ }): Promise<AgentConfig>;
106
+ send(message: string, options?: SendOptions): Promise<SendResult>;
107
+ /** The messages of the current conversation, or of the latest one of this visitor. */
108
+ history(): Promise<ChatMessage[]>;
109
+ /** Tells BitPalm who the logged-in user is. */
110
+ identify(identity: Identity): Promise<void>;
111
+ /** A photo for the next message, when the agent takes photos. */
112
+ upload(file: Blob, fileName?: string): Promise<{
113
+ id: string;
114
+ url: string;
115
+ }>;
116
+ /** Thumbs up or down for the agent's answer number index (0 is the first answer). */
117
+ feedback(index: number, value: "up" | "down"): Promise<void>;
118
+ /** Starts a new conversation. */
119
+ reset(): void;
120
+ }
121
+ declare function createChatClient(options: ChatClientOptions): ChatClient;
122
+
123
+ export { type AgentConfig, BitPalmApiError, type ChatCard, type ChatClient, type ChatClientOptions, type ChatMessage, type Identity, type QuickLink, type SendOptions, type SendResult, createChatClient };
@@ -0,0 +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(`
5
+
6
+ `);for(;o>=0;){let c=P(a.slice(0,o));c&&i.push(c),a=a.slice(o+2),o=a.indexOf(`
7
+
8
+ `)}return{events:i,rest:a}}function I(r){return h(`${r}
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}
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};
13
+ //# sourceMappingURL=headless.js.map
@@ -0,0 +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"]}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var ve=Object.defineProperty;var mt=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var ft=Object.prototype.hasOwnProperty;var pt=(t,n)=>{for(var r in n)ve(t,r,{get:n[r],enumerable:!0})},gt=(t,n,r,a)=>{if(n&&typeof n=="object"||typeof n=="function")for(let m of ut(n))!ft.call(t,m)&&m!==r&&ve(t,m,{get:()=>n[m],enumerable:!(a=mt(n,m))||a.enumerable});return t};var ht=t=>gt(ve({},"__esModule",{value:!0}),t);var Pt={};pt(Pt,{createWidget:()=>oe,detectHostTheme:()=>H});module.exports=ht(Pt);var yt=["dark","dark-mode","dark-theme","theme-dark"],bt=["light","light-mode","light-theme","theme-light"],et=["data-theme","data-color-scheme","data-color-mode","data-mode","data-bs-theme"],tt="(prefers-color-scheme: dark)";function R(t){return t==="light"||t==="dark"?t:"auto"}function Ze(t){if(!t)return null;if(yt.some(n=>t.classList.contains(n)))return"dark";if(bt.some(n=>t.classList.contains(n)))return"light";for(let n of et){let r=(t.getAttribute(n)||"").toLowerCase();if(r.includes("dark"))return"dark";if(r.includes("light"))return"light"}return null}function we(t){let n=t/255;return n<=.03928?n/12.92:((n+.055)/1.055)**2.4}function Qe(t,n){if(!t)return null;let r=n.getComputedStyle(t).backgroundColor.match(/rgba?\(([^)]+)\)/);if(!r)return null;let[a,m,y,p=1]=r[1].split(/[\s,/]+/).filter(Boolean).map(Number);return[a,m,y,p].some(g=>Number.isNaN(g))||p<.5?null:.2126*we(a)+.7152*we(m)+.0722*we(y)<.2?"dark":"light"}function vt(t,n){let r=n.getComputedStyle(t.documentElement).colorScheme||"",a=t.querySelector('meta[name="color-scheme"]')?.getAttribute("content")||"",m=`${r} ${a}`.toLowerCase();return m.includes("dark")?m.includes("light")?n.matchMedia?.(tt).matches?"dark":"light":"dark":null}function H(t=document,n=window){return Ze(t.documentElement)??Ze(t.body)??Qe(t.body,n)??Qe(t.documentElement,n)??vt(t,n)??"light"}function Ee(t,n=document,r=window){let a=H(n,r),m=!1,y=()=>{m=!1;let c=H(n,r);c!==a&&(a=c,t(c))},p=()=>{m||(m=!0,typeof r.requestAnimationFrame=="function"?r.requestAnimationFrame(y):setTimeout(y,16))},l=typeof MutationObserver<"u"?new MutationObserver(p):null,g={attributes:!0,attributeFilter:["class","style",...et]};l?.observe(n.documentElement,g),n.body&&l?.observe(n.body,g);let b=typeof r.matchMedia=="function"?r.matchMedia(tt):null;return b?.addEventListener?.("change",p),()=>{l?.disconnect(),b?.removeEventListener?.("change",p)}}var wt="https://agents.bitpalm.ai",v="_bp_",Et=new Set(["password","file","checkbox","radio","submit","button","reset","image"]),xt=8e3,nt=4096,ot=`${v}identify_signature`,it=`${v}identify_fingerprint`,st=`${v}identify_sent_at`,at="0 4px 14px rgba(0,0,0,0.18)";function Tt(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 d(t,n=180){return t?t.replace(/\s+/g," ").trim().slice(0,n):""}function St(t){return t?` ${t.toLowerCase().replace(/[_-]+/g," ").replace(/[^a-z0-9\s@.]/g," ").replace(/\s+/g," ").trim()} `:""}function D(t,n){for(let r of n)if(t.includes(r))return!0;return!1}function A(t){return/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i.test(t)}function _(t){let n=d(t,50);if(!n)return"";let r=n.startsWith("+"),a=n.replace(/\D/g,"");return a.length<6?"":`${r?"+":""}${a.slice(0,20)}`}function rt(t){let n=d(t,140).toLowerCase();return!n||!A(n)?"":n}function F(t,n){for(let r of n){let a=t.querySelector(r),m=d(a?.value);if(m)return m}return""}function Lt(t){return d(t.getAttribute("data-bp-field")||t.getAttribute("data-bitpalm-field"),64).toLowerCase().replace(/[_\s]+/g,"-")}function It(t){return t.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function _t(t,n){let r=[],a=(g,b=140)=>{let c=d(g,b);c&&r.push(c)};a(n.name),a(n.id),a(n.getAttribute("autocomplete")),a(n.getAttribute("placeholder")),a(n.getAttribute("aria-label")),a(n.getAttribute("data-field")),a(n.getAttribute("data-name")),a(n.getAttribute("data-label")),a(n.getAttribute("data-bp-field")),a(n.getAttribute("data-bitpalm-field"));let m=new Set,y=g=>{let b=d(g,200);!b||m.has(b)||(m.add(b),r.push(b))};for(let g of Array.from(n.labels||[]))y(g.textContent);if(n.id){let g=t.querySelector(`label[for="${It(n.id)}"]`);y(g?.textContent)}let p=n.closest("label");y(p?.textContent);let l=n.getAttribute("aria-labelledby");if(l)for(let g of l.split(/\s+/)){if(!g)continue;let b=t.ownerDocument.getElementById(g);y(b?.textContent)}return r}function At(t){let n=d(F(t,["[data-bp-email]","[data-bitpalm-email]"]),140).toLowerCase(),r=_(F(t,["[data-bp-phone]","[data-bitpalm-phone]"])),a=d(F(t,["[data-bp-name]","[data-bitpalm-name]","[data-bp-full-name]","[data-bitpalm-full-name]"])),m=d(F(t,["[data-bp-first-name]","[data-bitpalm-first-name]"])),y=d(F(t,["[data-bp-last-name]","[data-bitpalm-last-name]"])),p=d(F(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&&Et.has(c.type.toLowerCase()))continue;let i=Lt(c),ie=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")||!!i;if(c instanceof HTMLInputElement&&c.type.toLowerCase()==="hidden"&&!ie)continue;let f=d(c.value);if(!f)continue;let J=c instanceof HTMLInputElement?c.type.toLowerCase():"",u=St(_t(t,c).join(" "));if(!n&&i==="email"&&A(f)){n=f.toLowerCase();continue}if(!r&&(i==="phone"||i==="tel"||i==="mobile"||i==="whatsapp")){let S=_(f);if(S){r=S;continue}}if(!p&&i==="company"){p=d(f,160);continue}if(!m&&(i==="first-name"||i==="firstname")){m=d(f,100);continue}if(!y&&(i==="last-name"||i==="lastname"||i==="surname")){y=d(f,100);continue}if(!a&&(i==="name"||i==="full-name"||i==="fullname")){!A(f)&&!_(f)&&(a=d(f,140));continue}let T=J==="email"||D(u,[" email "," e mail "," mail "," email adresse "," mailadresse "," correo "]),$=J==="tel"||D(u,[" phone "," phone number "," mobile "," tel "," telefon "," telefonnummer "," whatsapp "," handy "," kontakt "," nummer "]),U=D(u,[" company "," company name "," firma "," firmenname "," organization "," organisation "," business "," unternehmen "," agency "," brokerage "]),G=D(u,[" first name "," firstname "," given name "," givenname "," vorname "," fname "]),j=D(u,[" last name "," lastname "," family name "," familyname "," surname "," nachname "," lname "]),O=D(u,[" full name "," fullname "," contact name "," name "])&&!T&&!$;if(!n&&T&&A(f)){n=f.toLowerCase();continue}if(!r&&$){let S=_(f);if(S){r=S;continue}}if(!p&&U){p=d(f,160);continue}if(!m&&G){m=d(f,100);continue}if(!y&&j){y=d(f,100);continue}if(!a&&O&&!A(f)&&!_(f)){a=d(f,140);continue}!n&&A(f)&&(n=f.toLowerCase())}if(a&&(A(a)||_(a))&&(a=""),p&&(A(p)||_(p))&&(p=""),a||(a=d([m,y].filter(Boolean).join(" "),140)),a&&n&&a.toLowerCase()===n.toLowerCase()&&(a=""),!!!(n||r)&&!!!(a&&p))return null;let b={...a?{name:a}:{},...n?{email:n}:{},...r?{phone:r}:{},...p?{company:p}:{}};return Object.keys(b).length>0?b:null}function Ct(){if(typeof document<"u"){let t=document.documentElement.lang;if(t)return t.slice(0,2).toLowerCase()}return"en"}function xe(t,n=1200){if(typeof window<"u"&&"requestIdleCallback"in window){window.requestIdleCallback(t,{timeout:n});return}setTimeout(t,Math.min(n,300))}function Te(){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 r=window.matchMedia("(pointer: coarse)").matches,a=window.matchMedia("(hover: none)").matches,m=Math.min(window.screen?.width||window.innerWidth,window.screen?.height||window.innerHeight);return r&&a&&m<=900}function oe(t){let{slug:n,locale:r=Ct(),baseUrl:a=wt,token:m,zIndex:y=9999,autoIdentify:p=!0}=t,l=document,g=R(t.theme),b=g==="auto"?H():g,c=null,i=l.createElement("iframe"),ie=`${a}/t/${n}/widget`,f=new URLSearchParams({locale:r,theme:b});m&&f.set("token",m),i.src=`${ie}?${f.toString()}`,i.allow="clipboard-write; microphone",i.setAttribute("allowtransparency","true"),i.loading="lazy",i.style.cssText=`position:fixed;bottom:0;right:0;width:1px;height:1px;border:none;z-index:${y};background:transparent;color-scheme:normal;opacity:0;pointer-events:none;`;let J=new URL(i.src).origin,u=l.createElement("div");if(u.setAttribute("role","button"),u.setAttribute("aria-label","Chat"),u.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:${y-1};background:#171717;box-shadow:${at};transition:transform .2s,opacity .3s;opacity:0;`,u.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>',u.onmouseenter=()=>{u.style.transform="scale(1.05)"},u.onmouseleave=()=>{u.style.transform="scale(1)"},u.onclick=()=>q(),l.body.appendChild(u),!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 T=null,$=!1,U=!1,G=!1,j=!1,O=!1,S=()=>{G||(G=!0,l.body.appendChild(i))},K=!1,se=0,V={overflow:"",overscrollBehavior:""},E={overflow:"",overscrollBehavior:"",position:"",top:"",left:"",right:"",width:""},Se=()=>{if(K||!Te())return;let s=l.documentElement,o=l.body;se=window.scrollY||window.pageYOffset||0,V.overflow=s.style.overflow,V.overscrollBehavior=s.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,s.style.overflow="hidden",s.style.overscrollBehavior="none",o.style.overflow="hidden",o.style.overscrollBehavior="none",o.style.position="fixed",o.style.top=`-${se}px`,o.style.left="0",o.style.right="0",o.style.width="100%",K=!0},N=()=>{if(!K)return;let e=l.documentElement,s=l.body;e.style.overflow=V.overflow,e.style.overscrollBehavior=V.overscrollBehavior,s.style.overflow=E.overflow,s.style.overscrollBehavior=E.overscrollBehavior,s.style.position=E.position,s.style.top=E.top,s.style.left=E.left,s.style.right=E.right,s.style.width=E.width,window.scrollTo(0,se),K=!1},Le=()=>{let e=Te();i.style.display==="none"&&(i.style.display=""),e?(i.style.width="100vw",i.style.height="100dvh",i.style.left="0",i.style.top="0",i.style.bottom="0",i.style.right="0",Se()):(i.style.width="420px",i.style.height="620px",i.style.bottom="24px",i.style.right="24px",i.style.left="",i.style.top="",N()),i.style.opacity="1",i.style.pointerEvents="auto"},C=()=>{T&&(T.remove(),T=null)},X=()=>{},ae=()=>{},W=!1,k=new Map;function re(e,s){let o=k.get(e);if(o)for(let h of o)try{h(s)}catch{}}let Ie=e=>{if(e.origin===J){if(e.data?.type==="bitpalm-widget-config"){U=!1,$=!0,i.style.display==="none"&&(i.style.display=""),e.data.primaryColor&&(u.style.background=e.data.primaryColor,u.style.boxShadow=e.data.chatShadow==="none"?"none":at);let s=e.data.chatButtonIconColor||"black";if(e.data.chatButtonIconSvg){u.innerHTML="";let o=l.createElement("span");o.style.cssText=`display:flex;align-items:center;justify-content:center;width:24px;height:24px;color:${s}`;let w=new DOMParser().parseFromString(e.data.chatButtonIconSvg,"image/svg+xml").querySelector("svg");w?(w.querySelectorAll("script,foreignObject").forEach(B=>B.remove()),w.querySelectorAll("*").forEach(B=>{for(let M of[...B.attributes])(M.name.startsWith("on")||M.value&&M.value.includes("javascript:"))&&B.removeAttribute(M.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>',u.appendChild(o)}else{let o=u.querySelector("svg");o&&(o.style.stroke=s)}u.style.display="flex",requestAnimationFrame(()=>{u.style.opacity="1"})}if(e.data?.type==="bitpalm-widget-resize"){let s=e.data.width>0,o=W;W=s,s&&!o&&re("widget_opened"),!s&&o&&re("widget_closed");let h=Te();s?(i.style.width=h?"100vw":`${e.data.width}px`,i.style.height=h?"100dvh":`${e.data.height}px`,h?(i.style.left="0",i.style.top="0",i.style.bottom="0",i.style.right="0",Se()):N(),i.style.opacity="1",i.style.pointerEvents="auto"):(N(),i.style.width="1px",i.style.height="1px",i.style.left="",i.style.top="",i.style.opacity="0",i.style.pointerEvents="none"),u.style.display=s?"none":"flex"}if(e.data?.type==="bitpalm-trigger-show"){if(U||!$)return;C(),T=l.createElement("div"),T.style.cssText=`position:fixed;bottom:90px;right:24px;max-width:240px;background:#fff;border-radius:16px;padding:12px 32px 12px 12px;box-shadow:0 2px 20px rgba(0,0,0,0.08);cursor:pointer;z-index:${y-1};font-family:system-ui,sans-serif;animation:_bp_fade .3s;`;let s=(e.data.message||"").replace(/</g,"&lt;");T.innerHTML=`<p style="font-size:14px;color:#1f2937;margin:0;">${s}</p><div style="position:absolute;bottom:-8px;right:20px;width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #fff;"></div>`;let o=l.createElement("button");o.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;",o.innerHTML="&#10005;",o.onclick=h=>{h.stopPropagation(),C(),i.contentWindow?.postMessage({type:"bitpalm-trigger-dismiss"},"*")},T.onclick=()=>{if(C(),u.style.display="none",Le(),S(),!j){O=!0;return}i.contentWindow?.postMessage({type:"bitpalm-trigger-engaged",message:s},"*")},T.appendChild(o),l.body.appendChild(T)}e.data?.type==="bitpalm-trigger-hide"&&C(),e.data?.type==="bitpalm-request-context"&&X(),e.data?.type==="bitpalm-chat-event"&&e.data.event&&re(e.data.event,e.data.data),e.data?.type==="bitpalm-widget-blocked"&&(U=!0,$=!1,u.style.display="none",C(),N(),i.style.display="none")}};window.addEventListener("message",Ie);let L=!1;try{L=localStorage.getItem(`${v}optout`)==="1"}catch{}let Z=`${v}vid`,x="";if(!L){try{x=localStorage.getItem(Z)||""}catch{}if(!x){let e=l.cookie.match(new RegExp(`(?:^|; )${Z}=([^;]+)`));x=e?decodeURIComponent(e[1]):""}x||(x=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2,11)}`);try{localStorage.setItem(Z,x)}catch{}try{l.cookie=`${Z}=${encodeURIComponent(x)};path=/;max-age=31536000;SameSite=Lax`}catch{}}L||xe(()=>{try{let e=new URLSearchParams(location.search),s={};for(let I of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){let w=e.get(I);w&&(s[I]=w)}let o=JSON.stringify({tenant_slug:n,visitor_id:x,url:location.href,referrer:l.referrer||void 0,...Object.keys(s).length>0?{utm:s}:{}}),h=`${a}/api/widget/impression`;typeof navigator.sendBeacon=="function"?navigator.sendBeacon(h,new Blob([o],{type:"application/json"})):fetch(h,{method:"POST",body:o,headers:{"Content-Type":"application/json"},keepalive:!0}).catch(()=>{})}catch{}},2e3);let le="",ce="",de=0;try{le=sessionStorage.getItem(ot)||"",ce=sessionStorage.getItem(it)||"";let e=parseInt(sessionStorage.getItem(st)||"0",10);Number.isFinite(e)&&e>0&&(de=e)}catch{}let _e=(e,s="")=>{if(L||!x)return;let o={},h=d(e.name,140),I=rt(e.email),w=_(e.phone),B=d(e.company,160),M=d(e.external_user_id,140),Ke=d(e.signature,260),he=Number(e.signed_at);if(h&&(o.name=h),I&&(o.email=I),w&&(o.phone=w),B&&(o.company=B),M&&(o.external_user_id=M),Ke&&(o.signature=Ke),Number.isFinite(he)&&he>0&&(o.signed_at=Math.floor(he)),(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 ne=Tt(o),ye=[s.toLowerCase(),ne].filter(Boolean).join("|"),be=Date.now();if(!(be-de<xt&&(ye===le||ne===ce))){le=ye,ce=ne,de=be;try{sessionStorage.setItem(ot,ye),sessionStorage.setItem(it,ne),sessionStorage.setItem(st,String(be))}catch{}try{let Ve=JSON.stringify({tenant_slug:n,visitor_id:x,url:location.href,referrer:l.referrer||void 0,...o}),Xe=`${a}/api/widget/identify`;typeof navigator.sendBeacon=="function"?navigator.sendBeacon(Xe,new Blob([Ve],{type:"application/json"})):fetch(Xe,{method:"POST",body:Ve,headers:{"Content-Type":"application/json"},keepalive:!0}).catch(()=>{})}catch{}}},Ae=e=>{if(L||!p||!x)return;let s=e.target instanceof HTMLFormElement?e.target:e.target instanceof Element?e.target.closest("form"):null;if(!(s instanceof HTMLFormElement))return;let o=(s.getAttribute("data-bp-identify")||s.getAttribute("data-bitpalm-identify")||"").toLowerCase();if(o==="off"||o==="false"||o==="0")return;let h=At(s);if(!h)return;let I=[s.getAttribute("id")||"",s.getAttribute("name")||"",s.getAttribute("action")||""].join("|");_e({...h,identify_source:"form"},I)};!L&&p&&l.addEventListener("submit",Ae,!0);let z=parseInt(sessionStorage.getItem(`${v}pages`)||"0")+1;sessionStorage.setItem(`${v}pages`,String(z));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 Ce=Date.now(),Q=parseInt(sessionStorage.getItem(`${v}site_start`)||"0");Q||(Q=Ce,sessionStorage.setItem(`${v}site_start`,String(Q)));let ke=[];X=()=>{let e=!1;try{e=!!localStorage.getItem(`${v}visited`)}catch{e=!1}if(i.contentWindow?.postMessage({type:"bitpalm-parent-context",url:location.href,title:l.title,returning:e,pageCount:z,pageHistory:P,loadedAt:Ce,siteStart:Q,locale:r,visitorId:L?"":x},"*"),De(),!e&&!L)try{localStorage.setItem(`${v}visited`,"1")}catch{}},i.addEventListener("load",()=>{j=!0,X(),[120,450,1100].forEach(e=>{let s=setTimeout(()=>X(),e);ke.push(s)}),O&&(O=!1,ae())}),l.readyState==="loading"?l.addEventListener("DOMContentLoaded",()=>xe(S,1600),{once:!0}):xe(S,1600);let Pe=history.pushState.bind(history),Be=history.replaceState.bind(history),ee=()=>{z++,sessionStorage.setItem(`${v}pages`,String(z));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)),i.contentWindow?.postMessage({type:"bitpalm-page-change",url:location.href,title:l.title,pageCount:z,pageHistory:e,loadedAt:Date.now()},"*"),!L)try{let s=JSON.stringify({tenant_slug:n,visitor_id:x,url:location.href}),o=`${a}/api/widget/impression`;typeof navigator.sendBeacon=="function"?navigator.sendBeacon(o,new Blob([s],{type:"application/json"})):fetch(o,{method:"POST",body:s,headers:{"Content-Type":"application/json"},keepalive:!0}).catch(()=>{})}catch{}};history.pushState=function(...e){Pe(...e),ee()},history.replaceState=function(...e){Be(...e),ee()},window.addEventListener("popstate",ee);let Me=-1,me,He=()=>{clearTimeout(me),me=setTimeout(()=>{let e=Math.max(l.documentElement.scrollHeight,l.body.scrollHeight)-window.innerHeight,s=e>0?Math.round(window.scrollY/e*100):100;s!==Me&&(Me=s,i.contentWindow?.postMessage({type:"bitpalm-scroll-depth",percent:s},"*"))},500)};window.addEventListener("scroll",He,{passive:!0});let $e=e=>{e.clientY<=0&&i.contentWindow?.postMessage({type:"bitpalm-exit-intent"},"*")};l.addEventListener("mouseout",$e);let ue,Oe=!1,fe=()=>{clearTimeout(ue),!Oe&&(ue=setTimeout(()=>{Oe=!0,i.contentWindow?.postMessage({type:"bitpalm-inactivity"},"*")},15e3))},Ne=["mousemove","keydown","scroll","touchstart"];Ne.forEach(e=>l.addEventListener(e,fe,{passive:!0})),fe(),ae=()=>{i.contentWindow?.postMessage({type:"bitpalm-open"},"*");let e=i.src.split("#")[0];i.src=`${e}#bp-open-${Date.now()}`};let q=()=>{if(u.style.display="none",C(),Le(),S(),!j){O=!0;return}ae()},pe=()=>{N(),i.contentWindow?.postMessage({type:"bitpalm-close"},"*")},We=e=>{!e||typeof e!="object"||_e({external_user_id:d(e.externalUserId,140)||void 0,name:d(e.name,140)||void 0,email:rt(e.email)||void 0,phone:_(e.phone)||void 0,company:d(e.company,160)||void 0,signature:d(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")},lt=()=>{W?pe():q()},ct=()=>W,Re=e=>{if(!e||typeof e!="string")return;let s=e.trim().slice(0,1e4);s&&(W||q(),setTimeout(()=>{i.contentWindow?.postMessage({type:"bitpalm-send-message",message:s},"*")},W?50:500))};function De(){i.contentWindow?.postMessage({type:"bitpalm-theme",theme:b},"*")}let te=e=>{e!==b&&(b=e,De())},Fe=e=>{g=R(e),c?.(),c=null,g==="auto"?(c=Ee(te),te(H())):te(g)};g==="auto"&&(c=Ee(te));let Ue=e=>{let s=e.detail;if(!s||typeof s!="object")return;let o=d(s.slug,120);o&&o!==n||Fe(R(s.theme))};window.addEventListener("bitpalm-theme",Ue);let Y={},je=e=>{if(!e||typeof e!="object"||Array.isArray(e))return;Y={...Y,...e};let s=JSON.stringify(Y);s.length>nt&&console.warn(`[BitPalm] Custom context exceeds ${nt} bytes (${s.length}). It may be truncated.`),i.contentWindow?.postMessage({type:"bitpalm-custom-context",data:Y},"*")},dt=()=>{Y={},i.contentWindow?.postMessage({type:"bitpalm-custom-context",data:{}},"*")},ze=e=>{let o=e.detail;if(!o||typeof o!="object")return;let h=d(o.slug,120);if(h&&h!==n)return;let{slug:I,...w}=o;je(w)};window.addEventListener("bitpalm-context",ze);let qe=e=>{let o=e.detail;if(!o||typeof o!="object")return;let h=d(o.slug,120);h&&h!==n||We(o)};window.addEventListener("bitpalm-identify",qe);let ge=e=>{let s=e.detail,o=d(s?.slug,120);return!o||o===n},Ye=e=>{ge(e)&&q()},Je=e=>{ge(e)&&pe()},Ge=e=>{if(!ge(e))return;let s=e.detail?.message;typeof s=="string"&&Re(s)};return window.addEventListener("bitpalm-open",Ye),window.addEventListener("bitpalm-close",Je),window.addEventListener("bitpalm-send",Ge),{open:q,close:pe,toggle:lt,isOpen:ct,identify:We,context:je,resetContext:dt,send:Re,on:(e,s)=>(k.has(e)||k.set(e,new Set),k.get(e).add(s),()=>k.get(e)?.delete(s)),off:(e,s)=>{k.get(e)?.delete(s)},setTheme:Fe,destroy:()=>{window.removeEventListener("message",Ie),window.removeEventListener("scroll",He),window.removeEventListener("popstate",ee),l.removeEventListener("mouseout",$e),l.removeEventListener("submit",Ae,!0),Ne.forEach(e=>l.removeEventListener(e,fe)),clearTimeout(me),clearTimeout(ue),ke.forEach(e=>clearTimeout(e)),history.pushState=Pe,history.replaceState=Be,window.removeEventListener("bitpalm-identify",qe),window.removeEventListener("bitpalm-context",ze),window.removeEventListener("bitpalm-theme",Ue),window.removeEventListener("bitpalm-open",Ye),window.removeEventListener("bitpalm-close",Je),window.removeEventListener("bitpalm-send",Ge),c?.(),k.clear(),N(),C(),u.remove(),i.remove()}}}function kt(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=()=>{oe({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:kt(t.dataset.autoIdentify),theme:R(t.dataset.theme)})};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",n):n()}}0&&(module.exports={createWidget,detectHostTheme});
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});
2
2
  //# sourceMappingURL=index.cjs.map