passline-ai 2.0.0 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/api/passlineApi.ts","../src/hooks/usePasslineSession.ts","../src/hooks/usePasslineClient.ts","../src/component/PasslineChat.tsx"],"sourcesContent":["import { PasslineSession } from \"../component/types\";\n\nexport type ChatbotSessionResponse = {\n sessionId: string;\n greeting: string;\n assistantName: string;\n companyName: string | null;\n logoUrl: string | null;\n};\n\nexport type ChatbotMessageResponse = {\n reply: string;\n};\n\nexport class PasslineApiError extends Error {\n readonly code?: string;\n readonly status?: number;\n\n constructor(message: string, options?: { code?: string; status?: number }) {\n super(message);\n this.name = \"PasslineApiError\";\n this.code = options?.code;\n this.status = options?.status;\n }\n}\n\nexport function isOfflineError(err: unknown): boolean {\n if (!err) return false;\n if (err instanceof PasslineApiError && err.code === \"OFFLINE\") return true;\n const message = err instanceof Error ? err.message : \"\";\n return /offline|failed to fetch|networkerror|load failed|request failed \\(5\\d\\d\\)/i.test(\n message,\n );\n}\n\nexport function isSessionInvalidError(err: unknown): boolean {\n const message = err instanceof Error ? err.message.toLowerCase() : \"\";\n // Booking/calendar 404s (\"credentials not found\") must not wipe the chat.\n return /session/.test(message) && /(not found|expired|invalid)/.test(message);\n}\n\nexport class PasslineApi {\n private token: string;\n private origin: string;\n\n constructor(token: string, origin?: string) {\n this.token = token;\n this.origin = (origin || \"https://api.passline.ai\").replace(/\\/$/, \"\");\n }\n\n private getHeaders(): HeadersInit {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Passline-Embed-Token\": this.token,\n };\n }\n\n private async request<T>(\n path: string,\n body: Record<string, unknown> = {},\n ): Promise<T> {\n const url = `${this.origin}/api/chatbot/${path.replace(/^\\//, \"\")}`;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: this.getHeaders(),\n body: JSON.stringify(body),\n cache: \"no-store\",\n });\n } catch {\n throw new PasslineApiError(\"Offline\", { code: \"OFFLINE\" });\n }\n\n const payload = (await response.json().catch(() => null)) as\n | (T & { message?: string })\n | null;\n\n if (!response.ok) {\n if (response.status >= 500 || response.status === 0) {\n throw new PasslineApiError(\"Offline\", {\n code: \"OFFLINE\",\n status: response.status,\n });\n }\n throw new PasslineApiError(\n payload?.message || `Request failed (${response.status})`,\n { status: response.status },\n );\n }\n\n return payload as T;\n }\n\n async createSession(): Promise<ChatbotSessionResponse> {\n return this.request<ChatbotSessionResponse>(\"session\", {});\n }\n\n async sendMessage(\n sessionId: string,\n message: string,\n ): Promise<ChatbotMessageResponse> {\n return this.request<ChatbotMessageResponse>(\n `session/${encodeURIComponent(sessionId)}/messages`,\n { message },\n );\n }\n}\n\nexport function toPasslineSession(\n response: ChatbotSessionResponse,\n messages: PasslineSession[\"messages\"] = [],\n): PasslineSession {\n return {\n sessionId: response.sessionId,\n assistantName: response.assistantName || \"Assistant\",\n companyName: response.companyName ?? null,\n logoUrl: response.logoUrl ?? null,\n greeting: response.greeting,\n messages,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { PasslineMessage, PasslineSession } from \"../component/types\";\nimport {\n isOfflineError,\n isSessionInvalidError,\n PasslineApi,\n toPasslineSession,\n} from \"../api/passlineApi\";\n\nconst DEFAULT_GREETING = \"Hi! How can I help?\";\n\ninterface StoredSession {\n sessionId: string;\n assistantName?: string;\n companyName?: string | null;\n logoUrl?: string | null;\n messages: PasslineMessage[];\n updatedAt: number;\n}\n\nfunction nextMessageId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\nexport function usePasslineSession(\n token: string,\n origin?: string,\n persistSession: boolean = true,\n maxSessionAge: number = 7 * 24 * 60 * 60 * 1000,\n maxStoredMessages: number = 200,\n) {\n const [session, setSession] = useState<PasslineSession | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [offline, setOffline] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const apiRef = useRef(new PasslineApi(token, origin));\n const sessionRef = useRef<PasslineSession | null>(null);\n const bootIdRef = useRef(0);\n const storageKey = `passline:chat:${token}`;\n\n sessionRef.current = session;\n\n useEffect(() => {\n apiRef.current = new PasslineApi(token, origin);\n }, [token, origin]);\n\n const readStoredSession = useCallback((): StoredSession | null => {\n if (!persistSession || typeof window === \"undefined\") return null;\n\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (!raw) return null;\n\n const parsed = JSON.parse(raw) as StoredSession;\n if (!parsed?.sessionId || !Array.isArray(parsed.messages)) {\n return null;\n }\n\n if (Date.now() - (parsed.updatedAt || 0) > maxSessionAge) {\n window.localStorage.removeItem(storageKey);\n return null;\n }\n\n return parsed;\n } catch {\n return null;\n }\n }, [maxSessionAge, persistSession, storageKey]);\n\n const writeStoredSession = useCallback(\n (data: StoredSession) => {\n if (!persistSession || typeof window === \"undefined\") return;\n\n try {\n const messages =\n data.messages.length > maxStoredMessages\n ? data.messages.slice(data.messages.length - maxStoredMessages)\n : data.messages;\n window.localStorage.setItem(\n storageKey,\n JSON.stringify({ ...data, messages }),\n );\n } catch {\n // Private browsing or quota exceeded — degrade to in-memory only.\n }\n },\n [maxStoredMessages, persistSession, storageKey],\n );\n\n const clearStoredSession = useCallback(() => {\n if (!persistSession || typeof window === \"undefined\") return;\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }, [persistSession, storageKey]);\n\n const persistFromSession = useCallback(\n (next: PasslineSession) => {\n writeStoredSession({\n sessionId: next.sessionId,\n assistantName: next.assistantName,\n companyName: next.companyName,\n logoUrl: next.logoUrl,\n messages: next.messages,\n updatedAt: Date.now(),\n });\n },\n [writeStoredSession],\n );\n\n const goOffline = useCallback(() => {\n setOffline(true);\n setSession(null);\n sessionRef.current = null;\n setError(\"Offline\");\n setIsLoading(false);\n }, []);\n\n const restoreCachedSession = useCallback((): PasslineSession | null => {\n const stored = readStoredSession();\n if (!stored) return null;\n\n const restored: PasslineSession = {\n sessionId: stored.sessionId,\n assistantName: stored.assistantName || \"Assistant\",\n companyName: stored.companyName ?? null,\n logoUrl: stored.logoUrl ?? null,\n messages: stored.messages,\n };\n setSession(restored);\n sessionRef.current = restored;\n setOffline(false);\n setError(null);\n setIsLoading(false);\n return restored;\n }, [readStoredSession]);\n\n const createSession = useCallback(\n async (forceNew: boolean = false): Promise<PasslineSession> => {\n const bootId = ++bootIdRef.current;\n setError(null);\n\n if (!forceNew) {\n const restored = restoreCachedSession();\n if (restored) return restored;\n }\n\n try {\n setIsLoading(true);\n const response = await apiRef.current.createSession();\n if (bootIdRef.current !== bootId) {\n const current = sessionRef.current;\n if (current) return current;\n }\n\n const greeting = response.greeting || DEFAULT_GREETING;\n const next = toPasslineSession(response, [\n {\n id: \"greeting\",\n role: \"assistant\",\n content: greeting,\n timestamp: Date.now(),\n },\n ]);\n\n setSession(next);\n sessionRef.current = next;\n setOffline(false);\n persistFromSession(next);\n return next;\n } catch (err) {\n if (bootIdRef.current !== bootId) {\n const current = sessionRef.current;\n if (current) return current;\n }\n if (isOfflineError(err)) {\n goOffline();\n throw new Error(\"Offline\");\n }\n const errorMessage =\n err instanceof Error ? err.message : \"Unable to start chat\";\n setError(errorMessage);\n setSession(null);\n sessionRef.current = null;\n throw new Error(errorMessage);\n } finally {\n if (bootIdRef.current === bootId) {\n setIsLoading(false);\n }\n }\n },\n [goOffline, persistFromSession, restoreCachedSession],\n );\n\n const ensureSession = useCallback(async (): Promise<PasslineSession | null> => {\n if (offline) return null;\n if (sessionRef.current?.sessionId) return sessionRef.current;\n try {\n return await createSession(false);\n } catch {\n return null;\n }\n }, [createSession, offline]);\n\n const sendMessage = useCallback(\n async (content: string): Promise<PasslineMessage> => {\n const active = sessionRef.current;\n if (!active?.sessionId) {\n throw new Error(\"No active session\");\n }\n\n const userMessage: PasslineMessage = {\n id: nextMessageId(\"u\"),\n role: \"user\",\n content,\n timestamp: Date.now(),\n };\n\n const withUser: PasslineSession = {\n ...active,\n messages: [...active.messages, userMessage],\n };\n setSession(withUser);\n sessionRef.current = withUser;\n persistFromSession(withUser);\n\n try {\n const response = await apiRef.current.sendMessage(\n active.sessionId,\n content,\n );\n\n const assistantMessage: PasslineMessage = {\n id: nextMessageId(\"a\"),\n role: \"assistant\",\n content: response.reply || \"\",\n timestamp: Date.now(),\n };\n\n const latest = sessionRef.current ?? withUser;\n const withAssistant: PasslineSession = {\n ...latest,\n messages: [...latest.messages, assistantMessage],\n };\n setSession(withAssistant);\n sessionRef.current = withAssistant;\n persistFromSession(withAssistant);\n return assistantMessage;\n } catch (err) {\n if (isOfflineError(err)) {\n goOffline();\n throw new Error(\"Offline\");\n }\n if (isSessionInvalidError(err)) {\n clearStoredSession();\n setSession(null);\n sessionRef.current = null;\n await createSession(true);\n throw new Error(\"Session expired. Please try your message again.\");\n }\n throw err;\n }\n },\n [clearStoredSession, createSession, goOffline, persistFromSession],\n );\n\n const newChat = useCallback(async () => {\n clearStoredSession();\n setSession(null);\n sessionRef.current = null;\n setOffline(false);\n return createSession(true);\n }, [clearStoredSession, createSession]);\n\n useEffect(() => {\n bootIdRef.current += 1;\n setSession(null);\n sessionRef.current = null;\n setOffline(false);\n setError(null);\n setIsLoading(false);\n restoreCachedSession();\n }, [restoreCachedSession, token]);\n\n return {\n session,\n messages: session?.messages || [],\n isLoading,\n offline,\n error,\n sendMessage,\n newChat,\n createSession,\n ensureSession,\n clearStoredSession,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { usePasslineSession } from \"./usePasslineSession\";\nimport { PasslineMessage, PasslineSession } from \"../component/types\";\n\nexport function usePasslineChat(\n token: string,\n options?: {\n origin?: string;\n persistSession?: boolean;\n maxSessionAge?: number;\n maxStoredMessages?: number;\n autoOpen?: boolean;\n onMessageSend?: (message: string) => void;\n onMessageReceive?: (message: PasslineMessage) => void;\n onError?: (error: Error) => void;\n onSessionStart?: (session: PasslineSession) => void;\n },\n) {\n const [isOpen, setIsOpen] = useState(Boolean(options?.autoOpen));\n const [isSending, setIsSending] = useState(false);\n const lastSessionIdRef = useRef<string | null>(null);\n\n const {\n session,\n messages,\n isLoading,\n offline,\n error,\n sendMessage: sendMessageApi,\n newChat: newChatApi,\n ensureSession,\n } = usePasslineSession(\n token,\n options?.origin,\n options?.persistSession,\n options?.maxSessionAge,\n options?.maxStoredMessages,\n );\n\n useEffect(() => {\n if (options?.autoOpen) {\n setIsOpen(true);\n }\n }, [options?.autoOpen]);\n\n useEffect(() => {\n lastSessionIdRef.current = null;\n }, [token]);\n\n useEffect(() => {\n if (!isOpen || offline) {\n return;\n }\n void ensureSession();\n }, [ensureSession, isOpen, offline, token]);\n\n useEffect(() => {\n if (!session?.sessionId || session.sessionId === lastSessionIdRef.current) {\n return;\n }\n lastSessionIdRef.current = session.sessionId;\n options?.onSessionStart?.(session);\n }, [options, session]);\n\n useEffect(() => {\n if (error && options?.onError) {\n options.onError(new Error(error));\n }\n }, [error, options]);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!content.trim() || isSending || isLoading || offline) return;\n\n try {\n setIsSending(true);\n options?.onMessageSend?.(content);\n const response = await sendMessageApi(content);\n options?.onMessageReceive?.(response);\n } catch (err) {\n options?.onError?.(\n err instanceof Error ? err : new Error(\"Failed to send message\"),\n );\n } finally {\n setIsSending(false);\n }\n },\n [isLoading, isSending, offline, options, sendMessageApi],\n );\n\n const newChat = useCallback(async () => {\n try {\n await newChatApi();\n } catch (err) {\n options?.onError?.(\n err instanceof Error ? err : new Error(\"Failed to start new chat\"),\n );\n }\n }, [newChatApi, options]);\n\n const toggleOpen = useCallback(() => {\n setIsOpen((prev) => !prev);\n }, []);\n\n return {\n isOpen,\n setIsOpen,\n toggleOpen,\n isSending,\n isLoading,\n offline,\n messages,\n session,\n error,\n sendMessage,\n newChat,\n };\n}\n","import React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport { usePasslineChat } from \"../hooks/usePasslineClient\";\nimport { PasslineChatProps, PasslineMessage, PasslineTheme } from \"./types\";\nimport \"./PasslineChat.css\";\n\nconst CHAT_ICON =\n \"M4 4h16a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H9l-5 4v-4H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z\";\n\nconst defaultTheme: Required<PasslineTheme> = {\n primaryColor: \"#0f766e\",\n primaryHoverColor: \"#0d9488\",\n backgroundColor: \"#f8fafc\",\n textColor: \"#0f172a\",\n userBubbleColor: \"#0f766e\",\n userBubbleTextColor: \"#ffffff\",\n assistantBubbleColor: \"#ffffff\",\n assistantBubbleTextColor: \"#1e293b\",\n borderRadius: \"16px\",\n borderWidth: \"1px\",\n borderColor: \"#e2e8f0\",\n buttonSize: \"medium\",\n buttonBorderRadius: \"999px\",\n buttonBackgroundColor: \"#0f766e\",\n buttonHoverColor: \"#0d9488\",\n buttonIconColor: \"#ffffff\",\n panelWidth: \"380px\",\n panelHeight: \"560px\",\n panelShadow: \"0 12px 40px rgba(0,0,0,.22)\",\n fontFamily:\n \"system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: \"14px\",\n spacing: \"12px\",\n padding: \"12px\",\n className: \"\",\n buttonClassName: \"\",\n panelClassName: \"\",\n headerClassName: \"\",\n messagesClassName: \"\",\n inputClassName: \"\",\n};\n\nfunction brandingInitials(label?: string | null): string {\n const parts = String(label || \"\")\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n if (parts.length === 0) return \"A\";\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();\n return (parts[0].charAt(0) + parts[1].charAt(0)).toUpperCase();\n}\n\nfunction BrandMark({\n logoUrl,\n label,\n fallback = \"initials\",\n className,\n backgroundColor,\n}: {\n logoUrl?: string | null;\n label: string;\n fallback?: \"initials\" | \"icon\";\n className: string;\n backgroundColor?: string;\n}) {\n const [broken, setBroken] = useState(false);\n\n useEffect(() => {\n setBroken(false);\n }, [logoUrl]);\n\n const showLogo = Boolean(logoUrl) && !broken;\n\n return (\n <div\n className={`${className}${showLogo ? \" passline-has-logo\" : \"\"}`}\n style={showLogo ? undefined : { backgroundColor }}\n >\n {showLogo ? (\n <img\n src={logoUrl ?? \"\"}\n alt={label || \"Organization logo\"}\n className=\"passline-chat-avatar-img\"\n onError={() => setBroken(true)}\n />\n ) : fallback === \"icon\" ? (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d={CHAT_ICON} />\n </svg>\n ) : (\n brandingInitials(label)\n )}\n </div>\n );\n}\n\nexport const PasslineChat: React.FC<PasslineChatProps> = ({\n token,\n origin,\n theme = {},\n className = \"\",\n buttonClassName = \"\",\n panelClassName = \"\",\n renderButton,\n renderHeader,\n renderMessage,\n renderInput,\n autoOpen = false,\n persistSession = true,\n maxSessionAge,\n maxStoredMessages,\n onOpen,\n onClose,\n onMessageSend,\n onMessageReceive,\n onError,\n onSessionStart,\n onNewChat,\n}) => {\n const mergedTheme = { ...defaultTheme, ...theme };\n const [inputValue, setInputValue] = useState(\"\");\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const {\n isOpen,\n setIsOpen,\n toggleOpen,\n isSending,\n isLoading,\n offline,\n messages,\n session,\n error,\n sendMessage,\n newChat,\n } = usePasslineChat(token, {\n origin,\n persistSession,\n maxSessionAge,\n maxStoredMessages,\n autoOpen,\n onMessageSend,\n onMessageReceive,\n onError,\n onSessionStart,\n });\n\n const brandLabel =\n session?.companyName || session?.assistantName || \"Assistant\";\n const inputLocked = isLoading || offline || !session?.sessionId;\n const subtitle = offline\n ? \"Offline\"\n : error && !session\n ? \"Unavailable\"\n : session?.companyName || (isLoading ? \"Connecting…\" : \"Online\");\n const placeholder = offline\n ? \"Offline\"\n : isLoading\n ? \"Connecting…\"\n : session?.sessionId\n ? \"Type a message…\"\n : \"Unavailable\";\n\n useEffect(() => {\n if (autoOpen) {\n setIsOpen(true);\n }\n }, [autoOpen, setIsOpen]);\n\n useEffect(() => {\n if (isOpen) {\n onOpen?.();\n if (!offline) {\n setTimeout(() => {\n inputRef.current?.focus();\n }, 100);\n }\n } else {\n onClose?.();\n }\n }, [isOpen, offline, onOpen, onClose]);\n\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages, isSending, isLoading]);\n\n const handleSend = useCallback(() => {\n if (inputValue.trim() && !isSending && !inputLocked) {\n sendMessage(inputValue);\n setInputValue(\"\");\n }\n }, [inputLocked, inputValue, isSending, sendMessage]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n },\n [handleSend],\n );\n\n const handleNewChat = useCallback(() => {\n newChat();\n onNewChat?.();\n }, [newChat, onNewChat]);\n\n const buttonSizePx =\n mergedTheme.buttonSize === \"small\"\n ? \"44px\"\n : mergedTheme.buttonSize === \"large\"\n ? \"64px\"\n : \"56px\";\n\n const defaultButton = (\n <button\n className={`passline-chat-button ${mergedTheme.buttonClassName} ${buttonClassName}`}\n onClick={toggleOpen}\n style={{\n backgroundColor: session?.logoUrl\n ? undefined\n : isOpen\n ? mergedTheme.primaryHoverColor\n : mergedTheme.buttonBackgroundColor,\n color: mergedTheme.buttonIconColor,\n borderRadius: mergedTheme.buttonBorderRadius,\n width: buttonSizePx,\n height: buttonSizePx,\n }}\n aria-label={isOpen ? \"Close chat\" : \"Open chat\"}\n >\n <BrandMark\n logoUrl={session?.logoUrl}\n label={brandLabel}\n fallback=\"icon\"\n className=\"passline-chat-button-mark\"\n />\n </button>\n );\n\n const defaultMessage = (message: PasslineMessage, index: number) => (\n <div\n key={message.id || index}\n className={`passline-message ${message.role === \"user\" ? \"message-user\" : \"message-assistant\"}`}\n style={{\n backgroundColor:\n message.role === \"user\"\n ? mergedTheme.userBubbleColor\n : mergedTheme.assistantBubbleColor,\n color:\n message.role === \"user\"\n ? mergedTheme.userBubbleTextColor\n : mergedTheme.assistantBubbleTextColor,\n borderRadius: mergedTheme.borderRadius,\n border:\n message.role === \"assistant\"\n ? `${mergedTheme.borderWidth} solid ${mergedTheme.borderColor}`\n : \"none\",\n }}\n >\n {message.content}\n </div>\n );\n\n const defaultHeader = (\n <div className={`passline-chat-header ${mergedTheme.headerClassName}`}>\n <BrandMark\n logoUrl={session?.logoUrl}\n label={brandLabel}\n className=\"passline-header-avatar\"\n backgroundColor={mergedTheme.primaryColor}\n />\n <div className=\"passline-header-info\">\n <div className=\"passline-header-title\">\n {session?.assistantName || \"Assistant\"}\n </div>\n <div className=\"passline-header-subtitle\">{subtitle}</div>\n </div>\n <button\n className=\"passline-header-newchat\"\n onClick={handleNewChat}\n title=\"Start new chat\"\n aria-label=\"Start new chat\"\n style={{\n color: mergedTheme.textColor,\n }}\n >\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M17.65 6.35A7.95 7.95 0 0 0 12 4a8 8 0 1 0 7.75 10h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4z\" />\n </svg>\n </button>\n </div>\n );\n\n const defaultInput = (\n <div\n className={`passline-chat-input-container ${mergedTheme.inputClassName}`}\n >\n <input\n ref={inputRef}\n type=\"text\"\n className=\"passline-chat-input\"\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={inputLocked}\n autoComplete=\"off\"\n style={{\n borderColor: mergedTheme.borderColor,\n borderRadius: mergedTheme.borderRadius,\n backgroundColor: mergedTheme.backgroundColor,\n color: mergedTheme.textColor,\n fontFamily: mergedTheme.fontFamily,\n fontSize: mergedTheme.fontSize,\n }}\n />\n <button\n className=\"passline-chat-send\"\n onClick={handleSend}\n disabled={inputLocked || isSending || !inputValue.trim()}\n style={{\n backgroundColor: mergedTheme.primaryColor,\n borderRadius: mergedTheme.borderRadius,\n color: \"#ffffff\",\n }}\n >\n Send\n </button>\n </div>\n );\n\n const defaultPanel = (\n <div\n className={`passline-chat-panel ${mergedTheme.panelClassName} ${panelClassName}`}\n role=\"dialog\"\n aria-label=\"Passline chat\"\n style={{\n width: mergedTheme.panelWidth,\n height: mergedTheme.panelHeight,\n boxShadow: mergedTheme.panelShadow,\n backgroundColor: mergedTheme.backgroundColor,\n borderRadius: mergedTheme.borderRadius,\n fontFamily: mergedTheme.fontFamily,\n fontSize: mergedTheme.fontSize,\n color: mergedTheme.textColor,\n }}\n >\n {renderHeader\n ? renderHeader({\n title: session?.assistantName || \"Assistant\",\n subtitle,\n avatar: brandingInitials(brandLabel),\n onNewChat: handleNewChat,\n })\n : defaultHeader}\n\n <div className={`passline-chat-messages ${mergedTheme.messagesClassName}`}>\n {isLoading && messages.length === 0 ? (\n <p className=\"passline-chat-meta\">Connecting…</p>\n ) : null}\n\n {messages.map((msg, index) =>\n renderMessage\n ? renderMessage({ message: msg, className: \"\" })\n : defaultMessage(msg, index),\n )}\n\n {isSending ? (\n <p className=\"passline-chat-typing\">Assistant is typing…</p>\n ) : null}\n\n {error ? <p className=\"passline-chat-error\">{error}</p> : null}\n <div ref={messagesEndRef} />\n </div>\n\n {renderInput\n ? renderInput({\n value: inputValue,\n onChange: setInputValue,\n onSend: handleSend,\n disabled: inputLocked || isSending,\n placeholder,\n className: \"\",\n })\n : defaultInput}\n </div>\n );\n\n return (\n <div\n className={`passline-chat-wrapper ${mergedTheme.className} ${className}`}\n >\n {isOpen && defaultPanel}\n {renderButton\n ? renderButton({ onClick: toggleOpen, isOpen, className: \"\" })\n : defaultButton}\n </div>\n );\n};\n"],"names":["PasslineApiError","Error","constructor","message","options","super","this","name","code","status","isOfflineError","err","test","isSessionInvalidError","toLowerCase","PasslineApi","token","origin","replace","getHeaders","Accept","request","path","body","url","response","fetch","method","headers","JSON","stringify","cache","payload","json","catch","ok","createSession","sendMessage","sessionId","encodeURIComponent","nextMessageId","prefix","Date","now","Math","random","toString","slice","usePasslineSession","persistSession","maxSessionAge","maxStoredMessages","session","setSession","useState","isLoading","setIsLoading","offline","setOffline","error","setError","apiRef","useRef","sessionRef","bootIdRef","storageKey","current","useEffect","readStoredSession","useCallback","window","raw","localStorage","getItem","parsed","parse","Array","isArray","messages","updatedAt","removeItem","writeStoredSession","data","length","setItem","clearStoredSession","persistFromSession","next","assistantName","companyName","logoUrl","goOffline","restoreCachedSession","stored","restored","async","forceNew","bootId","greeting","toPasslineSession","id","role","content","timestamp","errorMessage","ensureSession","active","userMessage","withUser","assistantMessage","reply","latest","withAssistant","newChat","usePasslineChat","isOpen","setIsOpen","Boolean","autoOpen","isSending","setIsSending","lastSessionIdRef","sendMessageApi","newChatApi","onSessionStart","onError","trim","onMessageSend","onMessageReceive","toggleOpen","prev","defaultTheme","primaryColor","primaryHoverColor","backgroundColor","textColor","userBubbleColor","userBubbleTextColor","assistantBubbleColor","assistantBubbleTextColor","borderRadius","borderWidth","borderColor","buttonSize","buttonBorderRadius","buttonBackgroundColor","buttonHoverColor","buttonIconColor","panelWidth","panelHeight","panelShadow","fontFamily","fontSize","spacing","padding","className","buttonClassName","panelClassName","headerClassName","messagesClassName","inputClassName","brandingInitials","label","parts","String","split","filter","toUpperCase","charAt","BrandMark","fallback","broken","setBroken","showLogo","_jsx","style","undefined","src","alt","viewBox","fill","d","theme","renderButton","renderHeader","renderMessage","renderInput","onOpen","onClose","onNewChat","mergedTheme","inputValue","setInputValue","messagesEndRef","inputRef","brandLabel","inputLocked","subtitle","placeholder","setTimeout","focus","scrollIntoView","behavior","handleSend","handleKeyDown","e","key","shiftKey","preventDefault","handleNewChat","buttonSizePx","defaultButton","onClick","color","width","height","children","defaultHeader","_jsxs","title","defaultInput","ref","type","value","onChange","target","onKeyDown","disabled","autoComplete","defaultPanel","boxShadow","avatar","map","msg","index","border","defaultMessage","onSend"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/crypto/envelope.ts","../src/api/passlineApi.ts","../src/hooks/usePasslineSession.ts","../src/hooks/usePasslineClient.ts","../src/component/labels.ts","../src/component/passlineChat.tsx"],"sourcesContent":["const ECDH: EcKeyGenParams = { name: \"ECDH\", namedCurve: \"P-256\" };\nconst AES: AesKeyGenParams = { name: \"AES-GCM\", length: 256 };\n\nexport const PROXY_PATH = \"/api/p\";\n/** Public widget gateway. This is the only host the npm package calls. */\nexport const PASSLINE_GATEWAY = \"https://api.passline.ai\";\n\nexport type HandshakeRequest = { v: 1; op: \"h\"; c: string };\nexport type HandshakeResponse = { v: 1; s: string; t: string };\nexport type RpcRequest = { v: 1; op: \"x\"; t: string; i: string; c: string };\nexport type RpcResponse = { v: 1; i: string; c: string };\n\nfunction bytesOf(data: ArrayBuffer | Uint8Array): Uint8Array<ArrayBuffer> {\n if (data instanceof Uint8Array) {\n const copy = new Uint8Array(data.byteLength);\n copy.set(data);\n return copy;\n }\n return new Uint8Array(data);\n}\n\nexport function utf8(value: string): Uint8Array<ArrayBuffer> {\n return new TextEncoder().encode(value);\n}\n\nexport function b64encode(data: ArrayBuffer | Uint8Array): string {\n const bytes = bytesOf(data);\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 1) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/g, \"\");\n}\n\nexport function b64decode(value: string): Uint8Array<ArrayBuffer> {\n const padded = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const pad =\n padded.length % 4 === 0 ? \"\" : \"=\".repeat(4 - (padded.length % 4));\n const binary = atob(padded + pad);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\nexport async function generateEcdhPair(): Promise<CryptoKeyPair> {\n return crypto.subtle.generateKey(ECDH, true, [\"deriveBits\"]);\n}\n\nexport async function exportPublicKey(key: CryptoKey): Promise<string> {\n return b64encode(await crypto.subtle.exportKey(\"spki\", key));\n}\n\nexport async function importPublicKey(spki: string): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n \"spki\",\n bytesOf(b64decode(spki)),\n ECDH,\n true,\n [],\n );\n}\n\nasync function deriveAesKey(\n privateKey: CryptoKey,\n publicKey: CryptoKey,\n): Promise<CryptoKey> {\n const bits = await crypto.subtle.deriveBits(\n { name: \"ECDH\", public: publicKey },\n privateKey,\n 256,\n );\n const ikm = await crypto.subtle.importKey(\"raw\", bits, \"HKDF\", false, [\n \"deriveKey\",\n ]);\n return crypto.subtle.deriveKey(\n { name: \"HKDF\", hash: \"SHA-256\", salt: utf8(\"p-ch\"), info: utf8(\"aes\") },\n ikm,\n AES,\n false,\n [\"encrypt\", \"decrypt\"],\n );\n}\n\nexport async function sharedAesKey(\n privateKey: CryptoKey,\n publicKey: CryptoKey,\n): Promise<CryptoKey> {\n return deriveAesKey(privateKey, publicKey);\n}\n\nexport async function encryptJson(\n key: CryptoKey,\n payload: unknown,\n): Promise<{ i: string; c: string }> {\n const iv = bytesOf(crypto.getRandomValues(new Uint8Array(12)));\n const ct = await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv },\n key,\n utf8(JSON.stringify(payload)),\n );\n return { i: b64encode(iv), c: b64encode(ct) };\n}\n\nexport async function decryptJson<T>(\n key: CryptoKey,\n i: string,\n c: string,\n): Promise<T> {\n const pt = await crypto.subtle.decrypt(\n { name: \"AES-GCM\", iv: bytesOf(b64decode(i)) },\n key,\n bytesOf(b64decode(c)),\n );\n return JSON.parse(new TextDecoder().decode(pt)) as T;\n}\n\nasync function sealKey(secret: string): Promise<CryptoKey> {\n const ikm = await crypto.subtle.importKey(\n \"raw\",\n bytesOf(utf8(secret)),\n \"HKDF\",\n false,\n [\"deriveKey\"],\n );\n return crypto.subtle.deriveKey(\n { name: \"HKDF\", hash: \"SHA-256\", salt: utf8(\"p-tk\"), info: utf8(\"seal\") },\n ikm,\n AES,\n false,\n [\"encrypt\", \"decrypt\"],\n );\n}\n\nexport async function sealTicket(\n secret: string,\n sharedBits: ArrayBuffer,\n ttlMs = 2 * 60 * 60 * 1000,\n): Promise<string> {\n const key = await sealKey(secret);\n const iv = bytesOf(crypto.getRandomValues(new Uint8Array(12)));\n const body = utf8(\n JSON.stringify({\n s: b64encode(sharedBits),\n exp: Date.now() + ttlMs,\n }),\n );\n const ct = await crypto.subtle.encrypt({ name: \"AES-GCM\", iv }, key, body);\n const packed = new Uint8Array(iv.length + ct.byteLength);\n packed.set(iv, 0);\n packed.set(new Uint8Array(ct), iv.length);\n return b64encode(packed);\n}\n\nexport async function openTicket(\n secret: string,\n ticket: string,\n): Promise<CryptoKey> {\n const key = await sealKey(secret);\n const packed = b64decode(ticket);\n if (packed.byteLength < 13) {\n throw new Error(\"bad ticket\");\n }\n const iv = bytesOf(packed.slice(0, 12));\n const ct = bytesOf(packed.slice(12));\n const pt = await crypto.subtle.decrypt({ name: \"AES-GCM\", iv }, key, ct);\n const parsed = JSON.parse(new TextDecoder().decode(pt)) as {\n s?: string;\n exp?: number;\n };\n if (!parsed.s || !parsed.exp || Date.now() > parsed.exp) {\n throw new Error(\"expired ticket\");\n }\n const bits = bytesOf(b64decode(parsed.s));\n const ikm = await crypto.subtle.importKey(\"raw\", bits, \"HKDF\", false, [\n \"deriveKey\",\n ]);\n return crypto.subtle.deriveKey(\n { name: \"HKDF\", hash: \"SHA-256\", salt: utf8(\"p-ch\"), info: utf8(\"aes\") },\n ikm,\n AES,\n false,\n [\"encrypt\", \"decrypt\"],\n );\n}\n\nexport async function ecdhBits(\n privateKey: CryptoKey,\n publicKey: CryptoKey,\n): Promise<ArrayBuffer> {\n return crypto.subtle.deriveBits(\n { name: \"ECDH\", public: publicKey },\n privateKey,\n 256,\n );\n}\n","import { PasslineSession } from \"../component/types\";\nimport {\n decryptJson,\n encryptJson,\n exportPublicKey,\n generateEcdhPair,\n importPublicKey,\n PASSLINE_GATEWAY,\n PROXY_PATH,\n sharedAesKey,\n type HandshakeResponse,\n type RpcResponse,\n} from \"../crypto/envelope\";\n\nexport type ChatbotSessionResponse = {\n sessionId: string;\n greeting: string;\n assistantName: string;\n companyName: string | null;\n logoUrl: string | null;\n};\n\nexport type ChatbotMessageResponse = {\n reply: string;\n};\n\nexport class PasslineApiError extends Error {\n readonly code?: string;\n readonly status?: number;\n\n constructor(message: string, options?: { code?: string; status?: number }) {\n super(message);\n this.name = \"PasslineApiError\";\n this.code = options?.code;\n this.status = options?.status;\n }\n}\n\nexport function isOfflineError(err: unknown): boolean {\n if (!err) return false;\n if (err instanceof PasslineApiError && err.code === \"OFFLINE\") return true;\n const message = err instanceof Error ? err.message : \"\";\n return /offline|failed to fetch|networkerror|load failed|request failed \\(5\\d\\d\\)/i.test(\n message,\n );\n}\n\nexport function isSessionInvalidError(err: unknown): boolean {\n const message = err instanceof Error ? err.message.toLowerCase() : \"\";\n return /session/.test(message) && /(not found|expired|invalid)/.test(message);\n}\n\nexport class PasslineApi {\n private token: string;\n private channel: { key: CryptoKey; ticket: string } | null = null;\n private handshake: Promise<void> | null = null;\n\n constructor(token: string) {\n this.token = token;\n }\n\n private gatewayUrl(): string {\n return `${PASSLINE_GATEWAY}${PROXY_PATH}`;\n }\n\n private async postJson(\n body: unknown,\n ): Promise<{ status: number; payload: unknown }> {\n let response: Response;\n try {\n response = await fetch(this.gatewayUrl(), {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n cache: \"no-store\",\n });\n } catch {\n throw new PasslineApiError(\"Offline\", { code: \"OFFLINE\" });\n }\n const payload = await response.json().catch(() => null);\n return { status: response.status, payload };\n }\n\n private throwIfFailed(status: number, payload: unknown): void {\n if (status >= 200 && status < 300) return;\n if (status >= 500 || status === 0) {\n throw new PasslineApiError(\"Offline\", { code: \"OFFLINE\", status });\n }\n const message =\n payload && typeof payload === \"object\" && \"message\" in payload\n ? String((payload as { message?: string }).message || \"\")\n : \"\";\n throw new PasslineApiError(message || `Request failed (${status})`, {\n status,\n });\n }\n\n private async ensureChannel(): Promise<{ key: CryptoKey; ticket: string }> {\n if (this.channel) return this.channel;\n if (!this.handshake) {\n this.handshake = this.openChannel().finally(() => {\n this.handshake = null;\n });\n }\n await this.handshake;\n if (!this.channel) {\n throw new PasslineApiError(\"Offline\", { code: \"OFFLINE\" });\n }\n return this.channel;\n }\n\n private async openChannel(): Promise<void> {\n const pair = await generateEcdhPair();\n const { status, payload } = await this.postJson({\n v: 1,\n op: \"h\",\n c: await exportPublicKey(pair.publicKey),\n });\n if (status >= 500) {\n throw new PasslineApiError(\"Offline\", { code: \"OFFLINE\", status });\n }\n const handshake = payload as HandshakeResponse | null;\n if (!handshake?.s || !handshake.t) {\n throw new PasslineApiError(\"Unable to start chat\", { status });\n }\n const serverPub = await importPublicKey(handshake.s);\n this.channel = {\n key: await sharedAesKey(pair.privateKey, serverPub),\n ticket: handshake.t,\n };\n }\n\n private async request<T>(\n route: \"s\" | \"m\",\n data: Record<string, unknown>,\n ): Promise<T> {\n const run = async (): Promise<T> => {\n const channel = await this.ensureChannel();\n const encrypted = await encryptJson(channel.key, {\n r: route,\n d: data,\n k: this.token,\n });\n const { status, payload } = await this.postJson({\n v: 1,\n op: \"x\",\n t: channel.ticket,\n ...encrypted,\n });\n if (status === 400 || status === 409) {\n this.channel = null;\n throw new PasslineApiError(\"retry\", { status });\n }\n const envelope = payload as RpcResponse | { message?: string } | null;\n if (!envelope || !(\"i\" in envelope) || !(\"c\" in envelope)) {\n this.throwIfFailed(status, payload);\n throw new PasslineApiError(\"Request failed\", { status });\n }\n const decoded = await decryptJson<T & { message?: string }>(\n channel.key,\n envelope.i,\n envelope.c,\n );\n this.throwIfFailed(status, decoded);\n return decoded;\n };\n\n try {\n return await run();\n } catch (error) {\n if (error instanceof PasslineApiError && error.message === \"retry\") {\n return run();\n }\n throw error;\n }\n }\n\n async createSession(options?: { locale?: string }): Promise<ChatbotSessionResponse> {\n const body: Record<string, unknown> = {};\n const locale = options?.locale?.trim();\n if (locale) body.locale = locale;\n return this.request<ChatbotSessionResponse>(\"s\", body);\n }\n\n async sendMessage(\n sessionId: string,\n message: string,\n ): Promise<ChatbotMessageResponse> {\n return this.request<ChatbotMessageResponse>(\"m\", {\n id: sessionId,\n message,\n });\n }\n}\n\nexport function toPasslineSession(\n response: ChatbotSessionResponse,\n messages: PasslineSession[\"messages\"] = [],\n): PasslineSession {\n return {\n sessionId: response.sessionId,\n assistantName: response.assistantName || \"Assistant\",\n companyName: response.companyName ?? null,\n logoUrl: response.logoUrl ?? null,\n greeting: response.greeting,\n messages,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { PasslineMessage, PasslineSession } from \"../component/types\";\nimport {\n isOfflineError,\n isSessionInvalidError,\n PasslineApi,\n toPasslineSession,\n} from \"../api/passlineApi\";\n\ninterface StoredSession {\n sessionId: string;\n assistantName?: string;\n companyName?: string | null;\n logoUrl?: string | null;\n messages: PasslineMessage[];\n updatedAt: number;\n}\n\nfunction nextMessageId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\nexport function usePasslineSession(\n token: string,\n persistSession: boolean = true,\n maxSessionAge: number = 7 * 24 * 60 * 60 * 1000,\n maxStoredMessages: number = 200,\n locale?: string,\n defaultGreeting: string = \"Hi! How can I help?\",\n) {\n const [session, setSession] = useState<PasslineSession | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [offline, setOffline] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const apiRef = useRef(new PasslineApi(token));\n const sessionRef = useRef<PasslineSession | null>(null);\n const bootIdRef = useRef(0);\n const storageKey = locale\n ? `passline:chat:${token}:${locale}`\n : `passline:chat:${token}`;\n\n sessionRef.current = session;\n\n useEffect(() => {\n apiRef.current = new PasslineApi(token);\n }, [token]);\n\n const readStoredSession = useCallback((): StoredSession | null => {\n if (!persistSession || typeof window === \"undefined\") return null;\n\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (!raw) return null;\n\n const parsed = JSON.parse(raw) as StoredSession;\n if (!parsed?.sessionId || !Array.isArray(parsed.messages)) {\n return null;\n }\n\n if (Date.now() - (parsed.updatedAt || 0) > maxSessionAge) {\n window.localStorage.removeItem(storageKey);\n return null;\n }\n\n return parsed;\n } catch {\n return null;\n }\n }, [maxSessionAge, persistSession, storageKey]);\n\n const writeStoredSession = useCallback(\n (data: StoredSession) => {\n if (!persistSession || typeof window === \"undefined\") return;\n\n try {\n const messages =\n data.messages.length > maxStoredMessages\n ? data.messages.slice(data.messages.length - maxStoredMessages)\n : data.messages;\n window.localStorage.setItem(\n storageKey,\n JSON.stringify({ ...data, messages }),\n );\n } catch {\n // Private browsing or quota exceeded — degrade to in-memory only.\n }\n },\n [maxStoredMessages, persistSession, storageKey],\n );\n\n const clearStoredSession = useCallback(() => {\n if (!persistSession || typeof window === \"undefined\") return;\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }, [persistSession, storageKey]);\n\n const persistFromSession = useCallback(\n (next: PasslineSession) => {\n writeStoredSession({\n sessionId: next.sessionId,\n assistantName: next.assistantName,\n companyName: next.companyName,\n logoUrl: next.logoUrl,\n messages: next.messages,\n updatedAt: Date.now(),\n });\n },\n [writeStoredSession],\n );\n\n const goOffline = useCallback(() => {\n setOffline(true);\n setSession(null);\n sessionRef.current = null;\n setError(\"Offline\");\n setIsLoading(false);\n }, []);\n\n const restoreCachedSession = useCallback((): PasslineSession | null => {\n const stored = readStoredSession();\n if (!stored) return null;\n\n const restored: PasslineSession = {\n sessionId: stored.sessionId,\n assistantName: stored.assistantName || \"Assistant\",\n companyName: stored.companyName ?? null,\n logoUrl: stored.logoUrl ?? null,\n messages: stored.messages,\n };\n setSession(restored);\n sessionRef.current = restored;\n setOffline(false);\n setError(null);\n setIsLoading(false);\n return restored;\n }, [readStoredSession]);\n\n const createSession = useCallback(\n async (forceNew: boolean = false): Promise<PasslineSession> => {\n const bootId = ++bootIdRef.current;\n setError(null);\n\n if (!forceNew) {\n const restored = restoreCachedSession();\n if (restored) return restored;\n }\n\n try {\n setIsLoading(true);\n const response = await apiRef.current.createSession(\n locale ? { locale } : undefined,\n );\n if (bootIdRef.current !== bootId) {\n const current = sessionRef.current;\n if (current) return current;\n }\n\n const greeting = response.greeting || defaultGreeting;\n const next = toPasslineSession(response, [\n {\n id: \"greeting\",\n role: \"assistant\",\n content: greeting,\n timestamp: Date.now(),\n },\n ]);\n\n setSession(next);\n sessionRef.current = next;\n setOffline(false);\n persistFromSession(next);\n return next;\n } catch (err) {\n if (bootIdRef.current !== bootId) {\n const current = sessionRef.current;\n if (current) return current;\n }\n if (isOfflineError(err)) {\n goOffline();\n throw new Error(\"Offline\");\n }\n const errorMessage =\n err instanceof Error ? err.message : \"Unable to start chat\";\n setError(errorMessage);\n setSession(null);\n sessionRef.current = null;\n throw new Error(errorMessage);\n } finally {\n if (bootIdRef.current === bootId) {\n setIsLoading(false);\n }\n }\n },\n [defaultGreeting, goOffline, locale, persistFromSession, restoreCachedSession],\n );\n\n const ensureSession = useCallback(async (): Promise<PasslineSession | null> => {\n if (offline) return null;\n if (sessionRef.current?.sessionId) return sessionRef.current;\n try {\n return await createSession(false);\n } catch {\n return null;\n }\n }, [createSession, offline]);\n\n const sendMessage = useCallback(\n async (content: string): Promise<PasslineMessage> => {\n const active = sessionRef.current;\n if (!active?.sessionId) {\n throw new Error(\"No active session\");\n }\n\n const userMessage: PasslineMessage = {\n id: nextMessageId(\"u\"),\n role: \"user\",\n content,\n timestamp: Date.now(),\n };\n\n const withUser: PasslineSession = {\n ...active,\n messages: [...active.messages, userMessage],\n };\n setSession(withUser);\n sessionRef.current = withUser;\n persistFromSession(withUser);\n\n try {\n const response = await apiRef.current.sendMessage(\n active.sessionId,\n content,\n );\n\n const assistantMessage: PasslineMessage = {\n id: nextMessageId(\"a\"),\n role: \"assistant\",\n content: response.reply || \"\",\n timestamp: Date.now(),\n };\n\n const latest = sessionRef.current ?? withUser;\n const withAssistant: PasslineSession = {\n ...latest,\n messages: [...latest.messages, assistantMessage],\n };\n setSession(withAssistant);\n sessionRef.current = withAssistant;\n persistFromSession(withAssistant);\n return assistantMessage;\n } catch (err) {\n if (isOfflineError(err)) {\n goOffline();\n throw new Error(\"Offline\");\n }\n if (isSessionInvalidError(err)) {\n clearStoredSession();\n setSession(null);\n sessionRef.current = null;\n await createSession(true);\n throw new Error(\"Session expired. Please try your message again.\");\n }\n throw err;\n }\n },\n [clearStoredSession, createSession, goOffline, persistFromSession],\n );\n\n const newChat = useCallback(async () => {\n clearStoredSession();\n setSession(null);\n sessionRef.current = null;\n setOffline(false);\n return createSession(true);\n }, [clearStoredSession, createSession]);\n\n useEffect(() => {\n bootIdRef.current += 1;\n setSession(null);\n sessionRef.current = null;\n setOffline(false);\n setError(null);\n setIsLoading(false);\n restoreCachedSession();\n }, [restoreCachedSession, token, locale]);\n\n return {\n session,\n messages: session?.messages || [],\n isLoading,\n offline,\n error,\n sendMessage,\n newChat,\n createSession,\n ensureSession,\n clearStoredSession,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { usePasslineSession } from \"./usePasslineSession\";\nimport { PasslineMessage, PasslineSession } from \"../component/types\";\n\nexport function usePasslineChat(\n token: string,\n options?: {\n locale?: string;\n defaultGreeting?: string;\n persistSession?: boolean;\n maxSessionAge?: number;\n maxStoredMessages?: number;\n autoOpen?: boolean;\n onMessageSend?: (message: string) => void;\n onMessageReceive?: (message: PasslineMessage) => void;\n onError?: (error: Error) => void;\n onSessionStart?: (session: PasslineSession) => void;\n },\n) {\n const [isOpen, setIsOpen] = useState(Boolean(options?.autoOpen));\n const [isSending, setIsSending] = useState(false);\n const lastSessionIdRef = useRef<string | null>(null);\n\n const {\n session,\n messages,\n isLoading,\n offline,\n error,\n sendMessage: sendMessageApi,\n newChat: newChatApi,\n ensureSession,\n } = usePasslineSession(\n token,\n options?.persistSession,\n options?.maxSessionAge,\n options?.maxStoredMessages,\n options?.locale,\n options?.defaultGreeting,\n );\n\n useEffect(() => {\n if (options?.autoOpen) {\n setIsOpen(true);\n }\n }, [options?.autoOpen]);\n\n useEffect(() => {\n lastSessionIdRef.current = null;\n }, [token, options?.locale]);\n\n useEffect(() => {\n if (!isOpen || offline) {\n return;\n }\n void ensureSession();\n }, [ensureSession, isOpen, offline, token, options?.locale]);\n\n useEffect(() => {\n if (!session?.sessionId || session.sessionId === lastSessionIdRef.current) {\n return;\n }\n lastSessionIdRef.current = session.sessionId;\n options?.onSessionStart?.(session);\n }, [options, session]);\n\n useEffect(() => {\n if (error && options?.onError) {\n options.onError(new Error(error));\n }\n }, [error, options]);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!content.trim() || isSending || isLoading || offline) return;\n\n try {\n setIsSending(true);\n options?.onMessageSend?.(content);\n const response = await sendMessageApi(content);\n options?.onMessageReceive?.(response);\n } catch (err) {\n options?.onError?.(\n err instanceof Error ? err : new Error(\"Failed to send message\"),\n );\n } finally {\n setIsSending(false);\n }\n },\n [isLoading, isSending, offline, options, sendMessageApi],\n );\n\n const newChat = useCallback(async () => {\n try {\n await newChatApi();\n } catch (err) {\n options?.onError?.(\n err instanceof Error ? err : new Error(\"Failed to start new chat\"),\n );\n }\n }, [newChatApi, options]);\n\n const toggleOpen = useCallback(() => {\n setIsOpen((prev) => !prev);\n }, []);\n\n return {\n isOpen,\n setIsOpen,\n toggleOpen,\n isSending,\n isLoading,\n offline,\n messages,\n session,\n error,\n sendMessage,\n newChat,\n };\n}\n","export interface PasslineChatLabels {\n assistant: string;\n offline: string;\n unavailable: string;\n connecting: string;\n online: string;\n typeMessage: string;\n send: string;\n openChat: string;\n closeChat: string;\n newChat: string;\n newChatTitle: string;\n typing: string;\n panelAriaLabel: string;\n organizationLogo: string;\n defaultGreeting: string;\n}\n\nexport const DEFAULT_PASSLINE_CHAT_LABELS: PasslineChatLabels = {\n assistant: \"Assistant\",\n offline: \"Offline\",\n unavailable: \"Unavailable\",\n connecting: \"Connecting…\",\n online: \"Online\",\n typeMessage: \"Type a message…\",\n send: \"Send\",\n openChat: \"Open chat\",\n closeChat: \"Close chat\",\n newChat: \"Start new chat\",\n newChatTitle: \"Start new chat\",\n typing: \"Assistant is typing…\",\n panelAriaLabel: \"Passline chat\",\n organizationLogo: \"Organization logo\",\n defaultGreeting: \"Hi! How can I help?\",\n};\n\nexport function mergePasslineChatLabels(\n labels?: Partial<PasslineChatLabels>,\n): PasslineChatLabels {\n return { ...DEFAULT_PASSLINE_CHAT_LABELS, ...labels };\n}\n","/// <reference path=\"../css.d.ts\" />\nimport React, {\n useState,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n} from \"react\";\nimport { usePasslineChat } from \"../hooks/usePasslineClient\";\nimport { PasslineChatProps, PasslineMessage, PasslineTheme } from \"./types\";\nimport { mergePasslineChatLabels } from \"./labels\";\nimport \"./PasslineChat.css\";\n\nconst CHAT_ICON =\n \"M4 4h16a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H9l-5 4v-4H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z\";\n\nconst defaultTheme: Required<PasslineTheme> = {\n primaryColor: \"#0f766e\",\n primaryHoverColor: \"#0d9488\",\n backgroundColor: \"#f8fafc\",\n textColor: \"#0f172a\",\n userBubbleColor: \"#0f766e\",\n userBubbleTextColor: \"#ffffff\",\n assistantBubbleColor: \"#ffffff\",\n assistantBubbleTextColor: \"#1e293b\",\n borderRadius: \"16px\",\n borderWidth: \"1px\",\n borderColor: \"#e2e8f0\",\n buttonSize: \"medium\",\n buttonBorderRadius: \"999px\",\n buttonBackgroundColor: \"#0f766e\",\n buttonHoverColor: \"#0d9488\",\n buttonIconColor: \"#ffffff\",\n panelWidth: \"380px\",\n panelHeight: \"560px\",\n panelShadow: \"0 12px 40px rgba(0,0,0,.22)\",\n fontFamily:\n \"system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: \"14px\",\n spacing: \"12px\",\n padding: \"12px\",\n className: \"\",\n buttonClassName: \"\",\n panelClassName: \"\",\n headerClassName: \"\",\n messagesClassName: \"\",\n inputClassName: \"\",\n};\n\nfunction brandingInitials(label?: string | null): string {\n const parts = String(label || \"\")\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n if (parts.length === 0) return \"A\";\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();\n return (parts[0].charAt(0) + parts[1].charAt(0)).toUpperCase();\n}\n\nfunction BrandMark({\n logoUrl,\n label,\n logoAlt = \"Organization logo\",\n fallback = \"initials\",\n className,\n backgroundColor,\n}: {\n logoUrl?: string | null;\n label: string;\n logoAlt?: string;\n fallback?: \"initials\" | \"icon\";\n className: string;\n backgroundColor?: string;\n}) {\n const [broken, setBroken] = useState(false);\n\n useEffect(() => {\n setBroken(false);\n }, [logoUrl]);\n\n const showLogo = Boolean(logoUrl) && !broken;\n\n return (\n <div\n className={`${className}${showLogo ? \" passline-has-logo\" : \"\"}`}\n style={showLogo ? undefined : { backgroundColor }}\n >\n {showLogo ? (\n <img\n src={logoUrl ?? \"\"}\n alt={label || logoAlt}\n className=\"passline-chat-avatar-img\"\n onError={() => setBroken(true)}\n />\n ) : fallback === \"icon\" ? (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d={CHAT_ICON} />\n </svg>\n ) : (\n brandingInitials(label)\n )}\n </div>\n );\n}\n\nexport const PasslineChat: React.FC<PasslineChatProps> = ({\n token,\n locale,\n labels: labelsProp,\n theme = {},\n className = \"\",\n buttonClassName = \"\",\n panelClassName = \"\",\n renderButton,\n renderHeader,\n renderMessage,\n renderInput,\n autoOpen = false,\n persistSession = true,\n maxSessionAge,\n maxStoredMessages,\n onOpen,\n onClose,\n onMessageSend,\n onMessageReceive,\n onError,\n onSessionStart,\n onNewChat,\n}) => {\n const mergedTheme = { ...defaultTheme, ...theme };\n const labels = useMemo(\n () => mergePasslineChatLabels(labelsProp),\n [labelsProp],\n );\n const [inputValue, setInputValue] = useState(\"\");\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const wasOpenRef = useRef(false);\n\n const {\n isOpen,\n setIsOpen,\n toggleOpen,\n isSending,\n isLoading,\n offline,\n messages,\n session,\n error,\n sendMessage,\n newChat,\n } = usePasslineChat(token, {\n locale,\n defaultGreeting: labels.defaultGreeting,\n persistSession,\n maxSessionAge,\n maxStoredMessages,\n autoOpen,\n onMessageSend,\n onMessageReceive,\n onError,\n onSessionStart,\n });\n\n const brandLabel =\n session?.companyName || session?.assistantName || labels.assistant;\n const inputLocked = isLoading || offline || !session?.sessionId;\n const subtitle = offline\n ? labels.offline\n : error && !session\n ? labels.unavailable\n : session?.companyName || (isLoading ? labels.connecting : labels.online);\n const placeholder = offline\n ? labels.offline\n : isLoading\n ? labels.connecting\n : session?.sessionId\n ? labels.typeMessage\n : labels.unavailable;\n\n useEffect(() => {\n if (autoOpen) {\n setIsOpen(true);\n }\n }, [autoOpen, setIsOpen]);\n\n useEffect(() => {\n if (isOpen === wasOpenRef.current) {\n return;\n }\n wasOpenRef.current = isOpen;\n if (isOpen) {\n onOpen?.();\n } else {\n onClose?.();\n }\n }, [isOpen, onOpen, onClose]);\n\n useEffect(() => {\n if (!isOpen || offline) {\n return;\n }\n const focusTimer = window.setTimeout(() => {\n inputRef.current?.focus();\n }, 100);\n return () => window.clearTimeout(focusTimer);\n }, [isOpen, offline]);\n\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages, isSending, isLoading]);\n\n const handleSend = useCallback(() => {\n if (inputValue.trim() && !isSending && !inputLocked) {\n sendMessage(inputValue);\n setInputValue(\"\");\n }\n }, [inputLocked, inputValue, isSending, sendMessage]);\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n handleSend();\n }\n },\n [handleSend],\n );\n\n const handleNewChat = useCallback(() => {\n void newChat();\n onNewChat?.();\n }, [newChat, onNewChat]);\n\n const buttonSizePx =\n mergedTheme.buttonSize === \"small\"\n ? \"44px\"\n : mergedTheme.buttonSize === \"large\"\n ? \"64px\"\n : \"56px\";\n\n const headerTitle = session?.assistantName || labels.assistant;\n\n return (\n <div\n className={`passline-chat-wrapper ${mergedTheme.className} ${className}`}\n >\n {isOpen ? (\n <div\n className={`passline-chat-panel ${mergedTheme.panelClassName} ${panelClassName}`}\n role=\"dialog\"\n aria-label={labels.panelAriaLabel}\n style={{\n width: mergedTheme.panelWidth,\n height: mergedTheme.panelHeight,\n boxShadow: mergedTheme.panelShadow,\n backgroundColor: mergedTheme.backgroundColor,\n borderRadius: mergedTheme.borderRadius,\n fontFamily: mergedTheme.fontFamily,\n fontSize: mergedTheme.fontSize,\n color: mergedTheme.textColor,\n }}\n >\n {renderHeader ? (\n renderHeader({\n title: headerTitle,\n subtitle,\n avatar: brandingInitials(brandLabel),\n onNewChat: handleNewChat,\n })\n ) : (\n <div\n className={`passline-chat-header ${mergedTheme.headerClassName}`}\n >\n <BrandMark\n logoUrl={session?.logoUrl}\n label={brandLabel}\n logoAlt={labels.organizationLogo}\n className=\"passline-header-avatar\"\n backgroundColor={mergedTheme.primaryColor}\n />\n <div className=\"passline-header-info\">\n <div className=\"passline-header-title\">{headerTitle}</div>\n <div className=\"passline-header-subtitle\">{subtitle}</div>\n </div>\n <button\n className=\"passline-header-newchat\"\n onClick={handleNewChat}\n title={labels.newChatTitle}\n aria-label={labels.newChat}\n style={{ color: mergedTheme.textColor }}\n type=\"button\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M17.65 6.35A7.95 7.95 0 0 0 12 4a8 8 0 1 0 7.75 10h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4z\" />\n </svg>\n </button>\n </div>\n )}\n\n <div\n className={`passline-chat-messages ${mergedTheme.messagesClassName}`}\n >\n {isLoading && messages.length === 0 ? (\n <p className=\"passline-chat-meta\">{labels.connecting}</p>\n ) : null}\n\n {messages.map((message: PasslineMessage, index: number) => (\n <React.Fragment key={message.id || index}>\n {renderMessage ? (\n renderMessage({ message, className: \"\" })\n ) : (\n <div\n className={`passline-message ${message.role === \"user\" ? \"message-user\" : \"message-assistant\"}`}\n style={{\n backgroundColor:\n message.role === \"user\"\n ? mergedTheme.userBubbleColor\n : mergedTheme.assistantBubbleColor,\n color:\n message.role === \"user\"\n ? mergedTheme.userBubbleTextColor\n : mergedTheme.assistantBubbleTextColor,\n borderRadius: mergedTheme.borderRadius,\n border:\n message.role === \"assistant\"\n ? `${mergedTheme.borderWidth} solid ${mergedTheme.borderColor}`\n : \"none\",\n }}\n >\n {message.content}\n </div>\n )}\n </React.Fragment>\n ))}\n\n {isSending ? (\n <p className=\"passline-chat-typing\">{labels.typing}</p>\n ) : null}\n\n {error ? <p className=\"passline-chat-error\">{error}</p> : null}\n <div ref={messagesEndRef} />\n </div>\n\n {renderInput ? (\n renderInput({\n value: inputValue,\n onChange: setInputValue,\n onSend: handleSend,\n disabled: inputLocked || isSending,\n placeholder,\n className: \"\",\n })\n ) : (\n <div\n className={`passline-chat-input-container ${mergedTheme.inputClassName}`}\n >\n <input\n ref={inputRef}\n type=\"text\"\n className=\"passline-chat-input\"\n value={inputValue}\n onChange={(event) => setInputValue(event.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={inputLocked}\n autoComplete=\"off\"\n style={{\n borderColor: mergedTheme.borderColor,\n borderRadius: mergedTheme.borderRadius,\n backgroundColor: mergedTheme.backgroundColor,\n color: mergedTheme.textColor,\n fontFamily: mergedTheme.fontFamily,\n fontSize: mergedTheme.fontSize,\n }}\n />\n <button\n className=\"passline-chat-send\"\n onClick={handleSend}\n disabled={inputLocked || isSending || !inputValue.trim()}\n style={{\n backgroundColor: mergedTheme.primaryColor,\n borderRadius: mergedTheme.borderRadius,\n color: \"#ffffff\",\n }}\n type=\"button\"\n >\n {labels.send}\n </button>\n </div>\n )}\n </div>\n ) : null}\n\n {renderButton ? (\n renderButton({ onClick: toggleOpen, isOpen, className: \"\" })\n ) : (\n <button\n className={`passline-chat-button ${mergedTheme.buttonClassName} ${buttonClassName}`}\n onClick={toggleOpen}\n style={{\n backgroundColor: session?.logoUrl\n ? undefined\n : isOpen\n ? mergedTheme.primaryHoverColor\n : mergedTheme.buttonBackgroundColor,\n color: mergedTheme.buttonIconColor,\n borderRadius: mergedTheme.buttonBorderRadius,\n width: buttonSizePx,\n height: buttonSizePx,\n }}\n aria-label={isOpen ? labels.closeChat : labels.openChat}\n type=\"button\"\n >\n <BrandMark\n logoUrl={session?.logoUrl}\n label={brandLabel}\n logoAlt={labels.organizationLogo}\n fallback=\"icon\"\n className=\"passline-chat-button-mark\"\n />\n </button>\n )}\n </div>\n );\n};\n"],"names":["ECDH","name","namedCurve","AES","length","bytesOf","data","Uint8Array","copy","byteLength","set","utf8","value","TextEncoder","encode","b64encode","bytes","binary","i","String","fromCharCode","btoa","replace","b64decode","padded","pad","repeat","atob","charCodeAt","async","exportPublicKey","key","crypto","subtle","exportKey","sharedAesKey","privateKey","publicKey","bits","deriveBits","public","ikm","importKey","deriveKey","hash","salt","info","deriveAesKey","PasslineApiError","Error","constructor","message","options","super","this","code","status","isOfflineError","err","test","PasslineApi","token","channel","handshake","gatewayUrl","postJson","body","response","fetch","method","headers","Accept","JSON","stringify","cache","payload","json","catch","throwIfFailed","ensureChannel","openChannel","finally","pair","generateKey","generateEcdhPair","v","op","c","s","t","serverPub","spki","importPublicKey","ticket","request","route","run","encrypted","iv","getRandomValues","ct","encrypt","encryptJson","r","d","k","envelope","decoded","pt","decrypt","parse","TextDecoder","decode","decryptJson","error","createSession","locale","trim","sendMessage","sessionId","id","nextMessageId","prefix","Date","now","Math","random","toString","slice","usePasslineSession","persistSession","maxSessionAge","maxStoredMessages","defaultGreeting","session","setSession","useState","isLoading","setIsLoading","offline","setOffline","setError","apiRef","useRef","sessionRef","bootIdRef","storageKey","current","useEffect","readStoredSession","useCallback","window","raw","localStorage","getItem","parsed","Array","isArray","messages","updatedAt","removeItem","writeStoredSession","setItem","clearStoredSession","persistFromSession","next","assistantName","companyName","logoUrl","goOffline","restoreCachedSession","stored","restored","forceNew","bootId","undefined","greeting","toPasslineSession","role","content","timestamp","errorMessage","ensureSession","active","userMessage","withUser","assistantMessage","reply","latest","withAssistant","toLowerCase","isSessionInvalidError","newChat","usePasslineChat","isOpen","setIsOpen","Boolean","autoOpen","isSending","setIsSending","lastSessionIdRef","sendMessageApi","newChatApi","onSessionStart","onError","onMessageSend","onMessageReceive","toggleOpen","prev","DEFAULT_PASSLINE_CHAT_LABELS","assistant","unavailable","connecting","online","typeMessage","send","openChat","closeChat","newChatTitle","typing","panelAriaLabel","organizationLogo","mergePasslineChatLabels","labels","defaultTheme","primaryColor","primaryHoverColor","backgroundColor","textColor","userBubbleColor","userBubbleTextColor","assistantBubbleColor","assistantBubbleTextColor","borderRadius","borderWidth","borderColor","buttonSize","buttonBorderRadius","buttonBackgroundColor","buttonHoverColor","buttonIconColor","panelWidth","panelHeight","panelShadow","fontFamily","fontSize","spacing","padding","className","buttonClassName","panelClassName","headerClassName","messagesClassName","inputClassName","brandingInitials","label","parts","split","filter","toUpperCase","charAt","BrandMark","logoAlt","fallback","broken","setBroken","showLogo","_jsx","style","src","alt","viewBox","fill","labelsProp","theme","renderButton","renderHeader","renderMessage","renderInput","onOpen","onClose","onNewChat","mergedTheme","useMemo","inputValue","setInputValue","messagesEndRef","inputRef","wasOpenRef","brandLabel","inputLocked","subtitle","placeholder","focusTimer","setTimeout","focus","clearTimeout","scrollIntoView","behavior","handleSend","handleKeyDown","event","shiftKey","preventDefault","handleNewChat","buttonSizePx","headerTitle","_jsxs","children","width","height","boxShadow","color","title","avatar","onClick","type","map","index","React","Fragment","border","ref","onChange","onSend","disabled","target","onKeyDown","autoComplete"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "passline-ai",
3
- "version": "2.0.0",
3
+ "version": "2.1.3",
4
4
  "description": "Passline chat widget for React and Next.js applications",
5
5
  "license": "MIT",
6
6
  "author": "passline.ai",
@@ -69,10 +69,10 @@
69
69
  ],
70
70
  "repository": {
71
71
  "type": "git",
72
- "url": "https://github.com/Himexa-Tech/passline-chatbot.git"
72
+ "url": "https://github.com/passline-ai/passline-chatbot.git"
73
73
  },
74
74
  "bugs": {
75
- "url": "https://github.com/Himexa-Tech/passline-chatbot/issues"
75
+ "url": "https://github.com/passline-ai/passline-chatbot/issues"
76
76
  },
77
- "homepage": "https://github.com/Himexa-Tech/passline-chatbot#readme"
77
+ "homepage": "https://github.com/passline-ai/passline-chatbot#readme"
78
78
  }